diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS new file mode 100644 index 0000000000..0d310fb71f --- /dev/null +++ b/.forgejo/CODEOWNERS @@ -0,0 +1,96 @@ +# This file describes the expected reviewers for a PR based on the changed +# files. Unlike what the name of the file suggests they don't own the code, but +# merely have a good understanding of that area of the codebase and therefore +# are usually suited as a reviewer. + +# Lines in this file match changed paths via Go-Style regular expressions: +# https://pkg.go.dev/regexp/syntax + +# Mind the alphabetical order + +# avcodec +# ======= +libavcodec/.*aac.* @lynne +libavcodec/.*ac3.* @lynne +libavcodec/.*atrac9.* @lynne +libavcodec/.*bitpacked.* @lynne +libavcodec/.*d3d12va.* @jianhuaw +libavcodec/.*dirac.* @lynne +libavcodec/.*ffv1.* @lynne @michaelni +libavcodec/golomb.* @michaelni +libavcodec/.*h266.* @frankplow @NuoMi @jianhuaw +libavcodec/h26x/.* @frankplow @NuoMi @jianhuaw +libavcodec/.*jpegxl.* @lynne @Traneptora +libavcodec/.*jxl.* @lynne @Traneptora +libavcodec/.*opus.* @lynne +libavcodec/.*png.* @Traneptora +libavcodec/.*prores.* @lynne +libavcodec/rangecoder.* @michaelni +libavcodec/ratecontrol.* @michaelni +libavcodec/.*siren.* @lynne +libavcodec/.*vc2.* @lynne +libavcodec/.*vvc.* @frankplow @NuoMi @jianhuaw + +libavcodec/aarch64/.* @lynne @mstorsjo +libavcodec/arm/.* @mstorsjo +libavcodec/ppc/.* @sean_mcg +libavcodec/x86/.* @lynne + +# avfilter +# ======= +libavfilter/aarch64/.* @mstorsjo +libavfilter/af_whisper.* @vpalmisano +libavfilter/vf_yadif.* @michaelni +libavfilter/vsrc_mandelbrot.* @michaelni + +# avformat +# ======= +libavformat/iamf.* @jamrial +libavformat/.*jpegxl.* @Traneptora +libavformat/.*jxl.* @Traneptora + +# avutil +# ====== +libavutil/.*crc.* @lynne @michaelni +libavutil/.*d3d12va.* @jianhuaw +libavutil/eval.* @michaelni +libavutil/iamf.* @jamrial +libavutil/integer.* @michaelni +libavutil/lfg.* @michaelni +libavutil/lls.* @michaelni +libavutil/md5.* @michaelni +libavutil/mathematics.* @michaelni +libavutil/mem.* @michaelni +libavutil/qsort.* @michaelni +libavutil/random_seed.* @michaelni +libavutil/rational.* @michaelni +libavutil/sfc.* @michaelni +libavutil/softfloat.* @michaelni +libavutil/tree.* @michaelni +libavutil/tx.* @lynne + +libavutil/aarch64/.* @lynne @mstorsjo +libavutil/arm/.* @mstorsjo +libavutil/ppc/.* @sean_mcg +libavutil/x86/.* @lynne + +# swresample +# ======= +libswresample/aarch64/.* @mstorsjo +libswresample/arm/.* @mstorsjo +libswresample/.* @michaelni + +# swscale +# ======= +libswscale/aarch64/.* @mstorsjo +libswscale/arm/.* @mstorsjo +libswscale/ppc/.* @sean_mcg + +# doc +# === +doc/.* @GyanD + +# Frameworks +# ========== +.*d3d12va.* @jianhuaw +.*vulkan.* @lynne diff --git a/.forgejo/ISSUE_TEMPLATE.md b/.forgejo/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..d58e832b73 --- /dev/null +++ b/.forgejo/ISSUE_TEMPLATE.md @@ -0,0 +1,9 @@ +# Summary of the bug + +Briefly describe the issue you're experiencing. Include any error messages, unexpected behavior, or relevant observations. + +# Steps to reproduce + +List the steps required to trigger the bug. +Include the exact CLI command used, if any. +Provide sample input files, logs, or scripts if available. diff --git a/.forgejo/labeler/labeler.js b/.forgejo/labeler/labeler.js new file mode 100644 index 0000000000..b1c05787f0 --- /dev/null +++ b/.forgejo/labeler/labeler.js @@ -0,0 +1,72 @@ +module.exports = async ({github, context}) => { + const title = (context.payload.pull_request?.title || context.payload.issue?.title || '').toLowerCase(); + const labels = []; + const issueNumber = context.payload.pull_request?.number || context.payload.issue?.number; + + const kwmap = { + 'avcodec': 'avcodec', + 'avdevice': 'avdevice', + 'avfilter': 'avfilter', + 'avformat': 'avformat', + 'avutil': 'avutil', + 'swresample': 'swresample', + 'swscale': 'swscale', + 'fftools': 'CLI' + }; + + async function isOrgMember(username) { + try { + const response = await github.rest.orgs.checkMembershipForUser({ + org: context.repo.owner, + username: username + }); + return response.status === 204; + } catch (error) { + return false; + } + } + + if (context.payload.action === 'closed' || + (context.payload.action !== 'opened' && ( + context.payload.action === 'assigned' || + context.payload.action === 'label_updated' || + context.payload.comment) && + await isOrgMember(context.payload.sender.login)) + ) { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + // this should say 'new', but forgejo deviates from GitHub API here and expects the ID + name: '41' + }); + console.log('Removed "new" label'); + } catch (error) { + if (error.status !== 404 && error.status !== 410) { + console.log('Could not remove "new" label'); + } + } + } else if (context.payload.action === 'opened') { + labels.push('new'); + console.log('Detected label: new'); + } + + if ((context.payload.action === 'opened' || context.payload.action === 'edited') && context.eventName !== 'issue_comment') { + for (const [kw, label] of Object.entries(kwmap)) { + if (title.includes(kw)) { + labels.push(label); + console.log('Detected label: ' + label); + } + } + } + + if (labels.length > 0) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + labels: labels, + }); + } +} diff --git a/.forgejo/labeler/labeler.yml b/.forgejo/labeler/labeler.yml new file mode 100644 index 0000000000..9c4721cf29 --- /dev/null +++ b/.forgejo/labeler/labeler.yml @@ -0,0 +1,31 @@ +avcodec: + - changed-files: + - any-glob-to-any-file: libavcodec/** + +avdevice: + - changed-files: + - any-glob-to-any-file: libavdevice/** + +avfilter: + - changed-files: + - any-glob-to-any-file: libavfilter/** + +avformat: + - changed-files: + - any-glob-to-any-file: libavformat/** + +avutil: + - changed-files: + - any-glob-to-any-file: libavutil/** + +swresample: + - changed-files: + - any-glob-to-any-file: libswresample/** + +swscale: + - changed-files: + - any-glob-to-any-file: libswscale/** + +CLI: + - changed-files: + - any-glob-to-any-file: fftools/** diff --git a/.forgejo/pre-commit/config.yaml b/.forgejo/pre-commit/config.yaml new file mode 100644 index 0000000000..9a7041543f --- /dev/null +++ b/.forgejo/pre-commit/config.yaml @@ -0,0 +1,28 @@ +exclude: ^tests/ref/ + +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-illegal-windows-names + - id: check-shebang-scripts-are-executable + - id: check-yaml + - id: end-of-file-fixer + - id: file-contents-sorter + files: + .forgejo/pre-commit/ignored-words.txt + args: + - --ignore-case + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: trailing-whitespace +- repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + args: + - --ignore-words=.forgejo/pre-commit/ignored-words.txt + - --ignore-multiline-regex=codespell:off.*?(codespell:on|\Z) + exclude: ^tools/(patcheck|clean-diff)$ diff --git a/.forgejo/pre-commit/ignored-words.txt b/.forgejo/pre-commit/ignored-words.txt new file mode 100644 index 0000000000..870fd96be3 --- /dev/null +++ b/.forgejo/pre-commit/ignored-words.txt @@ -0,0 +1,119 @@ +abl +ACN +acount +addin +alis +alls +ALOG +ALS +als +ANC +anc +ANS +ans +anull +basf +bloc +brane +BREIF +BU +bu +bufer +CAF +caf +clen +clens +Collet +compre +dum +endin +erro +FIEL +fiel +filp +fils +FILTERD +filterd +fle +fo +FPR +fro +Hald +indx +ine +inh +inout +inouts +inport +ist +LAF +laf +lastr +LinS +mapp +mis +mot +nd +nIn +offsetp +orderd +ot +outout +padd +PAETH +paeth +PARM +parm +parms +pEvents +PixelX +Psot +quater +readd +recuse +redY +Reencode +reencode +remaind +renderD +rin +SAV +SEH +SER +ser +setts +shft +SIZ +siz +skipd +sme +som +sover +STAP +startd +statics +struc +suble +TE +tE +te +tha +tne +tolen +tpye +tre +TRUN +trun +truns +Tung +TYE +ue +UES +ues +vai +vas +vie +VILL +vor +wel +wih diff --git a/.forgejo/workflows/autolabel.yml b/.forgejo/workflows/autolabel.yml new file mode 100644 index 0000000000..cb4dac67aa --- /dev/null +++ b/.forgejo/workflows/autolabel.yml @@ -0,0 +1,28 @@ +on: + pull_request_target: + types: [opened, edited, synchronize, closed, assigned, labeled, unlabeled] + issues: + types: [opened, edited, closed, assigned, labeled, unlabeled] + issue_comment: + types: [created] + +jobs: + pr_labeler: + runs-on: utilities + if: ${{ github.event.sender.login != 'ffmpeg-devel' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Label by file-changes + uses: https://github.com/actions/labeler@v5 + if: ${{ forge.event_name == 'pull_request_target' }} + with: + configuration-path: .forgejo/labeler/labeler.yml + repo-token: ${{ secrets.AUTOLABELER_TOKEN }} + - name: Label by title-match + uses: https://github.com/actions/github-script@v7 + with: + script: | + const script = require('.forgejo/labeler/labeler.js') + await script({github, context}) + github-token: ${{ secrets.AUTOLABELER_TOKEN }} diff --git a/.forgejo/workflows/lint.yml b/.forgejo/workflows/lint.yml new file mode 100644 index 0000000000..42e925ad8b --- /dev/null +++ b/.forgejo/workflows/lint.yml @@ -0,0 +1,26 @@ +on: + push: + branches: + - master + pull_request: + +jobs: + lint: + runs-on: utilities + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install pre-commit CI + id: install + run: | + python3 -m venv ~/pre-commit + ~/pre-commit/bin/pip install --upgrade pip setuptools + ~/pre-commit/bin/pip install pre-commit + echo "envhash=$({ python3 --version && cat .forgejo/pre-commit/config.yaml; } | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT + - name: Cache + uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ steps.install.outputs.envhash }} + - name: Run pre-commit CI + run: ~/pre-commit/bin/pre-commit run -c .forgejo/pre-commit/config.yaml --show-diff-on-failure --color=always --all-files diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml new file mode 100644 index 0000000000..56e844ff4b --- /dev/null +++ b/.forgejo/workflows/test.yml @@ -0,0 +1,59 @@ +on: + push: + branches: + - master + pull_request: + +jobs: + run_fate: + strategy: + fail-fast: false + matrix: + runner: [linux-amd64,linux-aarch64] + runs-on: ${{ matrix.runner }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Configure + run: ./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 + - name: Build + run: make -j$(nproc) + - name: Restore Cached Fate-Suite + id: cache + uses: actions/cache/restore@v4 + with: + path: fate-suite + key: fate-suite + restore-keys: | + fate-suite- + - name: Sync Fate-Suite + id: fate + run: | + make fate-rsync SAMPLES=$PWD/fate-suite + echo "hash=$(find fate-suite -type f | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT + - name: Cache Fate-Suite + uses: actions/cache/save@v4 + if: ${{ format('fate-suite-{0}', steps.fate.outputs.hash) != steps.cache.outputs.cache-matched-key }} + with: + path: fate-suite + key: fate-suite-${{ steps.fate.outputs.hash }} + - name: Run Fate + run: make fate SAMPLES=$PWD/fate-suite -j$(nproc) + compile_only: + strategy: + fail-fast: false + matrix: + image: ["ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest"] + runs-on: linux-amd64 + container: ${{ matrix.image }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Configure + run: | + ./configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \ + --cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" --nm="$NM" \ + --extra-cflags="$FF_CFLAGS" --extra-cxxflags="$FF_CXXFLAGS" \ + --extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" --extra-ldexeflags="$FF_LDEXEFLAGS" + - name: Build + run: make -j$(nproc) diff --git a/.gitattributes b/.gitattributes index a900528e47..b64bbed2eb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.pnm -diff -text +Changelog merge=union diff --git a/.gitignore b/.gitignore index e810d11107..4aa49c52c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.a *.o +*.objs *.o.* *.d *.def @@ -41,3 +42,7 @@ /src /mapfile /tools/python/__pycache__/ +/libavcodec/vulkan/*.c +/libavfilter/vulkan/*.c +/.*/ +!/.forgejo/ diff --git a/.mailmap b/.mailmap index fe019b88c7..58383fa568 100644 --- a/.mailmap +++ b/.mailmap @@ -26,3 +26,5 @@ rcombs Cosmin Stejerean Cosmin Stejerean via ffmpeg-devel + + diff --git a/COPYING.LGPLv2.1 b/COPYING.LGPLv2.1 index 58af0d3787..40924c2a6d 100644 --- a/COPYING.LGPLv2.1 +++ b/COPYING.LGPLv2.1 @@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - + Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a @@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -158,7 +158,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -267,7 +267,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - + 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -422,7 +422,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is @@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest diff --git a/Changelog b/Changelog index 0c05ad2946..98b259f17f 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,45 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. +version : + + +version 8.0: +- Whisper filter +- Drop support for OpenSSL < 1.1.0 +- Enable TLS peer certificate verification by default (on next major version bump) +- Drop support for OpenSSL < 1.1.1 +- yasm support dropped, users need to use nasm +- VVC VAAPI decoder +- RealVideo 6.0 decoder +- OpenMAX encoders deprecated +- libx265 alpha layer encoding +- ADPCM IMA Xbox decoder +- Enhanced FLV v2: Multitrack audio/video, modern codec support +- Animated JPEG XL encoding (via libjxl) +- VVC in Matroska +- CENC AV1 support in MP4 muxer +- pngenc: set default prediction method to PAETH +- APV decoder and APV raw bitstream muxing and demuxing +- APV parser +- APV encoding support through a libopenapv wrapper +- VVC decoder supports all content of SCC (Screen Content Coding): + IBC (Inter Block Copy), Palette Mode and ACT (Adaptive Color Transform +- G.728 decoder +- pad_cuda filter +- Sanyo LD-ADPCM decoder +- APV in MP4/ISOBMFF muxing and demuxing +- OpenHarmony hardware decoder/encoder +- Colordetect filter +- Add vf_scale_d3d11 filter +- No longer disabling GCC autovectorization, on X86, ARM and AArch64 +- VP9 Vulkan hwaccel +- AV1 Vulkan encoder +- ProRes RAW decoder +- ProRes RAW Vulkan hwaccel +- ffprobe -codec option + + version 7.1: - Raw Captions with Time (RCWT) closed caption demuxer - LC3/LC3plus decoding/encoding using external library liblc3 @@ -27,6 +66,20 @@ version 7.1: - LCEVC enhancement data exporting in H.26x and MP4/ISOBMFF - LCEVC filter - MV-HEVC decoding +- minor stream specifier syntax changes: + - when matching by metadata (:m::), the colon character + in keys or values now has to be backslash-escaped + - in optional maps (-map ....?) with a metadata-matching stream specifier, + the value has to be separated from the question mark by a colon, i.e. + -map ....:m:::? (otherwise it would be ambiguous whether the + question mark is a part of or not) + - multiple stream types in a single specifier (e.g. :s:s:0) now cause an + error, as such a specifier makes no sense +- Mastering Display and Content Light Level metadata support in hevc_nvenc + and av1_nvenc encoders +- libswresample now accepts custom order channel layouts as input, with some + constrains +- FFV1 parser version 7.0: @@ -115,6 +168,7 @@ version 6.1: variable-fields elements within the same parent element - ffprobe -output_format option added as an alias of -of +# codespell:off version 6.0: - Radiance HDR image support diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 0000000000..3ffd54cecc --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x2f3900e7064eE63D30d749971265858612AA7139" + } + } +} diff --git a/INSTALL.md b/INSTALL.md index 3b220bc6ff..5b98b45d88 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,5 +1,8 @@ ## Installing FFmpeg +0. If you like to include source plugins, merge them before configure +for example run tools/merge-all-source-plugins + 1. Type `./configure` to create the configuration. A list of configure options is printed by running `configure --help`. @@ -15,3 +18,11 @@ NOTICE ------ - Non system dependencies (e.g. libx264, libvpx) are disabled by default. + +NOTICE for Package Maintainers +------------------------------ + + - It is recommended to build FFmpeg twice, first with minimal external dependencies so + that 3rd party packages, which depend on FFmpegs libavutil/libavfilter/libavcodec/libavformat + can then be built. And last build FFmpeg with full dependencies (which may in turn depend on + some of these 3rd party packages). This avoids circular dependencies during build. diff --git a/LICENSE.md b/LICENSE.md index 613070e1b6..371b0913ce 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -12,7 +12,6 @@ configure to activate them. In this case, FFmpeg's license changes to GPL v2+. Specifically, the GPL parts of FFmpeg are: -- libpostproc - optional x86 optimization in the files - `libavcodec/x86/flac_dsp_gpl.asm` - `libavcodec/x86/idct_mmx.c` @@ -45,7 +44,6 @@ Specifically, the GPL parts of FFmpeg are: - `vf_owdenoise.c` - `vf_perspective.c` - `vf_phase.c` - - `vf_pp.c` - `vf_pp7.c` - `vf_pullup.c` - `vf_repeatfields.c` diff --git a/MAINTAINERS b/MAINTAINERS index 76651d5ff8..fe4bcc69b0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -45,17 +45,20 @@ Commandline utility code: QuickTime faststart: tools/qt-faststart.c Baptiste Coudurier +Execution Graph Printing + fftools/graph, fftools/resources [2] softworkz Miscellaneous Areas =================== documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Gyan Doshi -project server day to day operations (L: root@ffmpeg.org) Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler -project server emergencies (L: root@ffmpeg.org) Árpád Gereöffy, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler +project server day to day operations (L: root@ffmpeg.org) Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler +project server emergencies (L: root@ffmpeg.org) Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler presets [0] metadata subsystem Aurelien Jacobs release management Michael Niedermayer API tests [0] +samples-request [2] Thilo Borgmann, James Almer, Ben Littler Communication @@ -82,12 +85,14 @@ Other: aes_ctr.c, aes_ctr.h Eran Kornblau bprint Nicolas George bswap.h + csp.c, csp.h Leo Izen, Ronald S. Bultje des Reimar Doeffinger dynarray.h Nicolas George eval.c, eval.h [2] Michael Niedermayer float_dsp Loren Merritt hash Reimar Doeffinger hwcontext_cuda* Timo Rothenpieler + hwcontext_d3d12va* Wu Jianhua hwcontext_vulkan* [2] Lynne intfloat* Michael Niedermayer integer.c, integer.h Michael Niedermayer @@ -133,8 +138,6 @@ Generic Parts: ratecontrol.c [2] Michael Niedermayer simple IDCT: simple_idct.c, simple_idct.h [2] Michael Niedermayer - postprocessing: - libpostproc/* [2] Michael Niedermayer table generation: tableprint.c, tableprint.h Reimar Doeffinger fixed point FFT: @@ -176,6 +179,7 @@ Codecs: dss_sp.c Oleksij Rempel dv.c Roman Shaposhnik dvbsubdec.c Anshul Maheshwari + dxv.*, dxvenc.* Emma Worley eacmv*, eaidct*, eat* Peter Ross exif.c, exif.h Thilo Borgmann ffv1* [2] Michael Niedermayer @@ -206,7 +210,6 @@ Codecs: libgsm.c Michel Bardiaux libkvazaar.c Arttu Ylä-Outinen libopenh264enc.c Martin Storsjo, Linjie Fu - libopenjpeg.c Jaikrishnan Menon libopenjpegenc.c Michael Bradshaw libtheoraenc.c David Conrad libvorbis.c David Conrad @@ -244,6 +247,7 @@ Codecs: rpza.c Roberto Togni rtjpeg.c, rtjpeg.h Reimar Doeffinger rv10.c Michael Niedermayer + sanm.c Manuel Lauss smc.c Mike Melanson snow* Michael Niedermayer, Loren Merritt sonic.c Alex Beregszaszi @@ -266,7 +270,7 @@ Codecs: vp8 David Conrad, Ronald Bultje vp9 Ronald Bultje vqavideo.c Mike Melanson - vvc [2] Nuo Mi + vvc [2] Nuo Mi, Wu Jianhua, Frank Plowman wmaprodec.c Sascha Sommer wmavoice.c Ronald S. Bultje wmv2.c Michael Niedermayer @@ -276,6 +280,7 @@ Codecs: Hardware acceleration: dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme d3d11va* Steve Lhomme + d3d12va* Wu Jianhua d3d12va_encode* Tong Wu mediacodec* Matthieu Bouron, Aman Gupta, Zhao Zhili vaapi* Haihao Xiang @@ -391,7 +396,7 @@ Muxers/Demuxers: dss.c Oleksij Rempel dtsdec.c foo86 dv.c Roman Shaposhnik - dvdvideodec.c Marth64 + dvdvideodec.c [2] Marth64 electronicarts.c Peter Ross evc* Samsung (Dawid Kozinski) ffm* Baptiste Coudurier @@ -445,7 +450,8 @@ Muxers/Demuxers: pva.c Ivo van Poorten r3d.c Baptiste Coudurier raw.c Michael Niedermayer - rcwtenc.c Marth64 + rcwtdec.c [2] Marth64 + rcwtenc.c [2] Marth64 rdt.c Ronald S. Bultje rl2.c Sascha Sommer rmdec.c, rmenc.c Ronald S. Bultje @@ -464,6 +470,7 @@ Muxers/Demuxers: sdp.c Martin Storsjo segafilm.c Mike Melanson segment.c Stefano Sabatini + smush.c Manuel Lauss spdif* Anssi Hannula srtdec.c Aurelien Jacobs swf.c Baptiste Coudurier @@ -511,9 +518,10 @@ Operating systems / CPU architectures Alpha [0] MIPS Manojkumar Bhosale, Shiyou Yin LoongArch [2] Shiyou Yin -Mac OS X / PowerPC Romain Dolbeau, Guillaume Poirier +Darwin (macOS, iOS) [2] Marvin Scholz +Mac OS X / PowerPC [0] Amiga / PowerPC Colin Ward -Linux / PowerPC Lauri Kasanen +Linux / PowerPC [1] Lauri Kasanen RISC-V [2] Rémi Denis-Courmont Windows MinGW Alex Beregszaszi, Ramiro Polla Windows Cygwin Victor Paesa @@ -541,6 +549,7 @@ James Darnley Jan Ekström Joakim Plate Jun Zhao +Kacper Michajłow Kieran Kunhya Kirill Gavrilov Limin Wang @@ -582,6 +591,7 @@ Benoit Fouet B22A 4F4F 43EF 636B BB66 FCDC 0023 AE1E 2985 49C8 Clément Bœsch 52D0 3A82 D445 F194 DB8B 2B16 87EE 2CB8 F4B8 FCF9 Daniel Verkamp 78A6 07ED 782C 653E C628 B8B9 F0EB 8DD8 2F0E 21C7 FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8 +Frank Plowman 34E2 48D6 B7DF 4769 70C7 3304 03A8 4C6A 098F 2C6B Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4 Haihao Xiang (haihao) 1F0C 31E8 B4FE F7A4 4DC1 DC99 E0F5 76D4 76FC 437F diff --git a/Makefile b/Makefile index b350d7748f..877b0071f6 100644 --- a/Makefile +++ b/Makefile @@ -19,14 +19,20 @@ vpath %/fate_config.sh.template $(SRC_PATH) TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options -ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample +ALLFFLIBS = \ + avcodec \ + avdevice \ + avfilter \ + avformat \ + avutil \ + swscale \ + swresample \ # $(FFLIBS-yes) needs to be in linking order FFLIBS-$(CONFIG_AVDEVICE) += avdevice FFLIBS-$(CONFIG_AVFILTER) += avfilter FFLIBS-$(CONFIG_AVFORMAT) += avformat FFLIBS-$(CONFIG_AVCODEC) += avcodec -FFLIBS-$(CONFIG_POSTPROC) += postproc FFLIBS-$(CONFIG_SWRESAMPLE) += swresample FFLIBS-$(CONFIG_SWSCALE) += swscale @@ -104,7 +110,7 @@ SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \ ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \ MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \ MMI-OBJS LSX-OBJS LASX-OBJS RV-OBJS RVV-OBJS RVVB-OBJS \ - OBJS SLIBOBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS + OBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS SIMD128-OBJS define RESET $(1) := diff --git a/RELEASE b/RELEASE index 72ec89de30..f5facffc32 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -7.0.git +8.0.git diff --git a/compat/cuda/cuda_runtime.h b/compat/cuda/cuda_runtime.h index 699c4b6c75..7614233eaf 100644 --- a/compat/cuda/cuda_runtime.h +++ b/compat/cuda/cuda_runtime.h @@ -189,4 +189,7 @@ static inline __device__ float __cosf(float a) { return __nvvm_cos_approx_f(a); static inline __device__ float __expf(float a) { return __nvvm_ex2_approx_f(a * (float)__builtin_log2(__builtin_exp(1))); } static inline __device__ float __powf(float a, float b) { return __nvvm_ex2_approx_f(__nvvm_lg2_approx_f(a) * b); } +// Misc helper functions +extern "C" __device__ int printf(const char*, ...); + #endif /* COMPAT_CUDA_CUDA_RUNTIME_H */ diff --git a/compat/getopt.c b/compat/getopt.c index 41a641f7c8..72110a95dd 100644 --- a/compat/getopt.c +++ b/compat/getopt.c @@ -38,7 +38,7 @@ static int optind = 1; static int optopt; static char *optarg; -static int getopt(int argc, char *argv[], char *opts) +static int getopt(int argc, char *argv[], const char *opts) { static int sp = 1; int c; diff --git a/compat/solaris/make_sunver.pl b/compat/solaris/make_sunver.pl index 0e9ed1d351..0c9268ea8d 100755 --- a/compat/solaris/make_sunver.pl +++ b/compat/solaris/make_sunver.pl @@ -218,7 +218,7 @@ while () { # Lines of the form '} SOME_VERSION_NAME_1.0;' if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) { $glob = 'glob'; - # We tried to match symbols agains this version, but none matched. + # We tried to match symbols against this version, but none matched. # Emit dummy hidden symbol to avoid marking this version WEAK. if ($matches_attempted && $matched_symbols == 0) { print " hidden:\n"; diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h index 2ff9735227..6f2734b470 100644 --- a/compat/w32pthreads.h +++ b/compat/w32pthreads.h @@ -44,13 +44,14 @@ #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/time.h" +#include "libavutil/wchar_filename.h" typedef struct pthread_t { void *handle; void *(*func)(void* arg); void *arg; void *ret; -} pthread_t; +} *pthread_t; /* use light weight mutex/condition variable API for Windows Vista and later */ typedef SRWLOCK pthread_mutex_t; @@ -74,7 +75,7 @@ typedef CONDITION_VARIABLE pthread_cond_t; static av_unused THREADFUNC_RETTYPE __stdcall attribute_align_arg win32thread_worker(void *arg) { - pthread_t *h = (pthread_t*)arg; + pthread_t h = (pthread_t)arg; h->ret = h->func(h->arg); return 0; } @@ -82,21 +83,35 @@ __stdcall attribute_align_arg win32thread_worker(void *arg) static av_unused int pthread_create(pthread_t *thread, const void *unused_attr, void *(*start_routine)(void*), void *arg) { - thread->func = start_routine; - thread->arg = arg; + pthread_t ret; + + ret = av_mallocz(sizeof(*ret)); + if (!ret) + return EAGAIN; + + ret->func = start_routine; + ret->arg = arg; #if HAVE_WINRT - thread->handle = (void*)CreateThread(NULL, 0, win32thread_worker, thread, - 0, NULL); + ret->handle = (void*)CreateThread(NULL, 0, win32thread_worker, ret, + 0, NULL); #else - thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread, - 0, NULL); + ret->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, ret, + 0, NULL); #endif - return !thread->handle; + + if (!ret->handle) { + av_free(ret); + return EAGAIN; + } + + *thread = ret; + + return 0; } static av_unused int pthread_join(pthread_t thread, void **value_ptr) { - DWORD ret = WaitForSingleObject(thread.handle, INFINITE); + DWORD ret = WaitForSingleObject(thread->handle, INFINITE); if (ret != WAIT_OBJECT_0) { if (ret == WAIT_ABANDONED) return EINVAL; @@ -104,8 +119,9 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr) return EDEADLK; } if (value_ptr) - *value_ptr = thread.ret; - CloseHandle(thread.handle); + *value_ptr = thread->ret; + CloseHandle(thread->handle); + av_free(thread); return 0; } @@ -194,4 +210,38 @@ static inline int pthread_setcancelstate(int state, int *oldstate) return 0; } +static inline int win32_thread_setname(const char *name) +{ +#if !HAVE_UWP + typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR); + + // Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016, + // Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in + // kernelbase.dll. So, load it from there for maximum coverage. + HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); + if (!kernelbase) + return AVERROR(ENOSYS); + + SetThreadDescriptionFn pSetThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription"); + if (!pSetThreadDescription) + return AVERROR(ENOSYS); + + wchar_t *wname; + if (utf8towchar(name, &wname) < 0) + return AVERROR(ENOMEM); + + HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname); + av_free(wname); + return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL); +#else + // UWP is not supported because we cannot use LoadLibrary/GetProcAddress to + // detect the availability of the SetThreadDescription API. There is a small + // gap in Windows builds 1507-1607 where it was not available. UWP allows + // querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it + // requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that. + return AVERROR(ENOSYS); +#endif +} + #endif /* COMPAT_W32PTHREADS_H */ diff --git a/configure b/configure index d77a55b653..e1809a3e58 100755 --- a/configure +++ b/configure @@ -130,7 +130,6 @@ Component options: --disable-avformat disable libavformat build --disable-swresample disable libswresample build --disable-swscale disable libswscale build - --disable-postproc disable libpostproc build --disable-avfilter disable libavfilter build --disable-pthreads disable pthreads [autodetect] --disable-w32threads disable Win32 threads [autodetect] @@ -250,6 +249,7 @@ External library support: --enable-liblensfun enable lensfun lens correction [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] + --enable-liboapv enable APV encoding via liboapv [no] --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] --enable-libopencv enable video filtering via libopencv [no] @@ -322,6 +322,7 @@ External library support: --enable-mediafoundation enable encoding via MediaFoundation [auto] --disable-metal disable Apple Metal framework [autodetect] --enable-libmysofa enable libmysofa, needed for sofalizer filter [no] + --enable-ohcodec enable OpenHarmony Codec support [no] --enable-openal enable OpenAL 1.1 capture support [no] --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] @@ -335,6 +336,7 @@ External library support: --disable-securetransport disable Secure Transport, needed for TLS support on OSX if openssl and gnutls are not used [autodetect] --enable-vapoursynth enable VapourSynth demuxer [no] + --enable-whisper enable whisper filter [no] --disable-xlib disable xlib [autodetect] --disable-zlib disable zlib [autodetect] @@ -363,6 +365,7 @@ External library support: --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] --disable-videotoolbox disable VideoToolbox code [autodetect] --disable-vulkan disable Vulkan code [autodetect] + --enable-vulkan-static statically link to libvulkan [no] Toolchain options: --arch=ARCH select architecture [$arch] @@ -379,10 +382,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) + ([-sanitizer[-...]], e.g. clang-asan-ubsan + tools: gcc, clang, msvc, icl, gcov, llvm-cov, + valgrind-memcheck, valgrind-massif, hardened + sanitizers: asan, fuzz, lsan, msan, tsan, ubsan) --nm=NM use nm tool NM [$nm_default] --ar=AR use archive tool AR [$ar_default] --as=AS use assembler AS [$as_default] @@ -426,6 +429,7 @@ Toolchain options: --enable-thumb compile for Thumb instruction set --enable-lto[=arg] use link-time optimization --env="ENV=override" override the environment variables + --disable-response-files Don't pass the list of objects to linker in a file [autodetect] Advanced options (experts only): --malloc-prefix=PREFIX prefix malloc and related names with PREFIX @@ -434,7 +438,9 @@ Advanced options (experts only): --enable-hardcoded-tables use hardcoded tables instead of runtime generation --disable-safe-bitstream-reader disable buffer boundary checking in bitreaders - (faster, but may crash) + (This disables some security checks and can cause undefined behavior, + crashes and arbitrary code execution, it may be faster, but + should only be used with trusted input) --sws-max-filter-size=N the max filter size swscale uses [$sws_max_filter_size_default] Optimization options (experts only): @@ -467,6 +473,8 @@ Optimization options (experts only): --disable-neon disable NEON optimizations --disable-dotprod disable DOTPROD optimizations --disable-i8mm disable I8MM optimizations + --disable-sve disable SVE optimizations + --disable-sve2 disable SVE2 optimizations --disable-inline-asm disable use of inline assembly --disable-x86asm disable use of standalone x86 assembly --disable-mipsdsp disable MIPS DSP ASE R1 optimizations @@ -478,6 +486,7 @@ Optimization options (experts only): --disable-lasx disable Loongson LASX optimizations --disable-rvv disable RISC-V Vector optimizations --disable-fast-unaligned consider unaligned accesses slow + --disable-simd128 disable WebAssembly simd128 optimizations Developer options (useful when working on FFmpeg itself): --disable-debug disable debugging symbols @@ -516,6 +525,7 @@ Developer options (useful when working on FFmpeg itself): --enable-macos-kperf enable macOS kperf (private) API --disable-large-tests disable tests that use a large amount of memory --disable-ptx-compression don't compress CUDA PTX code even when possible + --disable-resource-compression don't compress resources even when possible --disable-version-tracking don't include the git/release version in the build NOTE: Object files are built at the place where configure is launched. @@ -814,7 +824,7 @@ is_in(){ } # The cfg loop is very hot (several thousands iterations), and in bash also -# potentialy quite slow. Try to abort the iterations early, preferably without +# potentially quite slow. Try to abort the iterations early, preferably without # calling functions. 70%+ of the time cfg is already done or without deps. check_deps(){ for cfg; do @@ -920,7 +930,7 @@ reverse () { ' } -# keeps the last occurence of each non-unique item +# keeps the last occurrence of each non-unique item unique(){ unique_out= eval unique_in=\$$1 @@ -1518,7 +1528,7 @@ test_pkg_config(){ funcs="$4" shift 4 disable $name - test_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) pkg_incdir=$($pkg_config --variable=includedir $pkg_config_flags $pkg) @@ -1538,7 +1548,7 @@ test_pkg_config_cpp(){ cond="$4" shift 4 disable $name - test_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_incdir=$($pkg_config --variable=includedir $pkg_config_flags $pkg) pkg_incflags=$($pkg_config --cflags-only-I $pkg_config_flags $pkg) @@ -1614,6 +1624,15 @@ check_type(){ test_code cc "$headers" "$type v" "$@" && enable_sanitized "$type" } +check_objc_class(){ + log check_objc_class "$@" + headers=$1 + type=$2 + shift 2 + disable_sanitized "$type" + test_code objcc "$headers" "$type* v" "$@" && enable_sanitized "$type" +} + check_struct(){ log check_struct "$@" headers=$1 @@ -1935,6 +1954,7 @@ EXTERNAL_LIBRARY_LIST=" libmodplug libmp3lame libmysofa + liboapv libopencv libopenh264 libopenjpeg @@ -1979,11 +1999,14 @@ EXTERNAL_LIBRARY_LIST=" libzvbi lv2 mediacodec + ohcodec openal opengl openssl pocketsphinx vapoursynth + vulkan_static + whisper " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -2053,7 +2076,6 @@ LIBRARY_LIST=" avdevice avfilter swscale - postproc avformat avcodec swresample @@ -2106,6 +2128,7 @@ CONFIG_LIST=" ossfuzz pic ptx_compression + resource_compression thumb valgrind_backtrace xmm_clobber_test @@ -2147,6 +2170,7 @@ ARCH_LIST=" sparc64 tilegx tilepro + wasm x86 x86_32 x86_64 @@ -2163,6 +2187,8 @@ ARCH_EXT_LIST_ARM=" vfp vfpv3 setend + sve + sve2 " ARCH_EXT_LIST_MIPS=" @@ -2185,6 +2211,10 @@ ARCH_EXT_LIST_LOONGSON=" lasx " +ARCH_EXT_LIST_WASM=" + simd128 +" + ARCH_EXT_LIST_X86_SIMD=" aesni amd3dnow @@ -2212,6 +2242,7 @@ ARCH_EXT_LIST_PPC=" ldbrx power8 ppc4xx + vec_xl vsx " @@ -2231,6 +2262,7 @@ ARCH_EXT_LIST=" $ARCH_EXT_LIST_ARM $ARCH_EXT_LIST_PPC $ARCH_EXT_LIST_RISCV + $ARCH_EXT_LIST_WASM $ARCH_EXT_LIST_X86 $ARCH_EXT_LIST_MIPS $ARCH_EXT_LIST_LOONGSON @@ -2242,7 +2274,6 @@ ARCH_FEATURES=" fast_clz fast_cmov fast_float16 - local_aligned simd_align_16 simd_align_32 simd_align_64 @@ -2273,11 +2304,6 @@ HEADERS_LIST=" cdio_paranoia_paranoia_h cuda_h dispatch_dispatch_h - dev_bktr_ioctl_bt848_h - dev_bktr_ioctl_meteor_h - dev_ic_bt8xx_h - dev_video_bktr_ioctl_bt848_h - dev_video_meteor_ioctl_meteor_h direct_h dirent_h dxgidebug_h @@ -2287,11 +2313,8 @@ HEADERS_LIST=" io_h linux_dma_buf_h linux_perf_event_h - machine_ioctl_bt848_h - machine_ioctl_meteor_h malloc_h opencv2_core_core_c_h - OpenGL_gl3_h poll_h pthread_np_h sys_hwprobe_h @@ -2432,6 +2455,8 @@ TOOLCHAIN_FEATURES=" as_arch_directive as_archext_dotprod_directive as_archext_i8mm_directive + as_archext_sve_directive + as_archext_sve2_directive as_dn_directive as_fpu_directive as_func @@ -2461,6 +2486,7 @@ TYPES_LIST=" kCMVideoCodecType_HEVC kCMVideoCodecType_HEVCWithAlpha kCMVideoCodecType_VP9 + kCMVideoCodecType_AV1 kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange @@ -2475,6 +2501,8 @@ TYPES_LIST=" kCVImageBufferColorPrimaries_ITU_R_2020 kCVImageBufferTransferFunction_ITU_R_2020 kCVImageBufferTransferFunction_SMPTE_ST_428_1 + kVTQPModulationLevel_Default + SecPkgContext_KeyingMaterialInfo socklen_t struct_addrinfo struct_group_source_req @@ -2510,6 +2538,7 @@ HAVE_LIST=" $TOOLCHAIN_FEATURES $TYPES_LIST gzip + ioctl_posix libdrm_getfb2 makeinfo makeinfo_html @@ -2522,7 +2551,6 @@ HAVE_LIST=" opencl_videotoolbox perl pod2man - posix_ioctl texi2html xmllint zlib_gzip @@ -2541,6 +2569,7 @@ CONFIG_EXTRA=" bswapdsp cabac cbs + cbs_apv cbs_av1 cbs_h264 cbs_h265 @@ -2549,6 +2578,7 @@ CONFIG_EXTRA=" cbs_mpeg2 cbs_vp8 cbs_vp9 + celp_math d3d12va_encode deflate_wrapper dirac_parse @@ -2582,7 +2612,6 @@ CONFIG_EXTRA=" iamfdec iamfenc idctdsp - iirfilter inflate_wrapper intrax8 iso_media @@ -2606,6 +2635,7 @@ CONFIG_EXTRA=" mpegvideo mpegvideodec mpegvideoenc + mpegvideoencdsp msmpeg4dec msmpeg4enc mss34dsp @@ -2623,6 +2653,7 @@ CONFIG_EXTRA=" rv34dsp scene_sad sinewin + smpte_436m snappy srtp startcode @@ -2631,12 +2662,14 @@ CONFIG_EXTRA=" tpeldsp vaapi_1 vaapi_encode + vulkan_1_4 vc1dsp videodsp vp3dsp vp56dsp vp8dsp vulkan_encode + vvc_sei wma_freqs wmv2dsp " @@ -2652,6 +2685,7 @@ CMDLINE_SELECT=" extra_warnings logging optimizations + response_files rpath stripping version_tracking @@ -2752,6 +2786,8 @@ vfpv3_deps="vfp" setend_deps="arm" dotprod_deps="aarch64 neon" i8mm_deps="aarch64 neon" +sve_deps="aarch64 neon" +sve2_deps="aarch64 neon sve" map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM @@ -2759,6 +2795,7 @@ altivec_deps="ppc" dcbzl_deps="ppc" ldbrx_deps="ppc" ppc4xx_deps="ppc" +vec_xl_deps="altivec" vsx_deps="altivec" power8_deps="vsx" @@ -2783,6 +2820,8 @@ mipsdsp_deps="mips" mipsdspr2_deps="mips" msa_deps="mipsfpu" +simd128_deps="wasm" + x86_64_select="i686" x86_64_suggest="fast_cmov" @@ -2838,6 +2877,7 @@ w32threads_deps="atomics_native" threads_if_any="$THREADS_LIST" # subsystems +cbs_apv_select="cbs" cbs_av1_select="cbs" cbs_h264_select="cbs" cbs_h265_select="cbs" @@ -2863,6 +2903,7 @@ h264parse_select="golomb" h264_sei_select="atsc_a53 golomb" hevcparse_select="golomb" hevc_sei_select="atsc_a53 golomb" +iso_writer_select="golomb" frame_thread_encoder_deps="encoders threads" iamfdec_deps="iamf" iamfdec_select="iso_media mpeg4audio" @@ -2875,30 +2916,31 @@ mpeg_er_select="error_resilience" mpegaudio_select="mpegaudiodsp mpegaudioheader" mpegvideo_select="blockdsp hpeldsp idctdsp videodsp" mpegvideodec_select="h264chroma mpegvideo mpeg_er" -mpegvideoenc_select="aandcttables fdctdsp me_cmp mpegvideo pixblockdsp" +mpegvideoenc_select="aandcttables fdctdsp me_cmp mpegvideo mpegvideoencdsp pixblockdsp" msmpeg4dec_select="h263_decoder" msmpeg4enc_select="h263_encoder" vc1dsp_select="h264chroma qpeldsp startcode" +vvc_sei_select="atsc_a53 golomb" wmv2dsp_select="qpeldsp" # decoders / encoders aac_decoder_select="adts_header mpeg4audio sinewin" aac_fixed_decoder_select="adts_header mpeg4audio" -aac_encoder_select="audio_frame_queue iirfilter lpc sinewin" +aac_encoder_select="audio_frame_queue lpc sinewin" aac_latm_decoder_select="aac_decoder aac_latm_parser" ac3_decoder_select="ac3_parser ac3dsp bswapdsp fmtconvert" ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp" ac3_encoder_select="ac3dsp audiodsp me_cmp" ac3_fixed_encoder_select="ac3dsp audiodsp me_cmp" -acelp_kelvin_decoder_select="audiodsp" +acelp_kelvin_decoder_select="audiodsp celp_math" adpcm_g722_decoder_select="g722dsp" adpcm_g722_encoder_select="g722dsp" agm_decoder_select="idctdsp" aic_decoder_select="golomb idctdsp" alac_encoder_select="lpc" als_decoder_select="bswapdsp mpeg4audio" -amrnb_decoder_select="lsp" -amrwb_decoder_select="lsp" +amrnb_decoder_select="lsp celp_math" +amrwb_decoder_select="lsp celp_math" amv_decoder_select="sp5x_decoder exif" amv_encoder_select="jpegtables mpegvideoenc" ape_decoder_select="bswapdsp llauddsp" @@ -2906,6 +2948,7 @@ apng_decoder_select="inflate_wrapper" apng_encoder_select="deflate_wrapper llvidencdsp" aptx_encoder_select="audio_frame_queue" aptx_hd_encoder_select="audio_frame_queue" +apv_decoder_select="cbs_apv" asv1_decoder_select="blockdsp bswapdsp idctdsp" asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" @@ -2925,7 +2968,7 @@ cook_decoder_select="audiodsp sinewin" cri_decoder_select="mjpeg_decoder" cscd_decoder_suggest="zlib" dds_decoder_select="texturedsp" -dirac_decoder_select="dirac_parse dwt golomb mpegvideoenc qpeldsp videodsp" +dirac_decoder_select="dirac_parse dwt golomb mpegvideoencdsp qpeldsp videodsp" dnxhd_decoder_select="blockdsp idctdsp" dnxhd_encoder_select="blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp videodsp" dvvideo_decoder_select="dvprofile idctdsp" @@ -2939,9 +2982,11 @@ eamad_decoder_select="aandcttables blockdsp bswapdsp" eatgq_decoder_select="aandcttables" eatqi_decoder_select="aandcttables blockdsp bswapdsp" exr_decoder_deps="zlib" +exr_decoder_select="bswapdsp" exr_encoder_deps="zlib" ffv1_decoder_select="rangecoder" ffv1_encoder_select="rangecoder" +ffv1_vulkan_encoder_select="vulkan spirv_compiler" ffvhuff_decoder_select="huffyuv_decoder" ffvhuff_encoder_select="huffyuv_encoder" fic_decoder_select="golomb" @@ -2957,7 +3002,9 @@ fraps_decoder_select="bswapdsp huffman" ftr_decoder_select="adts_header" g2m_decoder_deps="zlib" g2m_decoder_select="blockdsp idctdsp jpegtables" -g729_decoder_select="audiodsp" +g723_1_decoder_select="celp_math" +g723_1_encoder_select="celp_math" +g729_decoder_select="audiodsp celp_math" h261_decoder_select="mpegvideodec" h261_encoder_select="mpegvideoenc" h263_decoder_select="h263_parser h263dsp mpegvideodec qpeldsp" @@ -2986,7 +3033,7 @@ ipu_decoder_select="mpegvideodec" jpegls_decoder_select="mjpeg_decoder" jv_decoder_select="blockdsp" lagarith_decoder_select="llviddsp" -lead_decoder_select="idctdsp jpegtables" +lead_decoder_select="blockdsp idctdsp jpegtables" ljpeg_encoder_select="jpegtables" lscr_decoder_select="inflate_wrapper" magicyuv_decoder_select="llviddsp" @@ -3047,6 +3094,7 @@ prores_decoder_select="blockdsp idctdsp" prores_encoder_select="fdctdsp" prores_aw_encoder_select="fdctdsp" prores_ks_encoder_select="fdctdsp" +prores_raw_decoder_select="blockdsp idctdsp" qcelp_decoder_select="lsp" qdm2_decoder_select="mpegaudiodsp" ra_144_decoder_select="audiodsp" @@ -3062,12 +3110,13 @@ rv20_decoder_select="h263_decoder" rv20_encoder_select="h263_encoder" rv30_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" rv40_decoder_select="golomb h264pred h264qpel mpegvideodec rv34dsp" +rv60_decoder_select="videodsp golomb" screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" -sipr_decoder_select="lsp" +sipr_decoder_select="lsp celp_math" smvjpeg_decoder_select="mjpeg_decoder" snow_decoder_select="dwt h264qpel rangecoder videodsp" -snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder videodsp" +snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoencdsp rangecoder videodsp" sonic_decoder_select="golomb rangecoder" sonic_encoder_select="golomb rangecoder" sonic_ls_encoder_select="golomb rangecoder" @@ -3076,7 +3125,7 @@ speedhq_decoder_select="blockdsp idctdsp" speedhq_encoder_select="mpegvideoenc" srgc_decoder_select="inflate_wrapper" svq1_decoder_select="hpeldsp" -svq1_encoder_select="hpeldsp me_cmp mpegvideoenc" +svq1_encoder_select="hpeldsp me_cmp mpegvideoencdsp" svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" svq3_decoder_suggest="zlib" tak_decoder_select="audiodsp" @@ -3111,8 +3160,8 @@ vp6a_decoder_select="vp6_decoder" vp6f_decoder_select="vp6_decoder" vp7_decoder_select="h264pred videodsp vp8dsp" vp8_decoder_select="h264pred videodsp vp8dsp" -vp9_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" -vvc_decoder_select="cabac cbs_h266 golomb videodsp" +vp9_decoder_select="videodsp vp9_parser cbs_vp9 vp9_superframe_split_bsf" +vvc_decoder_select="cabac cbs_h266 golomb videodsp vvc_sei" wcmv_decoder_select="inflate_wrapper" webp_decoder_select="vp8_decoder exif" wmalossless_decoder_select="llauddsp" @@ -3144,7 +3193,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" d3d12va_deps="dxva_h ID3D12Device ID3D12VideoDecoder" dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" -mediacodec_deps="android mediandk" +mediacodec_deps="android mediandk pthreads" nvdec_deps="ffnvcodec" vaapi_x11_deps="xlib_x11" videotoolbox_hwaccel_deps="videotoolbox pthreads" @@ -3166,8 +3215,12 @@ av1_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferAV1_bit_depth_idx" av1_vaapi_hwaccel_select="av1_decoder" av1_vdpau_hwaccel_deps="vdpau VdpPictureInfoAV1" av1_vdpau_hwaccel_select="av1_decoder" +av1_videotoolbox_hwaccel_deps="videotoolbox" +av1_videotoolbox_hwaccel_select="av1_decoder" av1_vulkan_hwaccel_deps="vulkan" av1_vulkan_hwaccel_select="av1_decoder" +ffv1_vulkan_hwaccel_deps="vulkan spirv_compiler" +ffv1_vulkan_hwaccel_select="ffv1_decoder" h263_vaapi_hwaccel_deps="vaapi" h263_vaapi_hwaccel_select="h263_decoder" h263_videotoolbox_hwaccel_deps="videotoolbox" @@ -3244,6 +3297,8 @@ mpeg4_videotoolbox_hwaccel_deps="videotoolbox" mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder" prores_videotoolbox_hwaccel_deps="videotoolbox" prores_videotoolbox_hwaccel_select="prores_decoder" +prores_raw_vulkan_hwaccel_deps="vulkan spirv_compiler" +prores_raw_vulkan_hwaccel_select="prores_raw_decoder" vc1_d3d11va_hwaccel_deps="d3d11va" vc1_d3d11va_hwaccel_select="vc1_decoder" vc1_d3d11va2_hwaccel_deps="d3d11va" @@ -3278,6 +3333,10 @@ vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9" vp9_vdpau_hwaccel_select="vp9_decoder" vp9_videotoolbox_hwaccel_deps="videotoolbox" vp9_videotoolbox_hwaccel_select="vp9_decoder" +vp9_vulkan_hwaccel_deps="vulkan vulkan_1_4" +vp9_vulkan_hwaccel_select="vp9_decoder" +vvc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVVC" +vvc_vaapi_hwaccel_select="vvc_decoder" wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel" wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel" wmv3_d3d12va_hwaccel_select="vc1_d3d12va_hwaccel" @@ -3296,6 +3355,7 @@ qsvdec_select="qsv" qsvenc_select="qsv" qsvvpp_select="qsv" vaapi_encode_deps="vaapi" +vulkan_1_4_deps="vulkan" vulkan_encode_deps="vulkan" v4l2_m2m_deps="linux_videodev2_h sem_timedwait" @@ -3315,9 +3375,12 @@ thumbnail_cuda_filter_deps_any="cuda_nvcc cuda_llvm" transpose_npp_filter_deps="ffnvcodec libnpp" overlay_cuda_filter_deps="ffnvcodec" overlay_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +pad_cuda_filter_deps="ffnvcodec" +pad_cuda_filter_deps_any="cuda_nvcc cuda_llvm" sharpen_npp_filter_deps="ffnvcodec libnpp" ddagrab_filter_deps="d3d11va IDXGIOutput1 DXGI_OUTDUPL_FRAME_INFO" +scale_d3d11_filter_deps="d3d11va" amf_deps_any="libdl LoadLibrary" nvenc_deps="ffnvcodec" @@ -3332,10 +3395,12 @@ amrnb_mediacodec_decoder_select="amr_parser" amrwb_mediacodec_decoder_deps="mediacodec" amrwb_mediacodec_decoder_select="amr_parser" av1_amf_encoder_deps="amf" +av1_amf_decoder_deps="amf" av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS" av1_mediacodec_decoder_deps="mediacodec" av1_mediacodec_encoder_deps="mediacodec" av1_mediacodec_encoder_select="extract_extradata_bsf" +av1_mf_encoder_deps="mediafoundation" av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" av1_nvenc_encoder_select="atsc_a53" av1_qsv_decoder_select="qsvdec" @@ -3343,9 +3408,12 @@ av1_qsv_encoder_deps="libvpl" av1_qsv_encoder_select="qsvenc" av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1" av1_vaapi_encoder_select="cbs_av1 vaapi_encode" +av1_vulkan_encoder_deps="vulkan_1_4" +av1_vulkan_encoder_select="cbs_av1 vulkan_encode" h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" h264_amf_encoder_deps="amf" +h264_amf_decoder_deps="amf" h264_cuvid_decoder_deps="cuvid" h264_cuvid_decoder_select="h264_mp4toannexb_bsf" h264_mediacodec_decoder_deps="mediacodec" @@ -3356,17 +3424,21 @@ h264_mf_encoder_deps="mediafoundation" h264_mmal_decoder_deps="mmal" h264_nvenc_encoder_deps="nvenc" h264_nvenc_encoder_select="atsc_a53" +h264_oh_decoder_deps="ohcodec" +h264_oh_decoder_select="h264_mp4toannexb_bsf" +h264_oh_encoder_deps="ohcodec" h264_omx_encoder_deps="omx" h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec" h264_qsv_encoder_select="atsc_a53 qsvenc" h264_rkmpp_decoder_deps="rkmpp" h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode" -h264_vulkan_encoder_select="cbs_h264 vulkan_encode" +h264_vulkan_encoder_select="atsc_a53 cbs_h264 vulkan_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" hevc_amf_encoder_deps="amf" +hevc_amf_decoder_deps="amf" hevc_cuvid_decoder_deps="cuvid" hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" hevc_d3d12va_encoder_select="cbs_h265 d3d12va_encode" @@ -3377,6 +3449,9 @@ hevc_mediacodec_encoder_select="extract_extradata_bsf hevc_metadata" hevc_mf_encoder_deps="mediafoundation" hevc_nvenc_encoder_deps="nvenc" hevc_nvenc_encoder_select="atsc_a53" +hevc_oh_decoder_deps="ohcodec" +hevc_oh_decoder_select="hevc_mp4toannexb_bsf" +hevc_oh_encoder_deps="ohcodec" hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec" hevc_qsv_encoder_select="hevcparse qsvenc" hevc_rkmpp_decoder_deps="rkmpp" @@ -3426,6 +3501,7 @@ 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_amf_decoder_deps="amf" vp9_cuvid_decoder_deps="cuvid" vp9_mediacodec_decoder_deps="mediacodec" vp9_mediacodec_encoder_deps="mediacodec" @@ -3440,8 +3516,10 @@ vvc_qsv_decoder_select="vvc_mp4toannexb_bsf qsvdec" # parsers aac_parser_select="adts_header mpeg4audio" +apv_parser_select="cbs_apv" av1_parser_select="cbs_av1" evc_parser_select="evcparse" +ffv1_parser_select="rangecoder" ftr_parser_select="adts_header mpeg4audio" h264_parser_select="golomb h264dsp h264parse h264_sei" hevc_parser_select="hevcparse hevc_sei" @@ -3458,6 +3536,7 @@ av1_metadata_bsf_select="cbs_av1" dovi_rpu_bsf_select="cbs_h265 cbs_av1 dovi_rpudec dovi_rpuenc" dts2pts_bsf_select="cbs_h264 h264parse" eac3_core_bsf_select="ac3_parser" +eia608_to_smpte436m_bsf_select="smpte_436m" evc_frame_merge_bsf_select="evcparse" filter_units_bsf_select="cbs" h264_metadata_bsf_deps="const_nan" @@ -3466,6 +3545,7 @@ h264_redundant_pps_bsf_select="cbs_h264" hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" +smpte436m_to_eia608_bsf_select="smpte_436m" trace_headers_bsf_select="cbs cbs_vp8" vp9_metadata_bsf_select="cbs_vp9" vvc_metadata_bsf_select="cbs_h266" @@ -3534,6 +3614,8 @@ libgsm_ms_decoder_deps="libgsm" libgsm_ms_encoder_deps="libgsm" libilbc_decoder_deps="libilbc" libilbc_encoder_deps="libilbc" +libjxl_anim_decoder_deps="libjxl libjxl_threads" +libjxl_anim_encoder_deps="libjxl libjxl_threads" libjxl_decoder_deps="libjxl libjxl_threads" libjxl_encoder_deps="libjxl libjxl_threads" libkvazaar_encoder_deps="libkvazaar" @@ -3543,6 +3625,7 @@ liblc3_encoder_select="audio_frame_queue" libmodplug_demuxer_deps="libmodplug" libmp3lame_encoder_deps="libmp3lame" libmp3lame_encoder_select="audio_frame_queue mpegaudioheader" +liboapv_encoder_deps="liboapv" libopencore_amrnb_decoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_select="audio_frame_queue" @@ -3593,7 +3676,7 @@ libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" -videotoolbox_deps="corefoundation coremedia corevideo" +videotoolbox_deps="corefoundation coremedia corevideo VTDecompressionSessionDecodeFrame" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" # demuxers / muxers @@ -3602,6 +3685,7 @@ act_demuxer_select="riffdec" adts_muxer_select="mpeg4audio" aiff_muxer_select="iso_media" amv_muxer_select="riffenc" +apv_demuxer_select="apv_parser" asf_demuxer_select="riffdec" asf_o_demuxer_select="riffdec" asf_muxer_select="riffenc" @@ -3647,6 +3731,9 @@ matroska_audio_muxer_select="matroska_muxer" matroska_demuxer_select="riffdec" matroska_demuxer_suggest="bzlib zlib" matroska_muxer_select="iso_writer mpeg4audio riffenc aac_adtstoasc_bsf pgs_frame_merge_bsf vp9_superframe_bsf" +mcc_demuxer_select="smpte_436m" +mcc_muxer_select="smpte_436m" +mcc_muxer_suggest="eia608_to_smpte436m_bsf" mlp_demuxer_select="mlp_parser" mmf_muxer_select="riffenc" mov_demuxer_select="iso_media riffdec" @@ -3660,6 +3747,7 @@ mpegts_demuxer_select="iso_media" mpegts_muxer_select="ac3_parser adts_muxer latm_muxer h264_mp4toannexb_bsf hevc_mp4toannexb_bsf vvc_mp4toannexb_bsf" mpegtsraw_demuxer_select="mpegts_demuxer" mxf_muxer_select="iso_writer pcm_rechunk_bsf rangecoder" +mxf_muxer_suggest="eia608_to_smpte436m_bsf" mxf_d10_muxer_select="mxf_muxer" mxf_opatom_muxer_select="mxf_muxer" nut_muxer_select="riffenc" @@ -3696,6 +3784,7 @@ wav_demuxer_select="riffdec" wav_muxer_select="riffenc" webm_chunk_muxer_select="webm_muxer" webm_dash_manifest_demuxer_select="matroska_demuxer" +whip_muxer_deps_any="dtls_protocol" wtv_demuxer_select="mpegts_demuxer riffdec" wtv_muxer_select="mpegts_muxer riffenc" xmv_demuxer_select="riffdec" @@ -3705,12 +3794,11 @@ xwma_demuxer_select="riffdec" android_camera_indev_deps="android camera2ndk mediandk pthreads" alsa_indev_deps="alsa" alsa_outdev_deps="alsa" -avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" +avfoundation_indev_deps="avfoundation corevideo coremedia pthreads AVCaptureSession" avfoundation_indev_suggest="coregraphics applicationservices" avfoundation_indev_extralibs="-framework Foundation" -audiotoolbox_outdev_deps="audiotoolbox pthreads" +audiotoolbox_outdev_deps="audiotoolbox pthreads AudioObjectPropertyAddress" audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework CoreAudio" -bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" caca_outdev_deps="libcaca" decklink_deps_any="libdl LoadLibrary" decklink_indev_deps="decklink threads" @@ -3735,13 +3823,10 @@ lavfi_indev_deps="avfilter" libcdio_indev_deps="libcdio" libdc1394_indev_deps="libdc1394" openal_indev_deps="openal" -opengl_outdev_deps="opengl" -opengl_outdev_suggest="sdl2" oss_indev_deps_any="sys_soundcard_h" oss_outdev_deps_any="sys_soundcard_h" pulse_indev_deps="libpulse" pulse_outdev_deps="libpulse" -sdl2_outdev_deps="sdl2" sndio_indev_deps="sndio" sndio_outdev_deps="sndio" v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" @@ -3798,6 +3883,9 @@ srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls" tls_protocol_select="tcp_protocol" +# TODO: Support libtls, mbedtls, and gnutls. +dtls_protocol_deps_any="openssl schannel" +dtls_protocol_select="udp_protocol" udp_protocol_select="network" udplite_protocol_select="network" unix_protocol_deps="sys_un_h" @@ -3832,6 +3920,7 @@ ass_filter_deps="libass" avgblur_opencl_filter_deps="opencl" avgblur_vulkan_filter_deps="vulkan spirv_compiler" azmq_filter_deps="libzmq" +blackdetect_vulkan_filter_deps="vulkan spirv_compiler" blackframe_filter_deps="gpl" blend_vulkan_filter_deps="vulkan spirv_compiler" boxblur_filter_deps="gpl" @@ -3886,6 +3975,7 @@ iccdetect_filter_deps="lcms2" iccgen_filter_deps="lcms2" identity_filter_select="scene_sad" interlace_filter_deps="gpl" +interlace_vulkan_filter_deps="vulkan spirv_compiler" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" lcevc_filter_deps="liblcevc_dec" @@ -3899,6 +3989,7 @@ mpdecimate_filter_deps="gpl" mpdecimate_filter_select="pixelutils" minterpolate_filter_select="scene_sad" mptestsrc_filter_deps="gpl" +msad_filter_select="scene_sad" negate_filter_deps="lut_filter" nlmeans_opencl_filter_deps="opencl" nlmeans_vulkan_filter_deps="vulkan spirv_compiler" @@ -3920,7 +4011,6 @@ pan_filter_deps="swresample" perspective_filter_deps="gpl" phase_filter_deps="gpl" pp7_filter_deps="gpl" -pp_filter_deps="gpl postproc" prewitt_opencl_filter_deps="opencl" procamp_vaapi_filter_deps="vaapi" program_opencl_filter_deps="opencl" @@ -3933,9 +4023,12 @@ rubberband_filter_deps="librubberband" sab_filter_deps="gpl swscale" scale2ref_filter_deps="swscale" scale_filter_deps="swscale" +sr_amf_filter_deps="amf" +vpp_amf_filter_deps="amf" scale_qsv_filter_deps="libmfx" scale_qsv_filter_select="qsvvpp" scdet_filter_select="scene_sad" +scdet_vulkan_filter_deps="vulkan spirv_compiler" select_filter_select="scene_sad" sharpness_vaapi_filter_deps="vaapi" showcqt_filter_deps="avformat swscale" @@ -3994,6 +4087,7 @@ xstack_qsv_filter_deps="libmfx" xstack_qsv_filter_select="qsvvpp" pad_vaapi_filter_deps="vaapi_1" drawbox_vaapi_filter_deps="vaapi_1" +whisper_filter_deps="whisper" # examples avio_http_serve_files_deps="avformat avutil fork" @@ -4027,22 +4121,20 @@ cws2fws_extralibs="zlib_extralibs" # libraries, in any order avcodec_deps="avutil" -avcodec_suggest="libm stdatomic liblcevc_dec" +avcodec_suggest="libm stdatomic spirv_compiler" avdevice_deps="avformat avcodec avutil" avdevice_suggest="libm stdatomic" avfilter_deps="avutil" -avfilter_suggest="libm stdatomic" +avfilter_suggest="libm stdatomic spirv_compiler" avformat_deps="avcodec avutil" avformat_suggest="libm network zlib stdatomic" avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" -postproc_deps="avutil gpl" -postproc_suggest="libm stdatomic" swresample_deps="avutil" swresample_suggest="libm libsoxr stdatomic" swscale_deps="avutil" swscale_suggest="libm stdatomic" -avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs lcms2_extralibs" +avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs liblcevc_dec_extralibs lcms2_extralibs" avfilter_extralibs="pthreads_extralibs" avutil_extralibs="d3d11va_extralibs d3d12va_extralibs mediacodec_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vaapi_win32_extralibs vdpau_x11_extralibs" @@ -4100,6 +4192,7 @@ objformat="elf32" x86asmexe_default="nasm" windres_default="windres" striptype="direct" +response_files_default="auto" # OS target_os_default=$(tolower $(uname -s)) @@ -4110,6 +4203,8 @@ if test "$target_os_default" = aix; then arch_default=$(uname -p) strip_default="strip -X32_64" nm_default="nm -g -X32_64" +elif test "$MSYSTEM_CARCH" != ""; then + arch_default="$MSYSTEM_CARCH" else arch_default=$(uname -m) fi @@ -4132,6 +4227,7 @@ enable iamf enable large_tests enable optimizations enable ptx_compression +enable resource_compression enable runtime_cpudetect enable safe_bitstream_reader enable static @@ -4232,7 +4328,7 @@ find_things_extern(){ find_filters_extern(){ file=$source_path/$1 - sed -n 's/^extern const AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file + sed -n 's/^extern const FFFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file } FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) @@ -4342,6 +4438,9 @@ do_random(){ $action $(rand_list "$@" | awk "BEGIN { srand($random_seed) } \$1 == \"prob\" { prob = \$2; next } rand() < prob { print }") } +# deprecated components (disabled by default) +disable sonic_encoder sonic_ls_encoder + for opt do optval="${opt#*=}" case "$opt" in @@ -4403,16 +4502,6 @@ for opt do test $action = enable && warn_if_gets_disabled $list $action $list ;; - --enable-yasm|--disable-yasm) - warn "The ${opt} option is only provided for compatibility and will be\n"\ - "removed in the future. Use --enable-x86asm / --disable-x86asm instead." - test $opt = --enable-yasm && x86asm=yes || x86asm=no - ;; - --yasmexe=*) - warn "The --yasmexe option is only provided for compatibility and will be\n"\ - "removed in the future. Use --x86asmexe instead." - x86asmexe="$optval" - ;; --enable-?*|--disable-?*) eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') if is_in $option $COMPONENT_LIST; then @@ -4460,7 +4549,7 @@ done if disabled autodetect; then - # Unless iconv is explicitely disabled by the user, we still want to probe + # Unless iconv is explicitly disabled by the user, we still want to probe # for the iconv from the libc. disabled iconv || enable libc_iconv @@ -4544,17 +4633,17 @@ set >> $logfile test -n "$valgrind" && toolchain="valgrind-memcheck" -enabled ossfuzz && ! echo $CFLAGS | grep -q -- "-fsanitize=" && ! echo $CFLAGS | grep -q -- "-fcoverage-mapping" &&{ - add_cflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -fno-omit-frame-pointer - add_ldflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -} - add_sanitizer_flags(){ case "$1" in asan) add_cflags -fsanitize=address add_ldflags -fsanitize=address ;; + fuzz) + add_cflags -fsanitize=fuzzer-no-link + add_ldflags -fsanitize=fuzzer-no-link + : "${libfuzzer_path:=-fsanitize=fuzzer}" + ;; lsan) add_cflags -fsanitize=leak add_ldflags -fsanitize=leak @@ -4567,7 +4656,7 @@ add_sanitizer_flags(){ add_cflags -fsanitize=thread add_ldflags -fsanitize=thread ;; - usan) + usan|ubsan) add_cflags -fsanitize=undefined add_ldflags -fsanitize=undefined ;; @@ -4577,14 +4666,24 @@ add_sanitizer_flags(){ esac } +add_sanitizers(){ + IFS=- + set -- $* + unset IFS + for sanitizer; do + add_sanitizer_flags "$sanitizer" + done + add_cflags -fno-omit-frame-pointer +} + case "$toolchain" in clang-*) - add_sanitizer_flags "${toolchain#clang-}" + add_sanitizers "${toolchain#clang-}" cc_default="clang" cxx_default="clang++" ;; gcc-*) - add_sanitizer_flags "${toolchain#gcc-}" + add_sanitizers "${toolchain#gcc-}" cc_default="gcc" cxx_default="g++" # In case of tsan with gcc, PIC has to be enabled @@ -4845,7 +4944,7 @@ msvc_common_flags(){ -lstdc++) ;; -l*) echo ${flag#-l}.lib ;; -LARGEADDRESSAWARE) echo $flag ;; - -L*) echo -libpath:${flag#-L} ;; + -L*) [ "$_flags_type" = "link" ] && echo -libpath:${flag#-L} ;; -Wl,*) ;; *) echo $flag ;; esac @@ -4867,6 +4966,12 @@ msvc_flags(){ done } +msvc_flags_link(){ + _flags_type=link + msvc_flags "$@" + unset _flags_type +} + icl_flags(){ msvc_common_flags "$@" for flag; do @@ -5052,7 +5157,7 @@ probe_cc(){ _cc_o='-Fo$@' _cc_e='-P' _flags_filter=icl_flags - _ld_lib='lib%.a' + _ld_lib='%.lib' _ld_path='-libpath:' # -Qdiag-error to make icl error when seeing certain unknown arguments _flags='-nologo -Qdiag-error:4044,10157' @@ -5062,20 +5167,22 @@ probe_cc(){ disable stripping elif $_cc -? 2>/dev/null | grep -q 'LLVM.*Linker'; then # lld can emulate multiple different linkers; in ms link.exe mode, - # the -? parameter gives the help output which contains an identifyable + # the -? parameter gives the help output which contains an identifiable # string, while it gives an error in other modes. _type=lld-link # The link.exe mode doesn't have a switch for getting the version, # but we can force it back to gnu mode and get the version from there. _ident=$($_cc -flavor gnu --version 2>/dev/null) _ld_o='-out:$@' - _flags_filter=msvc_flags - _ld_lib='lib%.a' + _flags_filter=msvc_flags_link + _ld_lib='%.lib' _ld_path='-libpath:' - elif $_cc -nologo- 2>&1 | grep -q Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then + elif VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then _type=msvc - if $_cc -nologo- 2>&1 | grep -q Microsoft; then - _ident=$($_cc 2>&1 | head -n1 | tr -d '\r') + if VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft; then + # Depending on the tool (cl.exe or link.exe), the version number + # is printed on the first line of stderr or stdout + _ident=$(VSLANG=1033 $_cc 2>&1 | grep ^Microsoft | head -n1 | tr -d '\r') else _ident=$($_cc --version 2>/dev/null | head -n1 | tr -d '\r') fi @@ -5091,13 +5198,14 @@ probe_cc(){ _cflags_noopt="-O1" if $_cc -nologo- 2>&1 | grep -q Linker; then _ld_o='-out:$@' + _flags_filter=msvc_flags_link else _ld_o='-Fe$@' + _flags_filter=msvc_flags fi _cc_o='-Fo$@' _cc_e='-P -Fi$@' - _flags_filter=msvc_flags - _ld_lib='lib%.a' + _ld_lib='%.lib' _ld_path='-libpath:' _flags='-nologo' disable stripping @@ -5152,7 +5260,7 @@ test -n "$cc_type" && enable $cc_type || : ${dep_cc_default:=$cc} : ${ld_default:=$cc} : ${host_ld_default:=$host_cc} -set_default ar as objcc dep_cc ld ln_s host_ld windres +set_default ar as objcc dep_cc ld ln_s host_ld windres response_files probe_cc as "$as" asflags_filter=$_flags_filter @@ -5184,7 +5292,7 @@ if [ -z "$CC_DEPFLAGS" ] && [ "$dep_cc" != "$cc" ]; then DEPCCFLAGS=$_flags fi -if $ar 2>&1 | grep -q Microsoft; then +if VSLANG=1033 $ar 2>&1 | grep -q ^Microsoft; then arflags="-nologo" ar_o='-out:$@' elif $ar 2>&1 | grep -q "\[D\] "; then @@ -5195,6 +5303,12 @@ else ar_o='$@' fi +# Treat unrecognized flags as errors on MSVC +test_cpp_condition windows.h "_MSC_FULL_VER >= 193030705" && + check_cflags -options:strict +test_host_cpp_condition windows.h "_MSC_FULL_VER >= 193030705" && + check_host_cflags -options:strict + add_cflags $extra_cflags add_cxxflags $extra_cxxflags add_objcflags $extra_objcflags @@ -5216,6 +5330,7 @@ if test "$cpu" = host; then case "$cc_type" in gcc|llvm_gcc) check_native(){ + : > $TMPC $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return sed -n "/cc1.*$1=/{ s/.*$1=\\([^ ]*\\).*/\\1/ @@ -5227,6 +5342,7 @@ if test "$cpu" = host; then ;; clang) check_native(){ + : > $TMPC $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return sed -n "/cc1.*-target-cpu /{ s/.*-target-cpu \\([^ ]*\\).*/\\1/ @@ -5250,7 +5366,7 @@ case "$arch" in arm*|iPad*|iPhone*) arch="arm" ;; - loongarch*) + loongarch*|loong64) arch="loongarch" ;; mips*|IP*) @@ -5284,6 +5400,9 @@ case "$arch" in tilegx|tile-gx) arch="tilegx" ;; + wasm*) + arch="wasm" + ;; i[3-6]86*|i86pc|BePC|x86pc|x86_64|x86_32|amd64) arch="x86" ;; @@ -5372,7 +5491,6 @@ elif enabled arm; then elif enabled loongarch; then - enable local_aligned enable simd_align_32 enable fast_64bit enable fast_clz @@ -5439,7 +5557,6 @@ elif enabled mips; then ;; # Cores from Loongson loongson2e|loongson2f|loongson3*) - enable local_aligned enable simd_align_16 enable fast_64bit enable fast_clz @@ -5522,7 +5639,7 @@ elif enabled ppc; then cpuflags="-mcpu=$cpu" disable vsx ;; - power[7-8]*) + power[7-9]*|power10) cpuflags="-mcpu=$cpu" ;; cell) @@ -5805,6 +5922,13 @@ case $target_os in clang_version=$($cc -dumpversion) test ${clang_version%%.*} -eq 11 && add_cflags -fno-stack-check fi + + # Xcode Clang doesn't default to -fno-common while upstream llvm.org + # Clang (and GCC) do. This avoids linker warnings on Xcode 16.3 about + # "reducing alignment of section __DATA,__common from 0x8000 to 0x4000 + # because it exceeds segment maximum alignment". + check_cflags -fno-common + ;; msys*) die "Native MSYS builds are discouraged, please use the MINGW environment." @@ -5868,9 +5992,6 @@ case $target_os in win32|win64) disable symver if enabled shared; then - # Link to the import library instead of the normal static library - # for shared libs. - LD_LIB='%.lib' # Cannot build both shared and static libs with MSVC or icl. disable static fi @@ -5878,6 +5999,8 @@ case $target_os in enabled x86_32 && check_ldflags -LARGEADDRESSAWARE add_cppflags -DWIN32_LEAN_AND_MEAN shlibdir_default="$bindir_default" + LIBPREF="" + LIBSUF=".lib" SLIBPREF="" SLIBSUF=".dll" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' @@ -5887,7 +6010,11 @@ case $target_os in SLIB_INSTALL_LINKS= SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' SLIB_INSTALL_EXTRA_LIB='$(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)' - SHFLAGS='-dll -def:$$(@:$(SLIBSUF)=.def) -implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + if test $ld_type = "clang"; then + SHFLAGS='-Wl,-dll -Wl,-def:$$(@:$(SLIBSUF)=.def) -Wl,-implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + else + SHFLAGS='-dll -def:$$(@:$(SLIBSUF)=.def) -implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + fi enabled x86_64 && objformat="win64" || objformat="win32" ranlib=: enable dos_paths @@ -6124,7 +6251,7 @@ set_default libdir set_default $PATHS_LIST set_default nm -disabled optimizations || enabled ossfuzz || check_cflags -fomit-frame-pointer +disabled optimizations || enabled ossfuzz || echo "$CFLAGS" | grep -q -- '-fsanitize=' || check_cflags -fomit-frame-pointer enable_weak_pic() { disabled pic && return @@ -6234,9 +6361,11 @@ if enabled aarch64; then # internal assembler in clang 3.3 does not support this instruction enabled neon && check_insn neon 'ext v0.8B, v0.8B, v1.8B, #1' - archext_list="dotprod i8mm" + archext_list="dotprod i8mm sve sve2" enabled dotprod && check_archext_insn dotprod 'udot v0.4s, v0.16b, v0.16b' enabled i8mm && check_archext_insn i8mm 'usdot v0.4s, v0.16b, v0.16b' + enabled sve && check_archext_insn sve 'whilelt p0.s, x0, x1' + enabled sve2 && check_archext_insn sve2 'sqrdmulh z0.s, z0.s, z0.s' # Disable the main feature (e.g. HAVE_NEON) if neither inline nor external # assembly support the feature out of the box. Skip this for the features @@ -6361,8 +6490,6 @@ elif enabled parisc; then elif enabled ppc; then - enable local_aligned - check_inline_asm dcbzl '"dcbzl 0, %0" :: "r"(0)' check_inline_asm ibm_asm '"add 0, 0, 0"' check_inline_asm ppc4xx '"maclhw r10, r11, r12"' @@ -6389,6 +6516,11 @@ elif enabled ppc; then check_cpp_condition power8 "altivec.h" "defined(_ARCH_PWR8)" fi + if enabled altivec; then + check_cc vec_xl altivec.h "const unsigned char *y1i = { 0 }; + vector unsigned char y0 = vec_xl(0, y1i);" + fi + elif enabled riscv; then enabled rv && check_inline_asm rv '".option arch, +zbb\nrev8 t0, t1"' @@ -6396,13 +6528,15 @@ elif enabled riscv; then enabled rv_zicbop && check_inline_asm rv_zicbop '".option arch, +zicbop\nprefetch.r 64(a0)"' enabled rv_zvbb && check_inline_asm rv_zvbb '".option arch, +zvbb\nvclz.v v0, v8"' +elif enabled wasm; then + + enabled simd128 && check_cc simd128 wasm_simd128.h "v128_t v = wasm_v128_load(0);" + elif enabled x86; then check_builtin rdtsc intrin.h "__rdtsc()" check_builtin mm_empty mmintrin.h "_mm_empty()" - enable local_aligned - # check whether EBP is available on x86 # As 'i' is stored on the stack, this program will crash # if the base pointer is used to access it because the @@ -6431,26 +6565,19 @@ EOF x86asmexe_probe=$1 if test_cmd $x86asmexe_probe -v; then x86asmexe=$x86asmexe_probe - x86asm_type=nasm x86asm_debug="-g -F dwarf" X86ASMDEP= X86ASM_DEPFLAGS='-MD $(@:.o=.d)' - elif test_cmd $x86asmexe_probe --version; then - x86asmexe=$x86asmexe_probe - x86asm_type=yasm - x86asm_debug="-g dwarf2" - X86ASMDEP='$(DEPX86ASM) $(X86ASMFLAGS) -M $(X86ASM_O) $< > $(@:.o=.d)' - X86ASM_DEPFLAGS= fi check_x86asm x86asm "movbe ecx, [5]" } if ! disabled_any asm mmx x86asm; then disable x86asm - for program in $x86asmexe nasm yasm; do + for program in $x86asmexe nasm; do probe_x86asm $program && break done - disabled x86asm && die "nasm/yasm not found or too old. Use --disable-x86asm for a crippled build." + disabled x86asm && die "nasm not found or too old. Please install/update nasm or use --disable-x86asm for a build without hand-optimized assembly." X86ASMFLAGS="-f $objformat" test -n "$extern_prefix" && append X86ASMFLAGS "-DPREFIX" case "$objformat" in @@ -6480,6 +6607,9 @@ check_cc intrinsics_sse2 emmintrin.h "__m128i test = _mm_setzero_si128()" check_ldflags -Wl,--as-needed check_ldflags -Wl,-z,noexecstack +if [ $target_os = "darwin" ]; then + check_ldflags -Wl,-no_warn_duplicate_libraries +fi if ! disabled network; then check_func getaddrinfo $network_extralibs @@ -6555,6 +6685,15 @@ if test -n "$custom_allocator"; then add_extralibs "$custom_allocator_extralibs" fi +# Unlike other feature flags or libraries, spirv_compiler is not defined +# within any of our predefined categories of components. +# It gets defined if either libshaderc or libglslang check succeeds. +# As such, its in a state of neither being explicitly enabled, nor +# explicitly disabled, but even in this state, being mentioned in +# _deps results in it always passing. +# Disable it explicitly to fix this. +disable spirv_compiler + check_func_headers malloc.h _aligned_malloc && enable aligned_malloc check_func ${malloc_prefix}memalign && enable memalign check_func ${malloc_prefix}posix_memalign && enable posix_memalign @@ -6647,6 +6786,7 @@ check_headers termios.h check_headers unistd.h check_headers valgrind/valgrind.h check_func_headers VideoToolbox/VTCompressionSession.h VTCompressionSessionPrepareToEncodeFrames -framework VideoToolbox +check_func_headers VideoToolbox/VideoToolbox.h VTDecompressionSessionDecodeFrame -framework VideoToolbox check_func_headers VideoToolbox/VideoToolbox.h VTPixelTransferSessionCreate -framework VideoToolbox check_func_headers VideoToolbox/VideoToolbox.h VTPixelRotationSessionCreate -framework VideoToolbox check_headers windows.h @@ -6687,16 +6827,23 @@ check_apple_framework CoreMedia check_apple_framework CoreVideo check_apple_framework CoreAudio +enabled audiotoolbox && { + check_type AudioToolbox/AudioToolbox.h AudioObjectPropertyAddress +} + enabled avfoundation && { disable coregraphics applicationservices check_lib coregraphics CoreGraphics/CoreGraphics.h CGGetActiveDisplayList "-framework CoreGraphics" || - check_lib applicationservices ApplicationServices/ApplicationServices.h CGGetActiveDisplayList "-framework ApplicationServices"; } + check_lib applicationservices ApplicationServices/ApplicationServices.h CGGetActiveDisplayList "-framework ApplicationServices" + check_objc_class AVFoundation/AVFoundation.h AVCaptureSession +} enabled videotoolbox && { check_lib coreservices CoreServices/CoreServices.h UTGetOSTypeFromString "-framework CoreServices" check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_HEVC "-framework CoreMedia" check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_HEVCWithAlpha "-framework CoreMedia" check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_VP9 "-framework CoreMedia" + check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_AV1 "-framework CoreMedia" check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange "-framework CoreVideo" check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange "-framework CoreVideo" check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange "-framework CoreVideo" @@ -6711,6 +6858,7 @@ enabled videotoolbox && { check_func_headers CoreVideo/CVImageBuffer.h kCVImageBufferColorPrimaries_ITU_R_2020 "-framework CoreVideo" check_func_headers CoreVideo/CVImageBuffer.h kCVImageBufferTransferFunction_ITU_R_2020 "-framework CoreVideo" check_func_headers CoreVideo/CVImageBuffer.h kCVImageBufferTransferFunction_SMPTE_ST_428_1 "-framework CoreVideo" + check_func_headers VideoToolbox/VTCompressionProperties.h kVTQPModulationLevel_Default "-framework CoreVideo" } enabled metal && test_cmd $metalcc -v || disable metal @@ -6731,6 +6879,7 @@ check_type "windows.h d3d12video.h" "ID3D12VideoEncoder" test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_VIDEO feature = D3D12_FEATURE_VIDEO_ENCODER_CODEC" && \ test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req" && enable d3d12_encoder_feature check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00 +check_type "windows.h security.h schnlsp.h" SecPkgContext_KeyingMaterialInfo -DSECURITY_WIN32 check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602 check_func_headers mfapi.h MFCreateAlignedMemoryBuffer -lmfplat @@ -6835,6 +6984,8 @@ EOF enabled zlib_gzip && enabled gzip || disable ptx_compression +enabled zlib_gzip && enabled gzip || disable resource_compression + # 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 @@ -6866,6 +7017,7 @@ enabled jni && { [ $target_os = "android" ] && check_headers jni.h enabled ladspa && require_headers "ladspa.h dlfcn.h" enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version +enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || { enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } || die "ERROR: libaribb24 requires version higher than 1.0.3 or --enable-gpl."; } @@ -6977,7 +7129,7 @@ enabled libopus && { require_pkg_config libopus opus opus_multistream.h opus_multistream_surround_encoder_create } } -enabled libplacebo && require_pkg_config libplacebo "libplacebo >= 4.192.0" libplacebo/vulkan.h pl_vulkan_create +enabled libplacebo && require_pkg_config libplacebo "libplacebo >= 5.229.0" libplacebo/vulkan.h pl_vulkan_create enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new enabled libqrencode && require_pkg_config libqrencode libqrencode qrencode.h QRcode_encodeString enabled libquirc && require libquirc quirc.h quirc_decode -lquirc @@ -7014,6 +7166,8 @@ enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_in 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 whisper && require_pkg_config whisper "whisper >= 1.7.5" whisper.h whisper_init_from_file_with_params + enabled libvpx && { enabled libvpx_vp8_decoder && { check_pkg_config libvpx_vp8_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || @@ -7071,6 +7225,10 @@ enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_co check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } || die "ERROR: mmal not found" && check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } +enabled ohcodec && { check_lib ohcodec "multimedia/player_framework/native_avcodec_videodecoder.h multimedia/player_framework/native_avcodec_videoencoder.h" \ + "OH_VideoDecoder_CreateByName OH_VideoEncoder_CreateByName" \ + -lnative_media_vdec -lnative_media_venc -lnative_media_codecbase -lnative_media_core -lnative_window || + die "ERROR: missing native_media libs"; } enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" alGetError || { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } || @@ -7096,17 +7254,16 @@ enabled omx_rpi && { test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoR test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame; } || die "ERROR: OpenMAX IL headers from raspberrypi/firmware not found"; } && enable omx -enabled omx && require_headers OMX_Core.h +enabled omx && require_headers OMX_Core.h && \ + warn "The OpenMAX encoders are deprecated and will be removed in future versions" + enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h OPENSSL_init_ssl && { enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL >=3.0.0 requires --enable-version3"; }; } || { enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL <3.0.0 is incompatible with the gpl"; } || - check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || - check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || + check_pkg_config openssl "openssl >= 1.1.1" openssl/ssl.h OPENSSL_init_ssl || check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto || - 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"; } + check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto -lws2_32 -lgdi32 || + die "ERROR: openssl (>= 1.1.1) not found"; } enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && @@ -7115,6 +7272,14 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r } enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" +enabled openssl && { + enabled whip_muxer && { + $pkg_config --exists --print-errors "openssl >= 1.0.1k" || + require_pkg_config openssl "openssl >= 1.0.1k" openssl/ssl.h SSL_library_init || + require_pkg_config openssl "openssl >= 1.0.1k" openssl/ssl.h OPENSSL_init_ssl + } +} + if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" @@ -7164,10 +7329,14 @@ enabled securetransport && enabled schannel && check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 && + check_func_headers "windows.h ncrypt.h" NCryptOpenStorageProvider -DSECURITY_WIN32 -lncrypt && + check_func_headers "windows.h wincrypt.h" CertCreateSelfSignCertificate -DSECURITY_WIN32 -lcrypt32 && test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && - schannel_extralibs="-lsecur32" || + schannel_extralibs="-lsecur32 -lncrypt -lcrypt32" || disable schannel +enabled schannel && check_cc dtls_protocol "windows.h security.h schnlsp.h" "int i = SP_PROT_DTLS1_X_CLIENT;" -DSECURITY_WIN32 + makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo enabled makeinfo \ && [ 0$(makeinfo --version | grep "texinfo" | sed 's/.*texinfo[^0-9]*\([0-9]*\)\..*/\1/') -ge 5 ] \ @@ -7175,13 +7344,13 @@ enabled makeinfo \ disabled makeinfo_html && texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html perl -v > /dev/null 2>&1 && enable perl || disable perl pod2man --help > /dev/null 2>&1 && enable pod2man || disable pod2man -rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout +rsync --help 2> /dev/null | grep -q 'contimeout=' && enable rsync_contimeout || disable rsync_contimeout xmllint --version > /dev/null 2>&1 && enable xmllint || disable xmllint check_headers linux/fb.h check_headers linux/videodev2.h test_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete -test_code cc sys/ioctl.h "int ioctl(int, int, ...)" && enable posix_ioctl +test_code cc sys/ioctl.h "int ioctl(int, int, ...)" && enable ioctl_posix # check V4L2 codecs available in the API if enabled v4l2_m2m; then @@ -7208,12 +7377,6 @@ check_cpp_condition vfwcap_defines vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" check_type "dshow.h" IBaseFilter -# check for ioctl_meteor.h, ioctl_bt848.h and alternatives -check_headers "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || - check_headers "machine/ioctl_meteor.h machine/ioctl_bt848.h" || - check_headers "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || - check_headers "dev/ic/bt8xx.h" - if check_struct sys/soundcard.h audio_buf_info bytes; then enable_sanitized sys/soundcard.h else @@ -7299,6 +7462,7 @@ if enabled vaapi; then check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC" + check_type "va/va.h va/va_dec_vvc.h" "VAPictureParameterBufferVVC" check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth check_struct "va/va.h" "VADecPictureParameterBufferAV1" bit_depth_idx check_type "va/va.h va/va_vpp.h" "VAProcFilterParameterBufferHDRToneMapping" @@ -7348,13 +7512,19 @@ enabled vdpau && enabled vdpau && check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11 -if enabled vulkan; then +if enabled_all vulkan vulkan_static; then + check_pkg_config vulkan "vulkan >= 1.3.277" "vulkan/vulkan.h" "defined VK_VERSION_1_3" || + check_lib vulkan "vulkan/vulkan.h" vkGetInstanceProcAddr -lvulkan +elif enabled vulkan; then check_pkg_config_header_only vulkan "vulkan >= 1.3.277" "vulkan/vulkan.h" "defined VK_VERSION_1_3" || check_cpp_condition vulkan "vulkan/vulkan.h" "defined(VK_VERSION_1_4) || (defined(VK_VERSION_1_3) && VK_HEADER_VERSION >= 277)" fi if disabled vulkan; then disable libglslang libshaderc spirv_compiler +else + check_pkg_config_header_only vulkan_1_4 "vulkan >= 1.4.317" "vulkan/vulkan.h" "defined VK_VERSION_1_4" || + check_cpp_condition vulkan_1_4 "vulkan/vulkan.h" "defined(VK_VERSION_1_5) || (defined(VK_VERSION_1_4) && VK_HEADER_VERSION >= 317)" fi if enabled x86; then @@ -7397,7 +7567,7 @@ fi 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) >= 0x0001000400210000" + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400240000" # Funny iconv installations are not unusual, so check it after all flags have been set if enabled libc_iconv; then @@ -7409,7 +7579,6 @@ fi enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel" # add some useful compiler flags if supported -check_cflags -Wdeclaration-after-statement check_cflags -Wall check_cflags -Wdisabled-optimization check_cflags -Wpointer-arith @@ -7444,6 +7613,8 @@ check_disable_warning -Wno-pointer-sign check_disable_warning -Wno-unused-const-variable check_disable_warning -Wno-bool-operation check_disable_warning -Wno-char-subscripts +check_disable_warning -Wno-implicit-const-int-float-conversion +check_disable_warning -Wno-microsoft-enum-forward-reference check_disable_warning_headers(){ warning_flag=-W${1#-Wno-} @@ -7458,7 +7629,7 @@ void (^block)(void); EOF # add some linker flags -check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil +check_ldflags -Wl,-rpath-link=:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic @@ -7581,7 +7752,25 @@ if enabled icc; then disable aligned_stack fi elif enabled gcc; then - check_optflags -fno-tree-vectorize + gcc_version=$($cc -dumpversion) + major_version=${gcc_version%%.*} + if [ $major_version -lt 13 ]; then + # Disable tree-vectorize for GCC <13 - it has historically been buggy. + check_optflags -fno-tree-vectorize + else + case $arch in + x86|arm|aarch64) + # Allow the default of having tree-vectorize enabled on well tested + # architectures. + ;; + *) + # Disable tree-vectorize on potentially less tested + # architectures. Known issues: + # - https://gcc.gnu.org/PR121064 on Loongarch + check_optflags -fno-tree-vectorize + ;; + esac + fi check_cflags -Werror=format-security check_cflags -Werror=implicit-function-declaration check_cflags -Werror=missing-prototypes @@ -7661,7 +7850,7 @@ elif enabled_any msvc icl; then fi # msvcrt10 x64 incorrectly enables log2, only msvcrt12 (MSVC 2013) onwards actually has log2. check_cpp_condition log2 crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" - # the new SSA optimzer in VS2015 U3 is mis-optimizing some parts of the code + # the new SSA optimizer in VS2015 U3 is mis-optimizing some parts of the code # Issue has been fixed in MSVC v19.00.24218. test_cpp_condition windows.h "_MSC_FULL_VER >= 190024218" || check_cflags -d2SSAOptimizer- @@ -7692,6 +7881,19 @@ case $ld_type in ;; esac +if [ "$response_files" != "no" ]; then + ar_out=${FFTMPDIR}/test$LIBSUF + respfile="@/dev/null" + out_arg="$(echo $ar_o | sed "s;\$@;$ar_out;g")" + if test_cmd $ar $arflags $out_arg $respfile; then + response_files="yes" + elif [ "$response_files" = "auto" ]; then + response_files="no" + else + die "Response files are not available with this toolchain. Exiting" + fi +fi + enable frame_thread_encoder enabled asm || { arch=c; disable $ARCH_LIST $ARCH_EXT_LIST; } @@ -7810,7 +8012,6 @@ enabled fsync_filter && prepend avfilter_deps "avformat" enabled mcdeint_filter && prepend avfilter_deps "avcodec" enabled movie_filter && prepend avfilter_deps "avformat avcodec" enabled pan_filter && prepend avfilter_deps "swresample" -enabled pp_filter && prepend avfilter_deps "postproc" enabled qrencode_filter && prepend avfilter_deps "swscale" enabled qrencodesrc_filter && prepend avfilter_deps "swscale" enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" @@ -7828,10 +8029,6 @@ enabled zoompan_filter && prepend avfilter_deps "swscale" enabled lavfi_indev && prepend avdevice_deps "avfilter" -#FIXME -enabled_any sdl2_outdev opengl_outdev && enabled sdl2 && - add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) - enabled opus_decoder && prepend avcodec_deps "swresample" # reorder the items at var $1 to align with the items order at var $2 . @@ -7866,9 +8063,6 @@ expand_deps(){ reorder_by ${1}_deps LIBRARY_LIST # linking order is expected later } -#we have to remove gpl from the deps here as some code assumes all lib deps are libs -postproc_deps="$(filter_out 'gpl' $postproc_deps)" - map 'expand_deps $v' $LIBRARY_LIST if test "$quiet" != "yes"; then @@ -7919,6 +8113,8 @@ if enabled aarch64; then echo "NEON enabled ${neon-no}" echo "DOTPROD enabled ${dotprod-no}" echo "I8MM enabled ${i8mm-no}" + echo "SVE enabled ${sve-no}" + echo "SVE2 enabled ${sve2-no}" fi if enabled arm; then echo "ARMv5TE enabled ${armv5te-no}" @@ -7941,6 +8137,7 @@ if enabled ppc; then echo "POWER8 enabled ${power8-no}" echo "PPC 4xx optimizations ${ppc4xx-no}" echo "dcbzl available ${dcbzl-no}" + echo "vec_xl available ${vec_xl-no}" fi if enabled loongarch; then echo "LSX enabled ${lsx-no}" @@ -7956,7 +8153,6 @@ echo "optimize for size ${small-no}" echo "optimizations ${optimizations-no}" echo "static ${static-no}" echo "shared ${shared-no}" -echo "postprocessing support ${postproc-no}" echo "network support ${network-no}" echo "threading support ${thread_type-no}" echo "safe bitstream reader ${safe_bitstream_reader-no}" @@ -8069,6 +8265,7 @@ DEPX86ASM=$x86asmexe DEPX86ASMFLAGS=\$(X86ASMFLAGS) AR=$ar ARFLAGS=$arflags +RESPONSE_FILES=$response_files AR_O=$ar_o AR_CMD=$ar NM_CMD=$nm @@ -8083,7 +8280,7 @@ LN_S=$ln_s CPPFLAGS=$CPPFLAGS CFLAGS=$CFLAGS CXXFLAGS=$CXXFLAGS -OBJCCFLAGS=$OBJCFLAGS +OBJCFLAGS=$OBJCFLAGS ASFLAGS=$ASFLAGS NVCCFLAGS=$nvccflags AS_C=$AS_C @@ -8191,7 +8388,7 @@ cat > $TMPH <max_buffered_frames. + +2025-07-07 - eca477da52 - lavc 62.6.100 - packet.h + Add AV_PKT_DATA_RTCP_SR. + +2025-07-01 - 39d5a998bd - lavc 62.4.101 - packet.h + Add AV_PKT_DATA_3D_REFERENCE_DISPLAYS. + +2025-07-01 - b2e4b0e282 - lavu 60.4.101 - frame.h + Add AV_FRAME_DATA_3D_REFERENCE_DISPLAYS. + +2025-07-01 - 80a05bea4f - lavu 60.4.100 - tdrdi.h + Add AV3DReferenceDisplaysInfo and AV3DReferenceDisplay structs. + Add av_tdrdi_alloc() and av_tdrdi_get_display(). + +2025-05-21 - 004cc60f0e3 - lavu 60.3.100 - avassert.h + Add av_unreachable() and av_assume() macros. + +2025-02-15 - e2f39671ae2 - lavfi 10.10.100 - avfilter.h + Add avfilter_link_get_hw_frames_ctx(). + +2025-04-21 - bf1579c904a - lavu 60.2.100 - log.h + Add AV_CLASS_CATEGORY_HWDEVICE. + +2025-04-16 - c818c67991 - libpostproc 59.1.100 - postprocess.h + Deprecate PP_CPU_CAPS_3DNOW. + +2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h + Add AV_DICT_DEDUP. + +2025-03-17 - 49af9746e8f - lavu 59.60.100 - pixfmt.h + Add AV_PIX_FMT_GBRAP32BE and AV_PIX_FMT_GBRAP32LE. + +2025-03-10 - 61fc9b6fee1 - lavu 59.59.100 - pixfmt.h + Add AV_PIX_FMT_YAF16BE, AV_PIX_FMT_YAF16LE, AV_PIX_FMT_YAF32BE, + and AV_PIX_FMT_YAF32LE. + +2025-03-01 - 0245e9382c7 - lavu 59.58.100 - pixfmt.h + Add AV_PIX_FMT_GRAY32BE and AV_PIX_FMT_GRAY32LE. + +2025-02-04 - 0ef678f5c50 - lavu 59.56.000 - pixfmt.h + Add AV_PIX_FMT_AMF_SURFACE. + +2025-01-09 - a73760da537 - lavu 59.55.100 - pixfmt.h + Add AV_PIX_FMT_GBRPF16BE, AV_PIX_FMT_GBRPF16LE, AV_PIX_FMT_GBRAPF16BE, + AV_PIX_FMT_GBRAPF16LE, AV_PIX_FMT_GRAYF16BE, and AV_PIX_FMT_GRAYF16LE. + +2025-02-16 - c79cdae3777 - lavu 59.57.100 - log.h + Add flags AV_LOG_PRINT_TIME and AV_LOG_PRINT_DATETIME. + +2025-02-09 - 9fb806fa577 - lavc 61.32.100 - codec_id.h + Add AV_CODEC_ID_IVTV_VBI. + +2025-01-25 - ea3c3b42dff - lavu 59.56.100 - frame.h + Add AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT. + +2025-01-25 - 6707d970c04 - lavfi 10.9.100 - buffersink.h + Add av_buffersink_get_side_data(). + +2025-01-25 - 7a025e1cb5f - lavfi 10.8.100 - buffersrc.h + Add AVBufferSrcParameters.side_data and AVBufferSrcParameters.nb_side_data + +2025-01-25 - ef1cb1c9c81 - lavfi 10.7.100 - avfilter.h + Add AVFilterLink.side_data and AVFilterLink.nb_side_data + +2025-01-05 - 42e72d5c8b5 - lavu 59.55.100 - frame.h + Add AV_FRAME_SIDE_DATA_FLAG_NEW_REF. + +2025-01-05 - 19c95ecbff8 - lavc 61.31.100 - avcodec.h + Deprecate AVCodecContext->properties. + +2025-01-05 - 2d91f89445d - lavc 61.30.100 - frame.h + Add AV_FRAME_FLAG_LOSSLESS. + +2025-01-03 - f3c40826455 - lavc 61.29.100 - codec_id.h + Add AV_CODEC_ID_JPEGXL_ANIM. + +2025-01-03 - da9dcaba69d - lavu 59.54.100 - frame.h + Add AV_CH_LAYOUT_5POINT1POINT2 and AV_CHANNEL_LAYOUT_5POINT1POINT2. + +2024-12-23 - b88944a8aa5 - lavu 59.53.100 - frame.h + Add av_frame_side_data_remove_by_props(). + +2024-12-23 - 3428a8d8303 - lavu 59.52.100 - frame.h + Add AV_SIDE_DATA_PROP_SIZE_DEPENDENT and AV_FRAME_DATA_PROP_COLOR_DEPENDENT. + +2024-12-23 - 45f0a7ad338 - lsws 8.13.100 - swscale.h + Add enum SwsIntent and SwsContext.intent. + +2024-12-15 - 2ac34d08542 - lavc 61.27.100 packet.h + Add av_container_fifo_alloc_avpacket(). + +2024-12-15 - 56ba57b6725 - lavu 59.51.100 - refstruct.h container_fifo.h + Add a new public header refstruct.h with new API for + reference-counted objects. + + Add a new public header container_fifo.h with new API for + a FIFO of container objects (e.g. AVFrame or AVPacket). + +2024-12-13 - 6eb4bf04e92 - lavu 59.50.100 - channel_layout.h + Add AV_CH_LAYOUT_9POINT1POINT6 and AV_CHANNEL_LAYOUT_9POINT1POINT6. + +2024-12-05 - 06f084468e0 - lavu 59.49.100 - csp.h + Add av_csp_itu_eotf() and av_csp_itu_eotf_inv(). + +2024-12-05 - bf0a6c41111 - lavu 59.48.100 - csp.h + Add av_csp_trc_func_inv_from_id(). + +2024-11-25 - 2a091d4f2ee - lsws 8.12.100 - swscale.h + Allow using sws_frame_scale() dynamically, without first initializing the + SwsContext. Deprecate sws_init_context(). Add sws_frame_setup() instead. + +2024-11-25 - fb169640092 - lsws 8.11.100 - swscale.h + Replace #define-based SWS_* flags by enum SwsFlags. + +2024-11-25 - ed5dd675624 - lsws 8.10.100 - swscale.h + Publicly expose struct SwsContext, enum SwsDither, and enum SwsAlphaBlend. + +2024-11-16 - 46cb7b8d9dc - lavu 59.47.101 - frame.h + av_frame_get_buffer() now also aligns the data pointers according to + the requested alignment. + +2024-11-13 - 20af68b63a4 - lavu 59.47.100 - channel_layout.h + Add AV_CHAN_BINAURAL_LEFT, AV_CHAN_BINAURAL_RIGHT + Add AV_CH_BINAURAL_LEFT, AV_CH_BINAURAL_RIGHT + Add AV_CH_LAYOUT_BINAURAL, AV_CHANNEL_LAYOUT_BINAURAL + +2024-10-26 - e02a3b40a5e - lavu 59.46.100 - pixfmt.h + Add AV_PIX_FMT_XV48. + +2024-10-23 - b03c758600f - lsws 8.9.100 - swscale.h + Add sws_is_noop(). + +2024-10-23 - 5e50a56b9c4 - lsws 8.8.100 - swscale.h + Add frame property testing API: + - sws_test_format() + - sws_test_colorspace() + - sws_test_primaries() + - sws_test_transfer() + - sws_test_frame() + +2024-10-23 - 87baf9ab2c2 - lsws 8.7.100 - swscale.h + Add sws_free_context(). + +2024-10-23 - f462ba05f54 - lavu 59.45.100 - pixfmt.h + Add AV_PIX_FMT_Y216. + +2024-10-15 - 2336e685657 - lavu 59.44.100 - pixfmt.h + Add AV_PIX_FMT_RGB96 and AV_PIX_FMT_RGBA128. + +2024-10-14 - c993a91bea - lavu 59.43.100 - pixfmt.h + Add AV_PIX_FMT_RGBF16. + +2024-10-08 - 29ea34728f1 - lavu 59.42.100 - pixfmt.h + Add AV_PIX_FMT_AYUV, AV_PIX_FMT_UYVA, AV_PIX_FMT_VYU444, + and AV_PIX_FMT_V30X. + +2024-10-01 - 0548ab2e425 - lavu 59.41.100 - log.h + Add AVClass.state_flags_offset and AV_CLASS_STATE_INITIALIZED. + +2024-09-30 - 50d1b89fa0d - lavf 61.9.100 - avformat.h + Add {nb_}coded_side_data to AVStreamGroupTileGrid. + +2024-09-30 - df9b80d21a2 - lavu 59 + Deprecate av_int_list_length_for_size(), av_int_list_length(), and + av_opt_set_int_list() without replacement. All AVOptions using these + should be replaced with AV_OPT_TYPE_FLAG_ARRAY. + +2024-09-30 - 1efcdbc54d9 - lavfi 10.6.100 + Buffersink now has array-type options + - pixel_formats + - colorspaces + - colorranges + replacing the int-list options + - pix_fmts + - color_spaces + - color_ranges + abuffersink now has array-type options + - sample_formats + - samplerates + - channel_layouts + replacing the int-list/string options + - sample_fmts + - sample_rates + - ch_layouts + +-------- 8< --------- FFmpeg 7.1 was cut here -------- 8< --------- + 2024-09-23 - 6940a6de2f0 - lavu 59.38.100 - frame.h Add AV_FRAME_DATA_VIEW_ID. @@ -412,7 +627,7 @@ API changes, most recent first: Deprecate AVFrame.palette_has_changed without replacement. 2023-05-15 - 7d1d61cc5f5 - lavc 60 - avcodec.h - Depreate AVCodecContext.ticks_per_frame in favor of + Deprecate AVCodecContext.ticks_per_frame in favor of AVCodecContext.framerate (encoding) and AV_CODEC_PROP_FIELDS (decoding). @@ -420,7 +635,7 @@ API changes, most recent first: Add AV_CODEC_PROP_FIELDS. 2023-05-15 - 8b20d0dcb5c - lavc 60 - codec.h - Depreate AV_CODEC_CAP_SUBFRAMES without replacement. + Deprecate AV_CODEC_CAP_SUBFRAMES without replacement. 2023-05-07 - c2ae8e30b7f - lavc 60.11.100 - codec_par.h Add AVCodecParameters.framerate. diff --git a/doc/Doxyfile b/doc/Doxyfile index 572c532da5..7ac70b95c9 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1093,7 +1093,7 @@ HTML_STYLESHEET = # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the @@ -1636,7 +1636,7 @@ EXTRA_PACKAGES = # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, # $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty string, # for the replacement values of the other commands the user is referred to # HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index e1cb87a522..fb31ca7380 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -189,6 +189,52 @@ see page 44-46 or section 5.5 of Extract the core from a E-AC-3 stream, dropping extra channels. +@section eia608_to_smpte436m + +Convert from a @code{EIA_608} stream to a @code{SMPTE_436M_ANC} data stream, wrapping the closed captions in CTA-708 CDP VANC packets. + +@table @option +@item line_number +Choose which line number the generated VANC packets should go on. You generally want either line 9 (the default) or 11. +@item wrapping_type +Choose the SMPTE 436M wrapping type, defaults to @samp{vanc_frame}. +It accepts the values: +@table @samp +@item vanc_frame +VANC frame (interlaced or segmented progressive frame) +@item vanc_field_1 +@item vanc_field_2 +@item vanc_progressive_frame +@end table +@item sample_coding +Choose the SMPTE 436M sample coding, defaults to @samp{8bit_luma}. +It accepts the values: +@table @samp +@item 8bit_luma +8-bit component luma samples +@item 8bit_color_diff +8-bit component color difference samples +@item 8bit_luma_and_color_diff +8-bit component luma and color difference samples +@item 10bit_luma +10-bit component luma samples +@item 10bit_color_diff +10-bit component color difference samples +@item 10bit_luma_and_color_diff +10-bit component luma and color difference samples +@item 8bit_luma_parity_error +8-bit component luma samples with parity error +@item 8bit_color_diff_parity_error +8-bit component color difference samples with parity error +@item 8bit_luma_and_color_diff_parity_error +8-bit component luma and color difference samples with parity error +@end table +@item initial_cdp_sequence_cntr +The initial value of the CDP's 16-bit unsigned integer @code{cdp_hdr_sequence_cntr} and @code{cdp_ftr_sequence_cntr} fields. Defaults to 0. +@item cdp_frame_rate +Set the CDP's @code{cdp_frame_rate} field. This doesn't actually change the timing of the data stream, it just changes the values inserted in that field in the generated CDP packets. Defaults to @samp{30000/1001}. +@end table + @section extract_extradata Extract the in-band extradata. @@ -423,9 +469,21 @@ Please note that this filter is auto-inserted for MPEG-TS (muxer @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. +This applies a specific fixup to some Blu-ray BDMV H264 streams +which contain redundant PPSs. The PPSs modify irrelevant parameters +of the stream, confusing other transformations which require +the correct extradata. + +The encoder used on these impacted streams adds extra PPSs throughout +the stream, varying the initial QP and whether weighted prediction +was enabled. This causes issues after copying the stream into +a global header container, as the starting PPS is not suitable +for the rest of the stream. One side effect, for example, +is seeking will return garbled output until a new PPS appears. + +This BSF removes the extra PPSs and rewrites the slice headers +such that the stream uses a single leading PPS in the global header, +which resolves the issue. @section hevc_metadata @@ -696,12 +754,12 @@ ffmpeg -i INPUT -c copy -bsf noise=1 output.mkv Drop every video packet not marked as a keyframe after timestamp 30s but do not modify any of the remaining packets. @example -ffmpeg -i INPUT -c copy -bsf:v noise=drop='gt(t\,30)*not(key)' output.mkv +ffmpeg -i INPUT -c copy -bsf:v noise=drop='gt(pts*tb\,30)*not(key)' output.mkv @end example Drop one second of audio every 10 seconds and add some random noise to the rest. @example -ffmpeg -i INPUT -c copy -bsf:a noise=amount=-1:drop='between(mod(t\,10)\,9\,10)' output.mkv +ffmpeg -i INPUT -c copy -bsf:a noise=amount=-1:drop='between(mod(pts*tb\,10)\,9\,10)' output.mkv @end example @section null @@ -936,6 +994,11 @@ ffmpeg -i INPUT -c:a copy -bsf:a setts=pts=DTS out.mkv Log basic packet information. Mainly useful for testing, debugging, and development. +@section smpte436m_to_eia608 + +Convert from a @code{SMPTE_436M_ANC} data stream to a @code{EIA_608} stream, +extracting the closed captions from CTA-708 CDP VANC packets, and ignoring all other data. + @anchor{text2movsub} @section text2movsub diff --git a/doc/build_system.txt b/doc/build_system.txt index 0b1b0c2054..77841b77ad 100644 --- a/doc/build_system.txt +++ b/doc/build_system.txt @@ -30,6 +30,13 @@ fate fate-list List all fate/regression test targets. +fate-list-failing + List the fate tests that failed the last time they were executed. + +fate-clear-reports + Remove the test reports from previous test executions (getting rid of + potentially stale results from fate-list-failing). + install Install headers, libraries and programs. @@ -63,4 +70,3 @@ make -j make -k Continue build in case of errors, this is useful for the regression tests sometimes but note that it will still not run all reg tests. - diff --git a/doc/codecs.texi b/doc/codecs.texi index 6bdeb664e7..f6bd50eb71 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -664,6 +664,8 @@ for codecs that support it. At present, those are H.264 and VP9. @item film_grain Export film grain parameters through frame side data (see @code{AV_FRAME_DATA_FILM_GRAIN_PARAMS}). Supported at present by AV1 decoders. +@item enhancements +Export picture enhancement metadata through frame side data, e.g. LCEVC (see @code{AV_FRAME_DATA_LCEVC}). @end table @item threads @var{integer} (@emph{decoding/encoding,video}) diff --git a/doc/decoders.texi b/doc/decoders.texi index 17bb361ffa..13eb40f4dd 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -395,7 +395,7 @@ without this library. @c man end AUDIO DECODERS @chapter Subtitles Decoders -@c man begin SUBTILES DECODERS +@c man begin SUBTITLES DECODERS @section libaribb24 @@ -427,7 +427,7 @@ Enabled by default. Yet another ARIB STD-B24 caption decoder using external @dfn{libaribcaption} library. -Implements profiles A and C of the Japanse ARIB STD-B24 standard, +Implements profiles A and C of the Japanese ARIB STD-B24 standard, Brazilian ABNT NBR 15606-1, and Philippines version of ISDB-T. Requires the presence of the libaribcaption headers and library @@ -477,7 +477,7 @@ Specify comma-separated list of font family names to be used for @dfn{bitmap} or @dfn{ass} type subtitle rendering. Only first font name is used for @dfn{ass} type subtitle. -If not specified, use internaly defined default font family. +If not specified, use internally defined default font family. @item -ass_single_rect @var{boolean} ARIB STD-B24 specifies that some captions may be displayed at different @@ -495,7 +495,7 @@ default behavior at compilation. @item -force_outline_text @var{boolean} Specify whether always render outline text for all characters regardless of -the indication by charactor style. +the indication by character style. The default is @var{false}. @@ -696,4 +696,4 @@ box and an end box, typically subtitles. Default value is 0 if @end table -@c man end SUBTILES DECODERS +@c man end SUBTITLES DECODERS diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 04293c4813..c6b72c3b69 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -292,7 +292,6 @@ DVD-Video demuxer, powered by libdvdnav and libdvdread. Can directly ingest DVD titles, specifically sequential PGCs, into a conversion pipeline. Menu assets, such as background video or audio, can also be demuxed given the menu's coordinates (at best effort). -Seeking is not supported at this time. Block devices (DVD drives), ISO files, and directory structures are accepted. Activate with @code{-f dvdvideo} in front of one of these inputs. @@ -380,11 +379,11 @@ Default is false. @item menu_lu @var{int} The menu language to demux. In DVD, menus are grouped by language. -Default is 0, the first language unit. +Default is 1, the first language unit. @item menu_vts @var{int} The VTS where the menu lives, or 0 if it is a VMG menu (root-level). -Default is 0, VMG menu. +Default is 1, menu of the first VTS. @item pgc @var{int} The entry PGC to start playback, in conjunction with @option{pg}. @@ -397,8 +396,7 @@ Default is 0, automatically resolve from value of @option{title}. The entry PG to start playback, in conjunction with @option{pgc}. Alternative to setting @option{title}. Chapter markers are not supported at this time. -Default is 0, automatically resolve from value of @option{title}, or -start from the beginning (PG 1) of the menu. +Default is 1, the first PG of the PGC. @item preindex @var{bool} Enable this to have accurate chapter (PTT) markers and duration measurement, @@ -406,7 +404,6 @@ which requires a slow second pass read in order to index the chapter marker timestamps from NAV packets. This is non-ideal extra work for real optical drives. It is recommended and faster to use this option with a backup of the DVD structure stored on a hard drive. Not compatible with @option{pgc} and @option{pg}. -Not applicable to menus. Default is 0, false. @item trim @var{bool} @@ -567,6 +564,13 @@ prefer to use #EXT-X-START if it's in playlist instead of live_start_index. @item allowed_extensions ',' separated list of file extensions that hls is allowed to access. +@item extension_picky +This blocks disallowed extensions from probing +It also requires all available segments to have matching extensions to the format +except mpegts, which is always allowed. +It is recommended to set the whitelists correctly instead of depending on extensions +Enabled by default. + @item max_reload Maximum number of times a insufficient list is attempted to be reloaded. Default value is 1000. @@ -851,6 +855,32 @@ Set the sample rate for libopenmpt to output. Range is from 1000 to INT_MAX. The value default is 48000. @end table +@anchor{mccdec} +@section mcc + +Demuxer for MacCaption MCC files, it supports MCC versions 1.0 and 2.0. +MCC files store VANC data, which can include closed captions (EIA-608 and CEA-708), ancillary time code, pan-scan data, etc. +By default, for backward compatibility, the MCC demuxer extracts just the EIA-608 and CEA-708 closed captions and returns a @code{EIA_608} stream, ignoring all other VANC data. +You can change it to return all VANC data in a @code{SMPTE_436M_ANC} data stream by setting @option{-eia608_extract 0} + +@subsection Examples + +@itemize +@item +Convert a MCC file to Scenarist (SCC) format: +@example +ffmpeg -i CC.mcc -c:s copy CC.scc +@end example +Note that the SCC format only supports EIA-608, so this will discard all other data such as CEA-708 extensions. + +@item +Merge a MCC file into a MXF file: +@example +ffmpeg -i video_and_audio.mxf -eia608_extract 0 -i CC.mcc -c copy -map 0 -map 1 out.mxf +@end example +This retains all VANC data and inserts it into the output MXF file as a @code{SMPTE_436M_ANC} data stream. +@end itemize + @section mov/mp4/3gp Demuxer for Quicktime File Format & ISO/IEC Base Media File Format (ISO/IEC 14496-12 or MPEG-4 Part 12, ISO/IEC 15444-12 or JPEG 2000 Part 12). @@ -986,7 +1016,7 @@ to 1 (-1 means automatic setting, 1 means enabled, 0 means disabled). Default value is -1. @item merge_pmt_versions -Re-use existing streams when a PMT's version is updated and elementary +Reuse existing streams when a PMT's version is updated and elementary streams move to different PIDs. Default value is 0. @item max_packet_size diff --git a/doc/developer.texi b/doc/developer.texi index 41b21938ef..10a2de00df 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -70,9 +70,6 @@ variable-length arrays; @item complex numbers; - -@item -mixed statements and declarations. @end itemize @subsection SIMD/DSP @@ -115,7 +112,7 @@ Objective-C where required for interacting with macOS-specific interfaces. @section Code formatting conventions -There are the following guidelines regarding the indentation in files: +There are the following guidelines regarding the code style in files: @itemize @bullet @item @@ -135,6 +132,104 @@ K&R coding style is used. @end itemize The presentation is one inspired by 'indent -i4 -kr -nut'. +@subsection Examples +Some notable examples to illustrate common code style in FFmpeg: + +@itemize @bullet + +@item +Space around assignments and after +@code{if}/@code{do}/@code{while}/@code{for} keywords: + +@example c, good +// Good +if (condition) + av_foo(); +@end example + +@example c, good +// Good +for (size_t i = 0; i < len; i++) + av_bar(i); +@end example + +@example c, good +// Good +size_t size = 0; +@end example + +However no spaces between the parentheses and condition, unless it helps +readability of complex conditions, so the following should not be done: + +@example c, bad +// Bad style +if ( condition ) + av_foo(); +@end example + +@item +No unnecessary parentheses, unless it helps readability: + +@example c, good +// Good +int fields = ilace ? 2 : 1; +@end example + +@item +Don't wrap single-line blocks in braces. Use braces only if there is an accompanying else statement. This keeps future code changes easier to keep track of. + +@example c, good +// Good +if (bits_pixel == 24) @{ + avctx->pix_fmt = AV_PIX_FMT_BGR24; +@} else if (bits_pixel == 8) @{ + avctx->pix_fmt = AV_PIX_FMT_GRAY8; +@} else + return AVERROR_INVALIDDATA; + +@end example + +@item +Avoid assignments in conditions where it makes sense: + +@example c, good +// Good +video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64) +if (!video_enc->chroma_intra_matrix) + return AVERROR(ENOMEM); +@end example + +@example c, bad +// Bad style +if (!(video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64))) + return AVERROR(ENOMEM); +@end example + +@example c, good +// Ok +while ((entry = av_dict_iterate(options, entry))) + av_log(ctx, AV_LOG_INFO, "Item '%s': '%s'\n", entry->key, entry->value); +@end example + +@item +When declaring a pointer variable, the @code{*} goes with the variable not the type: + +@example c, good +// Good +AVStream *stream; +@end example + +@example c, bad +// Bad style +AVStream* stream; +@end example + +@end itemize + +If you work on a file that does not follow these guidelines consistently, +change the parts that you are editing to follow these guidelines but do +not make unrelated changes in the file to make it conform to these. + @subsection Vim configuration In order to configure Vim to follow FFmpeg formatting conventions, paste the following snippet into your @file{.vimrc}: @@ -451,7 +546,7 @@ FFmpeg also has a defined scope - your new API must fit within it. @subsubheading Replacing existing APIs If your new API is replacing an existing one, it should be strictly superior to -it, so that the advantages of using the new API outweight the cost to the +it, so that the advantages of using the new API outweigh the cost to the callers of changing their code. After adding the new API you should then deprecate the old one and schedule it for removal, as described in @ref{Removing interfaces}. @@ -501,7 +596,7 @@ change in @file{doc/APIchanges}. Backward-incompatible API or ABI changes require incrementing (bumping) the major version number, as described in @ref{Major version bumps}. Major bumps are significant events that happen on a schedule - so if your change -strictly requires one you should add it under @code{#if} preprocesor guards that +strictly requires one you should add it under @code{#if} preprocessor guards that disable it until the next major bump happens. New APIs that can be added without breaking API or ABI compatibility require @@ -822,10 +917,10 @@ improves readability. Consider adding a regression test for your code. All new modules should be covered by tests. That includes demuxers, muxers, decoders, encoders filters, bitstream filters, parsers. If its not possible to do that, add -an explanation why to your patchset, its ok to not test if theres a reason. +an explanation why to your patchset, its ok to not test if there's a reason. @item -If you added YASM code please check that things still work with --disable-yasm. +If you added NASM code please check that things still work with --disable-x86asm. @item Test your code with valgrind and or Address Sanitizer to ensure it's free @@ -927,6 +1022,25 @@ In case you need finer control over how valgrind is invoked, use the @code{--target-exec='valgrind } option in your configure line instead. +@anchor{Maintenance} +@chapter Maintenance process + +@anchor{MAINTAINERS} +@section MAINTAINERS + +The developers maintaining each part of the codebase are listed in @file{MAINTAINERS}. +Being listed in @file{MAINTAINERS}, gives one the right to have git write access to +the specific repository. + +@anchor{Becoming a maintainer} +@section Becoming a maintainer + +People add themselves to @file{MAINTAINERS} by sending a patch like any other code +change. These get reviewed by the community like any other patch. It is expected +that, if someone has an objection to a new maintainer, she is willing to object +in public with her full name and is willing to take over maintainership for the area. + + @anchor{Release process} @chapter Release process diff --git a/doc/encoders.texi b/doc/encoders.texi index 0749417db4..b24f98946a 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -106,15 +106,8 @@ debugging by setting the option to "disable". Enables the use of the long term prediction extension which increases coding efficiency in very low bandwidth situations such as encoding of voice or solo piano music by extending constant harmonic peaks in bands throughout -frames. This option is implied by profile:a aac_low and is incompatible with -aac_pred. Use in conjunction with @option{-ar} to decrease the samplerate. - -@item aac_pred -Enables the use of a more traditional style of prediction where the spectral -coefficients transmitted are replaced by the difference of the current -coefficients minus the previous "predicted" coefficients. In theory and sometimes -in practice this can improve quality for low to mid bitrate audio. -This option implies the aac_main profile and is incompatible with aac_ltp. +frames. This option is implied by profile:a aac_low. +Use in conjunction with @option{-ar} to decrease the samplerate. @item profile Sets the encoding profile, possible values: @@ -132,10 +125,6 @@ MPEG4 specifications. Long term prediction profile, is enabled by and will enable the @option{aac_ltp} option. Introduced in MPEG4. -@item aac_main -Main-type prediction profile, is enabled by and will enable the @option{aac_pred} -option. Introduced in MPEG2. - @end table If this option is unspecified it is set to @samp{aac_low}. @end table @@ -1049,7 +1038,7 @@ forces a wideband cutoff for bitrates < 15 kbps, unless CELT-only Set channel mapping family to be used by the encoder. The default value of -1 uses mapping family 0 for mono and stereo inputs, and mapping family 1 otherwise. The default also disables the surround masking and LFE bandwidth -optimzations in libopus, and requires that the input contains 8 channels or +optimizations in libopus, and requires that the input contains 8 channels or fewer. Other values include 0 for mono and stereo, 1 for surround sound with masking @@ -1391,6 +1380,48 @@ Higher is better but slower. @end table +@anchor{ffv1} +@section ffv1 + +FFv1 Encoder + +@subsection Options + +The following options are supported by FFmpeg's FFv1 encoder. + +@table @option +@item context +Sets the context size, 0 (default) is small, 1 is big. + +@item coder +Set the coder, +@table @samp +@item rice +Golomb rice coder +@item range_def +Range coder with default table +@item range_tab +Range coder with custom table +@end table + +@item slicecrc +-1 (default, automatic), 1 use crc with zero initial and final state, 2 use crc with non zero initial and final state + +@item qtable +@table @samp +@item default +default, automatic +@item 8bit +use 8bit default +@item greater8bit +use >8bit default +@end table + +@item remap_optimizer +0 - 5, default 3, how much effort the encoder puts into optimizing the remap table. + +@end table + @section GIF GIF image/animation encoder. @@ -1858,6 +1889,42 @@ ffmpeg -i input -c:v libaom-av1 -b:v 500K -aom-params tune=psnr:enable-tpl-model @end table +@section liboapv + +Advanced Professional Video codec encoder wrapper. + +This encoder requires the presence of the liboapv headers and library +during configuration. You need to explicitly configure the build with +@option{--enable-liboapv}. + +@float NOTE +Many liboapv encoder options are mapped to FFmpeg global codec options, +while unique encoder options are provided through private options. +@end float + +The apv project website is at @url{https://github.com/AcademySoftwareFoundation/openapv}. + +@subsection Options + +The following options are supported by the liboapv wrapper. + +@float NOTE +To get a more extensive documentation of the liboapv options, consult the +liboapv documentation. +@end float + +@table @option +@item preset +Set the quality-speed tradeoff [fastest, fast, medium, slow, placebo, default] + +@item qp +Set the quantization parameter value for CQP rate control mode. + +@item oapv-params (@emph{parse_apv_params}) +Set liboapvenc options using a list of @var{key}=@var{value} pairs separated +by ":". See the liboapv encoder user guide for a list of accepted parameters. +@end table + @section libsvtav1 SVT-AV1 encoder wrapper. @@ -3275,6 +3342,75 @@ fastest. @end table +@section MediaCodec + +MediaCodec encoder wrapper enables hardware-accelerated video encoding on +Android device. It supports H.264, H.265 (HEVC), VP8, VP9, MPEG-4, and AV1 +encoding (whether works or not is device dependent). + +Android provides two sets of APIs: Java MediaCodec and NDK MediaCodec. The +MediaCodec encoder wrapper supports both. Note that the NDK MediaCodec API +operates without requiring JVM, but may fail to function outside the JVM +environment due to dependencies on system framework services, particularly +after Android 15. + +@table @option +@item ndk_codec @var{boolean} +Use the NDK-based MediaCodec API instead of the Java API. Enabled by default +if @code{av_jni_get_java_vm()} return NULL. + +@item ndk_async @var{boolean} +Use NDK MediaCodec in async mode. Async mode has less overhead than poll in a +loop in sync mode. The drawback of async mode is AV_CODEC_FLAG_GLOBAL_HEADER +doesn't work (use extract_extradata bsf when necessary). It doesn't work and +will be disabled automatically on devices below Android 8.0. + +@item codec_name @var{string} +A codec type can have multiple implementations on a single device, this option +specify which backend to use (via MediaCodec createCodecByName API). It's NULL +by default, and encoder is created by createEncoderByType. + +@item bitrate_mode @var{integer} + +Possible values: +@table @samp +@item cq +Constant quality mode +@item vbr +Variable bitrate mode +@item cbr +Constant bitrate mode +@item cbr_fd +Constant bitrate mode with frame drops +@end table + +@item pts_as_dts @var{boolean} +Use PTS as DTS. This is a workaround since MediaCodec API doesn't provide +decoding timestamp. It is enabled automatically if B frame is 0. + +@item operating_rate @var{integer} +The desired operating rate that the codec will need to operate at, zero for +unspecified. This is used for cases like high-speed/slow-motion video capture, +where the video encoder format contains the target playback rate (e.g. 30fps), +but the component must be able to handle the high operating capture rate (e.g. +240fps). This rate will be used by codec for resource planning and setting the +operating points. + +@item qp_i_min @var{integer} +Minimum quantization parameter for I frame. +@item qp_p_min @var{integer} +Minimum quantization parameter for P frame. +@item qp_b_min @var{integer} +Minimum quantization parameter for B frame. +@item qp_i_max @var{integer} +Maximum quantization parameter for I frame. +@item qp_p_max @var{integer} +Maximum quantization parameter for P frame. +@item qp_b_max @var{integer} +Maximum quantization parameter for B frame. + +@end table + @section MediaFoundation This provides wrappers to encoders (both audio and video) in the @@ -3357,6 +3493,13 @@ Default is 1 (on). PNG image encoder. +@subsection Options + +@table @option +@item compression_level +Sets the compression level, from 0 to 9(default) +@end table + @subsection Private options @table @option @@ -3364,6 +3507,8 @@ PNG image encoder. Set physical density of pixels, in dots per inch, unset by default @item dpm @var{integer} Set physical density of pixels, in dots per meter, unset by default +@item pred @var{method} +Set prediction method (none, sub, up, avg, paeth, mixed), default is paeth @end table @section ProRes @@ -3558,7 +3703,7 @@ For encoders set this flag to ON to reduce power consumption and GPU usage. @end table @subsection Runtime Options -Following options can be used durning qsv encoding. +Following options can be used during qsv encoding. @table @option @item @var{global_quality} @@ -3668,7 +3813,7 @@ improves subjective visual quality. Enabling this flag may have negative impact on performance and objective visual quality metric. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -3867,7 +4012,7 @@ improves subjective visual quality. Enabling this flag may have negative impact on performance and objective visual quality metric. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -4101,7 +4246,7 @@ Extended bitrate control. Depth of look ahead in number frames, available when extbrc option is enabled. @item @var{low_delay_brc} -Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provides +Setting this flag turns on or off LowDelayBRC feature in qsv plugin, which provides more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on @@ -4457,6 +4602,25 @@ Reduces detail but attempts to preserve color at extremely low bitrates. @chapter Subtitles Encoders @c man begin SUBTITLES ENCODERS +@section dvbsub + +This codec encodes the bitmap subtitle format that is used in DVB +broadcasts and recordings. The bitmaps are typically embedded in a +container such as MPEG-TS as a separate stream. + +@subsection Options + +@table @option +@item min_bpp @var{integer (2, 4, or 8)} +Set a minimum bits-per-pixel value for the subtitle color lookup tables. + +DVB supports 2, 4, and 8 bits-per-pixel color lookup tables. This +option enables forcing a particular bits-per-pixel value regardless of +the number of colors. Since not all players support or properly +support 2 bits-per-pixel, this value defaults to 4. + +@end table + @section dvdsub This codec encodes the bitmap subtitle format that is used in DVDs. @@ -4484,4 +4648,18 @@ one byte per subtitle on average. By default, this work-around is disabled. @end table +@section lrc + +This codec encodes the LRC lyrics format. + +@subsection Options + +@table @option +@item precision +Specify the precision of the fractional part of the timestamp. Time base is +determined based on this value. + +Defaults to 2 for centiseconds. +@end table + @c man end SUBTITLES ENCODERS diff --git a/doc/examples/avio_read_callback.c b/doc/examples/avio_read_callback.c index dffc061d9f..0a299b4c73 100644 --- a/doc/examples/avio_read_callback.c +++ b/doc/examples/avio_read_callback.c @@ -96,6 +96,7 @@ int main(int argc, char *argv[]) avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0, &bd, &read_packet, NULL, NULL); if (!avio_ctx) { + av_freep(&avio_ctx_buffer); ret = AVERROR(ENOMEM); goto end; } diff --git a/doc/examples/decode_audio.c b/doc/examples/decode_audio.c index bcb3d87a69..26ce07a552 100644 --- a/doc/examples/decode_audio.c +++ b/doc/examples/decode_audio.c @@ -128,6 +128,10 @@ int main(int argc, char **argv) outfilename = argv[2]; pkt = av_packet_alloc(); + if (!pkt) { + fprintf(stderr, "Could not allocate AVPacket\n"); + exit(1); /* or proper cleanup and returning */ + } /* find the MPEG audio decoder */ codec = avcodec_find_decoder(AV_CODEC_ID_MP2); @@ -161,7 +165,7 @@ int main(int argc, char **argv) } outfile = fopen(outfilename, "wb"); if (!outfile) { - av_free(c); + fprintf(stderr, "Could not open %s\n", outfilename); exit(1); } diff --git a/doc/examples/decode_filter_audio.c b/doc/examples/decode_filter_audio.c index d637ca1724..67c8a14aab 100644 --- a/doc/examples/decode_filter_audio.c +++ b/doc/examples/decode_filter_audio.c @@ -30,8 +30,6 @@ * file to be played with ffplay. */ -#include - #include #include #include @@ -96,8 +94,7 @@ static int init_filters(const char *filters_descr) 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 }; - static const int out_sample_rates[] = { 8000, -1 }; + static const int out_sample_rate = 8000; const AVFilterLink *outlink; AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base; @@ -123,34 +120,40 @@ static int init_filters(const char *filters_descr) } /* buffer audio sink: to terminate the filter chain. */ - ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1, - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "sample_formats", "s16", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); goto end; } - ret = av_opt_set(buffersink_ctx, "ch_layouts", "mono", - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "channel_layouts", "mono", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1, - AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set_array(buffersink_ctx, "samplerates", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_INT, &out_sample_rate); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize audio buffer sink\n"); + goto end; + } + /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. diff --git a/doc/examples/decode_filter_video.c b/doc/examples/decode_filter_video.c index b91ca56d4e..62ada4bca7 100644 --- a/doc/examples/decode_filter_video.c +++ b/doc/examples/decode_filter_video.c @@ -27,8 +27,6 @@ * @example decode_filter_video.c */ -#define _XOPEN_SOURCE 600 /* for usleep */ -#include #include #include @@ -38,6 +36,7 @@ #include #include #include +#include const char *filter_descr = "scale=78:24,transpose=cclock"; /* other way: @@ -99,7 +98,6 @@ static int init_filters(const char *filters_descr) AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base; - enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; filter_graph = avfilter_graph_alloc(); if (!outputs || !inputs || !filter_graph) { @@ -122,20 +120,26 @@ static int init_filters(const char *filters_descr) } /* buffer video sink: to terminate the filter chain. */ - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } - ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, - AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set(buffersink_ctx, "pixel_formats", "gray8", + AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize buffer sink\n"); + goto end; + } + /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. @@ -190,7 +194,7 @@ static void display_frame(const AVFrame *frame, AVRational time_base) delay = av_rescale_q(frame->pts - last_pts, time_base, AV_TIME_BASE_Q); if (delay > 0 && delay < 1000000) - usleep(delay); + av_usleep(delay); } last_pts = frame->pts; } diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c index 8b237e2adf..ad77bf1f89 100644 --- a/doc/examples/filter_audio.c +++ b/doc/examples/filter_audio.c @@ -270,7 +270,6 @@ int main(int argc, char *argv[]) AVFilterGraph *graph; AVFilterContext *src, *sink; AVFrame *frame; - uint8_t errstr[1024]; float duration; int err, nb_frames, i; @@ -295,6 +294,7 @@ int main(int argc, char *argv[]) md5 = av_md5_alloc(); if (!md5) { + av_frame_free(&frame); fprintf(stderr, "Error allocating the MD5 context\n"); return 1; } @@ -302,8 +302,10 @@ int main(int argc, char *argv[]) /* Set up the filtergraph. */ err = init_filter_graph(&graph, &src, &sink); if (err < 0) { + av_frame_free(&frame); + av_freep(&md5); fprintf(stderr, "Unable to init filter graph:"); - goto fail; + return 1; } /* the main filtering loop */ @@ -354,7 +356,10 @@ int main(int argc, char *argv[]) return 0; fail: - av_strerror(err, errstr, sizeof(errstr)); - fprintf(stderr, "%s\n", errstr); + avfilter_graph_free(&graph); + av_frame_free(&frame); + av_freep(&md5); + + fprintf(stderr, "%s\n", av_err2str(err)); return 1; } diff --git a/doc/examples/mux.c b/doc/examples/mux.c index 0f3a2bb125..9b22c8dd1d 100644 --- a/doc/examples/mux.c +++ b/doc/examples/mux.c @@ -418,7 +418,7 @@ static void open_video(AVFormatContext *oc, const AVCodec *codec, exit(1); } - /* allocate and init a re-usable frame */ + /* allocate and init a reusable frame */ ost->frame = alloc_frame(c->pix_fmt, c->width, c->height); if (!ost->frame) { fprintf(stderr, "Could not allocate video frame\n"); diff --git a/doc/examples/qsv_decode.c b/doc/examples/qsv_decode.c index 5a6f3625aa..ec91109480 100644 --- a/doc/examples/qsv_decode.c +++ b/doc/examples/qsv_decode.c @@ -219,11 +219,8 @@ int main(int argc, char **argv) ret = decode_packet(decoder_ctx, frame, sw_frame, NULL, output_ctx); finish: - if (ret < 0) { - char buf[1024]; - av_strerror(ret, buf, sizeof(buf)); - fprintf(stderr, "%s\n", buf); - } + if (ret < 0) + fprintf(stderr, "%s\n", av_err2str(ret)); avformat_close_input(&input_ctx); diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c index 665a76af2e..13b4933041 100644 --- a/doc/examples/qsv_transcode.c +++ b/doc/examples/qsv_transcode.c @@ -101,7 +101,7 @@ static int dynamic_set_parameter(AVCodecContext *avctx) /* Set codec specific option */ if ((ret = av_opt_set_dict(avctx->priv_data, &opts)) < 0) goto fail; - /* There is no "framerate" option in commom option list. Use "-r" to set + /* There is no "framerate" option in common option list. Use "-r" to set * framerate, which is compatible with ffmpeg commandline. The video is * assumed to be average frame rate, so set time_base to 1/framerate. */ e = av_dict_get(opts, "r", NULL, 0); @@ -180,7 +180,7 @@ static int open_input_file(char *filename) decoder = avcodec_find_decoder_by_name("mjpeg_qsv"); break; default: - fprintf(stderr, "Codec is not supportted by qsv\n"); + fprintf(stderr, "Codec is not supported by qsv\n"); return AVERROR(EINVAL); } @@ -289,7 +289,7 @@ static int dec_enc(AVPacket *pkt, const AVCodec *enc_codec, char *optstr) fprintf(stderr, "Failed to set encoding parameter.\n"); goto fail; } - /* There is no "framerate" option in commom option list. Use "-r" to + /* There is no "framerate" option in common option list. Use "-r" to * set framerate, which is compatible with ffmpeg commandline. The * video is assumed to be average frame rate, so set time_base to * 1/framerate. */ diff --git a/doc/examples/transcode.c b/doc/examples/transcode.c index cbe5088ef6..1dc1b50502 100644 --- a/doc/examples/transcode.c +++ b/doc/examples/transcode.c @@ -171,23 +171,38 @@ static int open_output_file(const char *filename) * sample rate etc.). These properties can be changed for output * streams easily using filters */ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { + const enum AVPixelFormat *pix_fmts = NULL; + enc_ctx->height = dec_ctx->height; enc_ctx->width = dec_ctx->width; enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; + + ret = avcodec_get_supported_config(dec_ctx, NULL, + AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void**)&pix_fmts, NULL); + /* take first format from list of supported formats */ - if (encoder->pix_fmts) - enc_ctx->pix_fmt = encoder->pix_fmts[0]; - else - enc_ctx->pix_fmt = dec_ctx->pix_fmt; + enc_ctx->pix_fmt = (ret >= 0 && pix_fmts) ? + pix_fmts[0] : dec_ctx->pix_fmt; + /* video time_base can be set to whatever is handy and supported by encoder */ enc_ctx->time_base = av_inv_q(dec_ctx->framerate); } else { + const enum AVSampleFormat *sample_fmts = NULL; + enc_ctx->sample_rate = dec_ctx->sample_rate; ret = av_channel_layout_copy(&enc_ctx->ch_layout, &dec_ctx->ch_layout); if (ret < 0) return ret; + + ret = avcodec_get_supported_config(dec_ctx, NULL, + AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, + (const void**)&sample_fmts, NULL); + /* take first format from list of supported formats */ - enc_ctx->sample_fmt = encoder->sample_fmts[0]; + enc_ctx->sample_fmt = (ret >= 0 && sample_fmts) ? + sample_fmts[0] : dec_ctx->sample_fmt; + enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate}; } @@ -283,10 +298,10 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, goto end; } - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } @@ -297,6 +312,12 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } + + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize buffer sink\n"); + goto end; + } } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { char buf[64]; buffersrc = avfilter_get_by_name("abuffer"); @@ -322,10 +343,10 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, goto end; } - ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", - NULL, NULL, filter_graph); - if (ret < 0) { + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, buffersink, "out"); + if (!buffersink_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); + ret = AVERROR(ENOMEM); goto end; } @@ -352,6 +373,15 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } + + if (enc_ctx->frame_size > 0) + av_buffersink_set_frame_size(buffersink_ctx, enc_ctx->frame_size); + + ret = avfilter_init_dict(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot initialize audio buffer sink\n"); + goto end; + } } else { ret = AVERROR_UNKNOWN; goto end; diff --git a/doc/fate.texi b/doc/fate.texi index 17644ce65a..7a2e0edfcc 100644 --- a/doc/fate.texi +++ b/doc/fate.texi @@ -208,6 +208,13 @@ Download/synchronize sample files to the configured samples directory. @item fate-list Will list all fate/regression test targets. +@item fate-list-failing +List the fate tests that failed the last time they were executed. + +@item fate-clear-reports +Remove the test reports from previous test executions (getting rid of +potentially stale results from fate-list-failing). + @item fate Run the FATE test suite (requires the fate-suite dataset). @end table diff --git a/doc/fate_config.sh.template b/doc/fate_config.sh.template index 8681805d65..4ff8629d44 100644 --- a/doc/fate_config.sh.template +++ b/doc/fate_config.sh.template @@ -1,5 +1,5 @@ slot= # some unique identifier -repo=git://source.ffmpeg.org/ffmpeg.git # the source repository +repo=https://git.ffmpeg.org/ffmpeg.git # the source repository #branch=release/2.6 # the branch to test samples= # path to samples directory workdir= # directory in which to do all the work diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 34007f7ea2..3daf2f7ec2 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -21,22 +21,24 @@ ffmpeg [@var{global_options}] @{[@var{input_file_options}] -i @file{input_url}@} inputs - including live grabbing/recording devices - filter, and transcode them into a plethora of output formats. -@command{ffmpeg} reads from an arbitrary number of input "files" (which can be regular +@command{ffmpeg} reads from an arbitrary number of inputs (which can be regular files, pipes, network streams, grabbing devices, etc.), specified by the -@code{-i} option, and writes to an arbitrary number of output "files", which are -specified by a plain output url. Anything found on the command line which -cannot be interpreted as an option is considered to be an output url. +@code{-i} option, and writes to an arbitrary number of outputs, which are +specified by a plain output url. Anything found on the command line which cannot +be interpreted as an option is considered to be an output url. -Each input or output url can, in principle, contain any number of streams of -different types (video/audio/subtitle/attachment/data). The allowed number and/or -types of streams may be limited by the container format. Selecting which -streams from which inputs will go into which output is either done automatically -or with the @code{-map} option (see the Stream selection chapter). +Each input or output can, in principle, contain any number of elementary streams +of different types (video/audio/subtitle/attachment/data), though the allowed +stream counts and/or types may be limited by the container format. Selecting +which streams from which inputs will go into which output is either done +automatically or with the @code{-map} option (see the @ref{Stream selection} +chapter). -To refer to input files in options, you must use their indices (0-based). E.g. -the first input file is @code{0}, the second is @code{1}, etc. Similarly, streams -within a file are referred to by their indices. E.g. @code{2:3} refers to the -fourth stream in the third input file. Also see the Stream specifiers chapter. +To refer to inputs/outputs in options, you must use their indices (0-based). +E.g. the first input is @code{0}, the second is @code{1}, etc. Similarly, +streams within an input/output are referred to by their indices. E.g. @code{2:3} +refers to the fourth stream in the third input or output. Also see the +@ref{Stream specifiers} chapter. As a general rule, options are applied to the next specified file. Therefore, order is important, and you can have the same @@ -85,140 +87,405 @@ The format option may be needed for raw input files. @chapter Detailed description @c man begin DETAILED DESCRIPTION -The transcoding process in @command{ffmpeg} for each output can be described by -the following diagram: +@command{ffmpeg} builds a transcoding pipeline out of the components listed +below. The program's operation then consists of input data chunks flowing from +the sources down the pipes towards the sinks, while being transformed by the +components they encounter along the way. +The following kinds of components are available: +@itemize +@item +@emph{Demuxers} (short for "demultiplexers") read an input source in order to +extract + +@itemize +@item +global properties such as metadata or chapters; +@item +list of input elementary streams and their properties +@end itemize + +One demuxer instance is created for each @option{-i} option, and sends encoded +@emph{packets} to @emph{decoders} or @emph{muxers}. + +In other literature, demuxers are sometimes called @emph{splitters}, because +their main function is splitting a file into elementary streams (though some +files only contain one elementary stream). + +A schematic representation of a demuxer looks like this: @verbatim - _______ ______________ -| | | | -| input | demuxer | encoded data | decoder -| file | ---------> | packets | -----+ -|_______| |______________| | - v - _________ - | | - | decoded | - | frames | - |_________| - ________ ______________ | -| | | | | -| output | <-------- | encoded data | <----+ -| file | muxer | packets | encoder -|________| |______________| - - +┌──────────┬───────────────────────┐ +│ demuxer │ │ packets for stream 0 +╞══════════╡ elementary stream 0 ├──────────────────────► +│ │ │ +│ global ├───────────────────────┤ +│properties│ │ packets for stream 1 +│ and │ elementary stream 1 ├──────────────────────► +│ metadata │ │ +│ ├───────────────────────┤ +│ │ │ +│ │ ........... │ +│ │ │ +│ ├───────────────────────┤ +│ │ │ packets for stream N +│ │ elementary stream N ├──────────────────────► +│ │ │ +└──────────┴───────────────────────┘ + ▲ + │ + │ read from file, network stream, + │ grabbing device, etc. + │ @end verbatim -@command{ffmpeg} calls the libavformat library (containing demuxers) to read -input files and get packets containing encoded data from them. When there are -multiple input files, @command{ffmpeg} tries to keep them synchronized by -tracking lowest timestamp on any active input stream. +@item +@emph{Decoders} receive encoded (compressed) @emph{packets} for an audio, video, +or subtitle elementary stream, and decode them into raw @emph{frames} (arrays of +pixels for video, PCM for audio). A decoder is typically associated with (and +receives its input from) an elementary stream in a @emph{demuxer}, but sometimes +may also exist on its own (see @ref{Loopback decoders}). + +A schematic representation of a decoder looks like this: +@verbatim + ┌─────────┐ + packets │ │ raw frames +─────────►│ decoder ├────────────► + │ │ + └─────────┘ +@end verbatim + +@item +@emph{Filtergraphs} process and transform raw audio or video @emph{frames}. A +filtergraph consists of one or more individual @emph{filters} linked into a +graph. Filtergraphs come in two flavors - @emph{simple} and @emph{complex}, +configured with the @option{-filter} and @option{-filter_complex} options, +respectively. + +A simple filtergraph is associated with an @emph{output elementary stream}; it +receives the input to be filtered from a @emph{decoder} and sends filtered +output to that output stream's @emph{encoder}. + +A simple video filtergraph that performs deinterlacing (using the @code{yadif} +deinterlacer) followed by resizing (using the @code{scale} filter) can look like +this: +@verbatim + + ┌────────────────────────┐ + │ simple filtergraph │ + frames from ╞════════════════════════╡ frames for + a decoder │ ┌───────┐ ┌───────┐ │ an encoder +────────────►├─►│ yadif ├─►│ scale ├─►│────────────► + │ └───────┘ └───────┘ │ + └────────────────────────┘ +@end verbatim + +A complex filtergraph is standalone and not associated with any specific stream. +It may have multiple (or zero) inputs, potentially of different types (audio or +video), each of which receiving data either from a decoder or another complex +filtergraph's output. It also has one or more outputs that feed either an +encoder or another complex filtergraph's input. + +The following example diagram represents a complex filtergraph with 3 inputs and +2 outputs (all video): +@verbatim + ┌─────────────────────────────────────────────────┐ + │ complex filtergraph │ + ╞═════════════════════════════════════════════════╡ + frames ├───────┐ ┌─────────┐ ┌─────────┐ ┌────────┤ frames +─────────►│input 0├─►│ overlay ├─────►│ overlay ├─►│output 0├────────► + ├───────┘ │ │ │ │ └────────┤ + frames ├───────┐╭►│ │ ╭►│ │ │ +─────────►│input 1├╯ └─────────┘ │ └─────────┘ │ + ├───────┘ │ │ + frames ├───────┐ ┌─────┐ ┌─────┬─╯ ┌────────┤ frames +─────────►│input 2├►│scale├►│split├───────────────►│output 1├────────► + ├───────┘ └─────┘ └─────┘ └────────┤ + └─────────────────────────────────────────────────┘ +@end verbatim +Frames from second input are overlaid over those from the first. Frames from the +third input are rescaled, then the duplicated into two identical streams. One of +them is overlaid over the combined first two inputs, with the result exposed as +the filtergraph's first output. The other duplicate ends up being the +filtergraph's second output. + +@item +@emph{Encoders} receive raw audio, video, or subtitle @emph{frames} and encode +them into encoded @emph{packets}. The encoding (compression) process is +typically @emph{lossy} - it degrades stream quality to make the output smaller; +some encoders are @emph{lossless}, but at the cost of much higher output size. A +video or audio encoder receives its input from some filtergraph's output, +subtitle encoders receive input from a decoder (since subtitle filtering is not +supported yet). Every encoder is associated with some muxer's @emph{output +elementary stream} and sends its output to that muxer. + +A schematic representation of an encoder looks like this: +@verbatim + ┌─────────┐ + raw frames │ │ packets +────────────►│ encoder ├─────────► + │ │ + └─────────┘ +@end verbatim + +@item +@emph{Muxers} (short for "multiplexers") receive encoded @emph{packets} for +their elementary streams from encoders (the @emph{transcoding} path) or directly +from demuxers (the @emph{streamcopy} path), interleave them (when there is more +than one elementary stream), and write the resulting bytes into the output file +(or pipe, network stream, etc.). + +A schematic representation of a muxer looks like this: +@verbatim + ┌──────────────────────┬───────────┐ + packets for stream 0 │ │ muxer │ +──────────────────────►│ elementary stream 0 ╞═══════════╡ + │ │ │ + ├──────────────────────┤ global │ + packets for stream 1 │ │properties │ +──────────────────────►│ elementary stream 1 │ and │ + │ │ metadata │ + ├──────────────────────┤ │ + │ │ │ + │ ........... │ │ + │ │ │ + ├──────────────────────┤ │ + packets for stream N │ │ │ +──────────────────────►│ elementary stream N │ │ + │ │ │ + └──────────────────────┴─────┬─────┘ + │ + write to file, network stream, │ + grabbing device, etc. │ + │ + ▼ +@end verbatim + +@end itemize + +@section Streamcopy +The simplest pipeline in @command{ffmpeg} is single-stream +@emph{streamcopy}, that is copying one @emph{input elementary stream}'s packets +without decoding, filtering, or encoding them. As an example, consider an input +file called @file{INPUT.mkv} with 3 elementary streams, from which we take the +second and write it to file @file{OUTPUT.mp4}. A schematic representation of +such a pipeline looks like this: +@verbatim +┌──────────┬─────────────────────┐ +│ demuxer │ │ unused +╞══════════╡ elementary stream 0 ├────────╳ +│ │ │ +│INPUT.mkv ├─────────────────────┤ ┌──────────────────────┬───────────┐ +│ │ │ packets │ │ muxer │ +│ │ elementary stream 1 ├─────────►│ elementary stream 0 ╞═══════════╡ +│ │ │ │ │OUTPUT.mp4 │ +│ ├─────────────────────┤ └──────────────────────┴───────────┘ +│ │ │ unused +│ │ elementary stream 2 ├────────╳ +│ │ │ +└──────────┴─────────────────────┘ +@end verbatim + +The above pipeline can be constructed with the following commandline: +@example +ffmpeg -i INPUT.mkv -map 0:1 -c copy OUTPUT.mp4 +@end example + +In this commandline +@itemize + +@item +there is a single input @file{INPUT.mkv}; + +@item +there are no input options for this input; + +@item +there is a single output @file{OUTPUT.mp4}; + +@item +there are two output options for this output: + +@itemize +@item +@code{-map 0:1} selects the input stream to be used - from input with index 0 +(i.e. the first one) the stream with index 1 (i.e. the second one); + +@item +@code{-c copy} selects the @code{copy} encoder, i.e. streamcopy with no decoding +or encoding. +@end itemize + +@end itemize + +Streamcopy is useful for changing the elementary stream count, container format, +or modifying container-level metadata. Since there is no decoding or encoding, +it is very fast and there is no quality loss. However, it might not work in some +cases because of a variety of factors (e.g. certain information required by the +target container is not available in the source). Applying filters is obviously +also impossible, since filters work on decoded frames. + +More complex streamcopy scenarios can be constructed - e.g. combining streams +from two input files into a single output: +@verbatim +┌──────────┬────────────────────┐ ┌────────────────────┬───────────┐ +│ demuxer 0│ │ packets │ │ muxer │ +╞══════════╡elementary stream 0 ├────────►│elementary stream 0 ╞═══════════╡ +│INPUT0.mkv│ │ │ │OUTPUT.mp4 │ +└──────────┴────────────────────┘ ├────────────────────┤ │ +┌──────────┬────────────────────┐ │ │ │ +│ demuxer 1│ │ packets │elementary stream 1 │ │ +╞══════════╡elementary stream 0 ├────────►│ │ │ +│INPUT1.aac│ │ └────────────────────┴───────────┘ +└──────────┴────────────────────┘ +@end verbatim +that can be built by the commandline +@example +ffmpeg -i INPUT0.mkv -i INPUT1.aac -map 0:0 -map 1:0 -c copy OUTPUT.mp4 +@end example + +The output @option{-map} option is used twice here, creating two streams in the +output file - one fed by the first input and one by the second. The single +instance of the @option{-c} option selects streamcopy for both of those streams. +You could also use multiple instances of this option together with +@ref{Stream specifiers} to apply different values to each stream, as will be +demonstrated in following sections. + +A converse scenario is splitting multiple streams from a single input into +multiple outputs: +@verbatim +┌──────────┬─────────────────────┐ ┌───────────────────┬───────────┐ +│ demuxer │ │ packets │ │ muxer 0 │ +╞══════════╡ elementary stream 0 ├─────────►│elementary stream 0╞═══════════╡ +│ │ │ │ │OUTPUT0.mp4│ +│INPUT.mkv ├─────────────────────┤ └───────────────────┴───────────┘ +│ │ │ packets ┌───────────────────┬───────────┐ +│ │ elementary stream 1 ├─────────►│ │ muxer 1 │ +│ │ │ │elementary stream 0╞═══════════╡ +└──────────┴─────────────────────┘ │ │OUTPUT1.mp4│ + └───────────────────┴───────────┘ +@end verbatim +built with +@example +ffmpeg -i INPUT.mkv -map 0:0 -c copy OUTPUT0.mp4 -map 0:1 -c copy OUTPUT1.mp4 +@end example +Note how a separate instance of the @option{-c} option is needed for every +output file even though their values are the same. This is because non-global +options (which is most of them) only apply in the context of the file before +which they are placed. + +These examples can of course be further generalized into arbitrary remappings +of any number of inputs into any number of outputs. + +@section Transcoding +@emph{Transcoding} is the process of decoding a stream and then encoding it +again. Since encoding tends to be computationally expensive and in most cases +degrades the stream quality (i.e. it is @emph{lossy}), you should only transcode +when you need to and perform streamcopy otherwise. Typical reasons to transcode +are: + +@itemize +@item +applying filters - e.g. resizing, deinterlacing, or overlaying video; resampling +or mixing audio; + +@item +you want to feed the stream to something that cannot decode the original codec. +@end itemize +Note that @command{ffmpeg} will transcode all audio, video, and subtitle streams +unless you specify @option{-c copy} for them. + +Consider an example pipeline that reads an input file with one audio and one +video stream, transcodes the video and copies the audio into a single output +file. This can be schematically represented as follows +@verbatim +┌──────────┬─────────────────────┐ +│ demuxer │ │ audio packets +╞══════════╡ stream 0 (audio) ├─────────────────────────────────────╮ +│ │ │ │ +│INPUT.mkv ├─────────────────────┤ video ┌─────────┐ raw │ +│ │ │ packets │ video │ video frames │ +│ │ stream 1 (video) ├─────────►│ decoder ├──────────────╮ │ +│ │ │ │ │ │ │ +└──────────┴─────────────────────┘ └─────────┘ │ │ + ▼ ▼ + │ │ +┌──────────┬─────────────────────┐ video ┌─────────┐ │ │ +│ muxer │ │ packets │ video │ │ │ +╞══════════╡ stream 0 (video) │◄─────────┤ encoder ├──────────────╯ │ +│ │ │ │(libx264)│ │ +│OUTPUT.mp4├─────────────────────┤ └─────────┘ │ +│ │ │ │ +│ │ stream 1 (audio) │◄────────────────────────────────────╯ +│ │ │ +└──────────┴─────────────────────┘ +@end verbatim +and implemented with the following commandline: +@example +ffmpeg -i INPUT.mkv -map 0:v -map 0:a -c:v libx264 -c:a copy OUTPUT.mp4 +@end example +Note how it uses stream specifiers @code{:v} and @code{:a} to select input +streams and apply different values of the @option{-c} option to them; see the +@ref{Stream specifiers} section for more details. -Encoded packets are then passed to the decoder (unless streamcopy is selected -for the stream, see further for a description). The decoder produces -uncompressed frames (raw video/PCM audio/...) which can be processed further by -filtering (see next section). After filtering, the frames are passed to the -encoder, which encodes them and outputs encoded packets. Finally, those are -passed to the muxer, which writes the encoded packets to the output file. @section Filtering -Before encoding, @command{ffmpeg} can process raw audio and video frames using -filters from the libavfilter library. Several chained filters form a filter -graph. @command{ffmpeg} distinguishes between two types of filtergraphs: -simple and complex. + +When transcoding, audio and video streams can be filtered before encoding, with +either a @emph{simple} or @emph{complex} filtergraph. @subsection Simple filtergraphs + Simple filtergraphs are those that have exactly one input and output, both of -the same type. In the above diagram they can be represented by simply inserting -an additional step between decoding and encoding: +the same type (audio or video). They are configured with the per-stream +@option{-filter} option (with @option{-vf} and @option{-af} aliases for +@option{-filter:v} (video) and @option{-filter:a} (audio) respectively). Note +that simple filtergraphs are tied to their output stream, so e.g. if you have +multiple audio streams, @option{-af} will create a separate filtergraph for each +one. +Taking the transcoding example from above, adding filtering (and omitting audio, +for clarity) makes it look like this: @verbatim - _________ ______________ -| | | | -| decoded | | encoded data | -| frames |\ _ | packets | -|_________| \ /||______________| - \ __________ / - simple _\|| | / encoder - filtergraph | filtered |/ - | frames | - |__________| - +┌──────────┬───────────────┐ +│ demuxer │ │ ┌─────────┐ +╞══════════╡ video stream │ packets │ video │ frames +│INPUT.mkv │ ├─────────►│ decoder ├─────►───╮ +│ │ │ └─────────┘ │ +└──────────┴───────────────┘ │ + ╭───────────◄───────────╯ + │ ┌────────────────────────┐ + │ │ simple filtergraph │ + │ ╞════════════════════════╡ + │ │ ┌───────┐ ┌───────┐ │ + ╰──►├─►│ yadif ├─►│ scale ├─►├╮ + │ └───────┘ └───────┘ ││ + └────────────────────────┘│ + │ + │ +┌──────────┬───────────────┐ video ┌─────────┐ │ +│ muxer │ │ packets │ video │ │ +╞══════════╡ video stream │◄─────────┤ encoder ├───────◄───────╯ +│OUTPUT.mp4│ │ │ │ +│ │ │ └─────────┘ +└──────────┴───────────────┘ @end verbatim -Simple filtergraphs are configured with the per-stream @option{-filter} option -(with @option{-vf} and @option{-af} aliases for video and audio respectively). -A simple filtergraph for video can look for example like this: - -@verbatim - _______ _____________ _______ ________ -| | | | | | | | -| input | ---> | deinterlace | ---> | scale | ---> | output | -|_______| |_____________| |_______| |________| - -@end verbatim - -Note that some filters change frame properties but not frame contents. E.g. the -@code{fps} filter in the example above changes number of frames, but does not -touch the frame contents. Another example is the @code{setpts} filter, which -only sets timestamps and otherwise passes the frames unchanged. - @subsection Complex filtergraphs + Complex filtergraphs are those which cannot be described as simply a linear -processing chain applied to one stream. This is the case, for example, when the graph has -more than one input and/or output, or when output stream type is different from -input. They can be represented with the following diagram: - -@verbatim - _________ -| | -| input 0 |\ __________ -|_________| \ | | - \ _________ /| output 0 | - \ | | / |__________| - _________ \| complex | / -| | | |/ -| input 1 |---->| filter |\ -|_________| | | \ __________ - /| graph | \ | | - / | | \| output 1 | - _________ / |_________| |__________| -| | / -| input 2 |/ -|_________| - -@end verbatim - -Complex filtergraphs are configured with the @option{-filter_complex} option. -Note that this option is global, since a complex filtergraph, by its nature, -cannot be unambiguously associated with a single stream or file. - -The @option{-lavfi} option is equivalent to @option{-filter_complex}. +processing chain applied to one stream. This is the case, for example, when the +graph has more than one input and/or output, or when output stream type is +different from input. Complex filtergraphs are configured with the +@option{-filter_complex} option. Note that this option is global, since a +complex filtergraph, by its nature, cannot be unambiguously associated with a +single stream or file. Each instance of @option{-filter_complex} creates a new +complex filtergraph, and there can be any number of them. A trivial example of a complex filtergraph is the @code{overlay} filter, which has two video inputs and one video output, containing one video overlaid on top of the other. Its audio counterpart is the @code{amix} filter. -@section Stream copy -Stream copy is a mode selected by supplying the @code{copy} parameter to the -@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding -step for the specified stream, so it does only demuxing and muxing. It is useful -for changing the container format or modifying container-level metadata. The -diagram above will, in this case, simplify to this: - -@verbatim - _______ ______________ ________ -| | | | | | -| input | demuxer | encoded data | muxer | output | -| file | ---------> | packets | -------> | file | -|_______| |______________| |________| - -@end verbatim - -Since there is no decoding or encoding, it is very fast and there is no quality -loss. However, it might not work in some cases because of many factors. Applying -filters is obviously also impossible, since filters work on uncompressed data. - +@anchor{Loopback decoders} @section Loopback decoders While decoders are normally associated with demuxer streams, it is also possible to create "loopback" decoders that decode the output from some encoder and allow @@ -259,8 +526,41 @@ reads an input video and @end itemize +Such a transcoding pipeline can be represented with the following diagram: +@verbatim +┌──────────┬───────────────┐ +│ demuxer │ │ ┌─────────┐ ┌─────────┐ ┌────────────────────┐ +╞══════════╡ video stream │ │ video │ │ video │ │ null muxer │ +│ INPUT │ ├──►│ decoder ├──┬────────►│ encoder ├─┬─►│(discards its input)│ +│ │ │ └─────────┘ │ │(libx264)│ │ └────────────────────┘ +└──────────┴───────────────┘ │ └─────────┘ │ + ╭───────◄──╯ ┌─────────┐ │ + │ │loopback │ │ + │ ╭─────◄──────┤ decoder ├────◄──╯ + │ │ └─────────┘ + │ │ + │ │ + │ │ ┌───────────────────┐ + │ │ │complex filtergraph│ + │ │ ╞═══════════════════╡ + │ │ │ ┌─────────────┐ │ + ╰─╫─►├─►│ hstack ├─►├╮ + ╰─►├─►│ │ ││ + │ └─────────────┘ ││ + └───────────────────┘│ + │ +┌──────────┬───────────────┐ ┌─────────┐ │ +│ muxer │ │ │ video │ │ +╞══════════╡ video stream │◄─┤ encoder ├───────◄──────────╯ +│ OUTPUT │ │ │ (ffv1) │ +│ │ │ └─────────┘ +└──────────┴───────────────┘ +@end verbatim + + @c man end DETAILED DESCRIPTION +@anchor{Stream selection} @chapter Stream selection @c man begin STREAM SELECTION @@ -621,24 +921,25 @@ ffmpeg -i INPUT -metadata:s:a:0 language=eng OUTPUT @end example @item -disposition[:stream_specifier] @var{value} (@emph{output,per-stream}) -Sets the disposition for a stream. +Sets the disposition flags for a stream. -By default, the disposition is copied from the input stream, unless the output -stream this option applies to is fed by a complex filtergraph - in that case the -disposition is unset by default. +Default value: by default, all disposition flags are copied from the input stream, +unless the output stream this option applies to is fed by a complex filtergraph +- in that case no disposition flags are set by default. -@var{value} is a sequence of items separated by '+' or '-'. The first item may -also be prefixed with '+' or '-', in which case this option modifies the default -value. Otherwise (the first item is not prefixed) this options overrides the -default value. A '+' prefix adds the given disposition, '-' removes it. It is -also possible to clear the disposition by setting it to 0. +@var{value} is a sequence of disposition flags separated by '+' or '-'. A '+' +prefix adds the given disposition, '-' removes it. If the first flag is also +prefixed with '+' or '-', the resulting disposition is the default value +updated by @var{value}. If the first flag is not prefixed, the resulting +disposition is @var{value}. It is also possible to clear the disposition by +setting it to 0. If no @code{-disposition} options were specified for an output file, ffmpeg will -automatically set the 'default' disposition on the first stream of each type, +automatically set the 'default' disposition flag on the first stream of each type, when there are multiple streams of this type in the output file and no stream of that type is already marked as default. -The @code{-dispositions} option lists the known dispositions. +The @code{-dispositions} option lists the known disposition flags. For example, to make the second audio stream the default stream: @example @@ -656,6 +957,29 @@ To add an embedded cover/thumbnail: ffmpeg -i in.mp4 -i IMAGE -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic out.mp4 @end example +To add the 'original' and remove the 'comment' disposition flag from the first +audio stream without removing its other disposition flags: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 +original-comment out.mkv +@end example + +To remove the 'original' and add the 'comment' disposition flag to the first +audio stream without removing its other disposition flags: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 -original+comment out.mkv +@end example + +To set only the 'original' and 'comment' disposition flags on the first audio +stream (and remove its other disposition flags): +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 original+comment out.mkv +@end example + +To remove all disposition flags from the first audio stream: +@example +ffmpeg -i in.mkv -c copy -disposition:a:0 0 out.mkv +@end example + Not all muxers support embedded thumbnails, and those who do, only support a few formats, like JPEG or PNG. @item -program [title=@var{title}:][program_num=@var{program_num}:]st=@var{stream}[:st=@var{stream}...] (@emph{output}) @@ -724,7 +1048,7 @@ The following flags are available: @table @option @item recon_gain -Wether to signal if recon_gain is present as metadata in parameter blocks within frames +Whether to signal if recon_gain is present as metadata in parameter blocks within frames @end table @item output_gain @@ -872,9 +1196,9 @@ ffmpeg -i front.wav -i back.wav -i center.wav -i lfe.wav demixing=parameter_id=998, recon_gain=parameter_id=101, layer=ch_layout=stereo, -layer=ch_layout=5.1, +layer=ch_layout=5.1(side), -stream_group type=iamf_mix_presentation:id=2:stg=0:annotations=en-us=Mix_Presentation, -submix=parameter_id=100:parameter_rate=48000|element=stg=0:parameter_id=100:annotations=en-us=Scalable_Submix|layout=sound_system=stereo|layout=sound_system=5.1 +submix=parameter_id=100:parameter_rate=48000|element=stg=0:parameter_id=100:annotations=en-us=Scalable_Submix|layout=sound_system=stereo|layout=sound_system=5.1(side) -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 output.iamf @end example @@ -1049,31 +1373,62 @@ The properties where a change triggers reinitialization are, for video, frame resolution or pixel format; for audio, sample format, sample rate, channel count or channel layout. +@item -drop_changed[:@var{stream_specifier}] @var{integer} (@emph{input,per-stream}) +This boolean option determines whether a frame with differing frame parameters mid-stream +gets dropped instead of leading to filtergraph reinitialization, as that would lead to loss +of filter state. Generally useful to avoid corrupted yet decodable packets in live streaming +inputs. Default is false. + @item -filter_threads @var{nb_threads} (@emph{global}) Defines how many threads are used to process a filter pipeline. Each pipeline will produce a thread pool with this many threads available for parallel processing. The default is the number of available CPUs. +@item -filter_buffered_frames @var{nb_frames} (@emph{global}) +Defines the maximum number of buffered frames allowed in a filtergraph. Under +normal circumstances, a filtergraph should not buffer more than a few frames, +especially if frames are being fed to it and read from it in a balanced way +(which is the intended behavior in ffmpeg). That said, this option allows you +to limit the total number of frames buffered across all links in a filtergraph. +If more frames are generated, filtering is aborted and an error is returned. +The default value is 0, which means no limit. + @item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream}) Specify the preset for matching stream(s). @item -stats (@emph{global}) -Print encoding progress/statistics. It is on by default, to explicitly -disable it you need to specify @code{-nostats}. +Log encoding progress/statistics as "info"-level log (see @code{-loglevel}). +It is on by default, to explicitly disable it you need to specify @code{-nostats}. @item -stats_period @var{time} (@emph{global}) Set period at which encoding progress/statistics are updated. Default is 0.5 seconds. +@item -print_graphs (@emph{global}) +Prints execution graph details to stderr in the format set via -print_graphs_format. + +@item -print_graphs_file @var{filename} (@emph{global}) +Writes execution graph details to the specified file in the format set via -print_graphs_format. + +@item -print_graphs_format @var{format} (@emph{global}) +Sets the output format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml) +The default format is json. + @item -progress @var{url} (@emph{global}) Send program-friendly progress information to @var{url}. Progress information is written periodically and at the end of 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". +progress information is always "progress" with the value "continue" or "end". The update period is set using @code{-stats_period}. +For example, log progress information to stdout: + +@example +ffmpeg -progress pipe:1 -i in.mkv out.mkv +@end example + @anchor{stdin option} @item -stdin Enable interaction on standard input. On by default unless standard input is @@ -1655,6 +2010,9 @@ transcoding, without copying the frames into the system memory. For it to work, both the decoder and the encoder must support QSV acceleration and no filters must be used. + +@item videotoolbox +Use Video Toolbox hardware acceleration. @end table This option has no effect if the selected hwaccel is not available or not @@ -1799,7 +2157,7 @@ Set the size of the canvas used to render subtitles. @section Advanced options @table @option -@item -map [-]@var{input_file_id}[:@var{stream_specifier}][:@var{view_specifier}][?] | @var{[linklabel]} (@emph{output}) +@item -map [-]@var{input_file_id}[:@var{stream_specifier}][:@var{view_specifier}][:?] | @var{[linklabel]} (@emph{output}) Create one or more streams in the output file. This option has two forms for specifying the data source(s): the first selects one or more streams from some @@ -1995,6 +2353,11 @@ Read input at native frame rate. This is equivalent to setting @code{-readrate 1 @item -readrate_initial_burst @var{seconds} Set an initial read burst time, in seconds, after which @option{-re/-readrate} will be enforced. +@item -readrate_catchup @var{speed} (@emph{input}) +If either the input or output is blocked leading to actual read speed falling behind the +specified readrate, then this rate takes effect till the input catches up with the +specified readrate. Must not be lower than the primary readrate. + @item -vsync @var{parameter} (@emph{global}) @itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream}) Set video sync method / framerate mode. vsync is applied to all output video streams diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index 6333249a6e..3be359f07a 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -139,13 +139,6 @@ stream. All the container format information is printed within a section with name "FORMAT". -@item -show_format_entry @var{name} -Like @option{-show_format}, but only prints the specified entry of the -container format information, rather than all. This option may be given more -than once, then all specified entries will be shown. - -This option is deprecated, use @code{show_entries} instead. - @item -show_entries @var{section_entries} Set list of entries to show. @@ -351,6 +344,19 @@ while other writers always print them. This option enables one to control this b Valid values are @code{always}/@code{1}, @code{never}/@code{0} and @code{auto}/@code{-1}. Default is @var{auto}. +@item -analyze_frames +Analyze frames and/or their side data up to the provided read interval, +providing additional information that may be useful at a stream level. +Must be paired with the @option{-show_streams} option or it will have no effect. + +Currently, the additional fields provided by this option when enabled are the +@code{closed_captions} and @code{film_grain} fields. + +For example, to analyze the first 20 seconds and populate these fields: +@example +ffprobe -show_streams -analyze_frames -read_intervals "%+20" INPUT +@end example + @item -bitexact Force bitexact output, useful to produce output which is not dependent on the specific build. @@ -362,6 +368,12 @@ Read @var{input_url}. Write output to @var{output_url}. If not specified, the output is sent to stdout. +@item -c:@var{media_specifier} @var{codec_name} +@itemx -codec:@var{media_specifier} @var{codec_name} +Force a specific decoder implementation for the stream identified by +@var{media_specifier}, which can assume the values @code{a} (audio), +@code{v} (video), @code{s} (subtitle), and @code{d} (data). + @end table @c man end diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index 64e2d88574..b53b799227 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -129,6 +129,7 @@ + diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 4e48789def..f6d452c40e 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -78,7 +78,8 @@ Match the stream by stream id (e.g. PID in MPEG-TS container). @item m:@var{key}[:@var{value}] Matches streams 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. +value. The colon character ':' in @var{key} or @var{value} needs to be +backslash-escaped. @item disp:@var{dispositions}[:@var{additional_stream_specifier}] Matches streams with the given disposition(s). @var{dispositions} is a list of one or more dispositions (as printed by the @option{-dispositions} option) @@ -225,6 +226,10 @@ and the "Last message repeated n times" line will be omitted. 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. +@item time +Indicates that log lines should be prefixed with time information. +@item datetime +Indicates that log lines should be prefixed with date and time information. @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 diff --git a/doc/filter_design.txt b/doc/filter_design.txt index 885b19b6f6..b6bfca12f5 100644 --- a/doc/filter_design.txt +++ b/doc/filter_design.txt @@ -214,6 +214,7 @@ Frame scheduling FF_FILTER_FORWARD_STATUS(inlink, outlink); FF_FILTER_FORWARD_STATUS_ALL(inlink, filter); FF_FILTER_FORWARD_WANTED(outlink, inlink); + FF_FILTER_FORWARD_WANTED_ANY(filter, inlink); filter_frame ------------ diff --git a/doc/filters.texi b/doc/filters.texi index 428986a1e9..908c98a3cf 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -216,7 +216,7 @@ filter input and output pads of all the filterchains are connected. Leading and trailing whitespaces (space, tabs, or line feeds) separating tokens in the filtergraph specification are ignored. This means that the filtergraph -can be expressed using empty lines and spaces to improve redability. +can be expressed using empty lines and spaces to improve readability. For example, the filtergraph: @example @@ -3383,7 +3383,7 @@ where applicable, an overall figure is also given. It accepts the following option: @table @option @item length -Short window length in seconds, used for peak and trough RMS measurement. +Short window length in seconds, used for peak and through RMS measurement. Default is @code{0.05} (50 milliseconds). Allowed range is @code{[0 - 10]}. @item metadata @@ -3544,7 +3544,7 @@ standard RMS level measured in dBFS @item RMS_peak @item RMS_trough -peak and trough values for RMS level measured over a short window, +peak and through values for RMS level measured over a short window, measured in dBFS. @item Zero crossings @@ -7682,6 +7682,113 @@ There are 6 samples at -4 dB, 62 at -5 dB, 286 at -6 dB, etc. In other words, raising the volume by +4 dB does not cause any clipping, raising it by +5 dB causes clipping for 6 samples, etc. +@anchor{whisper} +@section whisper + +It runs automatic speech recognition using the OpenAI's Whisper model. + +It requires the whisper.cpp library (https://github.com/ggml-org/whisper.cpp) +as a prerequisite. After installing the library it can be enabled using: +@code{./configure --enable-whisper}. + +The filter has following options: + +@table @option +@item model +The file path of the downloaded whisper.cpp model (mandatory). + +@item language +The language to use for transcription ('auto' for auto-detect). +Default value: @code{"auto"} + +@item queue +The maximum size that will be queued into the filter before processing the audio +with whisper. Using a small value the audio stream will be processed more often, +but the transcription quality will be lower and the required processing power +will be higher. Using a large value (e.g. 10-20s) will produce more accurate +results using less CPU (as using the whisper-cli tool), but the transcription +latency will be higher, thus not useful to process real-time streams. +Consider using the vad_model option associated with a large queue value. +Default value: @code{"3"} + +@item use_gpu +If the GPU support should be enabled. +Default value: @code{"true"} + +@item gpu_device +The GPU device index to use. +Default value: @code{"0"} + +@item destination +If set, the transcription output will be sent to the specified file or URL +(use one of the FFmpeg AVIO protocols); otherwise, the output will be logged as +info messages. +The output will also be set in the "lavfi.whisper.text" frame metadata. +If the destination is a file and it already exists, it will be overwritten. + +@item format +The destination format string; it could be "text" (only the transcribed text +will be sent to the destination), "srt" (subtitle format) or "json". +Default value: @code{"text"} + +@item vad_model +Path to the VAD model file. If set, the filter will load an additional voice +activity detection module (https://github.com/snakers4/silero-vad) that will be +used to fragment the audio queue; use this option setting a valid path obtained +from the whisper.cpp repository (e.g. "../whisper.cpp/models/ggml-silero-v5.1.2.bin") +and increase the queue parameter to a higher value (e.g. 20). + +@item vad_threshold +The VAD threshold to use. +Default value: @code{"0.5"} + +@item vad_min_speech_duration +The minimum VAD speaking duration. +Default value: @code{"0.1"} + +@item vad_min_silence_duration +The minimum VAD silence duration. +Default value: @code{"0.5"} + +@end table + +@subsection Examples +@itemize + +@item +Run a transcription with srt file generation: +@example +ffmpeg -i input.mp4 -vn -af "whisper=model=../whisper.cpp/models/ggml-base.en.bin\ +:language=en\ +:queue=3\ +:destination=output.srt\ +:format=srt" -f null - +@end example + +@item +Run a transcription and send the output in JSON format to an HTTP service: +@example +ffmpeg -i input.mp4 -vn -af "whisper=model=../whisper.cpp/models/ggml-base.en.bin\ +:language=en\ +:queue=3\ +:destination=http\\://localhost\\:3000\ +:format=json' -f null - +@end example + +@item +Transcribe the microphone input using the VAD option: +@example +ffmpeg -loglevel warning -f pulse -i default \ +-af 'highpass=f=200,lowpass=f=3000,whisper=model=../whisper.cpp/models/ggml-medium.bin\ +:language=en\ +:queue=10\ +:destination=-\ +:format=json\ +:vad_model=../whisper.cpp/models/ggml-silero-v5.1.2.bin' -f null - +@end example + +@end itemize + @c man end AUDIO FILTERS @chapter Audio Sources @@ -7904,7 +8011,7 @@ Gains are separated by white spaces and each gain is set in dBFS. Default is @code{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}. @item bands, b -Set the custom bands from where custon equalizer gains are set. +Set the custom bands from where custom equalizer gains are set. This must be in strictly increasing order. Only used if the preset option is set to @code{custom}. Bands are separated by white spaces and each band represent frequency in Hz. Default is @code{25 40 63 100 160 250 400 630 1000 1600 2500 4000 6300 10000 16000 24000}. @@ -8619,45 +8726,6 @@ Set planes to filter. Default is first only. This filter supports the all above options as @ref{commands}. -@section bilateral_cuda -CUDA accelerated bilateral filter, an edge preserving filter. -This filter is mathematically accurate thanks to the use of GPU acceleration. -For best output quality, use one to one chroma subsampling, i.e. yuv444p format. - -The filter accepts the following options: -@table @option -@item sigmaS -Set sigma of gaussian function to calculate spatial weight, also called sigma space. -Allowed range is 0.1 to 512. Default is 0.1. - -@item sigmaR -Set sigma of gaussian function to calculate color range weight, also called sigma color. -Allowed range is 0.1 to 512. Default is 0.1. - -@item window_size -Set window size of the bilateral function to determine the number of neighbours to loop on. -If the number entered is even, one will be added automatically. -Allowed range is 1 to 255. Default is 1. -@end table -@subsection Examples - -@itemize -@item -Apply the bilateral filter on a video. - -@example -./ffmpeg -v verbose \ --hwaccel cuda -hwaccel_output_format cuda -i input.mp4 \ --init_hw_device cuda \ --filter_complex \ -" \ -[0:v]scale_cuda=format=yuv444p[scaled_video]; -[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ --an -sn -c:v h264_nvenc -cq 20 out.mp4 -@end example - -@end itemize - @section bitplanenoise Show and measure bit plane noise. @@ -8673,7 +8741,7 @@ Filter out noisy pixels from @code{bitplane} set above. Default is disabled. @end table -@section blackdetect +@section blackdetect, blackdetect_vulkan Detect video intervals that are (almost) completely black. Can be useful to detect chapter transitions, commercials, or invalid @@ -8726,6 +8794,12 @@ the input video format, the range is [0-255] for YUV full-range formats and [16-235] for YUV non full-range formats. Default value is 0.10. + +@item alpha +If true, check the alpha channel instead of the luma channel. Detects frames +which are (almost) transparent, instead of frames which are almost black. + +Default value is disabled. @end table The following example sets the maximum pixel threshold to the minimum @@ -9243,63 +9317,11 @@ Only deinterlace frames marked as interlaced. The default value is @code{all}. @end table -@section bwdif_cuda - -Deinterlace the input video using the @ref{bwdif} algorithm, but implemented -in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec -and/or nvenc. - -It accepts the following parameters: - -@table @option -@item mode -The interlacing mode to adopt. It accepts one of the following values: - -@table @option -@item 0, send_frame -Output one frame for each frame. -@item 1, send_field -Output one frame for each field. -@end table - -The default value is @code{send_field}. - -@item parity -The picture field parity assumed for the input interlaced video. It accepts one -of the following values: - -@table @option -@item 0, tff -Assume the top field is first. -@item 1, bff -Assume the bottom field is first. -@item -1, auto -Enable automatic detection of field parity. -@end table - -The default value is @code{auto}. -If the interlacing is unknown or the decoder does not export this information, -top field first will be assumed. - -@item deint -Specify which frames to deinterlace. Accepts one of the following -values: - -@table @option -@item 0, all -Deinterlace all frames. -@item 1, interlaced -Only deinterlace frames marked as interlaced. -@end table - -The default value is @code{all}. -@end table - @section ccrepack Repack CEA-708 closed captioning side data -This filter fixes various issues seen with commerical encoders +This filter fixes various issues seen with commercial encoders related to upstream malformed CEA-708 payloads, specifically incorrect number of tuples (wrong cc_count for the target FPS), and incorrect ordering of tuples (i.e. the CEA-608 tuples are not at @@ -9408,48 +9430,6 @@ ffmpeg -f lavfi -i color=c=black:s=1280x720 -i video.mp4 -shortest -filter_compl @end example @end itemize -@section chromakey_cuda -CUDA accelerated YUV colorspace color/chroma keying. - -This filter works like normal chromakey filter but operates on CUDA frames. -for more details and parameters see @ref{chromakey}. - -@subsection Examples - -@itemize -@item -Make all the green pixels in the input video transparent and use it as an overlay for another video: - -@example -./ffmpeg \ - -hwaccel cuda -hwaccel_output_format cuda -i input_green.mp4 \ - -hwaccel cuda -hwaccel_output_format cuda -i base_video.mp4 \ - -init_hw_device cuda \ - -filter_complex \ - " \ - [0:v]chromakey_cuda=0x25302D:0.1:0.12:1[overlay_video]; \ - [1:v]scale_cuda=format=yuv420p[base]; \ - [base][overlay_video]overlay_cuda" \ - -an -sn -c:v h264_nvenc -cq 20 output.mp4 -@end example - -@item -Process two software sources, explicitly uploading the frames: - -@example -./ffmpeg -init_hw_device cuda=cuda -filter_hw_device cuda \ - -f lavfi -i color=size=800x600:color=white,format=yuv420p \ - -f lavfi -i yuvtestsrc=size=200x200,format=yuv420p \ - -filter_complex \ - " \ - [0]hwupload[under]; \ - [1]hwupload,chromakey_cuda=green:0.1:0.12[over]; \ - [under][over]overlay_cuda" \ - -c:v hevc_nvenc -cq 18 -preset slow output.mp4 -@end example - -@end itemize - @section chromanr Reduce chrominance noise. @@ -9484,19 +9464,19 @@ Mostly useful to speed-up filtering. @item threy Set Y threshold for averaging chrominance values. Set finer control for max allowed difference between Y components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item threu Set U threshold for averaging chrominance values. Set finer control for max allowed difference between U components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item threv Set V threshold for averaging chrominance values. Set finer control for max allowed difference between V components -of current pixel and neigbour pixels. +of current pixel and neighbour pixels. Default value is 200. Allowed range is from 1 to 200. @item distance @@ -9880,6 +9860,33 @@ colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131 This filter supports the all above options as @ref{commands}. +@section colordetect +Analyze the video frames to determine the effective value range and alpha +mode. + +The filter accepts the following options: + +@table @option +@item mode +Set of properties to detect. Unavailable properties, such as alpha mode for +an input image without an alpha channel, will be ignored automatically. + +Accepts a combination of the following flags: + +@table @samp +@item color_range +Detect if the source contains luma pixels outside the limited (MPEG) range, +which indicates that this is a full range YUV source. +@item alpha_mode +Detect if the source contains color values above the alpha channel, which +indicates that the alpha channel is independent (straight), rather than +premultiplied. +@item all +Enable detection of all of the above properties. This is the default. +@end table + +@end table + @section colorize Overlay a solid color on the video stream. @@ -10427,38 +10434,6 @@ For example to convert the input to SMPTE-240M, use the command: colorspace=smpte240m @end example -@section colorspace_cuda - -CUDA accelerated implementation of the colorspace filter. - -It is by no means feature complete compared to the software colorspace filter, -and at the current time only supports color range conversion between jpeg/full -and mpeg/limited range. - -The filter accepts the following options: - -@table @option -@item range -Specify output color range. - -The accepted values are: -@table @samp -@item tv -TV (restricted) range - -@item mpeg -MPEG (restricted) range - -@item pc -PC (full) range - -@item jpeg -JPEG (full) range - -@end table - -@end table - @section colortemperature Adjust color temperature in video to simulate variations in ambient color temperature. @@ -14330,7 +14305,7 @@ A '|'-separated list of color space names, such as @item color_ranges A '|'-separated list of color range names, such as -"color_spaces=tv|pc". +"color_ranges=tv|pc". @end table @@ -14706,7 +14681,7 @@ e.g. quality comparison. Each line of the map file must contain three items per input frame, the input PTS (decimal), the output PTS (decimal) and the -output TIMEBASE (decimal/decimal), seperated by a space. +output TIMEBASE (decimal/decimal), separated by a space. This file format corresponds to the output of @code{-stats_mux_pre_fmt="@{ptsi@} @{pts@} @{tb@}"}. @@ -16041,7 +16016,7 @@ If 0, plane will remain unchanged. This filter supports the all above options as @ref{commands}. -@section interlace +@section interlace, interlace_vulkan Simple interlacing filter from progressive contents. This interleaves upper (or lower) lines from odd frames with lower (or upper) lines from even frames, @@ -16372,6 +16347,11 @@ ffmpeg -i input.mov -vf lensfun=make=Canon:model="Canon EOS 100D":lens_model="Ca @end itemize +@section lcevc + +Low Complexity Enhancement Video Codec filter based on liblcevc_dec +(@url{https://github.com/v-novaltd/LCEVCdec}). + @section libplacebo Flexible GPU-accelerated processing filter based on libplacebo @@ -16419,6 +16399,16 @@ and @code{(oh-ph)/2}. Set the output placement width/height expressions, default values are @code{ow} and @code{oh}. +@item rotate +Rotate the input frame clockwise by the specified angle. + +@table @samp +@item 0, 360 +@item 90 +@item 180 +@item 270 +@end table + @item fps Set the output frame rate. This can be rational, e.g. @code{60000/1001}. If set to the special string @code{none} (the default), input timestamps will @@ -16435,11 +16425,15 @@ will be performed. @item force_divisible_by Work the same as the identical @ref{scale} filter options. +@item reset_sar +If enabled, output frames will always have a pixel aspect ratio of 1:1. If +disabled (the default), any aspect ratio mismatches, including those from +e.g. anamorphic video sources, are forwarded to the output pixel aspect ratio. + @item normalize_sar -If enabled, output frames will always have a pixel aspect ratio of 1:1. This -will introduce additional padding/cropping as necessary. If disabled (the -default), any aspect ratio mismatches, including those from e.g. anamorphic -video sources, are forwarded to the output pixel aspect ratio. +Like @option{reset_sar}, but instead of stretching the video content to fill +the new output aspect ratio, the content is instead padded or cropped as +necessary. @item pad_crop_ratio Specifies a ratio (between @code{0.0} and @code{1.0}) between padding and @@ -16453,7 +16447,7 @@ approaches. Set the color used to fill the output area not covered by the output image, for example as a result of @option{normalize_sar}. For the general syntax of this option, check the @ref{color syntax,,"Color" section in the ffmpeg-utils -manual,ffmpeg-utils}. Defaults to @code{black}. +manual,ffmpeg-utils}. Defaults to @code{black@@0}. @item corner_rounding Render frames with rounded corners. The value, given as a float ranging from @@ -16461,6 +16455,36 @@ Render frames with rounded corners. The value, given as a float ranging from square to fully circular. In other words, it gives the radius divided by half the smaller side length. Defaults to @code{0.0}. +@item lut +Specifies a custom LUT (in Adobe .cube format) to apply to the colors +as part of color conversion. The exact interpretation depends on the value +of @option{lut_type}. + +@item lut_type +Controls the interpretation of color values fed to and from the LUT +specified as @option{lut}. Valid values are: + +@table @samp +@item auto +Chooses the interpretation of the LUT automatically from tagged +metadata, and otherwise falls back to @samp{native}. (Default) + +@item native +Applied to raw image contents in its native RGB colorspace (non-linear +light), before conversion to the output color space. + +@item normalized +Applied to the normalized RGB image contents, in linear light, before +conversion to the output color space. + +@item conversion +Fully replaces the conversion from the image color space to the output +color space. If such a LUT is present, it has the highest priority, and +overrides any ICC profiles, as well as options related to tone mapping +and output colorimetry (@option{color_primaries}, @option{color_trc}). + +@end table + @item extra_opts Pass extra libplacebo internal configuration options. These can be specified as a list of @var{key}=@var{value} pairs separated by ':'. The following example @@ -16471,6 +16495,18 @@ to double the input image resolution: -vf "libplacebo=w=iw*2:h=ih*2:extra_opts='upscaler=custom\:upscaler_preset=ewa_lanczos\:upscaler_blur=0.9812505644269356'" @end example + +@item shader_cache +File path of a cache directory that libplacebo will use to store and load +cached shader objects. This cache is not cleaned up automatically. If the +path does not end in a directory separator, the generated filenames will be +effectively prefixed by the last path component. All directories must already +exist. + +@example +-vf "libplacebo=shader_cache=/tmp/pl-shader-" +@end example + @item colorspace @item color_primaries @item color_trc @@ -16557,7 +16593,7 @@ Cubic spline approximation of lanczos. No difference in performance, but has very slightly less ringing. @item ewa_lanczos -Elliptically weighted average version of lanczos, based on a jinc-sinc kernel. +Elliptically weighted average version of lanczos, based on a jinc-jinc kernel. This is also popularly referred to as just "Jinc scaling". Slow but very high quality. @@ -16595,11 +16631,6 @@ Linear blend/fade between frames. Especially useful for constructing e.g. slideshows. @end table -@item lut_entries -Configures the size of scaler LUTs, ranging from @code{1} to @code{256}. The -default of @code{0} will pick libplacebo's internal default, typically -@code{64}. - @item antiringing Enables anti-ringing (for non-EWA filters). The value (between @code{0.0} and @code{1.0}) configures the strength of the anti-ringing algorithm. May increase @@ -16610,6 +16641,30 @@ Enable sigmoidal compression during upscaling. Reduces ringing slightly. Enabled by default. @end table +@subsubsection Deinterlacing +Deinterlacing is automatically supported when frames are tagged as interlaced, +however frames are not deinterlaced unless a deinterlacing algorithm is chosen. +@table @option +@item deinterlace +The the deinterlacing algorithm to use. +@table @samp +@item weave +No deinterlacing, weave fields together into a single frame. This is the default. +@item bob +Naive bob deinterlacing, simply repeat each field line twice. +@item yadif +Yet another deinterlacing filter. See the @ref{yadif} filter for more details. +@end table + +@item skip_spatial_check +Skip the spatial deinterlacing check when using @code{yadif} deinterlacing. + +@item send_fields +Output a frame for each field, rather than for each frame. Note that this will +always double the tagged output frame rate, even if the input does not contain +any interlaced frames. Disabled by default. +@end table + @subsubsection Debanding Libplacebo comes with a built-in debanding filter that is good at counteracting many common sources of banding and blocking. Turning this on is highly @@ -16697,10 +16752,6 @@ Peak detection smoothing period, between @code{0.0} and @code{1000.0}. Higher values result in peak detection becoming less responsive to changes in the input. Defaults to @code{100.0}. -@item minimum_peak -Lower bound on the detected peak (relative to SDR white), between @code{0.0} -and @code{100.0}. Defaults to @code{1.0}. - @item scene_threshold_low @item scene_threshold_high Lower and upper thresholds for scene change detection. Expressed in a @@ -16905,10 +16956,6 @@ attempting to squeeze the maximum performance at the cost of quality. @item skip_aa Disable anti-aliasing when downscaling. -@item polar_cutoff -Truncate polar (EWA) scaler kernels below this absolute magnitude, between -@code{0.0} and @code{1.0}. - @item disable_linear Disable linear light scaling. @@ -18972,84 +19019,6 @@ testsrc=s=100x100, split=4 [in0][in1][in2][in3]; @end itemize -@anchor{overlay_cuda} -@section overlay_cuda - -Overlay one video on top of another. - -This is the CUDA variant of the @ref{overlay} filter. -It only accepts CUDA frames. The underlying input pixel formats have to match. - -It takes two inputs and has one output. The first input is the "main" -video on which the second input is overlaid. - -It accepts the following parameters: - -@table @option -@item x -@item y -Set expressions for the x and y coordinates of the overlaid video -on the main video. - -They can contain the following parameters: - -@table @option - -@item main_w, W -@item main_h, H -The main input width and height. - -@item overlay_w, w -@item overlay_h, h -The overlay input width and height. - -@item x -@item y -The computed values for @var{x} and @var{y}. They are evaluated for -each new frame. - -@item n -The ordinal index of the main input frame, starting from 0. - -@item pos -The byte offset position in the file of the main input frame, NAN if unknown. -Deprecated, do not use. - -@item t -The timestamp of the main input frame, expressed in seconds, NAN if unknown. - -@end table - -Default value is "0" for both expressions. - -@item eval -Set when the expressions for @option{x} and @option{y} are evaluated. - -It accepts the following values: -@table @option -@item init -Evaluate expressions once during filter initialization or -when a command is processed. - -@item frame -Evaluate expressions for each incoming frame -@end table - -Default value is @option{frame}. - -@item eof_action -See @ref{framesync}. - -@item shortest -See @ref{framesync}. - -@item repeatlast -See @ref{framesync}. - -@end table - -This filter also supports the @ref{framesync} options. - @section owdenoise Apply Overcomplete Wavelet denoiser. @@ -19614,181 +19583,6 @@ Set window Y position, relative offset on Y axis. This filter supports same @ref{commands} as options. -@section pp - -Enable the specified chain of postprocessing subfilters using libpostproc. This -library should be automatically selected with a GPL build (@code{--enable-gpl}). -Subfilters must be separated by '/' and can be disabled by prepending a '-'. -Each subfilter and some options have a short and a long name that can be used -interchangeably, i.e. dr/dering are the same. - -The filters accept the following options: - -@table @option -@item subfilters -Set postprocessing subfilters string. -@end table - -All subfilters share common options to determine their scope: - -@table @option -@item a/autoq -Honor the quality commands for this subfilter. - -@item c/chrom -Do chrominance filtering, too (default). - -@item y/nochrom -Do luma filtering only (no chrominance). - -@item n/noluma -Do chrominance filtering only (no luma). -@end table - -These options can be appended after the subfilter name, separated by a '|'. - -Available subfilters are: - -@table @option -@item hb/hdeblock[|difference[|flatness]] -Horizontal deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item vb/vdeblock[|difference[|flatness]] -Vertical deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item ha/hadeblock[|difference[|flatness]] -Accurate horizontal deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table - -@item va/vadeblock[|difference[|flatness]] -Accurate vertical deblocking filter -@table @option -@item difference -Difference factor where higher values mean more deblocking (default: @code{32}). -@item flatness -Flatness threshold where lower values mean more deblocking (default: @code{39}). -@end table -@end table - -The horizontal and vertical deblocking filters share the difference and -flatness values so you cannot set different horizontal and vertical -thresholds. - -@table @option -@item h1/x1hdeblock -Experimental horizontal deblocking filter - -@item v1/x1vdeblock -Experimental vertical deblocking filter - -@item dr/dering -Deringing filter - -@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer -@table @option -@item threshold1 -larger -> stronger filtering -@item threshold2 -larger -> stronger filtering -@item threshold3 -larger -> stronger filtering -@end table - -@item al/autolevels[:f/fullyrange], automatic brightness / contrast correction -@table @option -@item f/fullyrange -Stretch luma to @code{0-255}. -@end table - -@item lb/linblenddeint -Linear blend deinterlacing filter that deinterlaces the given block by -filtering all lines with a @code{(1 2 1)} filter. - -@item li/linipoldeint -Linear interpolating deinterlacing filter that deinterlaces the given block by -linearly interpolating every second line. - -@item ci/cubicipoldeint -Cubic interpolating deinterlacing filter deinterlaces the given block by -cubically interpolating every second line. - -@item md/mediandeint -Median deinterlacing filter that deinterlaces the given block by applying a -median filter to every second line. - -@item fd/ffmpegdeint -FFmpeg deinterlacing filter that deinterlaces the given block by filtering every -second line with a @code{(-1 4 2 4 -1)} filter. - -@item l5/lowpass5 -Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given -block by filtering all lines with a @code{(-1 2 6 2 -1)} filter. - -@item fq/forceQuant[|quantizer] -Overrides the quantizer table from the input with the constant quantizer you -specify. -@table @option -@item quantizer -Quantizer to use -@end table - -@item de/default -Default pp filter combination (@code{hb|a,vb|a,dr|a}) - -@item fa/fast -Fast pp filter combination (@code{h1|a,v1|a,dr|a}) - -@item ac -High quality pp filter combination (@code{ha|a|128|7,va|a,dr|a}) -@end table - -@subsection Examples - -@itemize -@item -Apply horizontal and vertical deblocking, deringing and automatic -brightness/contrast: -@example -pp=hb/vb/dr/al -@end example - -@item -Apply default filters without brightness/contrast correction: -@example -pp=de/-al -@end example - -@item -Apply default filters and temporal denoiser: -@example -pp=default/tmpnoise|1|2|3 -@end example - -@item -Apply deblocking on luma only, and switch vertical deblocking on or off -automatically depending on available CPU time: -@example -pp=hb|y/vb|a -@end example -@end itemize - @section pp7 Apply Postprocessing filter 7. It is variant of the @ref{spp} filter, similar to spp = 6 with 7 point DCT, where only the center sample is @@ -19985,7 +19779,7 @@ Specifies which version of the stats file format to use. Details of each format are written below. Default value is 1. -@item stats_add_max +@item output_max Determines whether the max value is output to the stats log. Default value is 0. Requires stats_version >= 2. If this is set and stats_version < 2, @@ -20160,7 +19954,7 @@ To enable the compilation of this filter, you need to configure FFmpeg with @code{--enable-libqrencode}. The QR code is generated from the provided text or text pattern. The -corresponding QR code is scaled and overlayed into the video output according to +corresponding QR code is scaled and overlaid into the video output according to the specified options. In case no text is specified, no QR code is overlaied. @@ -21066,7 +20860,38 @@ Set libswscale input parameters for scaling algorithms that need them. See complete documentation. If not explicitly specified the filter applies empty parameters. +@item intent +Set the ICC rendering intent to use when transforming between different color +spaces. It accepts the following values: +@table @samp +@item perceptual +Use a perceptually guided tone and gamut mapping curve. The exact details of +the mapping used may change at any time and should not be relied on as stable. +This intent is recommended for final viewing of image/video content in typical +viewing settings. + +@item relative_colorimetric +Statically clip out-of-gamut colors using a colorimetric clipping curve which +attempts to find the colorimetrically least dissimilar in-gamut color. This +intent performs white point adaptation and black point adaptation. This is +the default. This intent is recommended wherever faithful color reproduction +is of the utmost importance, even at the cost of clipping. + +@item absolute_colorimetric +Hard clip out-of-gamut colors with no attempt at white or black point +reproduction. This intent will reproduce in-gamut colors 1:1 on the output +display as they would appear on the reference display, assuming the output +display is appropriately calibrated. + +@item saturation +Performs saturation mapping - that is, stretches the input color volume +directly onto the output color volume, in non-linear fashion that preserves the +original signal appearance as much as possible. This intent is recommended for +signal content evaluation, as it will not lead to any clipping. It is roughly +analogous to not performing any color mapping, although it still takes into +account the mastering display primaries and any differences in encoding TRC. +@end table @item size, s Set the video size. For the syntax of this option, check the @@ -21153,6 +20978,62 @@ is used by default. Possible values: @item bottom @end table +@item in_primaries +@item out_primaries +Set in/output RGB primaries. + +This allows the autodetected value to be overridden as well as allows forcing +a specific value used for the output and encoder. Possible values: + +@table @samp +@item auto +Choose automatically. This is the default. + +@item bt709 +@item bt470m +@item bt470bg +@item smpte170m +@item smpte240m +@item film +@item bt2020 +@item smpte428 +@item smpte431 +@item smpte432 +@item jedec-p22 +@item ebu3213 +@end table + +@item in_transfer +@item out_transfer +Set in/output transfer response curve (TRC). + +This allows the autodetected value to be overridden as well as allows forcing +a specific value used for the output and encoder. Possible values: + +@table @samp +@item auto +Choose automatically. This is the default. + +@item bt709 +@item bt470m +@item gamma22 +@item bt470bg +@item gamma28 +@item smpte170m +@item smpte240m +@item linear +@item iec61966-2-1 +@item srgb +@item iec61966-2-4 +@item xvycc +@item bt1361e +@item bt2020-10 +@item bt2020-12 +@item smpte2084 +@item smpte428 +@item arib-std-b67 +@end table + @item force_original_aspect_ratio Enable decreasing or increasing output video width or height if necessary to keep the original aspect ratio. Possible values: @@ -21193,6 +21074,14 @@ This option can be handy if you need to have a video fit within or exceed a defined resolution using @option{force_original_aspect_ratio} but also have encoder restrictions on width or height divisibility. +@item reset_sar +Enabling this option leads to the output SAR being reset to 1. +Additionally, if the user requests proportional scaling either +through the width or height expressions, e.g. @code{w=-4:h=360} or @code{w=iw/2:h=-1} +or by enabling @code{force_original_aspect_ratio}, then the input DAR is taken into +account and the output is scaled to produce square pixels. +Default is false. + @end table The values of the @option{w} and @option{h} options are expressions @@ -21353,10 +21242,28 @@ scale='trunc(ih*dar):ih',setsar=1/1 @end example @item -Make pixels square by combining scale and setsar, +Make pixels square using reset_sar, 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 +scale='-2:ih-mod(ih,2):reset_sar=1' +@end example + +@item +Scale to target exactly, however reset SAR to 1: +@example +scale='400:300:reset_sar=1' +@end example + +@item +Scale to even dimensions that fit within 400x300, preserving input SAR: +@example +scale='400:300:force_original_aspect_ratio=decrease:force_divisible_by=2' +@end example + +@item +Scale to produce square pixels with even dimensions that fit within 400x300: +@example +scale='400:300:force_original_aspect_ratio=decrease:force_divisible_by=2:reset_sar=1' @end example @item @@ -21387,281 +21294,6 @@ If the specified expression is not valid, it is kept at its current value. @end table -@anchor{scale_cuda} -@section scale_cuda - -Scale (resize) and convert (pixel format) the input video, using accelerated CUDA kernels. -Setting the output width and height works in the same way as for the @ref{scale} filter. - -The filter accepts the following options: -@table @option -@item w -@item h -Set the output video dimension expression. Default value is the input dimension. - -Allows for the same expressions as the @ref{scale} filter. - -@item interp_algo -Sets the algorithm used for scaling: - -@table @var -@item nearest -Nearest neighbour - -Used by default if input parameters match the desired output. - -@item bilinear -Bilinear - -@item bicubic -Bicubic - -This is the default. - -@item lanczos -Lanczos - -@end table - -@item format -Controls the output pixel format. By default, or if none is specified, the input -pixel format is used. - -The filter does not support converting between YUV and RGB pixel formats. - -@item passthrough -If set to 0, every frame is processed, even if no conversion is necessary. -This mode can be useful to use the filter as a buffer for a downstream -frame-consumer that exhausts the limited decoder frame pool. - -If set to 1, frames are passed through as-is if they match the desired output -parameters. This is the default behaviour. - -@item param -Algorithm-Specific parameter. - -Affects the curves of the bicubic algorithm. - -@item force_original_aspect_ratio -@item force_divisible_by -Work the same as the identical @ref{scale} filter options. - -@end table - -@subsection Examples - -@itemize -@item -Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. -@example -scale_cuda=-2:720:format=yuv420p -@end example - -@item -Upscale to 4K using nearest neighbour algorithm. -@example -scale_cuda=4096:2160:interp_algo=nearest -@end example - -@item -Don't do any conversion or scaling, but copy all input frames into newly allocated ones. -This can be useful to deal with a filter and encode chain that otherwise exhausts the -decoders frame pool. -@example -scale_cuda=passthrough=0 -@end example -@end itemize - -@anchor{scale_npp} -@section scale_npp - -Use the NVIDIA Performance Primitives (libnpp) to perform scaling and/or pixel -format conversion on CUDA video frames. Setting the output width and height -works in the same way as for the @var{scale} filter. - -The following additional options are accepted: -@table @option -@item format -The pixel format of the output CUDA frames. If set to the string "same" (the -default), the input format will be kept. Note that automatic format negotiation -and conversion is not yet supported for hardware frames - -@item interp_algo -The interpolation algorithm used for resizing. One of the following: -@table @option -@item nn -Nearest neighbour. - -@item linear -@item cubic -@item cubic2p_bspline -2-parameter cubic (B=1, C=0) - -@item cubic2p_catmullrom -2-parameter cubic (B=0, C=1/2) - -@item cubic2p_b05c03 -2-parameter cubic (B=1/2, C=3/10) - -@item super -Supersampling - -@item lanczos -@end table - -@item force_original_aspect_ratio -Enable decreasing or increasing output video width or height if necessary to -keep the original aspect ratio. Possible values: - -@table @samp -@item disable -Scale the video as specified and disable this feature. - -@item decrease -The output video dimensions will automatically be decreased if needed. - -@item increase -The output video dimensions will automatically be increased if needed. - -@end table - -One useful instance of this option is that when you know a specific device's -maximum allowed resolution, you can use this to limit the output video to -that, while retaining the aspect ratio. For example, device A allows -1280x720 playback, and your video is 1920x800. Using this option (set it to -decrease) and specifying 1280x720 to the command line makes the output -1280x533. - -Please note that this is a different thing than specifying -1 for @option{w} -or @option{h}, you still need to specify the output resolution for this option -to work. - -@item force_divisible_by -Ensures that both the output dimensions, width and height, are divisible by the -given integer when used together with @option{force_original_aspect_ratio}. This -works similar to using @code{-n} in the @option{w} and @option{h} options. - -This option respects the value set for @option{force_original_aspect_ratio}, -increasing or decreasing the resolution accordingly. The video's aspect ratio -may be slightly modified. - -This option can be handy if you need to have a video fit within or exceed -a defined resolution using @option{force_original_aspect_ratio} but also have -encoder restrictions on width or height divisibility. - -@item eval -Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values: - -@table @samp -@item init -Only evaluate expressions once during the filter initialization or when a command is processed. - -@item frame -Evaluate expressions for each incoming frame. - -@end table - -@end table - -The values of the @option{w} and @option{h} options are expressions -containing the following constants: - -@table @var -@item in_w -@item in_h -The input width and height - -@item iw -@item ih -These are the same as @var{in_w} and @var{in_h}. - -@item out_w -@item out_h -The output (scaled) width and height - -@item ow -@item oh -These are the same as @var{out_w} and @var{out_h} - -@item a -The same as @var{iw} / @var{ih} - -@item sar -input sample aspect ratio - -@item dar -The input display aspect ratio. Calculated from @code{(iw / ih) * sar}. - -@item n -The (sequential) number of the input frame, starting from 0. -Only available with @code{eval=frame}. - -@item t -The presentation timestamp of the input frame, expressed as a number of -seconds. Only available with @code{eval=frame}. - -@item pos -The position (byte offset) of the frame in the input stream, or NaN if -this information is unavailable and/or meaningless (for example in case of synthetic video). -Only available with @code{eval=frame}. -Deprecated, do not use. -@end table - -@section scale2ref_npp - -Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input -video, based on a reference video. - -See the @ref{scale_npp} filter for available options, scale2ref_npp supports the same -but uses the reference video instead of the main input as basis. scale2ref_npp -also supports the following additional constants for the @option{w} and -@option{h} options: - -@table @var -@item main_w -@item main_h -The main input video's width and height - -@item main_a -The same as @var{main_w} / @var{main_h} - -@item main_sar -The main input video's sample aspect ratio - -@item main_dar, mdar -The main input video's display aspect ratio. Calculated from -@code{(main_w / main_h) * main_sar}. - -@item main_n -The (sequential) number of the main input frame, starting from 0. -Only available with @code{eval=frame}. - -@item main_t -The presentation timestamp of the main input frame, expressed as a number of -seconds. Only available with @code{eval=frame}. - -@item main_pos -The position (byte offset) of the frame in the main input stream, or NaN if -this information is unavailable and/or meaningless (for example in case of synthetic video). -Only available with @code{eval=frame}. -@end table - -@subsection Examples - -@itemize -@item -Scale a subtitle stream (b) to match the main video (a) in size before overlaying -@example -'scale2ref_npp[b][a];[a][b]overlay_cuda' -@end example - -@item -Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio. -@example -[logo-in][video-in]scale2ref_npp=w=oh*mdar:h=ih/10[logo-out][video-out] -@end example -@end itemize - @section scale_vt Scale and convert the color parameters using VTPixelTransferSession. @@ -22108,23 +21740,6 @@ Keep the same chroma location (default). @end table @end table -@section sharpen_npp -Use the NVIDIA Performance Primitives (libnpp) to perform image sharpening with -border control. - -The following additional options are accepted: -@table @option - -@item border_type -Type of sampling to be used ad frame borders. One of the following: -@table @option - -@item replicate -Replicate pixel values. - -@end table -@end table - @section shear Apply shear transform to input video. @@ -22827,6 +22442,76 @@ input upscaled using bicubic upscaling with proper scale factor. To get full functionality (such as async execution), please use the @ref{dnn_processing} filter. +@anchor{sr_amf} +@section sr_amf + +Upscale (size increasing) for the input video using AMD Advanced Media Framework library for hardware acceleration. +Use advanced algorithms for upscaling with higher output quality. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item algorithm +Sets the algorithm used for scaling: + +@table @var +@item bilinear +Bilinear + +@item bicubic +Bicubic + +@item sr1-0 +Video SR1.0 +This is a default value + +@item point +Point + +@item sr1-1 +Video SR1.1 + +@end table + +@item sharpness +Control hq scaler sharpening. The value is a float in the range of [0.0, 2.0] + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + +@item keep-ratio +Force the scaler to keep the aspect ratio of the input image when the output size has a different aspect ratio. +Default value is false. + +@item fill +Specifies whether the output image outside the region of interest, +which does not fill the entire output surface should be filled with a solid color. + +@end table + +@subsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +sr_amf=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K with algorithm video SR1.1. +@example +sr_amf=4096:2160:algorithm=sr1-1 +@end example +@end itemize + @section ssim Obtain the SSIM (Structural SImilarity Metric) between two input videos. @@ -23598,7 +23283,7 @@ by progressively selecting a different column from each input frame. The end result is a sort of inverted parallax, so that far away objects move much faster that the ones in the front. The ideal conditions for this video -effect are when there is either very little motion and the backgroud is static, +effect are when there is either very little motion and the background is static, or when there is a lot of motion and a very wide depth of field (e.g. wide panorama, while moving on a train). @@ -23626,7 +23311,7 @@ How many columns should be inserted before end of filtering. Normally the filter shifts and tilts from the very first frame, and stops when the last one is received. However, before filtering starts, normal video may -be preseved, so that the effect is slowly shifted in its place. Similarly, +be preserved, so that the effect is slowly shifted in its place. Similarly, the last video frame may be reconstructed at the end. Alternatively it is possible to just start and end with black. @@ -24212,47 +23897,6 @@ The command above can also be specified as: transpose=1:portrait @end example -@section transpose_npp - -Transpose rows with columns in the input video and optionally flip it. -For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. - -It accepts the following parameters: - -@table @option - -@item dir -Specify the transposition direction. - -Can assume the following values: -@table @samp -@item cclock_flip -Rotate by 90 degrees counterclockwise and vertically flip. (default) - -@item clock -Rotate by 90 degrees clockwise. - -@item cclock -Rotate by 90 degrees counterclockwise. - -@item clock_flip -Rotate by 90 degrees clockwise and vertically flip. -@end table - -@item passthrough -Do not apply the transposition if the input geometry matches the one -specified by the specified value. It accepts the following values: -@table @samp -@item none -Always apply transposition. (default) -@item portrait -Preserve portrait geometry (when @var{height} >= @var{width}). -@item landscape -Preserve landscape geometry (when @var{width} >= @var{height}). -@end table - -@end table - @section trim Trim the input so that the output contains one continuous subpart of the input. @@ -25565,6 +25209,175 @@ Example: ffmpeg -i ref.mpg -vf vmafmotion -f null - @end example +@anchor{vpp_amf} +@section vpp_amf + +Scale (resize) and convert colorspace, transfer characteristics or color primaries for the input video, using AMD Advanced Media Framework library for hardware acceleration. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item scale_type +Sets the algorithm used for scaling: + +@table @var +@item bilinear +Bilinear + +This is the default. + +@item bicubic +Bicubic + +@end table + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + + +@item force_original_aspect_ratio +@item force_divisible_by +Work the same as the identical @ref{scale} filter options. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@anchor{color_profile} +@item color_profile +Specify all color properties at once. + +The accepted values are: +@table @samp +@item bt601 +BT.601 + +@item bt709 +BT.709 + +@item bt2020 +BT.2020 + +@end table + +@item trc +Specify output transfer characteristics. + +The accepted values are: +@table @samp +@item bt709 +BT.709 + +@item gamma22 +Constant gamma of 2.2 + +@item gamma28 +Constant gamma of 2.8 + +@item smpte170m +SMPTE-170M + +@item smpte240m +SMPTE-240M + +@item linear +Linear + +@item log +LOG + +@item log-sqrt +LOG_SQRT + +@item iec61966-2-4 +iec61966-2-4 + +@item bt1361-ecg +BT1361_ECG + +@item iec61966-2-1 +iec61966-2-1 + +@item bt2020-10 +BT.2020 for 10-bits content + +@item bt2020-12 +BT.2020 for 12-bits content + +@item smpte2084 +SMPTE2084 + +@item smpte428 +SMPTE428 + +@item arib-std-b67 +ARIB_STD_B67 + +@end table + +@item primaries +Specify output color primaries. + +The accepted values are: +@table @samp +@item bt709 +BT.709 + +@item bt470m +BT.470M + +@item bt470bg +BT.470BG or BT.601-6 625 + +@item smpte170m +SMPTE-170M or BT.601-6 525 + +@item smpte240m +SMPTE-240M + +@item film +film + +@item bt2020 +BT.2020 + +@item smpte428 +SMPTE-428 + +@item smpte431 +SMPTE-431 + +@item smpte432 +SMPTE-432 + +@item jedec-p22 +JEDEC P22 phosphors + +@end table +@end table + +@subsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +vpp_amf=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K and change color profile to bt2020. +@example +vpp_amf=4096:2160:color_profile=bt2020 +@end example +@end itemize + @anchor{vstack} @section vstack Stack input videos vertically. @@ -25819,7 +25632,7 @@ pixel formats are not RGB. @item fitmode, fm Set sample aspect ratio of video output frames. Can be used to configure waveform so it is not -streched too much in one of directions. +stretched too much in one of directions. @table @samp @item none @@ -26270,64 +26083,6 @@ filter"). It accepts the following parameters: -@table @option - -@item mode -The interlacing mode to adopt. It accepts one of the following values: - -@table @option -@item 0, send_frame -Output one frame for each frame. -@item 1, send_field -Output one frame for each field. -@item 2, send_frame_nospatial -Like @code{send_frame}, but it skips the spatial interlacing check. -@item 3, send_field_nospatial -Like @code{send_field}, but it skips the spatial interlacing check. -@end table - -The default value is @code{send_frame}. - -@item parity -The picture field parity assumed for the input interlaced video. It accepts one -of the following values: - -@table @option -@item 0, tff -Assume the top field is first. -@item 1, bff -Assume the bottom field is first. -@item -1, auto -Enable automatic detection of field parity. -@end table - -The default value is @code{auto}. -If the interlacing is unknown or the decoder does not export this information, -top field first will be assumed. - -@item deint -Specify which frames to deinterlace. Accepts one of the following -values: - -@table @option -@item 0, all -Deinterlace all frames. -@item 1, interlaced -Only deinterlace frames marked as interlaced. -@end table - -The default value is @code{all}. -@end table - -@section yadif_cuda - -Deinterlace the input video using the @ref{yadif} algorithm, but implemented -in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec -and/or nvenc. - -It accepts the following parameters: - - @table @option @item mode @@ -26798,6 +26553,771 @@ value. @c man end VIDEO FILTERS +@chapter CUDA Video Filters +@c man begin CUDA Video Filters + +To enable CUDA and/or NPP filters please refer to configuration guidelines for @ref{CUDA} and for @ref{CUDA NPP} filters. + +Running CUDA filters requires you to initialize a hardware device and to pass that device to all filters in any filter graph. +@table @option + +@item -init_hw_device cuda[=@var{name}][:@var{device}[,@var{key=value}...]] +Initialise a new hardware device of type @var{cuda} called @var{name}, using the +given device parameters. + +@item -filter_hw_device @var{name} +Pass the hardware device called @var{name} to all filters in any filter graph. + +@end table + +For more detailed information see @url{https://www.ffmpeg.org/ffmpeg.html#Advanced-Video-options} + +@itemize +@item +Example of initializing second CUDA device on the system and running scale_cuda and bilateral_cuda filters. +@example +./ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -init_hw_device cuda:1 -filter_complex \ +"[0:v]scale_cuda=format=yuv444p[scaled_video];[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ +-an -sn -c:v h264_nvenc -cq 20 out.mp4 +@end example +@end itemize + +Since CUDA filters operate exclusively on GPU memory, frame data must sometimes be uploaded (@ref{hwupload}) to hardware surfaces associated with the appropriate CUDA device before processing, and downloaded (@ref{hwdownload}) back to normal memory afterward, if required. Whether @ref{hwupload} or @ref{hwdownload} is necessary depends on the specific workflow: + +@itemize +@item If the input frames are already in GPU memory (e.g., when using @code{-hwaccel cuda} or @code{-hwaccel_output_format cuda}), explicit use of @ref{hwupload} is not needed, as the data is already in the appropriate memory space. +@item If the input frames are in CPU memory (e.g., software-decoded frames or frames processed by CPU-based filters), it is necessary to use @ref{hwupload} to transfer the data to GPU memory for CUDA processing. +@item If the output of the CUDA filters needs to be further processed by software-based filters or saved in a format not supported by GPU-based encoders, @ref{hwdownload} is required to transfer the data back to CPU memory. +@end itemize +Note that @ref{hwupload} uploads data to a surface with the same layout as the software frame, so it may be necessary to add a @ref{format} filter immediately before @ref{hwupload} to ensure the input is in the correct format. Similarly, @ref{hwdownload} may not support all output formats, so an additional @ref{format} filter may need to be inserted immediately after @ref{hwdownload} in the filter graph to ensure compatibility. + +@anchor{CUDA} +@section CUDA +Below is a description of the currently available Nvidia CUDA video filters. + +Prerequisites: +@itemize +@item Install Nvidia CUDA Toolkit +@end itemize + +Note: If FFmpeg detects the Nvidia CUDA Toolkit during configuration, it will enable CUDA filters automatically without requiring any additional flags. If you want to explicitly enable them, use the following options: + +@itemize +@item Configure FFmpeg with @code{--enable-cuda-nvcc --enable-nonfree}. +@item Configure FFmpeg with @code{--enable-cuda-llvm}. Additional requirement: @code{llvm} lib must be installed. +@end itemize + +@subsection bilateral_cuda +CUDA accelerated bilateral filter, an edge preserving filter. +This filter is mathematically accurate thanks to the use of GPU acceleration. +For best output quality, use one to one chroma subsampling, i.e. yuv444p format. + +The filter accepts the following options: +@table @option +@item sigmaS +Set sigma of gaussian function to calculate spatial weight, also called sigma space. +Allowed range is 0.1 to 512. Default is 0.1. + +@item sigmaR +Set sigma of gaussian function to calculate color range weight, also called sigma color. +Allowed range is 0.1 to 512. Default is 0.1. + +@item window_size +Set window size of the bilateral function to determine the number of neighbours to loop on. +If the number entered is even, one will be added automatically. +Allowed range is 1 to 255. Default is 1. +@end table +@subsubsection Examples + +@itemize +@item +Apply the bilateral filter on a video. + +@example +./ffmpeg -v verbose \ +-hwaccel cuda -hwaccel_output_format cuda -i input.mp4 \ +-init_hw_device cuda \ +-filter_complex \ +" \ +[0:v]scale_cuda=format=yuv444p[scaled_video]; +[scaled_video]bilateral_cuda=window_size=9:sigmaS=3.0:sigmaR=50.0" \ +-an -sn -c:v h264_nvenc -cq 20 out.mp4 +@end example + +@end itemize + +@subsection bwdif_cuda + +Deinterlace the input video using the @ref{bwdif} algorithm, but implemented +in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec +and/or nvenc. + +It accepts the following parameters: + +@table @option +@item mode +The interlacing mode to adopt. It accepts one of the following values: + +@table @option +@item 0, send_frame +Output one frame for each frame. +@item 1, send_field +Output one frame for each field. +@end table + +The default value is @code{send_field}. + +@item parity +The picture field parity assumed for the input interlaced video. It accepts one +of the following values: + +@table @option +@item 0, tff +Assume the top field is first. +@item 1, bff +Assume the bottom field is first. +@item -1, auto +Enable automatic detection of field parity. +@end table + +The default value is @code{auto}. +If the interlacing is unknown or the decoder does not export this information, +top field first will be assumed. + +@item deint +Specify which frames to deinterlace. Accepts one of the following +values: + +@table @option +@item 0, all +Deinterlace all frames. +@item 1, interlaced +Only deinterlace frames marked as interlaced. +@end table + +The default value is @code{all}. +@end table + +@subsection chromakey_cuda +CUDA accelerated YUV colorspace color/chroma keying. + +This filter works like normal chromakey filter but operates on CUDA frames. +for more details and parameters see @ref{chromakey}. + +@subsubsection Examples + +@itemize +@item +Make all the green pixels in the input video transparent and use it as an overlay for another video: + +@example +./ffmpeg \ + -hwaccel cuda -hwaccel_output_format cuda -i input_green.mp4 \ + -hwaccel cuda -hwaccel_output_format cuda -i base_video.mp4 \ + -init_hw_device cuda \ + -filter_complex \ + " \ + [0:v]chromakey_cuda=0x25302D:0.1:0.12:1[overlay_video]; \ + [1:v]scale_cuda=format=yuv420p[base]; \ + [base][overlay_video]overlay_cuda" \ + -an -sn -c:v h264_nvenc -cq 20 output.mp4 +@end example + +@item +Process two software sources, explicitly uploading the frames: + +@example +./ffmpeg -init_hw_device cuda=cuda -filter_hw_device cuda \ + -f lavfi -i color=size=800x600:color=white,format=yuv420p \ + -f lavfi -i yuvtestsrc=size=200x200,format=yuv420p \ + -filter_complex \ + " \ + [0]hwupload[under]; \ + [1]hwupload,chromakey_cuda=green:0.1:0.12[over]; \ + [under][over]overlay_cuda" \ + -c:v hevc_nvenc -cq 18 -preset slow output.mp4 +@end example + +@end itemize + +@subsection colorspace_cuda + +CUDA accelerated implementation of the colorspace filter. + +It is by no means feature complete compared to the software colorspace filter, +and at the current time only supports color range conversion between jpeg/full +and mpeg/limited range. + +The filter accepts the following options: + +@table @option +@item range +Specify output color range. + +The accepted values are: +@table @samp +@item tv +TV (restricted) range + +@item mpeg +MPEG (restricted) range + +@item pc +PC (full) range + +@item jpeg +JPEG (full) range + +@end table + +@end table + +@anchor{overlay_cuda} +@subsection overlay_cuda + +Overlay one video on top of another. + +This is the CUDA variant of the @ref{overlay} filter. +It only accepts CUDA frames. The underlying input pixel formats have to match. + +It takes two inputs and has one output. The first input is the "main" +video on which the second input is overlaid. + +It accepts the following parameters: + +@table @option +@item x +@item y +Set expressions for the x and y coordinates of the overlaid video +on the main video. + +They can contain the following parameters: + +@table @option + +@item main_w, W +@item main_h, H +The main input width and height. + +@item overlay_w, w +@item overlay_h, h +The overlay input width and height. + +@item x +@item y +The computed values for @var{x} and @var{y}. They are evaluated for +each new frame. + +@item n +The ordinal index of the main input frame, starting from 0. + +@item pos +The byte offset position in the file of the main input frame, NAN if unknown. +Deprecated, do not use. + +@item t +The timestamp of the main input frame, expressed in seconds, NAN if unknown. + +@end table + +Default value is "0" for both expressions. + +@item eval +Set when the expressions for @option{x} and @option{y} are evaluated. + +It accepts the following values: +@table @option +@item init +Evaluate expressions once during filter initialization or +when a command is processed. + +@item frame +Evaluate expressions for each incoming frame +@end table + +Default value is @option{frame}. + +@item eof_action +See @ref{framesync}. + +@item shortest +See @ref{framesync}. + +@item repeatlast +See @ref{framesync}. + +@end table + +This filter also supports the @ref{framesync} options. + + +@anchor{pad_cuda} +@subsection pad_cuda +Add paddings to an input video stream using CUDA. + +This filter is the CUDA-accelerated version of the @ref{pad} filter. It accepts the same options and expressions and provides the same core functionality. +For a detailed description of available options, please see the documentation for the @ref{pad} filter. + +@subsubsection Examples + +@itemize +@item +Add a 200-pixel black border to all sides of a video frame: +@example +ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=iw+400:h=ih+400:x=200:y=200" -c:v h264_nvenc out.mp4 +@end example + +@item +Pad the input video to a 16:9 aspect ratio, filling with the color "blue": +@example +ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=ih*16/9/sar:h=ih:x=(ow-iw)/2:y=(oh-ih)/2:color=blue" -c:v h264_nvenc out.mp4 +@end example +@end itemize + +@anchor{scale_cuda} +@subsection scale_cuda + +Scale (resize) and convert (pixel format) the input video, using accelerated CUDA kernels. +Setting the output width and height works in the same way as for the @ref{scale} filter. + +The filter accepts the following options: +@table @option +@item w +@item h +Set the output video dimension expression. Default value is the input dimension. + +Allows for the same expressions as the @ref{scale} filter. + +@item interp_algo +Sets the algorithm used for scaling: + +@table @var +@item nearest +Nearest neighbour + +Used by default if input parameters match the desired output. + +@item bilinear +Bilinear + +@item bicubic +Bicubic + +This is the default. + +@item lanczos +Lanczos + +@end table + +@item format +Controls the output pixel format. By default, or if none is specified, the input +pixel format is used. + +The filter does not support converting between YUV and RGB pixel formats. + +@item passthrough +If set to 0, every frame is processed, even if no conversion is necessary. +This mode can be useful to use the filter as a buffer for a downstream +frame-consumer that exhausts the limited decoder frame pool. + +If set to 1, frames are passed through as-is if they match the desired output +parameters. This is the default behaviour. + +@item param +Algorithm-Specific parameter. + +Affects the curves of the bicubic algorithm. + +@item force_original_aspect_ratio +@item force_divisible_by +Work the same as the identical @ref{scale} filter options. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@end table + +@subsubsection Examples + +@itemize +@item +Scale input to 720p, keeping aspect ratio and ensuring the output is yuv420p. +@example +scale_cuda=-2:720:format=yuv420p +@end example + +@item +Upscale to 4K using nearest neighbour algorithm. +@example +scale_cuda=4096:2160:interp_algo=nearest +@end example + +@item +Don't do any conversion or scaling, but copy all input frames into newly allocated ones. +This can be useful to deal with a filter and encode chain that otherwise exhausts the +decoders frame pool. +@example +scale_cuda=passthrough=0 +@end example +@end itemize + +@subsection thumbnail_cuda + +Select the most representative frame in a given sequence of consecutive frames using CUDA. + +The filter accepts the following options: + +@table @option +@item n +Set the frames batch size to analyze; in a set of @var{n} frames, the filter +will pick one of them, and then handle the next batch of @var{n} frames until +the end. Default is @code{100}. +@end table + +Since the filter keeps track of the whole frames sequence, a bigger @var{n} +value will result in a higher memory usage, so a high value is not recommended. + +@subsubsection Example + +@itemize + +@item +Thumbnails are extracted from every @var{n}=150-frame batch, selecting one per batch. Chosen frames are then scaled with @ref{scale_cuda}. +@example +./ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i ./input.mp4 -vf "thumbnail_cuda=150,scale_cuda=1920:1080,hwdownload,format=nv12" ./output/out%03d.png +@end example + +@end itemize + +@subsection yadif_cuda + +Deinterlace the input video using the @ref{yadif} algorithm, but implemented +in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec +and/or nvenc. + +It accepts the following parameters: + + +@table @option + +@item mode +The interlacing mode to adopt. It accepts one of the following values: + +@table @option +@item 0, send_frame +Output one frame for each frame. +@item 1, send_field +Output one frame for each field. +@item 2, send_frame_nospatial +Like @code{send_frame}, but it skips the spatial interlacing check. +@item 3, send_field_nospatial +Like @code{send_field}, but it skips the spatial interlacing check. +@end table + +The default value is @code{send_frame}. + +@item parity +The picture field parity assumed for the input interlaced video. It accepts one +of the following values: + +@table @option +@item 0, tff +Assume the top field is first. +@item 1, bff +Assume the bottom field is first. +@item -1, auto +Enable automatic detection of field parity. +@end table + +The default value is @code{auto}. +If the interlacing is unknown or the decoder does not export this information, +top field first will be assumed. + +@item deint +Specify which frames to deinterlace. Accepts one of the following +values: + +@table @option +@item 0, all +Deinterlace all frames. +@item 1, interlaced +Only deinterlace frames marked as interlaced. +@end table + +The default value is @code{all}. +@end table + +@anchor{CUDA NPP} +@section CUDA NPP +Below is a description of the currently available NVIDIA Performance Primitives (libnpp) video filters. + +Prerequisites: +@itemize +@item Install Nvidia CUDA Toolkit +@item Install libnpp +@end itemize + +To enable CUDA NPP filters: + +@itemize +@item Configure FFmpeg with @code{--enable-nonfree --enable-libnpp}. +@end itemize + + +@anchor{scale_npp} +@subsection scale_npp + +Use the NVIDIA Performance Primitives (libnpp) to perform scaling and/or pixel +format conversion on CUDA video frames. Setting the output width and height +works in the same way as for the @var{scale} filter. + +The following additional options are accepted: +@table @option +@item format +The pixel format of the output CUDA frames. If set to the string "same" (the +default), the input format will be kept. Note that automatic format negotiation +and conversion is not yet supported for hardware frames + +@item interp_algo +The interpolation algorithm used for resizing. One of the following: +@table @option +@item nn +Nearest neighbour. + +@item linear +@item cubic +@item cubic2p_bspline +2-parameter cubic (B=1, C=0) + +@item cubic2p_catmullrom +2-parameter cubic (B=0, C=1/2) + +@item cubic2p_b05c03 +2-parameter cubic (B=1/2, C=3/10) + +@item super +Supersampling + +@item lanczos +@end table + +@item force_original_aspect_ratio +Enable decreasing or increasing output video width or height if necessary to +keep the original aspect ratio. Possible values: + +@table @samp +@item disable +Scale the video as specified and disable this feature. + +@item decrease +The output video dimensions will automatically be decreased if needed. + +@item increase +The output video dimensions will automatically be increased if needed. + +@end table + +One useful instance of this option is that when you know a specific device's +maximum allowed resolution, you can use this to limit the output video to +that, while retaining the aspect ratio. For example, device A allows +1280x720 playback, and your video is 1920x800. Using this option (set it to +decrease) and specifying 1280x720 to the command line makes the output +1280x533. + +Please note that this is a different thing than specifying -1 for @option{w} +or @option{h}, you still need to specify the output resolution for this option +to work. + +@item force_divisible_by +Ensures that both the output dimensions, width and height, are divisible by the +given integer when used together with @option{force_original_aspect_ratio}. This +works similar to using @code{-n} in the @option{w} and @option{h} options. + +This option respects the value set for @option{force_original_aspect_ratio}, +increasing or decreasing the resolution accordingly. The video's aspect ratio +may be slightly modified. + +This option can be handy if you need to have a video fit within or exceed +a defined resolution using @option{force_original_aspect_ratio} but also have +encoder restrictions on width or height divisibility. + +@item reset_sar +Works the same as the identical @ref{scale} filter option. + +@item eval +Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values: + +@table @samp +@item init +Only evaluate expressions once during the filter initialization or when a command is processed. + +@item frame +Evaluate expressions for each incoming frame. + +@end table + +@end table + +The values of the @option{w} and @option{h} options are expressions +containing the following constants: + +@table @var +@item in_w +@item in_h +The input width and height + +@item iw +@item ih +These are the same as @var{in_w} and @var{in_h}. + +@item out_w +@item out_h +The output (scaled) width and height + +@item ow +@item oh +These are the same as @var{out_w} and @var{out_h} + +@item a +The same as @var{iw} / @var{ih} + +@item sar +input sample aspect ratio + +@item dar +The input display aspect ratio. Calculated from @code{(iw / ih) * sar}. + +@item n +The (sequential) number of the input frame, starting from 0. +Only available with @code{eval=frame}. + +@item t +The presentation timestamp of the input frame, expressed as a number of +seconds. Only available with @code{eval=frame}. + +@item pos +The position (byte offset) of the frame in the input stream, or NaN if +this information is unavailable and/or meaningless (for example in case of synthetic video). +Only available with @code{eval=frame}. +Deprecated, do not use. +@end table + +@subsection scale2ref_npp + +Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input +video, based on a reference video. + +See the @ref{scale_npp} filter for available options, scale2ref_npp supports the same +but uses the reference video instead of the main input as basis. scale2ref_npp +also supports the following additional constants for the @option{w} and +@option{h} options: + +@table @var +@item main_w +@item main_h +The main input video's width and height + +@item main_a +The same as @var{main_w} / @var{main_h} + +@item main_sar +The main input video's sample aspect ratio + +@item main_dar, mdar +The main input video's display aspect ratio. Calculated from +@code{(main_w / main_h) * main_sar}. + +@item main_n +The (sequential) number of the main input frame, starting from 0. +Only available with @code{eval=frame}. + +@item main_t +The presentation timestamp of the main input frame, expressed as a number of +seconds. Only available with @code{eval=frame}. + +@item main_pos +The position (byte offset) of the frame in the main input stream, or NaN if +this information is unavailable and/or meaningless (for example in case of synthetic video). +Only available with @code{eval=frame}. +@end table + +@subsubsection Examples + +@itemize +@item +Scale a subtitle stream (b) to match the main video (a) in size before overlaying +@example +'scale2ref_npp[b][a];[a][b]overlay_cuda' +@end example + +@item +Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio. +@example +[logo-in][video-in]scale2ref_npp=w=oh*mdar:h=ih/10[logo-out][video-out] +@end example +@end itemize + +@subsection sharpen_npp +Use the NVIDIA Performance Primitives (libnpp) to perform image sharpening with +border control. + +The following additional options are accepted: +@table @option + +@item border_type +Type of sampling to be used ad frame borders. One of the following: +@table @option + +@item replicate +Replicate pixel values. + +@end table +@end table + +@subsection transpose_npp + +Transpose rows with columns in the input video and optionally flip it. +For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. + +It accepts the following parameters: + +@table @option + +@item dir +Specify the transposition direction. + +Can assume the following values: +@table @samp +@item cclock_flip +Rotate by 90 degrees counterclockwise and vertically flip. (default) + +@item clock +Rotate by 90 degrees clockwise. + +@item cclock +Rotate by 90 degrees counterclockwise. + +@item clock_flip +Rotate by 90 degrees clockwise and vertically flip. +@end table + +@item passthrough +Do not apply the transposition if the input geometry matches the one +specified by the specified value. It accepts the following values: +@table @samp +@item none +Always apply transposition. (default) +@item portrait +Preserve portrait geometry (when @var{height} >= @var{width}). +@item landscape +Preserve landscape geometry (when @var{width} >= @var{height}). +@end table + +@end table + +@c man end CUDA Video Filters + @chapter OpenCL Video Filters @c man begin OPENCL VIDEO FILTERS @@ -29167,7 +29687,7 @@ Set the initial y position. Must be a floating point value between Generate various test patterns, as generated by the MPlayer test filter. -The size of the generated video is fixed, and is 256x256. +The size of the generated video is fixed, and is 512x512. This source is useful in particular for testing encoding features. This source accepts the following options: @@ -31386,6 +31906,12 @@ This filter accepts the following options: @item expr The expression which is evaluated for each frame to construct its timestamp. +@item strip_fps (@emph{video only}) +Boolean option which determines if the original framerate metadata is unset. +If set to true, be advised that a sane frame rate should be explicitly +specified if output is sent to a constant frame rate muxer. +Default is @code{false}. + @end table The expression is evaluated through the eval API and can contain the following diff --git a/doc/general_contents.texi b/doc/general_contents.texi index 5980ac6f02..b9dab580f1 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -162,7 +162,7 @@ Then pass @code{--enable-libmp3lame} to configure to enable it. @section LCEVCdec -FFmpeg can make use of the liblcevc_dec library for LCEVC enhacement layer +FFmpeg can make use of the liblcevc_dec library for LCEVC enhancement layer decoding on supported bitstreams. Go to @url{https://github.com/v-novaltd/LCEVCdec} and follow the instructions @@ -625,6 +625,7 @@ library: @item raw AMR-NB @tab @tab X @item raw AMR-WB @tab @tab X @item raw APAC @tab @tab X +@item raw APV @tab X @tab X @item raw aptX @tab X @tab X @item raw aptX HD @tab X @tab X @item raw Bonk @tab @tab X @@ -637,6 +638,7 @@ library: @item raw E-AC-3 @tab X @tab X @item raw EVC @tab X @tab X @item raw FLAC @tab X @tab X +@item raw G.728 @tab @tab X @item raw GSM @tab @tab X @item raw H.261 @tab X @tab X @item raw H.263 @tab X @tab X @@ -895,6 +897,7 @@ following image formats are supported: @tab fourcc: apch,apcn,apcs,apco,ap4h,ap4x @item Apple QuickDraw @tab @tab X @tab fourcc: qdrw +@item APV @tab @tab X @item Argonaut Video @tab @tab X @tab Used in some Argonaut games. @item Asus v1 @tab X @tab X @@ -1109,6 +1112,7 @@ following image formats are supported: @item RealVideo 3.0 @tab @tab X @tab still far from ideal @item RealVideo 4.0 @tab @tab X +@item RealVideo 6.0 @tab @tab X @item Renderware TXD (TeXture Dictionary) @tab @tab X @tab Texture dictionaries used by the Renderware Engine. @item RivaTuner Video @tab @tab X @@ -1232,6 +1236,7 @@ following image formats are supported: @item ADPCM IMA Duck DK4 @tab @tab X @tab Used in some Sega Saturn console games. @item ADPCM IMA Radical @tab @tab X +@item ADPCM IMA Xbox @tab @tab X @item ADPCM Microsoft @tab X @tab X @item ADPCM MS IMA @tab X @tab X @item ADPCM Nintendo Gamecube AFC @tab @tab X @@ -1239,6 +1244,7 @@ following image formats are supported: @item ADPCM Nintendo THP @tab @tab X @item ADPCM Playstation @tab @tab X @item ADPCM QT IMA @tab X @tab X +@item ADPCM Sanyo @tab @tab X @item ADPCM SEGA CRI ADX @tab X @tab X @tab Used in Sega Dreamcast games. @item ADPCM Shockwave Flash @tab X @tab X @@ -1313,6 +1319,7 @@ following image formats are supported: @item FLAC (Free Lossless Audio Codec) @tab X @tab IX @item FTR Voice @tab @tab X @item G.723.1 @tab X @tab X +@item G.728 @tab @tab X @item G.729 @tab @tab X @item GSM @tab E @tab X @tab encoding supported through external library libgsm diff --git a/doc/git-howto.texi b/doc/git-howto.texi index 075b188abe..e20d114f9e 100644 --- a/doc/git-howto.texi +++ b/doc/git-howto.texi @@ -71,7 +71,6 @@ git clone git@@ffmpeg.org:ffmpeg-web This will put the source of the FFmpeg website into the directory @var{} and let you push back your changes to the remote repository. -(Note that @var{gil} stands for GItoLite and is not a typo of @var{git}.) If you don't have write-access to the ffmpeg-web repository, you can create patches after making a read-only ffmpeg-web clone: @@ -143,7 +142,7 @@ git log @end example You may also use the graphical tools like @command{gitview} or @command{gitk} -or the web interface available at @url{http://source.ffmpeg.org/}. +or the web interface available at @url{https://git.ffmpeg.org/ffmpeg.git}. @section Checking source tree status diff --git a/doc/htmlxref.cnf b/doc/htmlxref.cnf new file mode 100644 index 0000000000..079c848a65 --- /dev/null +++ b/doc/htmlxref.cnf @@ -0,0 +1,6 @@ +ffmpeg mono ./ffmpeg.html +ffmpeg-filters mono ./ffmpeg-filters.html +ffmpeg-formats mono ./ffmpeg-formats.html +ffmpeg-resampler mono ./ffmpeg-resampler.html +ffmpeg-scaler mono ./ffmpeg-scaler.html +ffmpeg-utils mono ./ffmpeg-utils.html diff --git a/doc/indevs.texi b/doc/indevs.texi index cdf44a6638..8822e070fe 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -220,41 +220,6 @@ $ ffmpeg -f avfoundation -capture_raw_data true -i "zr100:none" out.dv @end itemize -@section bktr - -BSD video input device. Deprecated and will be removed - please contact -the developers if you are interested in maintaining it. - -@subsection Options - -@table @option - -@item framerate -Set the frame rate. - -@item video_size -Set the video frame size. Default is @code{vga}. - -@item standard - -Available values are: -@table @samp -@item pal - -@item ntsc - -@item secam - -@item paln - -@item palm - -@item ntscj - -@end table - -@end table - @section decklink The decklink input device provides capture capabilities for Blackmagic @@ -739,7 +704,7 @@ Win32 GDI-based screen capture device. This device allows you to capture a region of the display on Windows. -Amongst options for the imput filenames are such elements as: +Amongst options for the input filenames are such elements as: @example desktop @end example diff --git a/doc/infra.txt b/doc/infra.txt index 30a85dd5ce..490c6cdbd9 100644 --- a/doc/infra.txt +++ b/doc/infra.txt @@ -1,8 +1,18 @@ FFmpeg Infrastructure: ====================== +Trademark: +~~~~~~~~~~ +ffmpeg trademark registered in france by ffmpeg creator. +Domain + NS: +~~~~~~~~~~~~ +ffmpeg.org domain name +ns1.avcodec.org Primary Name server (provided by Telepoint, hosted at Telepoint in bulgaria) +ns2.avcodec.org Replica Name server (provided by an ffmpeg developer, hosted at Hetzner in germany) +ns3.avcodec.org Replica Name server (provided by an ffmpeg developer, hosted at Prometeus Cdlan in italy) + Servers: ~~~~~~~~ @@ -23,6 +33,8 @@ Web, mail, and public facing git, also website git fftrac VM: ---------- trac.ffmpeg.org Issue tracking +gpg encrypted backups of the trac repositories are created once a day +and can be downloaded by any of the admins. ffaux VM: @@ -65,6 +77,9 @@ Github mirrors are redundantly synced by multiple people You need a new git repository related to FFmpeg ? contact root at ffmpeg.org +git repositories are managed by gitolite, every change to permissions is +logged, including when, what and by whom + Fate: ~~~~~ @@ -87,8 +102,47 @@ You need a VM, docker container for FFmpeg? contact root at ffmpeg.org +Multimedia Wiki: +~~~~~~~~~~~~~~~~ +The Multimedia Wiki http://wiki.multimedia.cx is ran by Mike Melanson. +While not directly part of FFmpeg infrastructure, technical codec and format +information written by FFmpeg developers can be found within. +It is our unofficial official tech wiki. For access contact Mike. + + + IRC: ~~~~ irc channels are at https://libera.chat/ irc channel archives are at https://libera.irclog.whitequark.org +#ffmpeg and #ffmpeg-devel founder/admins: BtbN, Michael, Compn +#ffmpeg-meeting founder/admins: BtbN, Michael + + +Twitter aka X: +~~~~~~~~~~~~~~ +https://twitter.com/FFmpeg or https://x.com/FFmpeg + +If you would like to post to twitter please contact twitter MAINTAINERS +for access. We want more developers posting to twitter! + + + +Reddit: +~~~~~~~ +https://www.reddit.com/r/ffmpeg/ +moderated by Gyan + + + +Facebook: +~~~~~~~~~ +https://www.facebook.com/ffmpeg +??? + + + +Wikipedia entry: +~~~~~~~~~~~~~~~~ +https://en.wikipedia.org/wiki/FFmpeg diff --git a/doc/libav-merge.txt b/doc/libav-merge.txt deleted file mode 100644 index bcd0aacba5..0000000000 --- a/doc/libav-merge.txt +++ /dev/null @@ -1,115 +0,0 @@ -CONTEXT -======= - -The FFmpeg project merges all the changes from the Libav project -(https://libav.org) since the origin of the fork (around 2011). - -With the exceptions of some commits due to technical/political disagreements or -issues, the changes are merged on a more or less regular schedule (daily for -years thanks to Michael, but more sparse nowadays). - -WHY -=== - -The majority of the active developers believe the project needs to keep this -policy for various reasons. - -The most important one is that we don't want our users to have to choose -between two distributors of libraries of the exact same name in order to have a -different set of features and bugfixes. By taking the responsibility of -unifying the two codebases, we allow users to benefit from the changes from the -two teams. - -Today, FFmpeg has a much larger user database (we are distributed by every -major distribution), so we consider this mission a priority. - -A different approach to the merge could have been to pick the changes we are -interested in and drop most of the cosmetics and other less important changes. -Unfortunately, this makes the following picks much harder, especially since the -Libav project is involved in various deep API changes. As a result, we decide -to virtually take everything done there. - -Any Libav developer is of course welcome anytime to contribute directly to the -FFmpeg tree. Of course, we fully understand and are forced to accept that very -few Libav developers are interested in doing so, but we still want to recognize -their work. This leads us to create merge commits for every single one from -Libav. The original commit appears totally unchanged with full authorship in -our history (and the conflict are solved in the merge one). That way, not a -single thing from Libav will be lost in the future in case some reunification -happens, or that project disappears one way or another. - -DOWNSIDES -========= - -Of course, there are many downsides to this approach. - -- It causes a non negligible merge commits pollution. We make sure there are - not several level of merges entangled (we do a 1:1 merge/commit), but it's - still a non-linear history. - -- Many duplicated work. For instance, we added libavresample in our tree to - keep compatibility with Libav when our libswresample was already covering the - exact same purpose. The same thing happened for various elements such as the - ProRes support (but differences in features, bugs, licenses, ...). There are - many work to do to unify them, and any help is very much welcome. - -- So much manpower from both FFmpeg and Libav is lost because of this mess. We - know it, and we don't know how to fix it. It takes incredible time to do - these merges, so we have even less time to work on things we personally care - about. The bad vibes also do not help with keeping our developers motivated. - -- There is a growing technical risk factor with the merges due to the codebase - differing more and more. - -MERGE GUIDELINES -================ - -The following gives developer guidelines on how to proceed when merging Libav commits. - -Before starting, you can reduce the risk of errors on merge conflicts by using -a different merge conflict style: - - $ git config --global merge.conflictstyle diff3 - -tools/libav-merge-next-commit is a script to help merging the next commit in -the queue. It assumes a remote named libav. It has two modes: merge, and noop. -The noop mode creates a merge with no change to the HEAD. You can pass a hash -as extra argument to reference a justification (it is common that we already -have the change done in FFmpeg). - -Also see tools/murge, you can copy and paste a 3 way conflict into its stdin -and it will display colored diffs. Any arguments to murge (like ones to suppress -whitespace differences) are passed into colordiff. - -TODO/FIXME/UNMERGED -=================== - -Stuff that didn't reach the codebase: -------------------------------------- - -- HEVC DSP and x86 MC SIMD improvements from Libav (see https://ffmpeg.org/pipermail/ffmpeg-devel/2015-December/184777.html) - - 1f821750f hevcdsp: split the qpel functions by width instead of by the subpixel fraction - - 818bfe7f0 hevcdsp: split the epel functions by width - - 688417399 hevcdsp: split the pred functions by width - - 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 - - 7993ec19a hevc: Add hevc_get_pixel_4/8/12/16/24/32/48/64 -- 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) -- avcodec/libaomenc: export the Sequence Header OBU as extradata (See a024c3ce9a) - -Collateral damage that needs work locally: ------------------------------------------- - -- Merge proresenc_anatoliy.c and proresenc_kostya.c -- Fix MIPS AC3 downmix - -Extra changes needed to be aligned with Libav: ----------------------------------------------- - -- Switching our examples to the new encode/decode API (see 67d28f4a0f) -- HEVC IDCT bit depth 12-bit support (Libav added 8 and 10 but doesn't have 12) diff --git a/doc/mips.txt b/doc/mips.txt index a42546f0cd..f7529bd8e7 100644 --- a/doc/mips.txt +++ b/doc/mips.txt @@ -60,6 +60,5 @@ Files that have MIPS copyright notice in them: compute_antialias_float.h lsp_mips.h fmtconvert_mips.c - iirfilter_mips.c mpegaudiodsp_mips_fixed.c mpegaudiodsp_mips_float.c diff --git a/doc/muxers.texi b/doc/muxers.texi index ce93ba1488..8c45b7d47a 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -319,7 +319,7 @@ This is the same as the @samp{vob} muxer with a few differences. @table @option @item muxrate @var{rate} Set user-defined mux rate expressed as a number of bits/s. If not -specied the automatically computed mux rate is employed. Default value +specified the automatically computed mux rate is employed. Default value is @code{0}. @item preload @var{delay} @@ -772,7 +772,7 @@ Force a delay expressed in seconds after the last frame of each repetition. Default value is @code{0.0}. @item plays @var{repetitions} -specify how many times to play the content, @code{0} causes an infinte +specify how many times to play the content, @code{0} causes an infinite loop, with @code{1} there is no loop @end table @@ -1770,7 +1770,7 @@ for looping indefinitely (default). @item final_delay @var{delay} Force the delay (expressed in centiseconds) after the last frame. Each frame ends with a delay until the next frame. The default is @code{-1}, which is a -special value to tell the muxer to re-use the previous delay. In case of a +special value to tell the muxer to reuse the previous delay. In case of a loop, you might want to customize this value to mark a pause for instance. @end table @@ -1856,7 +1856,7 @@ This muxer creates an .f4m (Adobe Flash Media Manifest File) manifest, an .abst (Adobe Bootstrap File) for each stream, and segment files in a directory specified as the output. -These needs to be accessed by an HDS player throuhg HTTPS for it to be able to +These needs to be accessed by an HDS player through HTTPS for it to be able to perform playback on the generated stream. @subsection Options @@ -2436,13 +2436,14 @@ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ @item Create a single variant stream. Add the @code{#EXT-X-MEDIA} tag with @code{TYPE=SUBTITLES} in the master playlist with webvtt subtitle group name -'subtitle'. Make sure the input file has one text subtitle stream at least. +'subtitle' and optional subtitle name, e.g. 'English'. Make sure the input +file has one text subtitle stream at least. @example ffmpeg -y -i input_with_subtitle.mkv \ -b:v:0 5250k -c:v h264 -pix_fmt yuv420p -profile:v main -level 4.1 \ -b:a:0 256k \ -c:s webvtt -c:a mp2 -ar 48000 -ac 2 -map 0:v -map 0:a:0 -map 0:s:0 \ - -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle" \ + -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle,sname:English" \ -master_pl_name master.m3u8 -t 300 -hls_time 10 -hls_init_time 4 -hls_list_size \ 10 -master_pl_publish_rate 10 -hls_flags \ delete_segments+discont_start+split_by_time ./tmp/video.m3u8 @@ -2537,7 +2538,7 @@ these applications, audio may be played back on a wide range of devices, e.g., headphones, mobile phones, tablets, TVs, sound bars, home theater systems, and big screens. -This format was promoted and desgined by Alliance for Open Media. +This format was promoted and designed by Alliance for Open Media. For more information about this format, see @url{https://aomedia.org/iamf/}. @@ -2939,6 +2940,44 @@ ffmpeg -i INPUT -f md5 - @end example @end itemize +@anchor{mccenc} +@section mcc +Muxer for MacCaption MCC files, it supports MCC versions 1.0 and 2.0. +MCC files store VANC data, which can include closed captions (EIA-608 and CEA-708), ancillary time code, pan-scan data, etc. + +@subsection Options + +The muxer options are: + +@table @option +@item override_time_code_rate +Override the @code{Time Code Rate} value in the output. Defaults to trying to deduce from the stream's @code{time_base}, which often doesn't work. +@item use_u_alias +Use the @code{U} alias for the byte sequence @code{E1h 00h 00h 00h}. +Disabled by default because some @file{.mcc} files disagree on whether it has 2 or 3 zero bytes. +@item mcc_version +The MCC file format version. Must be either 1 or 2, defaults to 2. +@item creation_program +The creation program. Defaults to this version of FFmpeg. +@item creation_time +The creation time. Defaults to the current time. +@end table + +@subsection Examples +@itemize +@item +Extract a MXF @code{SMPTE_436M_ANC} stream from a MXF file and write it to a MCC file at 30 fps. +@example +ffmpeg -i input.mxf -c copy -map 0:d -override_time_code_rate 30 out.mcc +@end example + +@item +Extract EIA-608/CTA-708 closed captions from a @file{.mp4} file and write them to a MCC file at 29.97 fps. +@example +ffmpeg -f lavfi -i "movie=input.mp4[out+subcc]" -c:s copy -map 0:s -override_time_code_rate 30000/1001 out.mcc +@end example +@end itemize + @section microdvd MicroDVD subtitle format muxer. @@ -3878,4 +3917,53 @@ ffmpeg -f webm_dash_manifest -i video1.webm \ manifest.xml @end example +@anchor{whip} +@section whip + +WebRTC (Real-Time Communication) muxer that supports sub-second latency streaming according to +the WHIP (WebRTC-HTTP ingestion protocol) specification. + +This is an experimental feature. + +It uses HTTP as a signaling protocol to exchange SDP capabilities and ICE lite candidates. Then, +it uses STUN binding requests and responses to establish a session over UDP. Subsequently, it +initiates a DTLS handshake to exchange the SRTP encryption keys. Lastly, it splits video and +audio frames into RTP packets and encrypts them using SRTP. + +Ensure that you use H.264 without B frames and Opus for the audio codec. For example, to convert +an input file with @command{ffmpeg} to WebRTC: +@example +ffmpeg -re -i input.mp4 -acodec libopus -ar 48000 -ac 2 \ + -vcodec libx264 -profile:v baseline -tune zerolatency -threads 1 -bf 0 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" +@end example + +For this example, we have employed low latency options, resulting in an end-to-end latency of +approximately 150ms. + +@subsection Options + +This muxer supports the following options: + +@table @option + +@item handshake_timeout @var{integer} +Set the timeout in milliseconds for ICE and DTLS handshake. +Default value is 5000. + +@item pkt_size @var{integer} +Set the maximum size, in bytes, of RTP packets that send out. +Default value is 1500. + +@item authorization @var{string} +The optional Bearer token for WHIP Authorization. + +@item cert_file @var{string} +The optional certificate file path for DTLS. + +@item key_file @var{string} +The optional private key file path for DTLS. + +@end table + @c man end MUXERS diff --git a/doc/nut.texi b/doc/nut.texi index f9b18f5660..d3a5b8de39 100644 --- a/doc/nut.texi +++ b/doc/nut.texi @@ -157,4 +157,3 @@ PFD[32] would for example be signed 32 bit little-endian IEEE float @item XVID @tab non-compliant MPEG-4 generated by old Xvid @item XVIX @tab non-compliant MPEG-4 generated by old Xvid with interlacing bug @end multitable - diff --git a/doc/optimization.txt b/doc/optimization.txt index 3ed29fe38c..40480e4fa9 100644 --- a/doc/optimization.txt +++ b/doc/optimization.txt @@ -188,7 +188,7 @@ Code that depends on data in registries being untouched, should be written as a single __asm__() statement. Ideally, a single function contains only one __asm__() block. -Use external asm (nasm/yasm) or inline asm (__asm__()), do not use intrinsics. +Use external asm (nasm) or inline asm (__asm__()), do not use intrinsics. The latter requires a good optimizing compiler which gcc is not. When debugging a x86 external asm compilation issue, if lost in the macro @@ -199,7 +199,7 @@ actual lines causing issues. Inline asm vs. external asm --------------------------- Both inline asm (__asm__("..") in a .c file, handled by a compiler such as gcc) -and external asm (.s or .asm files, handled by an assembler such as nasm/yasm) +and external asm (.s or .asm files, handled by an assembler such as nasm) are accepted in FFmpeg. Which one to use differs per specific case. - if your code is intended to be inlined in a C function, inline asm is always diff --git a/doc/outdevs.texi b/doc/outdevs.texi index 9ee857528e..86c78f31b7 100644 --- a/doc/outdevs.texi +++ b/doc/outdevs.texi @@ -301,45 +301,6 @@ ffmpeg -re -i INPUT -c:v rawvideo -pix_fmt bgra -f fbdev /dev/fb0 See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1). -@section opengl -OpenGL output device. Deprecated and will be removed. - -To enable this output device you need to configure FFmpeg with @code{--enable-opengl}. - -This output device allows one to render to OpenGL context. -Context may be provided by application or default SDL window is created. - -When device renders to external context, application must implement handlers for following messages: -@code{AV_DEV_TO_APP_CREATE_WINDOW_BUFFER} - create OpenGL context on current thread. -@code{AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER} - make OpenGL context current. -@code{AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER} - swap buffers. -@code{AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER} - destroy OpenGL context. -Application is also required to inform a device about current resolution by sending @code{AV_APP_TO_DEV_WINDOW_SIZE} message. - -@subsection Options -@table @option - -@item background -Set background color. Black is a default. -@item no_window -Disables default SDL window when set to non-zero value. -Application must provide OpenGL context and both @code{window_size_cb} and @code{window_swap_buffers_cb} callbacks when set. -@item window_title -Set the SDL window title, if not specified default to the filename specified for the output device. -Ignored when @option{no_window} is set. -@item window_size -Set preferred window size, can be a string of the form widthxheight or a video size abbreviation. -If not specified it defaults to the size of the input video, downscaled according to the aspect ratio. -Mostly usable when @option{no_window} is not set. - -@end table - -@subsection Examples -Play a file on SDL window using OpenGL rendering: -@example -ffmpeg -i INPUT -f opengl "window title" -@end example - @section oss OSS (Open Sound System) output device. @@ -406,78 +367,6 @@ Play a file on default device on default server: ffmpeg -i INPUT -f pulse "stream name" @end example -@section sdl - -SDL (Simple DirectMedia Layer) output device. Deprecated and will be removed. - -For monitoring purposes in FFmpeg, pipes and a video player such as ffplay can be used: - -@example -ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay - -@end example - -"sdl2" can be used as alias for "sdl". - -This output device allows one to show a video stream in an SDL -window. Only one SDL window is allowed per application, so you can -have only one instance of this output device in an application. - -To enable this output device you need libsdl installed on your system -when configuring your build. - -For more information about SDL, check: -@url{http://www.libsdl.org/} - -@subsection Options - -@table @option - -@item window_borderless -Set SDL window border off. -Default value is 0 (enable window border). - -@item window_enable_quit -Enable quit action (using window button or keyboard key) -when non-zero value is provided. -Default value is 1 (enable quit action). - -@item window_fullscreen -Set fullscreen mode when non-zero value is provided. -Default value is zero. - -@item window_size -Set the SDL window size, can be a string of the form -@var{width}x@var{height} or a video size abbreviation. -If not specified it defaults to the size of the input video, -downscaled according to the aspect ratio. - -@item window_title -Set the SDL window title, if not specified default to the filename -specified for the output device. - -@item window_x -@item window_y -Set the position of the window on the screen. -@end table - -@subsection Interactive commands - -The window created by the device can be controlled through the -following interactive commands. - -@table @key -@item q, ESC -Quit the device immediately. -@end table - -@subsection Examples - -The following command shows the @command{ffmpeg} output is an -SDL window, forcing its size to the qcif format: -@example -ffmpeg -i INPUT -c:v rawvideo -pix_fmt yuv420p -window_size qcif -f sdl "SDL output" -@end example - @section sndio sndio audio output device. diff --git a/doc/platform.texi b/doc/platform.texi index 764911d230..d9ee436a9f 100644 --- a/doc/platform.texi +++ b/doc/platform.texi @@ -158,7 +158,7 @@ You will need the following prerequisites: To set up a proper environment in MSYS2, you need to run @code{msys_shell.bat} from the Visual Studio or Intel Compiler command prompt. -Place @code{yasm.exe} somewhere in your @code{PATH}. +Place @code{nasm.exe} somewhere in your @code{PATH}. Next, make sure any other headers and libs you want to use, such as zlib, are located in a spot that the compiler can see. Do so by modifying the @code{LIB} @@ -301,7 +301,7 @@ These library packages are only available from @uref{http://sourceware.org/cygwinports/, Cygwin Ports}: @example -yasm, libSDL-devel, libgsm-devel, libmp3lame-devel, +libSDL-devel, libgsm-devel, libmp3lame-devel, speex-devel, libtheora-devel, libxvidcore-devel @end example diff --git a/doc/protocols.texi b/doc/protocols.texi index ed70af4b33..fa2df39a1d 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -71,7 +71,7 @@ client may also set a user/password for authentication. The default for both fields is "guest". Name of virtual host on broker can be set with vhost. The default value is "/". -Muliple subscribers may stream from the broker using the command: +Multiple subscribers may stream from the broker using the command: @example ffplay amqp://[[user]:[password]@@]hostname[:port][/vhost] @end example @@ -607,7 +607,7 @@ The resource requested by a client, when the experimental HTTP server is in use. The HTTP code returned to the client, when the experimental HTTP server is in use. @item short_seek_size -Set the threshold, in bytes, for when a readahead should be prefered over a seek and +Set the threshold, in bytes, for when a readahead should be preferred over a seek and new HTTP request. This is useful, for example, to make sure the same connection is used for reading large video packets with small audio packets in between. @@ -1150,10 +1150,15 @@ ffplay "rtmp://myserver/live/mystream live=1" Real-time Transport Protocol. The required syntax for an RTP URL is: -rtp://@var{hostname}[:@var{port}][?@var{option}=@var{val}...] +@example +rtp://@var{hostname}[:@var{port}][?@var{options}] +@end example @var{port} specifies the RTP port to use. +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. + The following URL options are supported: @table @option @@ -1193,16 +1198,15 @@ set to 1) or to a default remote address (if set to 0). @item localport=@var{n} Set the local RTP port to @var{n}. +This is a deprecated option. Instead, @option{localrtpport} should be +used. + @item localaddr=@var{addr} Local IP address of a network interface used for sending packets or joining multicast groups. @item timeout=@var{n} Set timeout (in microseconds) of socket I/O operations to @var{n}. - -This is a deprecated option. Instead, @option{localrtpport} should be -used. - @end table Important notes: @@ -2024,6 +2028,87 @@ To play back a stream from the TLS/SSL server using @command{ffplay}: ffplay tls://@var{hostname}:@var{port} @end example +@section dtls + +Datagram Transport Layer Security (DTLS) + +The required syntax for a DTLS URL is: +@example +dtls://@var{hostname}:@var{port} +@end example + +DTLS shares most options with TLS, but operates over UDP instead of TCP. +The following parameters can be set via command line options +(or in code via @code{AVOption}s): + +@table @option + +@item ca_file, cafile=@var{filename} +A file containing certificate authority (CA) root certificates to treat +as trusted. If the linked TLS library contains a default this might not +need to be specified for verification to work, but not all libraries and +setups have defaults built in. +The file must be in OpenSSL PEM format. + +@item tls_verify=@var{1|0} +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. + +This is disabled by default since it requires a CA database to be +provided by the caller in many cases. + +@item cert_file, cert=@var{filename} +A file containing a certificate to use in the handshake with the peer. +(When operating as server, in listen mode, this is more often required +by the peer, while client certificates only are mandated in certain +setups.) + +@item key_file, key=@var{filename} +A file containing the private key for the certificate. + +@item cert_pem=@var{string} +Certificate PEM string + +@item key_pem=@var{string} +Private key PEM string + +@item listen=@var{1|0} +If enabled, listen for connections on the provided port, and assume +the server role in the handshake instead of the client role. + +@item mtu=@var{size} +Set the Maximum Transmission Unit (MTU) for DTLS packets. + +@item use_srtp=@var{1|0} +Enable the use_srtp DTLS extension. +This is used in WebRTC applications to establish SRTP encryption keys +through the DTLS handshake. Default is disabled. + +@item external_sock=@var{1|0} +Use an external socket instead of creating a new one. +This option only makes sense to pass when interacting with the code via +API, enabling this from CLI will cause immediate failure. +Default is disabled. + +@end table + +Example command lines: + +To create a DTLS server: + +@example +ffmpeg -listen 1 -i dtls://@var{hostname}:@var{port} @var{output} +@end example + +To create a DTLS client and send data to server: + +@example +ffmpeg -i @var{input} -f @var{format} dtls://@var{hostname}:@var{port} +@end example + @section udp User Datagram Protocol. diff --git a/doc/scaler.texi b/doc/scaler.texi index eb045de6b7..a9ed10e34e 100644 --- a/doc/scaler.texi +++ b/doc/scaler.texi @@ -96,6 +96,9 @@ If value is set to @code{1}, indicates source is full range. Default value is If value is set to @code{1}, enable full range for destination. Default value is @code{0}, which enables limited range. +@item gamma @var{(boolean)} +If value is set to @code{1}, enable gamma correct scaling. Default value is @code{0}. + @anchor{sws_params} @item param0, param1 Set scaling algorithm parameters. The specified values are specific of diff --git a/doc/style.min.css b/doc/style.min.css index 6843fda57d..a502310bb9 100644 --- a/doc/style.min.css +++ b/doc/style.min.css @@ -20,4 +20,4 @@ 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. - */body{background-color:#313131;color:#e6e6e6;text-align:justify}body, h1, h2, h3, h4, h5, h6{font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Helvetica Neue",Helvetica,Verdana,Tahoma,sans-serif}a{color:#4cae4c}a strong{color:#e6e6e6}a:hover{color:#7fc77f}a:hover strong{color:#4cae4c}main{width:100% ! important;min-height:600px;margin:auto}h1, h2, h3, h4{font-weight:bold;text-align:left}h1, h2, h3{color:#bebebe}h1 strong, h2 strong, h3 strong{color:#e6e6e6}h4, h5, h6{color:#3c8b3c}h1{border-bottom:4px #bebebe solid;padding:20px 2%}h3{border-bottom:2px #bebebe solid;padding:15px 1%}h4{border-bottom:1px solid #e6e6e6;padding:10px 0;margin:20px 0;color:#e6e6e6}.list-group .list-group-item{background-color:#3e3e3e;border-color:black}.list-group.list-group-big .list-group-item{padding:25px}.list-group a.list-group-item{color:#7fc77f}.list-group a.list-group-item:hover{background-color:#313131;color:#4cae4c}.well{background-color:#242424;border-color:black;color:#bebebe}.well strong{color:#e6e6e6}.well code{background-color:#313131}.well hr{border-color:#3c8b3c}.well h3{margin:5px 0 15px 0;border:0;padding:0}.well a{color:#4cae4c}.well a.btn{color:white}.well small{display:block;padding:0 10px;font-style:italic}.well.example{padding-top:40px;margin-bottom:130px}.well.example pre{margin:50px;margin-bottom:30px;font-size:1.5em}.well.example .btn{margin-right:50px;margin-bottom:20px}.well.well-with-icon{min-height:136px}.well.well-with-icon .pull-right,.well.well-with-icon .pull-left{background-color:#4cae4c;color:#e6e6e6;padding:10px;border-radius:5px;margin:5px}.well.well-with-icon .pull-right{margin-left:20px}.well.well-with-icon .pull-left{margin-right:20px}a.well{display:block}a.well:hover{text-decoration:none;opacity:0.8}.info, .warning{margin:10px;padding:10px;background-color:#3e3e3e;color:#e6e6e6}.info code, .warning code{background-color:#313131}.info{border-left:10px #4cae4c solid}.warning{border-left:10px #ae4c4c solid}.with-icon{padding:30px}.with-icon .pull-left{padding-right:30px}.with-icon .pull-right{padding-left:30px}dd{margin-left:20px}code{background-color:#242424;color:#7fc77f;display:inline-block;margin:5px}.table{margin:20px 0;border-radius:4px}.table th,.table td,.table tr{border:1px solid #171717}.table tr th{background-color:#3e3e3e;border-bottom:2px solid #e6e6e6}.table tr:nth-child(odd){background-color:#242424}#sidebar-wrapper, .navbar{background-color:#171717;overflow-x:hidden}#sidebar-wrapper .sidebar-brand img,#sidebar-wrapper .navbar-brand img, .navbar .sidebar-brand img, .navbar .navbar-brand img{opacity:0.6;margin-right:8px}#sidebar-wrapper .sidebar-brand:hover,#sidebar-wrapper .navbar-brand:hover, .navbar .sidebar-brand:hover, .navbar .navbar-brand:hover{color:#fff}#sidebar-wrapper .sidebar-brand:hover img,#sidebar-wrapper .navbar-brand:hover img, .navbar .sidebar-brand:hover img, .navbar .navbar-brand:hover img{opacity:1}#sidebar-wrapper .sidebar-nav li ul, .navbar .sidebar-nav li ul{list-style-type:none;padding:0}#sidebar-wrapper .sidebar-nav li ul li, .navbar .sidebar-nav li ul li{line-height:20px}#sidebar-wrapper .sidebar-nav li ul li a, .navbar .sidebar-nav li ul li a{padding-left:20px}.content-header{height:auto;background-color:#242424}.content-header h1{color:#e6e6e6;display:block;margin:0;margin-bottom:20px;line-height:normal;border-bottom:none}#download h4, #index h4{margin-top:180px}#download h4.first, #index h4.first{margin-top:20px}#download h4.first small, #index h4.first small{color:inherit;font-size:1em}#download .btn-download-wrapper, #index .btn-download-wrapper{text-align:center;margin:160px auto}#download .btn-download-wrapper .btn, #index .btn-download-wrapper .btn{font-size:3em;padding:3%;display:inline-block;margin-bottom:5px}#download .btn-download-wrapper small, #index .btn-download-wrapper small{display:block;font-size:0.4em}#download h2.description, #index h2.description{color:#e6e6e6;font-size:2em;font-weight:bold;margin:120px 50px;line-height:2em}#download h2.description .label, #index h2.description .label{font-size:0.5em}#download .btn-download-wrapper{margin:40px auto}#download .os-selector{text-align:center;color:#e6e6e6;margin:30px 0}#download .os-selector a.btn-build{color:#e6e6e6;display:block;padding:20px;border-radius:2px}#download .os-selector .btn-build[href="#build-linux"]{background-color:#e43}#download .os-selector .btn-build[href="#build-linux"]:hover{color:#e43;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-windows"]{background-color:#06a}#download .os-selector .btn-build[href="#build-windows"]:hover{color:#06a;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-mac"]{background-color:darkgrey}#download .os-selector .btn-build[href="#build-mac"]:hover{color:darkgrey;background-color:#e6e6e6}#download .os-selector .tab-content{margin-top:20px}#download .os-selector #build-linux h3{color:#e43}#download .os-selector #build-windows h3{color:#06a}#download .os-selector #build-mac h3{color:darkgrey}footer{background-color:#242424;border-top:1px #101010 solid;padding:20px 0%}footer a{display:block}footer img[alt="FFmpeg"]{width:50%;display:block;margin:auto} + */body{background-color:#313131;color:#e6e6e6;text-align:justify}body, h1, h2, h3, h4, h5, h6{font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Helvetica Neue",Helvetica,Verdana,Tahoma,sans-serif}a{color:#4cae4c}a strong{color:#e6e6e6}a:hover{color:#7fc77f}a:hover strong{color:#4cae4c}main{width:100% ! important;min-height:600px;margin:auto}h1, h2, h3, h4{font-weight:bold;text-align:left}h1, h2, h3{color:#bebebe}h1 strong, h2 strong, h3 strong{color:#e6e6e6}h4, h5, h6{color:#3c8b3c}h1{border-bottom:4px #bebebe solid;padding:20px 2%}h3{border-bottom:2px #bebebe solid;padding:15px 1%}h4{border-bottom:1px solid #e6e6e6;padding:10px 0;margin:20px 0;color:#e6e6e6}.list-group .list-group-item{background-color:#3e3e3e;border-color:black}.list-group.list-group-big .list-group-item{padding:25px}.list-group a.list-group-item{color:#7fc77f}.list-group a.list-group-item:hover{background-color:#313131;color:#4cae4c}.well{background-color:#242424;border-color:black;color:#bebebe}.well strong{color:#e6e6e6}.well code{background-color:#313131}.well hr{border-color:#3c8b3c}.well h3{margin:5px 0 15px 0;border:0;padding:0}.well a{color:#4cae4c}.well a.btn{color:white}.well small{display:block;padding:0 10px;font-style:italic}.well.example{padding-top:40px;margin-bottom:130px}.well.example pre{margin:50px;margin-bottom:30px;font-size:1.5em}.well.example .btn{margin-right:50px;margin-bottom:20px}.well.well-with-icon{min-height:136px}.well.well-with-icon .pull-right,.well.well-with-icon .pull-left{background-color:#4cae4c;color:#e6e6e6;padding:10px;border-radius:5px;margin:5px}.well.well-with-icon .pull-right{margin-left:20px}.well.well-with-icon .pull-left{margin-right:20px}a.well{display:block}a.well:hover{text-decoration:none;opacity:0.8}.info, .warning{margin:10px;padding:10px;background-color:#3e3e3e;color:#e6e6e6}.info code, .warning code{background-color:#313131}.info{border-left:10px #4cae4c solid}.warning{border-left:10px #ae4c4c solid}.with-icon{padding:30px}.with-icon .pull-left{padding-right:30px}.with-icon .pull-right{padding-left:30px}dd{margin-left:20px}code{background-color:#242424;color:#7fc77f;display:inline-block;margin:5px}.table{margin:20px 0;border-radius:4px}.table th,.table td,.table tr{border:1px solid #171717}.table tr th{background-color:#3e3e3e;border-bottom:2px solid #e6e6e6}.table tr:nth-child(odd){background-color:#242424}#sidebar-wrapper, .navbar{background-color:#171717;overflow-x:hidden}#sidebar-wrapper .sidebar-brand img,#sidebar-wrapper .navbar-brand img, .navbar .sidebar-brand img, .navbar .navbar-brand img{opacity:0.6;margin-right:8px}#sidebar-wrapper .sidebar-brand:hover,#sidebar-wrapper .navbar-brand:hover, .navbar .sidebar-brand:hover, .navbar .navbar-brand:hover{color:#fff}#sidebar-wrapper .sidebar-brand:hover img,#sidebar-wrapper .navbar-brand:hover img, .navbar .sidebar-brand:hover img, .navbar .navbar-brand:hover img{opacity:1}#sidebar-wrapper .sidebar-nav li ul, .navbar .sidebar-nav li ul{list-style-type:none;padding:0}#sidebar-wrapper .sidebar-nav li ul li, .navbar .sidebar-nav li ul li{line-height:20px}#sidebar-wrapper .sidebar-nav li ul li a, .navbar .sidebar-nav li ul li a{padding-left:20px}.content-header{height:auto;background-color:#242424}.content-header h1{color:#e6e6e6;display:block;margin:0;margin-bottom:20px;line-height:normal;border-bottom:none}#download h4, #index h4{margin-top:180px}#download h4.first, #index h4.first{margin-top:20px}#download h4.first small, #index h4.first small{color:inherit;font-size:1em}#download .btn-download-wrapper, #index .btn-download-wrapper{text-align:center;margin:160px auto}#download .btn-download-wrapper .btn, #index .btn-download-wrapper .btn{font-size:3em;padding:3%;display:inline-block;margin-bottom:5px}#download .btn-download-wrapper small, #index .btn-download-wrapper small{display:block;font-size:0.4em}#download h2.description, #index h2.description{color:#e6e6e6;font-size:2em;font-weight:bold;margin:120px 50px;line-height:2em}#download h2.description .label, #index h2.description .label{font-size:0.5em}#download .btn-download-wrapper{margin:40px auto}#download .os-selector{text-align:center;color:#e6e6e6;margin:30px 0}#download .os-selector a.btn-build{color:#e6e6e6;display:block;padding:20px;border-radius:2px}#download .os-selector .btn-build[href="#build-linux"]{background-color:#e43}#download .os-selector .btn-build[href="#build-linux"]:hover{color:#e43;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-windows"]{background-color:#06a}#download .os-selector .btn-build[href="#build-windows"]:hover{color:#06a;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-mac"]{background-color:darkgrey}#download .os-selector .btn-build[href="#build-mac"]:hover{color:darkgrey;background-color:#e6e6e6}#download .os-selector .tab-content{margin-top:20px}#download .os-selector #build-linux h3{color:#e43}#download .os-selector #build-windows h3{color:#06a}#download .os-selector #build-mac h3{color:darkgrey}footer{background-color:#242424;border-top:1px #101010 solid;padding:20px 0%}footer a{display:block}footer img[alt="FFmpeg"]{width:50%;display:block;margin:auto}.example.user-good pre{color:#bfbfbf;border:1px solid #357735;border-left:10px solid #357735;background-color:#242424}.example.user-bad pre{color:#bfbfbf;border:1px solid #ae4c4c;border-left:10px solid #ae4c4c;background-color:#242424} diff --git a/doc/swscale-v2.txt b/doc/swscale-v2.txt new file mode 100644 index 0000000000..d14cb36eb7 --- /dev/null +++ b/doc/swscale-v2.txt @@ -0,0 +1,344 @@ +New swscale design to change everything (tm) +============================================ + +SwsGraph +-------- + +The entry point to the new architecture, SwsGraph is what coordinates +multiple "passes". These can include cascaded scaling passes, error diffusion +dithering, and so on. Or we could have separate passes for the vertical and +horizontal scaling. In between each SwsPass lies a fully allocated image buffer. +Graph passes may have different levels of threading, e.g. we can have a single +threaded error diffusion pass following a multi-threaded scaling pass. + +SwsGraph is internally recreated whenever the image format, dimensions or +settings change in any way. sws_scale_frame() is itself just a light-weight +wrapper that runs ff_sws_graph_create() whenever the format changes, splits +interlaced images into separate fields, and calls ff_sws_graph_run() on each. + +From the point of view of SwsGraph itself, all inputs are progressive. + +SwsOp / SwsOpList +----------------- + +This is the newly introduced abstraction layer between the high-level format +handling logic and the low-level backing implementation. Each SwsOp is designed +to be as small and atomic as possible, with the possible exception of the +read / write operations due to their numerous variants. + +The basic idea is to split logic between three major components: + +1. The high-level format "business logic", which generates in a very + naive way a sequence of operations guaranteed to get you from point A + to point B. This logic is written with correctness in mind only, and + ignoring any performance concerns or low-level implementation decisions. + Semantically, everything is always decoded from the input format to + normalized (real valued) RGB, and then encoded back to output format. + + This code lives in libswscale/format.c + +2. The optimizer. This is where the "magic" happens, so to speak. The + optimizer's job is to take the abstract sequence of operations + produced by the high-level format analysis code and incrementally + optimize it. Each optimization step is designed to be minute and provably + lossless, or otherwise guarded behind the BITEXACT flag. This ensures that + the resulting output is always identical, no matter how many layers of + optimization we add. + + This code lives in libswscale/ops.c + +3. The compiler. Once we have a sequence of operations as output by the + optimizer, we "compile" this down to a callable function. This is then + applied by the dispatch wrapper by striping it over the input image. + + See libswscale/ops_backend.c for the reference backend, or + libswscale/x86/ops.c for a more complex SIMD example. + +This overall approach has a considerable number of benefits: + +1. It allows us to verify correctness of logic and spot semantic errors at a + very high level, by simply looking at the sequence of operations (available + by default at debug / verbose log level), without having to dig through the + multiple levels of complicated, interwoven format handling code that is + legacy swscale. + +2. Because most of the brains lives inside the the powerful optimizer, we get + fast paths "for free" for any suitable format conversion, rather than having + to enumerate them one by one. SIMD code itself can be written in a very + general way and does need to be tied to specific pixel formats - subsequent + low-level implementations can be strung together without much overhead. + +3. We can in the future, with relative ease, compile these operations + down to SPIR-V (or even LLVM IR) and generate efficient GPU or + target-machine specific implementations. This also opens the window for + adding hardware frame support to libswscale, and even transparently using + GPU acceleration for CPU frames. + +4. Platform-specific SIMD can be reduced down to a comparatively small set of + optimized routines, while still providing 100% coverage for all possible + pixel formats and operations. (As of writing, the x86 example backend has + about 60 unique implementations, of which 20 are trivial swizzles, 10 are + read/write ops, 10 are pixel type conversions and the remaining 20 are the + various logic/arithmetic ops). + +5. Backends hide behind a layer of abstraction offering them a considerable + deal of flexibility in how they want to implement their operations. For + example, the x86 backend has a dedicated function for compiling compatible + operations down to a single in-place pshufb instruction. + + Platform specific low level data is self-contained within its own setup() + function and private data structure, eliminating all reads into SwsContext + or the possibility of conflicts between platforms. + +6. We can compute an exact reference result for each operation with fixed + precision (ff_sws_op_apply_q), and use that to e.g. measure the amount of + error introduced by dithering, or even catch bugs in the reference C + implementation. (In theory - currently checkasm just compares against C) + +Examples of SwsOp in action +--------------------------- + +For illustration, here is the sequence of operations currently generated by +my prototype, for a conversion from RGB24 to YUV444P: + +Unoptimized operation list: + [ u8 .... -> ....] SWS_OP_READ : 3 elem(s) packed >> 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_RSHIFT : >> 0 + [ u8 .... -> ....] SWS_OP_CLEAR : {_ _ _ 0} + [ u8 .... -> ....] SWS_OP_CONVERT : u8 -> f32 + [f32 .... -> ....] SWS_OP_LINEAR : diag3+alpha [[1/255 0 0 0 0] [0 1/255 0 0 0] [0 0 1/255 0 0] [0 0 0 1 1]] + [f32 .... -> ....] SWS_OP_LINEAR : matrix3 [[0.299000 0.587000 0.114000 0 0] [-0.168736 -0.331264 1/2 0 0] [1/2 -0.418688 -57/701 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_LINEAR : diag3+off3 [[219 0 0 0 16] [0 224 0 0 128] [0 0 224 0 128] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_DITHER : 16x16 matrix + [f32 .... -> ....] SWS_OP_MAX : {0 0 0 0} <= x + [f32 .... -> ....] SWS_OP_MIN : x <= {255 255 255 _} + [f32 .... -> ....] SWS_OP_CONVERT : f32 -> u8 + [ u8 .... -> ....] SWS_OP_LSHIFT : << 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_WRITE : 3 elem(s) planar >> 0 + +This is optimized into the following sequence: + +Optimized operation list: + [ u8 XXXX -> +++X] SWS_OP_READ : 3 elem(s) packed >> 0 + [ u8 ...X -> +++X] SWS_OP_CONVERT : u8 -> f32 + [f32 ...X -> ...X] SWS_OP_LINEAR : matrix3+off3 [[0.256788 0.504129 0.097906 0 16] [-0.148223 -0.290993 112/255 0 128] [112/255 -0.367788 -0.071427 0 128] [0 0 0 1 0]] + [f32 ...X -> ...X] SWS_OP_DITHER : 16x16 matrix + [f32 ...X -> +++X] SWS_OP_CONVERT : f32 -> u8 + [ u8 ...X -> +++X] SWS_OP_WRITE : 3 elem(s) planar >> 0 + (X = unused, + = exact, 0 = zero) + +The extra metadata on the left of the operation list is just a dump of the +internal state used by the optimizer during optimization. It keeps track of +knowledge about the pixel values, such as their value range, whether or not +they're exact integers, and so on. + +In this example, you can see that the input values are exact (except for +the alpha channel, which is undefined), until the first SWS_OP_LINEAR +multiplies them by a noninteger constant. They regain their exact integer +status only after the (truncating) conversion to U8 in the output step. + +Example of more aggressive optimization +--------------------------------------- + +Conversion pass for gray -> rgb48: +Unoptimized operation list: + [ u8 .... -> ....] SWS_OP_READ : 1 elem(s) planar >> 0 + [ u8 .... -> ....] SWS_OP_SWIZZLE : 0123 + [ u8 .... -> ....] SWS_OP_RSHIFT : >> 0 + [ u8 .... -> ....] SWS_OP_CLEAR : {_ 0 0 0} + [ u8 .... -> ....] SWS_OP_CONVERT : u8 -> f32 + [f32 .... -> ....] SWS_OP_LINEAR : luma+alpha [[1/255 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 1]] + [f32 .... -> ....] SWS_OP_LINEAR : matrix3 [[1 0 701/500 0 0] [1 -0.344136 -0.714136 0 0] [1 443/250 0 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_LINEAR : diag3 [[65535 0 0 0 0] [0 65535 0 0 0] [0 0 65535 0 0] [0 0 0 1 0]] + [f32 .... -> ....] SWS_OP_MAX : {0 0 0 0} <= x + [f32 .... -> ....] SWS_OP_MIN : x <= {65535 65535 65535 _} + [f32 .... -> ....] SWS_OP_CONVERT : f32 -> u16 + [u16 .... -> ....] SWS_OP_LSHIFT : << 0 + [u16 .... -> ....] SWS_OP_SWIZZLE : 0123 + [u16 .... -> ....] SWS_OP_WRITE : 3 elem(s) packed >> 0 + +Optimized operation list: + [ u8 XXXX -> +XXX] SWS_OP_READ : 1 elem(s) planar >> 0 + [ u8 .XXX -> +XXX] SWS_OP_CONVERT : u8 -> u16 (expand) + [u16 .XXX -> +++X] SWS_OP_SWIZZLE : 0003 + [u16 ...X -> +++X] SWS_OP_WRITE : 3 elem(s) packed >> 0 + (X = unused, + = exact, 0 = zero) + +Here, the optimizer has managed to eliminate all of the unnecessary linear +operations on previously zero'd values, turn the resulting column matrix into +a swizzle operation, avoid the unnecessary dither (and round trip via float) +because the pixel values are guaranteed to be bit exact, and finally, turns +the multiplication by 65535 / 255 = 257 into a simple integer expand operation. + +As a final bonus, the x86 backend further optimizes this into a 12-byte shuffle: + pshufb = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1} + +time=208 us, ref=4212 us, speedup=20.236x faster (single thread) +time=57 us, ref=472 us, speedup=8.160x faster (multi thread) + +Compiler and underlying implementation layer (SwsOpChain) +--------------------------------------------------------- + +While the backend API is flexible enough to permit more exotic implementations +(e.g. using JIT code generation), we establish a common set of helpers for use +in "traditional" SIMD implementations. + +The basic idea is to have one "kernel" (or implementation) per operation, +and then just chain a list of these kernels together as separate function +calls. For best performance, we want to keep data in vector registers in +between function calls using a custom calling convention, thus avoiding any +unnecessary memory accesses. Additionally, we want the per-kernel overhead to +be as low as possible, with each kernel ideally just jumping directly into +the next kernel. + +As a result, we arrive at a design where we first divide the image into small +chunks, or "blocks", and then dispatch the "chain" of kernels on each chunk in +sequence. Each kernel processes a fixed number of pixels, with the overall +entry point taking care of looping. Remaining pixels (the "tail") are handled +generically by the backend-invariant dispatch code (located in ops.c), using a +partial memcpy into a suitably sized temporary buffer. + +To minimize the per-kernel function call overhead, we use a "continuation +passing style" for chaining kernels. Each operation computes its result and +then directly calls the next operation in the sequence, with the appropriate +internal function signature. + +The C reference backend reads data into the stack and then passes the array +pointers to the next continuation as regular function arguments: + + void process(GlobalContext *ctx, OpContext *op, + block_t x, block_t y, block_t z, block_t w) + { + for (int i = 0; i < SWS_BLOCK_SIZE; i++) + // do something with x[i], y[i], z[i], w[i] + + op->next(ctx, &op[1], x, y, z, w); + } + +With type conversions pushing the new data onto the stack as well: + + void convert8to16(GlobalContext *ctx, OpContext *op, + block_t x, block_t y, block_t z, block_t w) + { + /* Pseudo-code */ + u16block_t x16 = (u16block_t) x; + u16block_t y16 = (u16block_t) y; + u16block_t z16 = (u16block_t) z; + u16block_t w16 = (u16block_t) w; + + op->next(ctx, &op[1], x16, y16, z16, w16); + } + +By contrast, the x86 backend always keeps the X/Y/Z/W values pinned in specific +vector registers (ymm0-ymm3 for the lower half, and ymm4-ymm7 for the second +half). + +Each kernel additionally has access to a 32 byte per-op context storing the +pointer to the next kernel plus 16 bytes of arbitrary private data. This is +used during construction of the function chain to place things like small +constants. + +In assembly, the per-kernel overhead looks like this: + + load $tmp, $arg1 + ... + add $arg1, 32 + jump $tmp + +This design gives vastly better performance than the alternative of returning +out to a central loop or "trampoline". This is partly because the order of +kernels within a chain is always the same, so the branch predictor can easily +remember the target address of each "jump" instruction. + +The only way to realistically improve on this design would be to directly +stitch the kernel body together using runtime code generation. + +Future considerations and limitations +------------------------------------- + +My current prototype has a number of severe limitations and opportunities +for improvements: + +1. It does not handle scaling at all. I am not yet entirely sure on how I want + to handle scaling; this includes handling of subsampled content. I have a + number of vague ideas in my head, but nothing where I can say with certainty + that it will work out well. + + It's possible that we won't come up with a perfect solution here, and will + need to decide on which set of compromises we are comfortable accepting: + + 1. Do we need the ability to scale YUV -> YUV by handling luma and chroma + independently? When downscaling 100x100 4:2:0 to 50x50 4:4:4, should we + support the option of reusing the chroma plane directly (even though + this would introduce a subpixel shift for typical chroma siting)? + + Looking towards zimg, I am also thinking that we probably also want to do + scaling on floating point values, since this is best for both performance + and accuracy, especially given that we need to go up to 32-bit intermediates + during scaling anyway. + + So far, the most promising approach seems to be to handle subsampled + input/output as a dedicated read/write operation type; perhaps even with a + fixed/static subsampling kernel. To avoid compromising on performance when + chroma resampling is not necessary, the optimizer could then relax the + pipeline to use non-interpolating read/writes when all intermediate + operations are component-independent. + +2. Since each operation is conceptually defined on 4-component pixels, we end + up defining a lot of variants of each implementation for each possible + *subset*. For example, we have four different implementations for + SWS_OP_SCALE in my current templates: + - op_scale_1000 + - op_scale_1001 + - op_scale_1110 + - op_scale_1111 + + This reflects the four different arrangements of pixel components that are + typically present (or absent). While best for performance, it does turn into + a bit of a chore when implementing these kernels. + + The only real alternative would be to either branch inside the kernel (bad), + or to use separate kernels for each individual component and chain them all + together. I have not yet tested whether the latter approach would be faster + after the latest round of refactors to the kernel glue code. + +3. I do not yet have any support for LUTs. But when I add them, something we + could do is have the optimized pass automatically "promote" a sequence of + operations to LUTs. For example, any sequence that looks like: + + 1. [u8] SWS_OP_CONVERT -> X + 2. [X] ... // only per-component operations + 4. [X] SWS_OP_CONVERT -> Y + 3. [Y] SWS_OP_WRITE + + could be replaced by a LUT with 256 entries. This is especially important + for anything involving packed 8-bit input (e.g. rgb8, rgb4_byte). + + We also definitely want to hook this up to the existing CMS code for + transformations between different primaries. + +4. Because we rely on AVRational math to generate the coefficients for + operations, we need to be able to represent all pixel values as an + AVRational. However, this presents a challenge for 32-bit formats (e.g. + GRAY32, RGBA128), because their size exceeds INT_MAX, which is the maximum + value representable by an AVRational. + + It's possible we may want to introduce an AVRational64 for this, or + perhaps more flexibly, extend AVRational to an AVFloating type which is + represented as { AVRational n; int exp; }, representing n/d * 2^exp. This + would preserve our ability to represent all pixel values exactly, while + opening up the range arbitrarily. + +5. Is there ever a situation where the use of floats introduces the risk of + non bit-exact output? For this reason, and possible performance advantages, + we may want to explore the use of a fixed-point 16 bit path as an alternative + to the floating point math. + + So far, I have managed to avoid any bit exactness issues inside the x86 + backend by ensuring that the order of linear operations is identical + between the C backend and the x86 backend, but this may not be practical + to guarantee on all backends. The x86 float code is also dramatically + faster than the old fixed point code, so I'm tentatively optimistic about + the lack of a need for a fixed point path. diff --git a/doc/t2h.pm b/doc/t2h.pm index b7485e1f1e..4875d66305 100644 --- a/doc/t2h.pm +++ b/doc/t2h.pm @@ -54,12 +54,24 @@ sub get_formatting_function($$) { } # determine texinfo version -my $program_version_num = version->declare(ff_get_conf('PACKAGE_VERSION'))->numify; +my $package_version = ff_get_conf('PACKAGE_VERSION'); +$package_version =~ s/\+dev$//; +my $program_version_num = version->declare($package_version)->numify; my $program_version_6_8 = $program_version_num >= 6.008000; # no navigation elements ff_set_from_init_file('HEADERS', 0); +my %sectioning_commands = %Texinfo::Common::sectioning_commands; +if (scalar(keys(%sectioning_commands)) == 0) { + %sectioning_commands = %Texinfo::Commands::sectioning_heading_commands; +} + +my %root_commands = %Texinfo::Common::root_commands; +if (scalar(keys(%root_commands)) == 0) { + %root_commands = %Texinfo::Commands::root_commands; +} + sub ffmpeg_heading_command($$$$$) { my $self = shift; @@ -77,6 +89,9 @@ sub ffmpeg_heading_command($$$$$) return $result; } + # no need to set it as the $element_id is output unconditionally + my $heading_id; + my $element_id = $self->command_id($command); $result .= "\n" if (defined($element_id) and $element_id ne ''); @@ -84,24 +99,40 @@ sub ffmpeg_heading_command($$$$$) print STDERR "Process $command " .Texinfo::Structuring::_print_root_command_texi($command)."\n" if ($self->get_conf('DEBUG')); - my $element; - if ($Texinfo::Common::root_commands{$command->{'cmdname'}} - and $command->{'parent'} - and $command->{'parent'}->{'type'} - and $command->{'parent'}->{'type'} eq 'element') { - $element = $command->{'parent'}; + my $output_unit; + if ($root_commands{$command->{'cmdname'}}) { + if ($command->{'associated_unit'}) { + $output_unit = $command->{'associated_unit'}; + } elsif ($command->{'structure'} + and $command->{'structure'}->{'associated_unit'}) { + $output_unit = $command->{'structure'}->{'associated_unit'}; + } elsif ($command->{'parent'} + and $command->{'parent'}->{'type'} + and $command->{'parent'}->{'type'} eq 'element') { + $output_unit = $command->{'parent'}; + } } - if ($element) { + + if ($output_unit) { $result .= &{get_formatting_function($self, 'format_element_header')}($self, $cmdname, - $command, $element); + $command, $output_unit); } my $heading_level; # node is used as heading if there is nothing else. if ($cmdname eq 'node') { - if (!$element or (!$element->{'extra'}->{'section'} - and $element->{'extra'}->{'node'} - and $element->{'extra'}->{'node'} eq $command + if (!$output_unit or + (((!$output_unit->{'extra'}->{'section'} + and $output_unit->{'extra'}->{'node'} + and $output_unit->{'extra'}->{'node'} eq $command) + or + ((($output_unit->{'extra'}->{'unit_command'} + and $output_unit->{'extra'}->{'unit_command'} eq $command) + or + ($output_unit->{'unit_command'} + and $output_unit->{'unit_command'} eq $command)) + and $command->{'extra'} + and not $command->{'extra'}->{'associated_section'})) # bogus node may not have been normalized and defined($command->{'extra'}->{'normalized'}))) { if ($command->{'extra'}->{'normalized'} eq 'Top') { @@ -111,7 +142,15 @@ sub ffmpeg_heading_command($$$$$) } } } else { - $heading_level = $command->{'level'}; + if (defined($command->{'extra'}) + and defined($command->{'extra'}->{'section_level'})) { + $heading_level = $command->{'extra'}->{'section_level'}; + } elsif ($command->{'structure'} + and defined($command->{'structure'}->{'section_level'})) { + $heading_level = $command->{'structure'}->{'section_level'}; + } else { + $heading_level = $command->{'level'}; + } } my $heading = $self->command_text($command); @@ -119,8 +158,8 @@ sub ffmpeg_heading_command($$$$$) # if there is an error in the node. if (defined($heading) and $heading ne '' and defined($heading_level)) { - if ($Texinfo::Common::root_commands{$cmdname} - and $Texinfo::Common::sectioning_commands{$cmdname}) { + if ($root_commands{$cmdname} + and $sectioning_commands{$cmdname}) { my $content_href = $self->command_contents_href($command, 'contents', $self->{'current_filename'}); if ($content_href) { @@ -140,7 +179,13 @@ sub ffmpeg_heading_command($$$$$) } } - if ($self->in_preformatted()) { + my $in_preformatted; + if ($program_version_num >= 7.001090) { + $in_preformatted = $self->in_preformatted_context(); + } else { + $in_preformatted = $self->in_preformatted(); + } + if ($in_preformatted) { $result .= $heading."\n"; } else { # if the level was changed, set the command name right @@ -149,21 +194,25 @@ sub ffmpeg_heading_command($$$$$) $cmdname = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level]; } - # format_heading_text expects an array of headings for texinfo >= 7.0 if ($program_version_num >= 7.000000) { - $heading = [$heading]; - } - $result .= &{get_formatting_function($self,'format_heading_text')}( + $result .= &{get_formatting_function($self,'format_heading_text')}($self, + $cmdname, [$cmdname], $heading, + $heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1, + $heading_id, $command); + + } else { + $result .= &{get_formatting_function($self,'format_heading_text')}( $self, $cmdname, $heading, $heading_level + $self->get_conf('CHAPTER_HEADER_LEVEL') - 1, $command); + } } } $result .= $content if (defined($content)); return $result; } -foreach my $command (keys(%Texinfo::Common::sectioning_commands), 'node') { +foreach my $command (keys(%sectioning_commands), 'node') { texinfo_register_command_formatting($command, \&ffmpeg_heading_command); } @@ -188,28 +237,56 @@ sub ffmpeg_begin_file($$$) my $filename = shift; my $element = shift; - my $command; - if ($element and $self->get_conf('SPLIT')) { - $command = $self->element_command($element); + my ($element_command, $node_command, $command_for_title); + if ($element) { + if ($element->{'unit_command'}) { + $element_command = $element->{'unit_command'}; + } elsif ($self->can('tree_unit_element_command')) { + $element_command = $self->tree_unit_element_command($element); + } elsif ($self->can('tree_unit_element_command')) { + $element_command = $self->element_command($element); + } + + $node_command = $element_command; + if ($element_command and $element_command->{'cmdname'} + and $element_command->{'cmdname'} ne 'node' + and $element_command->{'extra'} + and $element_command->{'extra'}->{'associated_node'}) { + $node_command = $element_command->{'extra'}->{'associated_node'}; + } + + $command_for_title = $element_command if ($self->get_conf('SPLIT')); } - my ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, - $extra_head, $program_and_version, $program_homepage, + my ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $body_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, $program, $generator); - if ($program_version_num >= 7.000000) { - ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, + if ($program_version_num >= 7.001090) { + ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $body_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, + $program, $generator) = $self->_file_header_information($command_for_title, + $filename); + } elsif ($program_version_num >= 7.000000) { + ($title, $description, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $copying_comment, $after_body_open, $extra_head, $program_and_version, $program_homepage, - $program, $generator) = $self->_file_header_information($command); + $program, $generator) = $self->_file_header_information($command_for_title, + $filename); } else { ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, - $extra_head, $program_and_version, $program_homepage, - $program, $generator) = $self->_file_header_informations($command); + $doctype, $root_html_element_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, + $program, $generator) = $self->_file_header_informations($command_for_title); } - my $links = $self->_get_links ($filename, $element); + my $links; + if ($program_version_num >= 7.000000) { + $links = $self->_get_links($filename, $element, $node_command); + } else { + $links = $self->_get_links ($filename, $element); + } my $head1 = $ENV{"FFMPEG_HEADER1"} || < @@ -252,13 +329,25 @@ sub ffmpeg_program_string($) if (defined($self->get_conf('PROGRAM')) and $self->get_conf('PROGRAM') ne '' and defined($self->get_conf('PACKAGE_URL'))) { - return $self->convert_tree( + if ($program_version_num >= 7.001090) { + return $self->convert_tree( + $self->cdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.', + { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')}, + 'program' => {'text' => $self->get_conf('PROGRAM') }})); + } else { + return $self->convert_tree( $self->gdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.', - { 'program_homepage' => $self->get_conf('PACKAGE_URL'), - 'program' => $self->get_conf('PROGRAM') })); + { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')}, + 'program' => {'text' => $self->get_conf('PROGRAM') }})); + } } else { - return $self->convert_tree( - $self->gdt('This document was generated automatically.')); + if ($program_version_num >= 7.001090) { + return $self->convert_tree( + $self->cdt('This document was generated automatically.')); + } else { + return $self->convert_tree( + $self->gdt('This document was generated automatically.')); + } } } if ($program_version_6_8) { diff --git a/doc/texi2pod.pl b/doc/texi2pod.pl old mode 100644 new mode 100755 diff --git a/doc/texidep.pl b/doc/texidep.pl old mode 100644 new mode 100755 diff --git a/doc/undefined.txt b/doc/undefined.txt index e01299bef1..faf8816c66 100644 --- a/doc/undefined.txt +++ b/doc/undefined.txt @@ -44,4 +44,3 @@ a+b*c; here the reader knows that a,b,c are meant to be signed integers but for C standard compliance / to avoid undefined behavior they are stored in unsigned ints. - diff --git a/doc/utils.texi b/doc/utils.texi index 9968725d2a..9c50dac949 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -731,8 +731,12 @@ FL+FR+FC+LFE+BL+BR+SL+SR+TFL+TFR+TBL+TBR FL+FR+FC+LFE+BL+BR+SL+SR+TFL+TFR+TBC+LFE2 @item 9.1.4 FL+FR+FC+LFE+BL+BR+FLC+FRC+SL+SR+TFL+TFR+TBL+TBR +@item 9.1.6 +FL+FR+FC+LFE+BL+BR+FLC+FRC+SL+SR+TFL+TFR+TBL+TBR+TSL+TSR @item hexadecagonal FL+FR+FC+BL+BR+BC+SL+SR+WL+WR+TBL+TBR+TBC+TFC+TFL+TFR +@item binaural +BIL+BIR @item downmix DL+DR @item 22.2 diff --git a/ffbuild/arch.mak b/ffbuild/arch.mak index 3fc40e5e5d..197e30bb89 100644 --- a/ffbuild/arch.mak +++ b/ffbuild/arch.mak @@ -3,6 +3,8 @@ OBJS-$(HAVE_ARMV6) += $(ARMV6-OBJS) $(ARMV6-OBJS-yes) OBJS-$(HAVE_ARMV8) += $(ARMV8-OBJS) $(ARMV8-OBJS-yes) OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes) OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes) +OBJS-$(HAVE_SVE) += $(SVE-OBJS) $(SVE-OBJS-yes) +OBJS-$(HAVE_SVE2) += $(SVE2-OBJS) $(SVE2-OBJS-yes) OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes) OBJS-$(HAVE_MIPSDSP) += $(MIPSDSP-OBJS) $(MIPSDSP-OBJS-yes) @@ -19,5 +21,7 @@ OBJS-$(HAVE_RV) += $(RV-OBJS) $(RV-OBJS-yes) OBJS-$(HAVE_RVV) += $(RVV-OBJS) $(RVV-OBJS-yes) OBJS-$(HAVE_RV_ZVBB) += $(RVVB-OBJS) $(RVVB-OBJS-yes) +OBJS-$(HAVE_SIMD128) += $(SIMD128-OBJS) $(SIMD128-OBJS-yes) + OBJS-$(HAVE_MMX) += $(MMX-OBJS) $(MMX-OBJS-yes) OBJS-$(HAVE_X86ASM) += $(X86ASM-OBJS) $(X86ASM-OBJS-yes) diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index dfeedd7669..91f2d81e5b 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -38,8 +38,10 @@ int main(int argc, char **argv) return -1; output = fopen(argv[2], "wb"); - if (!output) + if (!output) { + fclose(input); return -1; + } if (argc == 4) { name = argv[3]; @@ -67,8 +69,10 @@ int main(int argc, char **argv) fclose(output); - if (ferror(input) || !feof(input)) + if (ferror(input) || !feof(input)) { + fclose(input); return -1; + } fclose(input); diff --git a/ffbuild/common.mak b/ffbuild/common.mak index 87a3ffd2b0..0a60d01623 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -18,7 +18,7 @@ BIN2C = $(BIN2CEXE) ifndef V Q = @ ECHO = printf "$(1)\t%s\n" $(2) -BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD STRIP CP WINDRES NVCC BIN2C +BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD STRIP CP WINDRES NVCC BIN2C METALCC METALLIB SILENT = DEPCC DEPHOSTCC DEPAS DEPX86ASM RANLIB RM MSG = $@ @@ -115,6 +115,12 @@ COMPILE_LASX = $(call COMPILE,CC,LASXFLAGS) $(BIN2CEXE): ffbuild/bin2c_host.o $(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS) +RUN_BIN2C = $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) +RUN_GZIP = $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@ +RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@ +%.gz: TAG = GZIP +%.min: TAG = MINIFY + %.metal.air: %.metal $(METALCC) $< -o $@ @@ -122,21 +128,46 @@ $(BIN2CEXE): ffbuild/bin2c_host.o $(METALLIB) --split-module-without-linking $< -o $@ %.metallib.c: %.metallib $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) %.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h $(COMPILE_NVCC) ifdef CONFIG_PTX_COMPRESSION -%.ptx.gz: TAG = GZIP %.ptx.gz: %.ptx - $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@ + $(RUN_GZIP) %.ptx.c: %.ptx.gz $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) else %.ptx.c: %.ptx $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) + $(RUN_BIN2C) +endif + +%.css.min: %.css + $(RUN_MINIFY) + +ifdef CONFIG_RESOURCE_COMPRESSION + +%.css.min.gz: %.css.min + $(RUN_GZIP) + +%.css.c: %.css.min.gz $(BIN2CEXE) + $(RUN_BIN2C) + +%.html.gz: %.html + $(RUN_GZIP) + +%.html.c: %.html.gz $(BIN2CEXE) + $(RUN_BIN2C) + +else # NO COMPRESSION + +%.css.c: %.css.min $(BIN2CEXE) + $(RUN_BIN2C) + +%.html.c: %.html $(BIN2CEXE) + $(RUN_BIN2C) endif clean:: @@ -159,7 +190,6 @@ endif include $(SRC_PATH)/ffbuild/arch.mak OBJS += $(OBJS-yes) -SLIBOBJS += $(SLIBOBJS-yes) SHLIBOBJS += $(SHLIBOBJS-yes) STLIBOBJS += $(STLIBOBJS-yes) FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS) @@ -169,7 +199,6 @@ LDLIBS = $(FFLIBS:%=%$(BUILDSUF)) FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=EXTRALIBS-%),$($(lib))) $(EXTRALIBS) OBJS := $(sort $(OBJS:%=$(SUBDIR)%)) -SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%)) SHLIBOBJS := $(sort $(SHLIBOBJS:%=$(SUBDIR)%)) STLIBOBJS := $(sort $(STLIBOBJS:%=$(SUBDIR)%)) TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o) @@ -194,7 +223,6 @@ PTXOBJS = $(filter %.ptx.o,$(OBJS)) $(HOBJS): CCFLAGS += $(CFLAGS_HEADERS) checkheaders: $(HOBJS) .SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=) - alltools: $(TOOLS) $(HOSTOBJS): %.o: %.c @@ -206,15 +234,14 @@ $(HOSTPROGS): %$(HOSTEXESUF): %.o $(OBJS): | $(sort $(dir $(OBJS))) $(HOBJS): | $(sort $(dir $(HOBJS))) $(HOSTOBJS): | $(sort $(dir $(HOSTOBJS))) -$(SLIBOBJS): | $(sort $(dir $(SLIBOBJS))) $(SHLIBOBJS): | $(sort $(dir $(SHLIBOBJS))) $(STLIBOBJS): | $(sort $(dir $(STLIBOBJS))) $(TESTOBJS): | $(sort $(dir $(TESTOBJS))) $(TOOLOBJS): | tools -OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS)) +OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS)) -CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.pc *.ptx *.ptx.gz *.ptx.c *.ver *.version *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb +CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a define RULES @@ -224,4 +251,4 @@ endef $(eval $(RULES)) --include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d) +-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d) diff --git a/ffbuild/library.mak b/ffbuild/library.mak index 793e9d41fa..dee05c5acd 100644 --- a/ffbuild/library.mak +++ b/ffbuild/library.mak @@ -26,7 +26,7 @@ ifdef CONFIG_SHARED # for purely shared builds. # Test programs are always statically linked against their library # to be able to access their library's internals, even with shared builds. -# Yet linking against dependend libraries still uses dynamic linking. +# Yet linking against dependent libraries still uses dynamic linking. # This means that we are in the scenario described above. # In case only static libs are used, the linker will only use # one of these copies; this depends on the duplicated object files @@ -35,8 +35,14 @@ OBJS += $(SHLIBOBJS) endif $(SUBDIR)$(LIBNAME): $(OBJS) $(STLIBOBJS) $(RM) $@ +ifeq ($(RESPONSE_FILES),yes) + $(Q)echo $^ > $@.objs + $(AR) $(ARFLAGS) $(AR_O) @$@.objs +else $(AR) $(ARFLAGS) $(AR_O) $^ +endif $(RANLIB) $@ + -$(RM) $@.objs install-headers: install-lib$(NAME)-headers install-lib$(NAME)-pkgconfig @@ -64,10 +70,16 @@ $(SUBDIR)lib$(NAME).ver: $(SUBDIR)lib$(NAME).v $(OBJS) $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR) $(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME) -$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver +$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SUBDIR)lib$(NAME).ver $(SLIB_CREATE_DEF_CMD) +ifeq ($(RESPONSE_FILES),yes) + $(Q)echo $$(filter %.o,$$^) > $$@.objs + $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) @$$@.objs $(FFEXTRALIBS) +else $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) +endif $(SLIB_EXTRA_CMD) + -$(RM) $$@.objs ifdef SUBDIR $(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(DEP_LIBS) diff --git a/ffbuild/pkgconfig_generate.sh b/ffbuild/pkgconfig_generate.sh index e5de6716d2..fc6af774a6 100755 --- a/ffbuild/pkgconfig_generate.sh +++ b/ffbuild/pkgconfig_generate.sh @@ -50,7 +50,7 @@ includedir=${source_path} prefix= exec_prefix= libdir=\${pcfiledir}/../../../$name -includedir=${source_path} +includedir=${includedir} Name: $fullname Description: $comment diff --git a/fftools/Makefile b/fftools/Makefile index 083a1368ce..bdb44fc5ce 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -9,6 +9,8 @@ AVBASENAMES = ffmpeg ffplay ffprobe ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF)) ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF)) +include $(SRC_PATH)/fftools/resources/Makefile + OBJS-ffmpeg += \ fftools/ffmpeg_dec.o \ fftools/ffmpeg_demux.o \ @@ -19,9 +21,35 @@ OBJS-ffmpeg += \ fftools/ffmpeg_mux_init.o \ fftools/ffmpeg_opt.o \ fftools/ffmpeg_sched.o \ - fftools/objpool.o \ + fftools/graph/graphprint.o \ fftools/sync_queue.o \ fftools/thread_queue.o \ + fftools/textformat/avtextformat.o \ + fftools/textformat/tf_compact.o \ + fftools/textformat/tf_default.o \ + fftools/textformat/tf_flat.o \ + fftools/textformat/tf_ini.o \ + fftools/textformat/tf_json.o \ + fftools/textformat/tf_mermaid.o \ + fftools/textformat/tf_xml.o \ + fftools/textformat/tw_avio.o \ + fftools/textformat/tw_buffer.o \ + fftools/textformat/tw_stdout.o \ + $(OBJS-resman) \ + $(RESOBJS) \ + +OBJS-ffprobe += \ + fftools/textformat/avtextformat.o \ + fftools/textformat/tf_compact.o \ + fftools/textformat/tf_default.o \ + fftools/textformat/tf_flat.o \ + fftools/textformat/tf_ini.o \ + fftools/textformat/tf_json.o \ + fftools/textformat/tf_mermaid.o \ + fftools/textformat/tf_xml.o \ + fftools/textformat/tw_avio.o \ + fftools/textformat/tw_buffer.o \ + fftools/textformat/tw_stdout.o \ OBJS-ffplay += fftools/ffplay_renderer.o @@ -31,7 +59,7 @@ ifdef HAVE_GNU_WINDRES OBJS-$(1) += fftools/fftoolsres.o endif $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1)) -$$(OBJS-$(1)): | fftools +$$(OBJS-$(1)): | fftools fftools/textformat fftools/resources fftools/graph $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1)) $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1)) $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1)) @@ -44,6 +72,9 @@ all: $(AVPROGS) fftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools OUTDIRS += fftools +OUTDIRS += fftools/textformat +OUTDIRS += fftools/resources +OUTDIRS += fftools/graph ifdef AVPROGS install: install-progs install-data @@ -62,4 +93,4 @@ uninstall-progs: $(RM) $(addprefix "$(BINDIR)/", $(ALLAVPROGS)) clean:: - $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%) + $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%) $(CLEANSUFFIXES:%=fftools/graph/%) $(CLEANSUFFIXES:%=fftools/textformat/%) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 9beed94ead..dc093b0bd3 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -255,9 +255,10 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, if (*opt == '/') { opt++; - if (po->type == OPT_TYPE_BOOL) { + if (!opt_has_arg(po)) { av_log(NULL, AV_LOG_FATAL, - "Requested to load an argument from file for a bool option '%s'\n", + "Requested to load an argument from file for an option '%s'" + " which does not take an argument\n", po->name); return AVERROR(EINVAL); } @@ -352,9 +353,11 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, ret = po->u.func_arg(optctx, opt, arg); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, - "Failed to set value '%s' for option '%s': %s\n", - arg, opt, av_err2str(ret)); + if ((strcmp(opt, "init_hw_device") != 0) || (strcmp(arg, "list") != 0)) { + av_log(NULL, AV_LOG_ERROR, + "Failed to set value '%s' for option '%s': %s\n", + arg, opt, av_err2str(ret)); + } goto finish; } } @@ -492,8 +495,9 @@ int locate_option(int argc, char **argv, const OptionDef *options, for (i = 1; i < argc; i++) { const char *cur_opt = argv[i]; - if (*cur_opt++ != '-') + if (!(cur_opt[0] == '-' && cur_opt[1])) continue; + cur_opt++; po = find_option(options, cur_opt); if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o') @@ -551,11 +555,12 @@ static void check_options(const OptionDef *po) void parse_loglevel(int argc, char **argv, const OptionDef *options) { - int idx = locate_option(argc, argv, options, "loglevel"); + int idx; char *env; check_options(options); + idx = locate_option(argc, argv, options, "loglevel"); if (!idx) idx = locate_option(argc, argv, options, "v"); if (idx && argv[idx + 1]) @@ -1466,9 +1471,12 @@ void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems) { void *new_elem; - if (!(new_elem = av_mallocz(elem_size)) || - av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) + new_elem = av_mallocz(elem_size); + if (!new_elem) return NULL; + if (av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) + av_freep(&new_elem); + return new_elem; } diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 316b6a8c64..ad020f893a 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -319,7 +319,7 @@ typedef struct Option { } Option; typedef struct OptionGroupDef { - /**< group name */ + /** group name */ const char *name; /** * Option to be used as group separator. Can be NULL for groups which diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 420ba3c6e4..de607cac93 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -81,6 +81,7 @@ #include "ffmpeg.h" #include "ffmpeg_sched.h" #include "ffmpeg_utils.h" +#include "graph/graphprint.h" const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -308,6 +309,9 @@ const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; static void ffmpeg_cleanup(int ret) { + if ((print_graphs || print_graphs_file) && nb_output_files > 0) + print_filtergraphs(filtergraphs, nb_filtergraphs, input_files, nb_input_files, output_files, nb_output_files); + if (do_benchmark) { int64_t maxrss = getmaxrss() / 1024; av_log(NULL, AV_LOG_INFO, "bench: maxrss=%"PRId64"KiB\n", maxrss); @@ -340,6 +344,9 @@ static void ffmpeg_cleanup(int ret) av_freep(&filter_nbthreads); + av_freep(&print_graphs_file); + av_freep(&print_graphs_format); + av_freep(&input_files); av_freep(&output_files); @@ -555,7 +562,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 first_report = 1; uint64_t nb_frames_dup = 0, nb_frames_drop = 0; - int mins, secs, us; + int mins, secs, ms, us; int64_t hours; const char *hours_sign; int ret; @@ -579,6 +586,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti vid = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC); + for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) { const float q = ost->enc ? atomic_load(&ost->quality) / (float) FF_QP2LAMBDA : -1; @@ -669,6 +677,15 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti av_bprintf(&buf_script, "speed=%4.3gx\n", speed); } + secs = (int)t; + ms = (int)((t - secs) * 1000); + mins = secs / 60; + secs %= 60; + hours = mins / 60; + mins %= 60; + + av_bprintf(&buf, " elapsed=%"PRId64":%02d:%02d.%02d", hours, mins, secs, ms / 10); + 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()) { @@ -728,7 +745,7 @@ static void print_stream_maps(void) av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index); av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file->index, - ost->index, ost->enc_ctx->codec->name); + ost->index, ost->enc->enc_ctx->codec->name); continue; } @@ -737,9 +754,9 @@ static void print_stream_maps(void) ost->ist->index, ost->file->index, ost->index); - if (ost->enc_ctx) { + if (ost->enc) { const AVCodec *in_codec = ost->ist->dec; - const AVCodec *out_codec = ost->enc_ctx->codec; + const AVCodec *out_codec = ost->enc->enc_ctx->codec; const char *decoder_name = "?"; const char *in_codec_name = "?"; const char *encoder_name = "?"; @@ -1012,5 +1029,8 @@ finish: sch_free(&sch); + av_log(NULL, AV_LOG_VERBOSE, "\n"); + av_log(NULL, AV_LOG_VERBOSE, "Exiting with exit code %d\n", ret); + return ret; } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 733d551fa4..53f71bc080 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -39,6 +39,7 @@ #include "libavfilter/avfilter.h" #include "libavutil/avutil.h" +#include "libavutil/bprint.h" #include "libavutil/dict.h" #include "libavutil/eval.h" #include "libavutil/fifo.h" @@ -163,6 +164,7 @@ typedef struct OptionsContext { int loop; int rate_emu; float readrate; + float readrate_catchup; double readrate_initial_burst; int accurate_seek; int thread_queue_size; @@ -231,6 +233,7 @@ typedef struct OptionsContext { SpecifierOptList filter_scripts; #endif SpecifierOptList reinit_filters; + SpecifierOptList drop_changed; SpecifierOptList fix_sub_duration; SpecifierOptList fix_sub_duration_heartbeat; SpecifierOptList canvas_sizes; @@ -261,6 +264,7 @@ enum IFilterFlags { IFILTER_FLAG_REINIT = (1 << 1), IFILTER_FLAG_CFR = (1 << 2), IFILTER_FLAG_CROP = (1 << 3), + IFILTER_FLAG_DROPCHANGED = (1 << 4), }; typedef struct InputFilterOptions { @@ -316,7 +320,7 @@ typedef struct OutputFilterOptions { AVDictionary *sws_opts; AVDictionary *swr_opts; - const char *nb_threads; + int64_t nb_threads; // A combination of OFilterFlags. unsigned flags; @@ -328,6 +332,8 @@ typedef struct OutputFilterOptions { enum AVColorRange color_range; enum VideoSyncMethod vsync_method; + AVRational frame_rate; + AVRational max_frame_rate; int sample_rate; AVChannelLayout ch_layout; @@ -347,6 +353,18 @@ typedef struct OutputFilterOptions { typedef struct InputFilter { struct FilterGraph *graph; uint8_t *name; + int index; + + // filter data type + enum AVMediaType type; + + AVFilterContext *filter; + + char *input_name; + + /* for filters that are not yet bound to an input stream, + * this stores the input linklabel, if any */ + uint8_t *linklabel; } InputFilter; typedef struct OutputFilter { @@ -354,6 +372,11 @@ typedef struct OutputFilter { struct FilterGraph *graph; uint8_t *name; + int index; + + AVFilterContext *filter; + + char *output_name; /* for filters that are not yet bound to an output stream, * this stores the output linklabel, if any */ @@ -376,6 +399,9 @@ typedef struct FilterGraph { int nb_inputs; OutputFilter **outputs; int nb_outputs; + + const char *graph_desc; + struct AVBPrint graph_print_buf; } FilterGraph; enum DecoderFlags { @@ -461,14 +487,6 @@ typedef struct InputStream { * currently video and audio only */ InputFilter **filters; int nb_filters; - - /* - * Output targets that do not go through lavfi, i.e. subtitles or - * streamcopy. Those two cases are distinguished by the OutputStream - * having an encoder or not. - */ - struct OutputStream **outputs; - int nb_outputs; } InputStream; typedef struct InputFile { @@ -545,13 +563,6 @@ typedef struct EncStats { int lock_initialized; } EncStats; -extern const char *const forced_keyframes_const_names[]; - -typedef enum { - ENCODER_FINISHED = 1, - MUXER_FINISHED = 2, -} OSTFinished ; - enum { KF_FORCE_SOURCE = 1, #if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP @@ -575,7 +586,15 @@ typedef struct KeyframeForceCtx { int dropped_keyframe; } KeyframeForceCtx; -typedef struct Encoder Encoder; +typedef struct Encoder { + const AVClass *class; + + AVCodecContext *enc_ctx; + + // number of frames/samples sent to the encoder + uint64_t frames_encoded; + uint64_t samples_encoded; +} Encoder; enum CroppingType { CROP_DISABLED = 0, @@ -594,12 +613,6 @@ typedef struct OutputStream { int index; /* stream index in the output file */ - /** - * Codec parameters for packets submitted to the muxer (i.e. before - * bitstream filtering, if any). - */ - AVCodecParameters *par_in; - /* input stream that is the source for this output stream; * may be NULL for streams with no well-defined source, e.g. * attachments or outputs from complex filtergraphs */ @@ -608,12 +621,8 @@ typedef struct OutputStream { AVStream *st; /* stream in the output file */ Encoder *enc; - AVCodecContext *enc_ctx; /* video only */ - AVRational frame_rate; - AVRational max_frame_rate; - int force_fps; #if FFMPEG_OPT_TOP int top_field_first; #endif @@ -636,9 +645,6 @@ typedef struct OutputStream { /* stats */ // number of packets send to the muxer atomic_uint_least64_t packets_written; - // number of frames/samples sent to the encoder - uint64_t frames_encoded; - uint64_t samples_encoded; /* packet quality factor */ atomic_int quality; @@ -731,7 +737,11 @@ extern float max_error_rate; extern char *filter_nbthreads; extern int filter_complex_nbthreads; +extern int filter_buffered_frames; extern int vstats_version; +extern int print_graphs; +extern char *print_graphs_file; +extern char *print_graphs_format; extern int auto_conversion_filters; extern const AVIOInterruptCB int_cb; @@ -762,10 +772,11 @@ int find_codec(void *logctx, const char *name, int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global); int filtergraph_is_simple(const FilterGraph *fg); -int init_simple_filtergraph(InputStream *ist, OutputStream *ost, - char *graph_desc, - Scheduler *sch, unsigned sch_idx_enc, - const OutputFilterOptions *opts); +int fg_create_simple(FilterGraph **pfg, + InputStream *ist, + char *graph_desc, + Scheduler *sch, unsigned sched_idx_enc, + const OutputFilterOptions *opts); int fg_finalise_bindings(void); /** @@ -779,7 +790,7 @@ const FrameData *frame_data_c(AVFrame *frame); FrameData *packet_data (AVPacket *pkt); const FrameData *packet_data_c(AVPacket *pkt); -int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, +int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc, const OutputFilterOptions *opts); @@ -858,7 +869,7 @@ int dec_request_view(Decoder *dec, const ViewSpecifier *vs, SchedulerNode *src); int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx); + Scheduler *sch, unsigned sch_idx, void *log_parent); void enc_free(Encoder **penc); int enc_open(void *opaque, const AVFrame *frame); @@ -871,7 +882,8 @@ int enc_loopback(Encoder *enc); * * Open the muxer once all the streams have been initialized. */ -int of_stream_init(OutputFile *of, OutputStream *ost); +int of_stream_init(OutputFile *of, OutputStream *ost, + const AVCodecContext *enc_ctx); int of_write_trailer(OutputFile *of); int of_open(const OptionsContext *o, const char *filename, Scheduler *sch); void of_free(OutputFile **pof); @@ -883,7 +895,8 @@ int64_t of_filesize(OutputFile *of); int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch); void ifile_close(InputFile **f); -int ist_output_add(InputStream *ist, OutputStream *ost); +int ist_use(InputStream *ist, int decoding_needed, + const ViewSpecifier *vs, SchedulerNode *src); int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, const ViewSpecifier *vs, InputFilterOptions *opts, SchedulerNode *src); diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c index 2723a0312e..1d7158f995 100644 --- a/fftools/ffmpeg_dec.c +++ b/fftools/ffmpeg_dec.c @@ -733,13 +733,12 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame) av_log(dp, AV_LOG_ERROR, "Error submitting %s to decoder: %s\n", pkt ? "packet" : "EOF", av_err2str(ret)); - if (ret != AVERROR_EOF) { - dp->dec.decode_errors++; - if (!exit_on_error) - ret = 0; - } + if (ret == AVERROR_EOF) + return ret; - return ret; + dp->dec.decode_errors++; + if (exit_on_error) + return ret; } while (1) { @@ -1595,7 +1594,7 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, if (o->flags & DECODER_FLAG_BITEXACT) dp->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT; - // we apply cropping outselves + // we apply cropping ourselves dp->apply_cropping = dp->dec_ctx->apply_cropping; dp->dec_ctx->apply_cropping = 0; @@ -1638,6 +1637,11 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, param_out->color_range = dp->dec_ctx->color_range; } + av_frame_side_data_free(¶m_out->side_data, ¶m_out->nb_side_data); + ret = clone_side_data(¶m_out->side_data, ¶m_out->nb_side_data, + dp->dec_ctx->decoded_side_data, dp->dec_ctx->nb_decoded_side_data, 0); + if (ret < 0) + return ret; param_out->time_base = dp->dec_ctx->pkt_timebase; } diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index 13aef15eab..78d8ff6b7d 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -67,17 +67,18 @@ typedef struct DemuxStream { int reinit_filters; int autorotate; int apply_cropping; + int drop_changed; int wrap_correction_done; int saw_first_ts; - ///< dts of the first packet read for this stream (in AV_TIME_BASE units) + /// dts of the first packet read for this stream (in AV_TIME_BASE units) int64_t first_dts; /* predicted dts of the next packet read for this stream or (when there are * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */ int64_t next_dts; - ///< dts of the last packet read for this stream (in AV_TIME_BASE units) + /// dts of the last packet read for this stream (in AV_TIME_BASE units) int64_t dts; const AVCodecDescriptor *codec_desc; @@ -94,6 +95,12 @@ typedef struct DemuxStream { uint64_t nb_packets; // combined size of all the packets read uint64_t data_size; + // latest wallclock time at which packet reading resumed after a stall - used for readrate + int64_t resume_wc; + // timestamp of first packet sent after the latest stall - used for readrate + int64_t resume_pts; + // measure of how far behind packet reading is against spceified readrate + int64_t lag; } DemuxStream; typedef struct Demuxer { @@ -127,6 +134,7 @@ typedef struct Demuxer { float readrate; double readrate_initial_burst; + float readrate_catchup; Scheduler *sch; @@ -240,7 +248,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, } } else { if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) { - av_log(NULL, AV_LOG_WARNING, + av_log(ist, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt->dts, ds->next_dts, pkt->stream_index); pkt->dts = AV_NOPTS_VALUE; @@ -249,7 +257,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, int64_t pkt_pts = av_rescale_q(pkt->pts, pkt->time_base, AV_TIME_BASE_Q); delta = pkt_pts - ds->next_dts; if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) { - av_log(NULL, AV_LOG_WARNING, + av_log(ist, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt->pts, ds->next_dts, pkt->stream_index); pkt->pts = AV_NOPTS_VALUE; @@ -261,7 +269,7 @@ static void ts_discontinuity_detect(Demuxer *d, InputStream *ist, int64_t delta = pkt_dts - d->last_ts; if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE) { d->ts_offset_discont -= delta; - av_log(NULL, AV_LOG_DEBUG, + av_log(ist, AV_LOG_DEBUG, "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", delta, d->ts_offset_discont); pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, pkt->time_base); @@ -476,7 +484,7 @@ static int input_packet_process(Demuxer *d, AVPacket *pkt, unsigned *send_flags) fd->wallclock[LATENCY_PROBE_DEMUX] = av_gettime_relative(); if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n", + av_log(ist, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n", f->index, pkt->stream_index, av_get_media_type_string(ist->par->codec_type), av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &pkt->time_base), @@ -495,16 +503,42 @@ static void readrate_sleep(Demuxer *d) (f->start_time_effective != AV_NOPTS_VALUE ? f->start_time_effective * !start_at_zero : 0) + (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0) ); - int64_t burst_until = AV_TIME_BASE * d->readrate_initial_burst; + int64_t initial_burst = AV_TIME_BASE * d->readrate_initial_burst; + int resume_warn = 0; + for (int i = 0; i < f->nb_streams; i++) { InputStream *ist = f->streams[i]; DemuxStream *ds = ds_from_ist(ist); - int64_t stream_ts_offset, pts, now; + int64_t stream_ts_offset, pts, now, wc_elapsed, elapsed, lag, max_pts, limit_pts; + + if (ds->discard) continue; + stream_ts_offset = FFMAX(ds->first_dts != AV_NOPTS_VALUE ? ds->first_dts : 0, file_start); pts = av_rescale(ds->dts, 1000000, AV_TIME_BASE); - now = (av_gettime_relative() - d->wallclock_start) * d->readrate + stream_ts_offset; - if (pts - burst_until > now) - av_usleep(pts - burst_until - now); + now = av_gettime_relative(); + wc_elapsed = now - d->wallclock_start; + max_pts = stream_ts_offset + initial_burst + wc_elapsed * d->readrate; + lag = FFMAX(max_pts - pts, 0); + if ( (!ds->lag && lag > 0.3 * AV_TIME_BASE) || ( lag > ds->lag + 0.3 * AV_TIME_BASE) ) { + ds->lag = lag; + ds->resume_wc = now; + ds->resume_pts = pts; + av_log_once(ds, AV_LOG_WARNING, AV_LOG_DEBUG, &resume_warn, + "Resumed reading at pts %0.3f with rate %0.3f after a lag of %0.3fs\n", + (float)pts/AV_TIME_BASE, d->readrate_catchup, (float)lag/AV_TIME_BASE); + } + if (ds->lag && !lag) + ds->lag = ds->resume_wc = ds->resume_pts = 0; + if (ds->resume_wc) { + elapsed = now - ds->resume_wc; + limit_pts = ds->resume_pts + elapsed * d->readrate_catchup; + } else { + elapsed = wc_elapsed; + limit_pts = max_pts; + } + + if (pts > limit_pts) + av_usleep(pts - limit_pts); } } @@ -840,7 +874,6 @@ static void ist_free(InputStream **pist) av_dict_free(&ds->decoder_opts); av_freep(&ist->filters); - av_freep(&ist->outputs); av_freep(&ds->dec_opts.hwaccel_device); avcodec_parameters_free(&ist->par); @@ -874,8 +907,8 @@ void ifile_close(InputFile **pf) av_freep(pf); } -static int ist_use(InputStream *ist, int decoding_needed, - const ViewSpecifier *vs, SchedulerNode *src) +int ist_use(InputStream *ist, int decoding_needed, + const ViewSpecifier *vs, SchedulerNode *src) { Demuxer *d = demuxer_from_ifile(ist->file); DemuxStream *ds = ds_from_ist(ist); @@ -912,9 +945,18 @@ static int ist_use(InputStream *ist, int decoding_needed, if (decoding_needed && ds->sch_idx_dec < 0) { int is_audio = ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; + int is_unreliable = !!(d->f.ctx->iformat->flags & AVFMT_NOTIMESTAMPS); + int64_t use_wallclock_as_timestamps; + + ret = av_opt_get_int(d->f.ctx, "use_wallclock_as_timestamps", 0, &use_wallclock_as_timestamps); + if (ret < 0) + return ret; + + if (use_wallclock_as_timestamps) + is_unreliable = 0; ds->dec_opts.flags |= (!!ist->fix_sub_duration * DECODER_FLAG_FIX_SUB_DURATION) | - (!!(d->f.ctx->iformat->flags & AVFMT_NOTIMESTAMPS) * DECODER_FLAG_TS_UNRELIABLE) | + (!!is_unreliable * DECODER_FLAG_TS_UNRELIABLE) | (!!(d->loop && is_audio) * DECODER_FLAG_SEND_END_TS) #if FFMPEG_OPT_TOP | ((ist->top_field_first >= 0) * DECODER_FLAG_TOP_FIELD_FIRST) @@ -975,25 +1017,6 @@ static int ist_use(InputStream *ist, int decoding_needed, return 0; } -int ist_output_add(InputStream *ist, OutputStream *ost) -{ - DemuxStream *ds = ds_from_ist(ist); - SchedulerNode src; - int ret; - - ret = ist_use(ist, ost->enc ? DECODING_FOR_OST : 0, NULL, &src); - if (ret < 0) - return ret; - - ret = GROW_ARRAY(ist->outputs, ist->nb_outputs); - if (ret < 0) - return ret; - - ist->outputs[ist->nb_outputs - 1] = ost; - - return ost->enc ? ds->sch_idx_dec : ds->sch_idx_stream; -} - int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, const ViewSpecifier *vs, InputFilterOptions *opts, SchedulerNode *src) @@ -1086,7 +1109,8 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, return AVERROR(ENOMEM); opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ds->autorotate) | - IFILTER_FLAG_REINIT * !!(ds->reinit_filters); + IFILTER_FLAG_REINIT * !!(ds->reinit_filters) | + IFILTER_FLAG_DROPCHANGED* !!(ds->drop_changed); return 0; } @@ -1124,7 +1148,7 @@ static int choose_decoder(const OptionsContext *o, void *logctx, for (int j = 0; config = avcodec_get_hw_config(c, j); j++) { if (config->device_type == hwaccel_device_type) { - av_log(NULL, AV_LOG_VERBOSE, "Selecting decoder '%s' because of requested hwaccel method %s\n", + av_log(logctx, AV_LOG_VERBOSE, "Selecting decoder '%s' because of requested hwaccel method %s\n", c->name, av_hwdevice_get_type_name(hwaccel_device_type)); *pcodec = c; return 0; @@ -1397,6 +1421,17 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona ds->reinit_filters = -1; opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters); + ds->drop_changed = 0; + opt_match_per_stream_int(ist, &o->drop_changed, ic, st, &ds->drop_changed); + + if (ds->drop_changed && ds->reinit_filters) { + if (ds->reinit_filters > 0) { + av_log(ist, AV_LOG_ERROR, "drop_changed and reinit_filters both enabled. These are mutually exclusive.\n"); + return AVERROR(EINVAL); + } + ds->reinit_filters = 0; + } + ist->user_set_discard = AVDISCARD_NONE; if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || @@ -1746,8 +1781,9 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) /* open the input file with generic avformat function */ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts); if (err < 0) { - av_log(d, AV_LOG_ERROR, - "Error opening input: %s\n", av_err2str(err)); + if (err != AVERROR_EXIT) + av_log(d, AV_LOG_ERROR, + "Error opening input: %s\n", av_err2str(err)); if (err == AVERROR_PROTOCOL_NOT_FOUND) av_log(d, AV_LOG_ERROR, "Did you mean file:%s?\n", filename); return err; @@ -1878,9 +1914,22 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) d->readrate_initial_burst); return AVERROR(EINVAL); } - } else if (o->readrate_initial_burst) { - av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored " - "since neither -readrate nor -re were given\n"); + d->readrate_catchup = o->readrate_catchup ? o->readrate_catchup : d->readrate * 1.05; + if (d->readrate_catchup < d->readrate) { + av_log(d, AV_LOG_ERROR, + "Option -readrate_catchup is %0.3f; it must be at least equal to %0.3f.\n", + d->readrate_catchup, d->readrate); + return AVERROR(EINVAL); + } + } else { + if (o->readrate_initial_burst) { + av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored " + "since neither -readrate nor -re were given\n"); + } + if (o->readrate_catchup) { + av_log(d, AV_LOG_WARNING, "Option -readrate_catchup ignored " + "since neither -readrate nor -re were given\n"); + } } /* Add all the streams from the given input file to the demuxer */ diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index c1c8aa0e78..4568c15073 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -38,7 +38,12 @@ #include "libavcodec/avcodec.h" -struct Encoder { +typedef struct EncoderPriv { + Encoder e; + + void *log_parent; + char log_name[32]; + // combined size of all the packets received from the encoder uint64_t data_size; @@ -50,7 +55,12 @@ struct Encoder { Scheduler *sch; unsigned sch_idx; -}; +} EncoderPriv; + +static EncoderPriv *ep_from_enc(Encoder *enc) +{ + return (EncoderPriv*)enc; +} // data that is local to the decoder thread and not visible outside of it typedef struct EncoderThread { @@ -65,56 +75,90 @@ void enc_free(Encoder **penc) if (!enc) return; + if (enc->enc_ctx) + av_freep(&enc->enc_ctx->stats_in); + avcodec_free_context(&enc->enc_ctx); + av_freep(penc); } -int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx) +static const char *enc_item_name(void *obj) { - Encoder *enc; + const EncoderPriv *ep = obj; + + return ep->log_name; +} + +static const AVClass enc_class = { + .class_name = "Encoder", + .version = LIBAVUTIL_VERSION_INT, + .parent_log_context_offset = offsetof(EncoderPriv, log_parent), + .item_name = enc_item_name, +}; + +int enc_alloc(Encoder **penc, const AVCodec *codec, + Scheduler *sch, unsigned sch_idx, void *log_parent) +{ + EncoderPriv *ep; + int ret = 0; *penc = NULL; - enc = av_mallocz(sizeof(*enc)); - if (!enc) + ep = av_mallocz(sizeof(*ep)); + if (!ep) return AVERROR(ENOMEM); - enc->sch = sch; - enc->sch_idx = sch_idx; + ep->e.class = &enc_class; + ep->log_parent = log_parent; - *penc = enc; + ep->sch = sch; + ep->sch_idx = sch_idx; + + snprintf(ep->log_name, sizeof(ep->log_name), "enc:%s", codec->name); + + ep->e.enc_ctx = avcodec_alloc_context3(codec); + if (!ep->e.enc_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + + *penc = &ep->e; return 0; +fail: + enc_free((Encoder**)&ep); + return ret; } -static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref) +static int hw_device_setup_for_encode(Encoder *e, AVCodecContext *enc_ctx, + AVBufferRef *frames_ref) { const AVCodecHWConfig *config; HWDevice *dev = NULL; if (frames_ref && ((AVHWFramesContext*)frames_ref->data)->format == - ost->enc_ctx->pix_fmt) { + enc_ctx->pix_fmt) { // Matching format, will try to use hw_frames_ctx. } else { frames_ref = NULL; } for (int i = 0;; i++) { - config = avcodec_get_hw_config(ost->enc_ctx->codec, i); + config = avcodec_get_hw_config(enc_ctx->codec, i); if (!config) break; if (frames_ref && config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && (config->pix_fmt == AV_PIX_FMT_NONE || - config->pix_fmt == ost->enc_ctx->pix_fmt)) { - av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input " + config->pix_fmt == enc_ctx->pix_fmt)) { + av_log(e, AV_LOG_VERBOSE, "Using input " "frames context (format %s) with %s encoder.\n", - av_get_pix_fmt_name(ost->enc_ctx->pix_fmt), - ost->enc_ctx->codec->name); - ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); - if (!ost->enc_ctx->hw_frames_ctx) + av_get_pix_fmt_name(enc_ctx->pix_fmt), + enc_ctx->codec->name); + enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); + if (!enc_ctx->hw_frames_ctx) return AVERROR(ENOMEM); return 0; } @@ -125,11 +169,11 @@ static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref } if (dev) { - av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s " + av_log(e, AV_LOG_VERBOSE, "Using device %s " "(type %s) with %s encoder.\n", dev->name, - av_hwdevice_get_type_name(dev->type), ost->enc_ctx->codec->name); - ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); - if (!ost->enc_ctx->hw_device_ctx) + av_hwdevice_get_type_name(dev->type), enc_ctx->codec->name); + enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); + if (!enc_ctx->hw_device_ctx) return AVERROR(ENOMEM); } else { // No device required, or no device available. @@ -137,37 +181,13 @@ static int hw_device_setup_for_encode(OutputStream *ost, AVBufferRef *frames_ref return 0; } -static int set_encoder_id(OutputFile *of, OutputStream *ost) -{ - const char *cname = ost->enc_ctx->codec->name; - uint8_t *encoder_string; - int encoder_string_len; - - if (av_dict_get(ost->st->metadata, "encoder", NULL, 0)) - return 0; - - encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; - encoder_string = av_mallocz(encoder_string_len); - if (!encoder_string) - return AVERROR(ENOMEM); - - if (!of->bitexact && !ost->bitexact) - av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); - else - av_strlcpy(encoder_string, "Lavc ", encoder_string_len); - av_strlcat(encoder_string, cname, encoder_string_len); - av_dict_set(&ost->st->metadata, "encoder", encoder_string, - AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); - - return 0; -} - int enc_open(void *opaque, const AVFrame *frame) { OutputStream *ost = opaque; InputStream *ist = ost->ist; Encoder *e = ost->enc; - AVCodecContext *enc_ctx = ost->enc_ctx; + EncoderPriv *ep = ep_from_enc(e); + AVCodecContext *enc_ctx = e->enc_ctx; Decoder *dec = NULL; const AVCodec *enc = enc_ctx->codec; OutputFile *of = ost->file; @@ -175,7 +195,7 @@ int enc_open(void *opaque, const AVFrame *frame) int frame_samples = 0; int ret; - if (e->opened) + if (ep->opened) return 0; // frame is always non-NULL for audio and video @@ -200,10 +220,6 @@ int enc_open(void *opaque, const AVFrame *frame) } } - ret = set_encoder_id(of, ost); - if (ret < 0) - return ret; - if (ist) dec = ist->decoder; @@ -211,7 +227,6 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->type == AVMEDIA_TYPE_AUDIO || ost->type == AVMEDIA_TYPE_VIDEO) { enc_ctx->time_base = frame->time_base; enc_ctx->framerate = fd->frame_rate_filter; - ost->st->avg_frame_rate = fd->frame_rate_filter; } switch (enc_ctx->codec_type) { @@ -238,7 +253,7 @@ int enc_open(void *opaque, const AVFrame *frame) frame->height > 0); enc_ctx->width = frame->width; enc_ctx->height = frame->height; - enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio = + enc_ctx->sample_aspect_ratio = ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) : frame->sample_aspect_ratio; @@ -251,11 +266,26 @@ int enc_open(void *opaque, const AVFrame *frame) enc_ctx->bits_per_raw_sample = FFMIN(fd->bits_per_raw_sample, av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth); + /** + * The video color properties should always be in sync with the user- + * requested values, since we forward them to the filter graph. + */ enc_ctx->color_range = frame->color_range; enc_ctx->color_primaries = frame->color_primaries; enc_ctx->color_trc = frame->color_trc; enc_ctx->colorspace = frame->colorspace; - enc_ctx->chroma_sample_location = frame->chroma_location; + + /* Video properties which are not part of filter graph negotiation */ + if (enc_ctx->chroma_sample_location == AVCHROMA_LOC_UNSPECIFIED) { + enc_ctx->chroma_sample_location = frame->chroma_location; + } else if (enc_ctx->chroma_sample_location != frame->chroma_location && + frame->chroma_location != AVCHROMA_LOC_UNSPECIFIED) { + av_log(e, AV_LOG_WARNING, + "Requested chroma sample location '%s' does not match the " + "frame tagged sample location '%s'; result may be incorrect.\n", + av_chroma_location_name(enc_ctx->chroma_sample_location), + av_chroma_location_name(frame->chroma_location)); + } if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) || (frame->flags & AV_FRAME_FLAG_INTERLACED) @@ -312,42 +342,31 @@ int enc_open(void *opaque, const AVFrame *frame) enc_ctx->flags |= AV_CODEC_FLAG_FRAME_DURATION; - ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL); + ret = hw_device_setup_for_encode(e, enc_ctx, frame ? frame->hw_frames_ctx : NULL); if (ret < 0) { - av_log(ost, AV_LOG_ERROR, + av_log(e, AV_LOG_ERROR, "Encoding hardware device setup failed: %s\n", av_err2str(ret)); return ret; } - if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { + if ((ret = avcodec_open2(enc_ctx, enc, NULL)) < 0) { if (ret != AVERROR_EXPERIMENTAL) - av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe " + av_log(e, AV_LOG_ERROR, "Error while opening encoder - maybe " "incorrect parameters such as bit_rate, rate, width or height.\n"); return ret; } - e->opened = 1; + ep->opened = 1; - if (ost->enc_ctx->frame_size) - frame_samples = ost->enc_ctx->frame_size; + if (enc_ctx->frame_size) + frame_samples = enc_ctx->frame_size; - 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(ost, AV_LOG_WARNING, "The bitrate parameter is set too low." + if (enc_ctx->bit_rate && enc_ctx->bit_rate < 1000 && + enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) + av_log(e, AV_LOG_WARNING, "The bitrate parameter is set too low." " It takes bits/s as argument, not kbits/s\n"); - ret = avcodec_parameters_from_context(ost->par_in, ost->enc_ctx); - if (ret < 0) { - av_log(ost, AV_LOG_FATAL, - "Error initializing the output stream codec context.\n"); - return ret; - } - - // copy timebase while removing common factors - if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) - ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1}); - - ret = of_stream_init(of, ost); + ret = of_stream_init(of, ost, enc_ctx); if (ret < 0) return ret; @@ -369,19 +388,20 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * AVPacket *pkt) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); int subtitle_out_max_size = 1024 * 1024; int subtitle_out_size, nb, i, ret; AVCodecContext *enc; int64_t pts; if (sub->pts == AV_NOPTS_VALUE) { - av_log(ost, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); + av_log(e, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); return exit_on_error ? AVERROR(EINVAL) : 0; } if ((of->start_time != AV_NOPTS_VALUE && sub->pts < of->start_time)) return 0; - enc = ost->enc_ctx; + enc = e->enc_ctx; /* Note: DVB subtitle need one packet to draw them and one other packet to clear them */ @@ -420,11 +440,11 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * local_sub.rects += i; } - ost->frames_encoded++; + e->frames_encoded++; subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, &local_sub); if (subtitle_out_size < 0) { - av_log(ost, AV_LOG_FATAL, "Subtitle encoding failed\n"); + av_log(e, AV_LOG_FATAL, "Subtitle encoding failed\n"); return subtitle_out_size; } @@ -442,7 +462,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * } pkt->dts = pkt->pts; - ret = sch_enc_send(e->sch, e->sch_idx, pkt); + ret = sch_enc_send(ep->sch, ep->sch_idx, pkt); if (ret < 0) { av_packet_unref(pkt); return ret; @@ -457,6 +477,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, uint64_t frame_num) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); AVIOContext *io = es->io; AVRational tb = frame ? frame->time_base : pkt->time_base; int64_t pts = frame ? frame->pts : pkt->pts; @@ -494,7 +515,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, if (frame) { switch (c->type) { - case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, ost->samples_encoded); continue; + case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, e->samples_encoded); continue; case ENC_STATS_NB_SAMPLES: avio_printf(io, "%d", frame->nb_samples); continue; default: av_assert0(0); } @@ -512,7 +533,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, } case ENC_STATS_AVG_BITRATE: { double duration = pkt->dts * av_q2d(tb); - avio_printf(io, "%g", duration > 0 ? 8.0 * e->data_size / duration : -1.); + avio_printf(io, "%g", duration > 0 ? 8.0 * ep->data_size / duration : -1.); continue; } default: av_assert0(0); @@ -533,9 +554,10 @@ static inline double psnr(double d) static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, NULL); - AVCodecContext *enc = ost->enc_ctx; + AVCodecContext *enc = e->enc_ctx; enum AVPictureType pict_type; int64_t frame_number; double ti1, bitrate, avg_bitrate; @@ -566,7 +588,7 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_ } } - frame_number = e->packets_encoded; + frame_number = ep->packets_encoded; if (vstats_version <= 1) { fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number, quality / (float)FF_QP2LAMBDA); @@ -586,9 +608,9 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_ ti1 = 0.01; bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0; - avg_bitrate = (double)(e->data_size * 8) / ti1 / 1000.0; + avg_bitrate = (double)(ep->data_size * 8) / ti1 / 1000.0; fprintf(vstats_file, "s_size= %8.0fKiB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)e->data_size / 1024, ti1, bitrate, avg_bitrate); + (double)ep->data_size / 1024, ti1, bitrate, avg_bitrate); fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(pict_type)); return 0; @@ -598,7 +620,8 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, AVPacket *pkt) { Encoder *e = ost->enc; - AVCodecContext *enc = ost->enc_ctx; + EncoderPriv *ep = ep_from_enc(e); + AVCodecContext *enc = e->enc_ctx; const char *type_desc = av_get_media_type_string(enc->codec_type); const char *action = frame ? "encode" : "flush"; int ret; @@ -613,13 +636,13 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, if (ost->enc_stats_pre.io) enc_stats_write(ost, &ost->enc_stats_pre, frame, NULL, - ost->frames_encoded); + e->frames_encoded); - ost->frames_encoded++; - ost->samples_encoded += frame->nb_samples; + e->frames_encoded++; + e->samples_encoded += frame->nb_samples; if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder <- type:%s " + av_log(e, AV_LOG_INFO, "encoder <- type:%s " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", type_desc, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), @@ -634,7 +657,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, ret = avcodec_send_frame(enc, frame); if (ret < 0 && !(ret == AVERROR_EOF && !frame)) { - av_log(ost, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", + av_log(e, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", type_desc); return ret; } @@ -659,7 +682,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, return 0; } else if (ret < 0) { if (ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "%s encoding failed\n", type_desc); + av_log(e, AV_LOG_ERROR, "%s encoding failed\n", type_desc); return ret; } @@ -670,7 +693,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, // attach stream parameters to first packet if requested avcodec_parameters_free(&fd->par_enc); - if (e->attach_par && !e->packets_encoded) { + if (ep->attach_par && !ep->packets_encoded) { fd->par_enc = avcodec_parameters_alloc(); if (!fd->par_enc) return AVERROR(ENOMEM); @@ -690,10 +713,10 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, if (ost->enc_stats_post.io) enc_stats_write(ost, &ost->enc_stats_post, NULL, pkt, - e->packets_encoded); + ep->packets_encoded); if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder -> type:%s " + av_log(e, AV_LOG_INFO, "encoder -> type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " "duration:%s duration_time:%s\n", type_desc, @@ -702,11 +725,11 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); } - e->data_size += pkt->size; + ep->data_size += pkt->size; - e->packets_encoded++; + ep->packets_encoded++; - ret = sch_enc_send(e->sch, e->sch_idx, pkt); + ret = sch_enc_send(ep->sch, ep->sch_idx, pkt); if (ret < 0) { av_packet_unref(pkt); return ret; @@ -764,6 +787,7 @@ force_keyframe: static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) { + Encoder *e = ost->enc; OutputFile *of = ost->file; enum AVMediaType type = ost->type; @@ -781,8 +805,8 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) return AVERROR_EOF; if (type == AVMEDIA_TYPE_VIDEO) { - frame->quality = ost->enc_ctx->global_quality; - frame->pict_type = forced_kf_apply(ost, &ost->kf, frame); + frame->quality = e->enc_ctx->global_quality; + frame->pict_type = forced_kf_apply(e, &ost->kf, frame); #if FFMPEG_OPT_TOP if (ost->top_field_first >= 0) { @@ -791,9 +815,9 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) } #endif } else { - if (!(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && - ost->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { - av_log(ost, AV_LOG_ERROR, + if (!(e->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && + e->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { + av_log(e, AV_LOG_ERROR, "Audio channel count changed and encoder does not support parameter changes\n"); return 0; } @@ -807,7 +831,7 @@ static void enc_thread_set_name(const OutputStream *ost) { char name[16]; snprintf(name, sizeof(name), "enc%d:%d:%s", ost->file->index, ost->index, - ost->enc_ctx->codec->name); + ost->enc->enc_ctx->codec->name); ff_thread_setname(name); } @@ -842,6 +866,7 @@ int encoder_thread(void *arg) { OutputStream *ost = arg; Encoder *e = ost->enc; + EncoderPriv *ep = ep_from_enc(e); EncoderThread et; int ret = 0, input_status = 0; int name_set = 0; @@ -864,17 +889,17 @@ int encoder_thread(void *arg) } while (!input_status) { - input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame); + input_status = sch_enc_receive(ep->sch, ep->sch_idx, et.frame); if (input_status < 0) { if (input_status == AVERROR_EOF) { - av_log(ost, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); - if (e->opened) + av_log(e, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); + if (ep->opened) break; - av_log(ost, AV_LOG_ERROR, "Could not open encoder before EOF\n"); + av_log(e, AV_LOG_ERROR, "Could not open encoder before EOF\n"); ret = AVERROR(EINVAL); } else { - av_log(ost, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", + av_log(e, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", av_err2str(ret)); ret = input_status; } @@ -893,9 +918,9 @@ int encoder_thread(void *arg) if (ret < 0) { if (ret == AVERROR_EOF) - av_log(ost, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); + av_log(e, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); else - av_log(ost, AV_LOG_ERROR, "Error encoding a frame: %s\n", + av_log(e, AV_LOG_ERROR, "Error encoding a frame: %s\n", av_err2str(ret)); break; } @@ -905,7 +930,7 @@ int encoder_thread(void *arg) if (ret == 0 || ret == AVERROR_EOF) { ret = frame_encode(ost, NULL, et.pkt); if (ret < 0 && ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "Error flushing encoder: %s\n", + av_log(e, AV_LOG_ERROR, "Error flushing encoder: %s\n", av_err2str(ret)); } @@ -921,6 +946,7 @@ finish: int enc_loopback(Encoder *enc) { - enc->attach_par = 1; - return enc->sch_idx; + EncoderPriv *ep = ep_from_enc(enc); + ep->attach_par = 1; + return ep->sch_idx; } diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 7ec328e04e..bf5e53efa9 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -21,6 +21,7 @@ #include #include "ffmpeg.h" +#include "graph/graphprint.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersink.h" @@ -30,6 +31,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/downmix_info.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -57,9 +59,7 @@ typedef struct FilterGraphPriv { unsigned nb_outputs_done; - const char *graph_desc; - - char *nb_threads; + int nb_threads; // frame for temporarily holding output from the filtergraph AVFrame *frame; @@ -106,25 +106,17 @@ typedef struct InputFilterPriv { InputFilterOptions opts; - int index; - - AVFilterContext *filter; - // used to hold submitted input AVFrame *frame; - /* for filters that are not yet bound to an input stream, - * this stores the input linklabel, if any */ - uint8_t *linklabel; - - // filter data type - enum AVMediaType type; // source data type: AVMEDIA_TYPE_SUBTITLE for sub2video, // same as type otherwise enum AVMediaType type_src; int eof; int bound; + int drop_warned; + uint64_t nb_dropped; // parameters configured for this input int format; @@ -139,6 +131,9 @@ typedef struct InputFilterPriv { AVRational time_base; + AVFrameSideData **side_data; + int nb_side_data; + AVFifo *frame_queue; AVBufferRef *hw_frames_ctx; @@ -147,13 +142,16 @@ typedef struct InputFilterPriv { int displaymatrix_applied; int32_t displaymatrix[9]; + int downmixinfo_present; + AVDownmixInfo downmixinfo; + struct { AVFrame *frame; int64_t last_pts; int64_t end_pts; - ///< marks if sub2video_update should force an initialization + /// marks if sub2video_update should force an initialization unsigned int initialize; } sub2video; } InputFilterPriv; @@ -188,15 +186,9 @@ typedef struct FPSConvContext { typedef struct OutputFilterPriv { OutputFilter ofilter; - int index; - void *log_parent; char log_name[32]; - char *name; - - AVFilterContext *filter; - /* desired output stream properties */ int format; int width, height; @@ -205,6 +197,9 @@ typedef struct OutputFilterPriv { enum AVColorSpace color_space; enum AVColorRange color_range; + AVFrameSideData **side_data; + int nb_side_data; + // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase AVRational tb_out; @@ -321,11 +316,12 @@ static void sub2video_push_ref(InputFilterPriv *ifp, int64_t pts) av_assert1(frame->data[0]); ifp->sub2video.last_pts = frame->pts = pts; - ret = av_buffersrc_add_frame_flags(ifp->filter, frame, + ret = av_buffersrc_add_frame_flags(ifp->ifilter.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_log(ifp->ifilter.graph, AV_LOG_WARNING, + "Error while add the frame to buffer source(%s).\n", av_err2str(ret)); } @@ -355,7 +351,7 @@ static void sub2video_update(InputFilterPriv *ifp, int64_t heartbeat_pts, num_rects = 0; } if (sub2video_get_blank_frame(ifp) < 0) { - av_log(NULL, AV_LOG_ERROR, + av_log(ifp->ifilter.graph, AV_LOG_ERROR, "Impossible to get a blank canvas.\n"); return; } @@ -425,7 +421,8 @@ static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) av_bprint_chars(bprint, ':', 1); } -static int read_binary(const char *path, uint8_t **data, int *len) +static int read_binary(void *logctx, const char *path, + uint8_t **data, int *len) { AVIOContext *io = NULL; int64_t fsize; @@ -436,14 +433,14 @@ static int read_binary(const char *path, uint8_t **data, int *len) ret = avio_open2(&io, path, AVIO_FLAG_READ, &int_cb, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s': %s\n", + av_log(logctx, AV_LOG_ERROR, "Cannot open file '%s': %s\n", path, av_err2str(ret)); return ret; } fsize = avio_size(io); if (fsize < 0 || fsize > INT_MAX) { - av_log(NULL, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); + av_log(logctx, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); ret = AVERROR(EIO); goto fail; } @@ -456,7 +453,7 @@ static int read_binary(const char *path, uint8_t **data, int *len) ret = avio_read(io, *data, fsize); if (ret != fsize) { - av_log(NULL, AV_LOG_ERROR, "Error reading file %s\n", path); + av_log(logctx, AV_LOG_ERROR, "Error reading file %s\n", path); ret = ret < 0 ? ret : AVERROR(EIO); goto fail; } @@ -473,7 +470,8 @@ fail: return ret; } -static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val) +static int filter_opt_apply(void *logctx, AVFilterContext *f, + const char *key, const char *val) { const AVOption *o = NULL; int ret; @@ -495,7 +493,7 @@ static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val uint8_t *data; int len; - ret = read_binary(val, &data, &len); + ret = read_binary(logctx, val, &data, &len); if (ret < 0) goto err_load; @@ -517,18 +515,18 @@ static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val return 0; err_apply: - av_log(NULL, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Error applying option '%s' to filter '%s': %s\n", key, f->filter->name, av_err2str(ret)); return ret; err_load: - av_log(NULL, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Error loading value for option '%s' from file '%s'\n", key, val); return ret; } -static int graph_opts_apply(AVFilterGraphSegment *seg) +static int graph_opts_apply(void *logctx, AVFilterGraphSegment *seg) { for (size_t i = 0; i < seg->nb_chains; i++) { AVFilterChain *ch = seg->chains[i]; @@ -540,7 +538,7 @@ static int graph_opts_apply(AVFilterGraphSegment *seg) av_assert0(p->filter); while ((e = av_dict_iterate(p->opts, e))) { - int ret = filter_opt_apply(p->filter, e->key, e->value); + int ret = filter_opt_apply(logctx, p->filter, e->key, e->value); if (ret < 0) return ret; } @@ -552,7 +550,8 @@ static int graph_opts_apply(AVFilterGraphSegment *seg) return 0; } -static int graph_parse(AVFilterGraph *graph, const char *desc, +static int graph_parse(void *logctx, + AVFilterGraph *graph, const char *desc, AVFilterInOut **inputs, AVFilterInOut **outputs, AVBufferRef *hw_device) { @@ -584,7 +583,7 @@ static int graph_parse(AVFilterGraph *graph, const char *desc, } } - ret = graph_opts_apply(seg); + ret = graph_opts_apply(logctx, seg); if (ret < 0) goto fail; @@ -651,10 +650,10 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg, enum AVMediaType type) ofp->format = -1; ofp->color_space = AVCOL_SPC_UNSPECIFIED; ofp->color_range = AVCOL_RANGE_UNSPECIFIED; - ofp->index = fg->nb_outputs - 1; + ofilter->index = fg->nb_outputs - 1; snprintf(ofp->log_name, sizeof(ofp->log_name), "%co%d", - av_get_media_type_string(type)[0], ofp->index); + av_get_media_type_string(type)[0], ofilter->index); return ofilter; } @@ -670,10 +669,10 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist, av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != ist->par->codec_type && - !(ifp->type == AVMEDIA_TYPE_VIDEO && ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) { + if (ifilter->type != ist->par->codec_type && + !(ifilter->type == AVMEDIA_TYPE_VIDEO && ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s stream to %s filtergraph input\n", - av_get_media_type_string(ist->par->codec_type), av_get_media_type_string(ifp->type)); + av_get_media_type_string(ist->par->codec_type), av_get_media_type_string(ifilter->type)); return AVERROR(EINVAL); } @@ -688,8 +687,12 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist, if (ret < 0) return ret; + ifilter->input_name = av_strdup(ifp->opts.name); + if (!ifilter->input_name) + return AVERROR(EINVAL); + ret = sch_connect(fgp->sch, - src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + src, SCH_FILTER_IN(fgp->sch_idx, ifilter->index)); if (ret < 0) return ret; @@ -724,19 +727,23 @@ static int ifilter_bind_dec(InputFilterPriv *ifp, Decoder *dec, av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != dec->type) { + if (ifp->ifilter.type != dec->type) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s decoder to %s filtergraph input\n", - av_get_media_type_string(dec->type), av_get_media_type_string(ifp->type)); + av_get_media_type_string(dec->type), av_get_media_type_string(ifp->ifilter.type)); return AVERROR(EINVAL); } - ifp->type_src = ifp->type; + ifp->type_src = ifp->ifilter.type; ret = dec_filter_add(dec, &ifp->ifilter, &ifp->opts, vs, &src); if (ret < 0) return ret; - ret = sch_connect(fgp->sch, src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + ifp->ifilter.input_name = av_strdup(ifp->opts.name); + if (!ifp->ifilter.input_name) + return AVERROR(EINVAL); + + ret = sch_connect(fgp->sch, src, SCH_FILTER_IN(fgp->sch_idx, ifp->ifilter.index)); if (ret < 0) return ret; @@ -783,8 +790,7 @@ static int set_channel_layout(OutputFilterPriv *f, const AVChannelLayout *layout return 0; } -int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, - unsigned sched_idx_enc, +int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc, const OutputFilterOptions *opts) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); @@ -793,7 +799,8 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, int ret; av_assert0(!ofilter->bound); - av_assert0(ofilter->type == ost->type); + av_assert0(!opts->enc || + ofilter->type == opts->enc->type); ofilter->bound = 1; av_freep(&ofilter->linklabel); @@ -805,8 +812,8 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, ofp->trim_start_us = opts->trim_start_us; ofp->trim_duration_us = opts->trim_duration_us; - ofp->name = av_strdup(opts->name); - if (!ofp->name) + ofilter->output_name = av_strdup(opts->name); + if (!ofilter->output_name) return AVERROR(EINVAL); ret = av_dict_copy(&ofp->sws_opts, opts->sws_opts, 0); @@ -826,7 +833,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, ofp->log_parent = NULL; av_strlcpy(ofp->log_name, fgp->log_name, sizeof(ofp->log_name)); } else - av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofp->name); + av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name); switch (ofilter->type) { case AVMEDIA_TYPE_VIDEO: @@ -854,10 +861,9 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, return AVERROR(ENOMEM); ofp->fps.vsync_method = opts->vsync_method; - ofp->fps.framerate = ost->frame_rate; - ofp->fps.framerate_max = ost->max_frame_rate; - ofp->fps.framerate_supported = ost->force_fps || !opts->enc ? - NULL : opts->frame_rates; + ofp->fps.framerate = opts->frame_rate; + ofp->fps.framerate_max = opts->max_frame_rate; + ofp->fps.framerate_supported = opts->frame_rates; // reduce frame rate for mpeg4 to be within the spec limits if (opts->enc && opts->enc->id == AV_CODEC_ID_MPEG4) @@ -886,7 +892,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, break; } - ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fgp->sch_idx, ofp->index), + ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fgp->sch_idx, ofilter->index), SCH_ENC(sched_idx_enc)); if (ret < 0) return ret; @@ -900,16 +906,16 @@ static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp, OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); av_assert0(!ofilter->bound); - av_assert0(ofilter->type == ifp->type); + av_assert0(ofilter->type == ifp->ifilter.type); ofilter->bound = 1; av_freep(&ofilter->linklabel); - ofp->name = av_strdup(opts->name); - if (!ofp->name) + ofilter->output_name = av_strdup(opts->name); + if (!ofilter->output_name) return AVERROR(EINVAL); - av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofp->name); + av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name); return 0; } @@ -925,18 +931,18 @@ static int ifilter_bind_fg(InputFilterPriv *ifp, FilterGraph *fg_src, int out_id av_assert0(!ifp->bound); ifp->bound = 1; - if (ifp->type != ofilter_src->type) { + if (ifp->ifilter.type != ofilter_src->type) { av_log(fgp, AV_LOG_ERROR, "Tried to connect %s output to %s input\n", av_get_media_type_string(ofilter_src->type), - av_get_media_type_string(ifp->type)); + av_get_media_type_string(ifp->ifilter.type)); return AVERROR(EINVAL); } - ifp->type_src = ifp->type; + ifp->type_src = ifp->ifilter.type; memset(&opts, 0, sizeof(opts)); - snprintf(name, sizeof(name), "fg:%d:%d", fgp->fg.index, ifp->index); + snprintf(name, sizeof(name), "fg:%d:%d", fgp->fg.index, ifp->ifilter.index); opts.name = name; ret = ofilter_bind_ifilter(ofilter_src, ifp, &opts); @@ -944,7 +950,7 @@ static int ifilter_bind_fg(InputFilterPriv *ifp, FilterGraph *fg_src, int out_id return ret; ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fg_src->index, out_idx), - SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + SCH_FILTER_IN(fgp->sch_idx, ifp->ifilter.index)); if (ret < 0) return ret; @@ -967,7 +973,7 @@ static InputFilter *ifilter_alloc(FilterGraph *fg) if (!ifp->frame) return NULL; - ifp->index = fg->nb_inputs - 1; + ifilter->index = fg->nb_inputs - 1; ifp->format = -1; ifp->color_space = AVCOL_SPC_UNSPECIFIED; ifp->color_range = AVCOL_RANGE_UNSPECIFIED; @@ -1004,9 +1010,11 @@ void fg_free(FilterGraph **pfg) av_frame_free(&ifp->opts.fallback); av_buffer_unref(&ifp->hw_frames_ctx); - av_freep(&ifp->linklabel); + av_freep(&ifilter->linklabel); av_freep(&ifp->opts.name); + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); av_freep(&ifilter->name); + av_freep(&ifilter->input_name); av_freep(&fg->inputs[j]); } av_freep(&fg->inputs); @@ -1020,14 +1028,14 @@ void fg_free(FilterGraph **pfg) av_freep(&ofilter->linklabel); av_freep(&ofilter->name); + av_freep(&ofilter->output_name); av_freep(&ofilter->apad); - av_freep(&ofp->name); av_channel_layout_uninit(&ofp->ch_layout); + av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data); av_freep(&fg->outputs[j]); } av_freep(&fg->outputs); - av_freep(&fgp->graph_desc); - av_freep(&fgp->nb_threads); + av_freep(&fg->graph_desc); av_frame_free(&fgp->frame); av_frame_free(&fgp->frame_enc); @@ -1059,8 +1067,10 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) int ret = 0; fgp = av_mallocz(sizeof(*fgp)); - if (!fgp) + if (!fgp) { + av_freep(&graph_desc); return AVERROR(ENOMEM); + } fg = &fgp->fg; if (pfg) { @@ -1069,6 +1079,7 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) } else { ret = av_dynarray_add_nofree(&filtergraphs, &nb_filtergraphs, fgp); if (ret < 0) { + av_freep(&graph_desc); av_freep(&fgp); return ret; } @@ -1077,8 +1088,9 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) } fg->class = &fg_class; - fgp->graph_desc = graph_desc; + fg->graph_desc = graph_desc; fgp->disable_conversions = !auto_conversion_filters; + fgp->nb_threads = -1; fgp->sch = sch; snprintf(fgp->log_name, sizeof(fgp->log_name), "fc#%d", fg->index); @@ -1095,14 +1107,16 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) return AVERROR(ENOMEM);; graph->nb_threads = 1; - ret = graph_parse(graph, fgp->graph_desc, &inputs, &outputs, NULL); + ret = graph_parse(fg, graph, fg->graph_desc, &inputs, &outputs, + hw_device_for_filter()); if (ret < 0) goto fail; for (unsigned i = 0; i < graph->nb_filters; i++) { const AVFilter *f = graph->filters[i]->filter; - if (!avfilter_filter_pad_count(f, 0) && - !(f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) { + if ((!avfilter_filter_pad_count(f, 0) && + !(f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) || + !strcmp(f->name, "apad")) { fgp->have_sources = 1; break; } @@ -1110,21 +1124,19 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) for (AVFilterInOut *cur = inputs; cur; cur = cur->next) { InputFilter *const ifilter = ifilter_alloc(fg); - InputFilterPriv *ifp; if (!ifilter) { ret = AVERROR(ENOMEM); goto fail; } - ifp = ifp_from_ifilter(ifilter); - ifp->linklabel = cur->name; + ifilter->linklabel = cur->name; cur->name = NULL; - ifp->type = avfilter_pad_get_type(cur->filter_ctx->input_pads, + ifilter->type = avfilter_pad_get_type(cur->filter_ctx->input_pads, cur->pad_idx); - if (ifp->type != AVMEDIA_TYPE_VIDEO && ifp->type != AVMEDIA_TYPE_AUDIO) { + if (ifilter->type != AVMEDIA_TYPE_VIDEO && ifilter->type != AVMEDIA_TYPE_AUDIO) { av_log(fg, AV_LOG_FATAL, "Only video and audio filters supported " "currently.\n"); ret = AVERROR(ENOSYS); @@ -1181,25 +1193,27 @@ fail: return 0; } -int init_simple_filtergraph(InputStream *ist, OutputStream *ost, - char *graph_desc, - Scheduler *sch, unsigned sched_idx_enc, - const OutputFilterOptions *opts) +int fg_create_simple(FilterGraph **pfg, + InputStream *ist, + char *graph_desc, + Scheduler *sch, unsigned sched_idx_enc, + const OutputFilterOptions *opts) { + const enum AVMediaType type = ist->par->codec_type; FilterGraph *fg; FilterGraphPriv *fgp; int ret; - ret = fg_create(&ost->fg_simple, graph_desc, sch); + ret = fg_create(pfg, graph_desc, sch); if (ret < 0) return ret; - fg = ost->fg_simple; + fg = *pfg; fgp = fgp_from_fg(fg); fgp->is_simple = 1; snprintf(fgp->log_name, sizeof(fgp->log_name), "%cf%s", - av_get_media_type_string(ost->type)[0], opts->name); + av_get_media_type_string(type)[0], opts->name); if (fg->nb_inputs != 1 || fg->nb_outputs != 1) { av_log(fg, AV_LOG_ERROR, "Simple filtergraph '%s' was expected " @@ -1209,53 +1223,46 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost, graph_desc, fg->nb_inputs, fg->nb_outputs); return AVERROR(EINVAL); } - if (fg->outputs[0]->type != ost->type) { + if (fg->outputs[0]->type != type) { av_log(fg, AV_LOG_ERROR, "Filtergraph has a %s output, cannot connect " "it to %s output stream\n", av_get_media_type_string(fg->outputs[0]->type), - av_get_media_type_string(ost->type)); + av_get_media_type_string(type)); return AVERROR(EINVAL); } - ost->filter = fg->outputs[0]; - ret = ifilter_bind_ist(fg->inputs[0], ist, opts->vs); if (ret < 0) return ret; - ret = ofilter_bind_ost(fg->outputs[0], ost, sched_idx_enc, opts); + ret = ofilter_bind_enc(fg->outputs[0], sched_idx_enc, opts); if (ret < 0) return ret; - if (opts->nb_threads) { - av_freep(&fgp->nb_threads); - fgp->nb_threads = av_strdup(opts->nb_threads); - if (!fgp->nb_threads) - return AVERROR(ENOMEM); - } + if (opts->nb_threads >= 0) + fgp->nb_threads = opts->nb_threads; return 0; } static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) { - FilterGraphPriv *fgp = fgp_from_fg(fg); InputFilterPriv *ifp = ifp_from_ifilter(ifilter); InputStream *ist = NULL; - enum AVMediaType type = ifp->type; + enum AVMediaType type = ifilter->type; ViewSpecifier vs = { .type = VIEW_SPECIFIER_TYPE_NONE }; const char *spec; char *p; int i, ret; - if (ifp->linklabel && !strncmp(ifp->linklabel, "dec:", 4)) { + if (ifilter->linklabel && !strncmp(ifilter->linklabel, "dec:", 4)) { // bind to a standalone decoder int dec_idx; - dec_idx = strtol(ifp->linklabel + 4, &p, 0); + dec_idx = strtol(ifilter->linklabel + 4, &p, 0); if (dec_idx < 0 || dec_idx >= nb_decoders) { av_log(fg, AV_LOG_ERROR, "Invalid decoder index %d in filtergraph description %s\n", - dec_idx, fgp->graph_desc); + dec_idx, fg->graph_desc); return AVERROR(EINVAL); } @@ -1271,7 +1278,7 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) av_log(fg, AV_LOG_ERROR, "Error binding a decoder to filtergraph input %s\n", ifilter->name); return ret; - } else if (ifp->linklabel) { + } else if (ifilter->linklabel) { StreamSpecifier ss; AVFormatContext *s; AVStream *st = NULL; @@ -1288,25 +1295,25 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) OutputFilter *ofilter = fg_src->outputs[j]; if (!ofilter->bound && ofilter->linklabel && - !strcmp(ofilter->linklabel, ifp->linklabel)) { + !strcmp(ofilter->linklabel, ifilter->linklabel)) { av_log(fg, AV_LOG_VERBOSE, "Binding input with label '%s' to filtergraph output %d:%d\n", - ifp->linklabel, i, j); + ifilter->linklabel, i, j); ret = ifilter_bind_fg(ifp, fg_src, j); if (ret < 0) av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n", - ifp->linklabel); + ifilter->linklabel); return ret; } } } // bind to an explicitly specified demuxer stream - file_idx = strtol(ifp->linklabel, &p, 0); + file_idx = strtol(ifilter->linklabel, &p, 0); if (file_idx < 0 || file_idx >= nb_input_files) { av_log(fg, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n", - file_idx, fgp->graph_desc); + file_idx, fg->graph_desc); return AVERROR(EINVAL); } s = input_files[file_idx]->ctx; @@ -1340,25 +1347,27 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) stream_specifier_uninit(&ss); if (!st) { av_log(fg, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s " - "matches no streams.\n", p, fgp->graph_desc); + "matches no streams.\n", p, fg->graph_desc); return AVERROR(EINVAL); } ist = input_files[file_idx]->streams[st->index]; av_log(fg, AV_LOG_VERBOSE, "Binding input with label '%s' to input stream %d:%d\n", - ifp->linklabel, ist->file->index, ist->index); + ifilter->linklabel, ist->file->index, ist->index); } else { ist = ist_find_unused(type); if (!ist) { - av_log(fg, AV_LOG_FATAL, "Cannot find a matching stream for " - "unlabeled input pad %s\n", ifilter->name); + av_log(fg, AV_LOG_FATAL, + "Cannot find an unused %s input stream to feed the " + "unlabeled input pad %s.\n", + av_get_media_type_string(type), ifilter->name); return AVERROR(EINVAL); } av_log(fg, AV_LOG_VERBOSE, "Binding unlabeled input %d to input stream %d:%d\n", - ifp->index, ist->file->index, ist->index); + ifilter->index, ist->file->index, ist->index); } av_assert0(ist); @@ -1408,8 +1417,10 @@ int fg_finalise_bindings(void) for (int j = 0; j < fg->nb_outputs; j++) { OutputFilter *output = fg->outputs[j]; if (!output->bound) { - av_log(filtergraphs[j], AV_LOG_FATAL, - "Filter %s has an unconnected output\n", output->name); + av_log(fg, AV_LOG_FATAL, + "Filter '%s' has output %d (%s) unconnected\n", + output->name, j, + output->linklabel ? (const char *)output->linklabel : "unlabeled"); return AVERROR(EINVAL); } } @@ -1418,7 +1429,7 @@ int fg_finalise_bindings(void) return 0; } -static int insert_trim(int64_t start_time, int64_t duration, +static int insert_trim(void *logctx, int64_t start_time, int64_t duration, AVFilterContext **last_filter, int *pad_idx, const char *filter_name) { @@ -1434,7 +1445,7 @@ static int insert_trim(int64_t start_time, int64_t duration, trim = avfilter_get_by_name(name); if (!trim) { - av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit " + av_log(logctx, AV_LOG_ERROR, "%s filter not present, cannot limit " "recording time.\n", name); return AVERROR_FILTER_NOT_FOUND; } @@ -1495,7 +1506,7 @@ static int insert_filter(AVFilterContext **last_filter, int *pad_idx, return 0; } -static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); @@ -1505,8 +1516,8 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, int ret; char name[255]; - snprintf(name, sizeof(name), "out_%s", ofp->name); - ret = avfilter_graph_create_filter(&ofp->filter, + snprintf(name, sizeof(name), "out_%s", ofilter->output_name); + ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), name, NULL, NULL, graph); @@ -1525,7 +1536,7 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value); } - snprintf(name, sizeof(name), "scaler_out_%s", ofp->name); + snprintf(name, sizeof(name), "scaler_out_%s", ofilter->output_name); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), name, args, NULL, graph)) < 0) return ret; @@ -1561,20 +1572,20 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, pad_idx = 0; } - snprintf(name, sizeof(name), "trim_out_%s", ofp->name); - ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, + snprintf(name, sizeof(name), "trim_out_%s", ofilter->output_name); + ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; - if ((ret = avfilter_link(last_filter, pad_idx, ofp->filter, 0)) < 0) + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; return 0; } -static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); @@ -1584,14 +1595,12 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, char name[255]; int ret; - snprintf(name, sizeof(name), "out_%s", ofp->name); - ret = avfilter_graph_create_filter(&ofp->filter, + snprintf(name, sizeof(name), "out_%s", ofilter->output_name); + ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("abuffersink"), name, NULL, NULL, graph); if (ret < 0) return ret; - if ((ret = av_opt_set_int(ofp->filter, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) - return ret; #define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \ AVFilterContext *filt_ctx; \ @@ -1624,7 +1633,7 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, if (args.len) { AVFilterContext *format; - snprintf(name, sizeof(name), "format_out_%s", ofp->name); + snprintf(name, sizeof(name), "format_out_%s", ofilter->output_name); ret = avfilter_graph_create_filter(&format, avfilter_get_by_name("aformat"), name, args.str, NULL, graph); @@ -1639,16 +1648,18 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, pad_idx = 0; } - if (ofilter->apad) + if (ofilter->apad) { AUTO_INSERT_FILTER("-apad", "apad", ofilter->apad); + fgp->have_sources = 1; + } - snprintf(name, sizeof(name), "trim for output %s", ofp->name); - ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, + snprintf(name, sizeof(name), "trim for output %s", ofilter->output_name); + ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) goto fail; - if ((ret = avfilter_link(last_filter, pad_idx, ofp->filter, 0)) < 0) + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) goto fail; fail: av_bprint_finalize(&args, NULL); @@ -1656,12 +1667,12 @@ fail: return ret; } -static int configure_output_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { switch (ofilter->type) { - case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, graph, ofilter, out); - case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, graph, ofilter, out); + case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fgp, graph, ofilter, out); + case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fgp, graph, ofilter, out); default: av_assert0(0); return 0; } } @@ -1685,9 +1696,6 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, AVFilterContext *last_filter; const AVFilter *buffer_filt = avfilter_get_by_name("buffer"); const AVPixFmtDescriptor *desc; - AVRational fr = ifp->opts.framerate; - AVRational sar; - AVBPrint args; char name[255]; int ret, pad_idx = 0; AVBufferSrcParameters *par = av_buffersrc_parameters_alloc(); @@ -1697,31 +1705,38 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, if (ifp->type_src == AVMEDIA_TYPE_SUBTITLE) sub2video_prepare(ifp); - sar = ifp->sample_aspect_ratio; - if(!sar.den) - sar = (AVRational){0,1}; - av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); - av_bprintf(&args, - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" - "pixel_aspect=%d/%d:colorspace=%d:range=%d", - ifp->width, ifp->height, ifp->format, - ifp->time_base.num, ifp->time_base.den, sar.num, sar.den, - ifp->color_space, ifp->color_range); - if (fr.num && fr.den) - av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den); snprintf(name, sizeof(name), "graph %d input from stream %s", fg->index, ifp->opts.name); - - if ((ret = avfilter_graph_create_filter(&ifp->filter, buffer_filt, name, - args.str, NULL, graph)) < 0) + ifilter->filter = avfilter_graph_alloc_filter(graph, buffer_filt, name); + if (!ifilter->filter) { + ret = AVERROR(ENOMEM); goto fail; - par->hw_frames_ctx = ifp->hw_frames_ctx; - ret = av_buffersrc_parameters_set(ifp->filter, par); + } + + par->format = ifp->format; + par->time_base = ifp->time_base; + par->frame_rate = ifp->opts.framerate; + par->width = ifp->width; + par->height = ifp->height; + par->sample_aspect_ratio = ifp->sample_aspect_ratio.den > 0 ? + ifp->sample_aspect_ratio : (AVRational){ 0, 1 }; + par->color_space = ifp->color_space; + par->color_range = ifp->color_range; + par->hw_frames_ctx = ifp->hw_frames_ctx; + par->side_data = ifp->side_data; + par->nb_side_data = ifp->nb_side_data; + + ret = av_buffersrc_parameters_set(ifilter->filter, par); if (ret < 0) goto fail; av_freep(&par); - last_filter = ifp->filter; + + ret = avfilter_init_dict(ifilter->filter, NULL); + if (ret < 0) + goto fail; + + last_filter = ifilter->filter; desc = av_pix_fmt_desc_get(ifp->format); av_assert0(desc); @@ -1777,7 +1792,7 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, } snprintf(name, sizeof(name), "trim_in_%s", ifp->opts.name); - ret = insert_trim(ifp->opts.trim_start_us, ifp->opts.trim_end_us, + ret = insert_trim(fg, ifp->opts.trim_start_us, ifp->opts.trim_end_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; @@ -1796,6 +1811,7 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, { InputFilterPriv *ifp = ifp_from_ifilter(ifilter); AVFilterContext *last_filter; + AVBufferSrcParameters *par; const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer"); AVBPrint args; char name[255]; @@ -1814,14 +1830,23 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, av_bprintf(&args, ":channels=%d", ifp->ch_layout.nb_channels); snprintf(name, sizeof(name), "graph_%d_in_%s", fg->index, ifp->opts.name); - if ((ret = avfilter_graph_create_filter(&ifp->filter, abuffer_filt, + if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt, name, args.str, NULL, graph)) < 0) return ret; - last_filter = ifp->filter; + par = av_buffersrc_parameters_alloc(); + if (!par) + return AVERROR(ENOMEM); + par->side_data = ifp->side_data; + par->nb_side_data = ifp->nb_side_data; + ret = av_buffersrc_parameters_set(ifilter->filter, par); + av_free(par); + if (ret < 0) + return ret; + last_filter = ifilter->filter; snprintf(name, sizeof(name), "trim for input stream %s", ifp->opts.name); - ret = insert_trim(ifp->opts.trim_start_us, ifp->opts.trim_end_us, + ret = insert_trim(fg, ifp->opts.trim_start_us, ifp->opts.trim_end_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; @@ -1835,7 +1860,7 @@ static int configure_input_audio_filter(FilterGraph *fg, AVFilterGraph *graph, static int configure_input_filter(FilterGraph *fg, AVFilterGraph *graph, InputFilter *ifilter, AVFilterInOut *in) { - switch (ifp_from_ifilter(ifilter)->type) { + switch (ifilter->type) { case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, graph, ifilter, in); case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, graph, ifilter, in); default: av_assert0(0); return 0; @@ -1845,9 +1870,9 @@ static int configure_input_filter(FilterGraph *fg, AVFilterGraph *graph, static void cleanup_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) { for (int i = 0; i < fg->nb_outputs; i++) - ofp_from_ofilter(fg->outputs[i])->filter = NULL; + fg->outputs[i]->filter = NULL; for (int i = 0; i < fg->nb_inputs; i++) - ifp_from_ifilter(fg->inputs[i])->filter = NULL; + fg->inputs[i]->filter = NULL; avfilter_graph_free(&fgt->graph); } @@ -1882,9 +1907,9 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) FilterGraphPriv *fgp = fgp_from_fg(fg); AVBufferRef *hw_device; AVFilterInOut *inputs, *outputs, *cur; - int ret, i, simple = filtergraph_is_simple(fg); + int ret = AVERROR_BUG, i, simple = filtergraph_is_simple(fg); int have_input_eof = 0; - const char *graph_desc = fgp->graph_desc; + const char *graph_desc = fg->graph_desc; cleanup_filtergraph(fg, fgt); fgt->graph = avfilter_graph_alloc(); @@ -1898,8 +1923,8 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ret = av_opt_set(fgt->graph, "threads", filter_nbthreads, 0); if (ret < 0) goto fail; - } else if (fgp->nb_threads) { - ret = av_opt_set(fgt->graph, "threads", fgp->nb_threads, 0); + } else if (fgp->nb_threads >= 0) { + ret = av_opt_set_int(fgt->graph, "threads", fgp->nb_threads, 0); if (ret < 0) return ret; } @@ -1924,9 +1949,16 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) fgt->graph->nb_threads = filter_complex_nbthreads; } + if (filter_buffered_frames) { + ret = av_opt_set_int(fgt->graph, "max_buffered_frames", filter_buffered_frames, 0); + if (ret < 0) + return ret; + } + hw_device = hw_device_for_filter(); - if ((ret = graph_parse(fgt->graph, graph_desc, &inputs, &outputs, hw_device)) < 0) + ret = graph_parse(fg, fgt->graph, graph_desc, &inputs, &outputs, hw_device); + if (ret < 0) goto fail; for (cur = inputs, i = 0; cur; cur = cur->next, i++) @@ -1938,7 +1970,7 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) avfilter_inout_free(&inputs); for (cur = outputs, i = 0; cur; cur = cur->next, i++) { - ret = configure_output_filter(fg, fgt->graph, fg->outputs[i], cur); + ret = configure_output_filter(fgp, fgt->graph, fg->outputs[i], cur); if (ret < 0) { avfilter_inout_free(&outputs); goto fail; @@ -1956,9 +1988,11 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) /* limit the lists of allowed formats to the ones selected, to * make sure they stay the same if the filtergraph is reconfigured later */ for (int i = 0; i < fg->nb_outputs; i++) { + const AVFrameSideData *const *sd; + int nb_sd; OutputFilter *ofilter = fg->outputs[i]; OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); - AVFilterContext *sink = ofp->filter; + AVFilterContext *sink = ofilter->filter; ofp->format = av_buffersink_get_format(sink); @@ -1984,16 +2018,32 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ret = av_buffersink_get_ch_layout(sink, &ofp->ch_layout); if (ret < 0) goto fail; + av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data); + sd = av_buffersink_get_side_data(sink, &nb_sd); + if (nb_sd) + for (int j = 0; j < nb_sd; j++) { + ret = av_frame_side_data_clone(&ofp->side_data, &ofp->nb_side_data, + sd[j], 0); + if (ret < 0) { + av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data); + goto fail; + } + } } for (int i = 0; i < fg->nb_inputs; i++) { + InputFilter *ifilter = fg->inputs[i]; InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); AVFrame *tmp; while (av_fifo_read(ifp->frame_queue, &tmp, 1) >= 0) { if (ifp->type_src == AVMEDIA_TYPE_SUBTITLE) { sub2video_frame(&ifp->ifilter, tmp, !fgt->graph); } else { - ret = av_buffersrc_add_frame(ifp->filter, tmp); + if (ifp->type_src == AVMEDIA_TYPE_VIDEO) { + if (ifp->displaymatrix_applied) + av_frame_remove_side_data(tmp, AV_FRAME_DATA_DISPLAYMATRIX); + } + ret = av_buffersrc_add_frame(ifilter->filter, tmp); } av_frame_free(&tmp); if (ret < 0) @@ -2003,9 +2053,9 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) /* send the EOFs for the finished inputs */ for (int i = 0; i < fg->nb_inputs; i++) { - InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); + InputFilter *ifilter = fg->inputs[i]; if (fgt->eof_in[i]) { - ret = av_buffersrc_add_frame(ifp->filter, NULL); + ret = av_buffersrc_add_frame(ifilter->filter, NULL); if (ret < 0) goto fail; have_input_eof = 1; @@ -2035,7 +2085,7 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr if (ret < 0) return ret; - ifp->time_base = (ifp->type == AVMEDIA_TYPE_AUDIO) ? (AVRational){ 1, frame->sample_rate } : + ifp->time_base = (ifilter->type == AVMEDIA_TYPE_AUDIO) ? (AVRational){ 1, frame->sample_rate } : (ifp->opts.flags & IFILTER_FLAG_CFR) ? av_inv_q(ifp->opts.framerate) : frame->time_base; @@ -2052,11 +2102,38 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr if (ret < 0) return ret; + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); + for (int i = 0; i < frame->nb_side_data; i++) { + const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type); + + if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL)) + continue; + + ret = av_frame_side_data_clone(&ifp->side_data, + &ifp->nb_side_data, + frame->side_data[i], 0); + if (ret < 0) + return ret; + } + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); if (sd) memcpy(ifp->displaymatrix, sd->data, sizeof(ifp->displaymatrix)); ifp->displaymatrix_present = !!sd; + /* Copy downmix related side data to InputFilterPriv so it may be propagated + * to the filter chain even though it's not "global", as filters like aresample + * require this information during init and not when remixing a frame */ + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO); + if (sd) { + ret = av_frame_side_data_clone(&ifp->side_data, + &ifp->nb_side_data, sd, 0); + if (ret < 0) + return ret; + memcpy(&ifp->downmixinfo, sd->data, sizeof(ifp->downmixinfo)); + } + ifp->downmixinfo_present = !!sd; + return 0; } @@ -2098,12 +2175,11 @@ static int choose_input(const FilterGraph *fg, const FilterGraphThread *fgt) for (int i = 0; i < fg->nb_inputs; i++) { InputFilter *ifilter = fg->inputs[i]; - InputFilterPriv *ifp = ifp_from_ifilter(ifilter); if (fgt->eof_in[i]) continue; - nb_requests = av_buffersrc_get_nb_failed_requests(ifp->filter); + nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter); if (nb_requests > nb_requests_max) { nb_requests_max = nb_requests; best_input = i; @@ -2147,7 +2223,7 @@ static int choose_out_timebase(OutputFilterPriv *ofp, AVFrame *frame) fr = fps->framerate; if (!fr.num) { - AVRational fr_sink = av_buffersink_get_frame_rate(ofp->filter); + AVRational fr_sink = av_buffersink_get_frame_rate(ofilter->filter); if (fr_sink.num > 0 && fr_sink.den > 0) fr = fr_sink; } @@ -2192,8 +2268,8 @@ finish: return 0; } -static double adjust_frame_pts_to_encoder_tb(AVFrame *frame, AVRational tb_dst, - int64_t start_time) +static double adjust_frame_pts_to_encoder_tb(void *logctx, AVFrame *frame, + AVRational tb_dst, int64_t start_time) { double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but with higher precision @@ -2221,7 +2297,8 @@ static double adjust_frame_pts_to_encoder_tb(AVFrame *frame, AVRational tb_dst, early_exit: if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n", + av_log(logctx, AV_LOG_INFO, + "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n", frame ? av_ts2str(frame->pts) : "NULL", av_ts2timestr(frame->pts, &tb_dst), float_pts, tb_dst.num, tb_dst.den); @@ -2256,7 +2333,8 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame, duration = frame->duration * av_q2d(frame->time_base) / av_q2d(ofp->tb_out); - sync_ipts = adjust_frame_pts_to_encoder_tb(frame, ofp->tb_out, ofp->ts_offset); + sync_ipts = adjust_frame_pts_to_encoder_tb(ofilter->graph, frame, + ofp->tb_out, ofp->ts_offset); /* delta0 is the "drift" between the input frame and * where it would fall in the output. */ delta0 = sync_ipts - ofp->next_pts; @@ -2380,6 +2458,11 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) if (ret < 0) return ret; } + av_frame_side_data_free(&frame->side_data, &frame->nb_side_data); + ret = clone_side_data(&frame->side_data, &frame->nb_side_data, + ofp->side_data, ofp->nb_side_data, 0); + if (ret < 0) + return ret; fd = frame_data(frame); if (!fd) @@ -2393,16 +2476,16 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) "No filtered frames for output stream, trying to " "initialize anyway.\n"); - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, frame); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, frame); if (ret < 0) { av_frame_unref(frame); return ret; } } - fgt->eof_out[ofp->index] = 1; + fgt->eof_out[ofp->ofilter.index] = 1; - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, NULL); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, NULL); return (ret == AVERROR_EOF) ? 0 : ret; } @@ -2455,12 +2538,12 @@ static int fg_output_frame(OutputFilterPriv *ofp, FilterGraphThread *fgt, } // send the frame to consumers - ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->index, frame_out); + ret = sch_filter_send(fgp->sch, fgp->sch_idx, ofp->ofilter.index, frame_out); if (ret < 0) { av_frame_unref(frame_out); - if (!fgt->eof_out[ofp->index]) { - fgt->eof_out[ofp->index] = 1; + if (!fgt->eof_out[ofp->ofilter.index]) { + fgt->eof_out[ofp->ofilter.index] = 1; fgp->nb_outputs_done++; } @@ -2493,13 +2576,13 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, AVFrame *frame) { FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph); - AVFilterContext *filter = ofp->filter; + AVFilterContext *filter = ofp->ofilter.filter; FrameData *fd; int ret; ret = av_buffersink_get_frame_flags(filter, frame, AV_BUFFERSINK_FLAG_NO_REQUEST); - if (ret == AVERROR_EOF && !fgt->eof_out[ofp->index]) { + if (ret == AVERROR_EOF && !fgt->eof_out[ofp->ofilter.index]) { ret = fg_output_frame(ofp, fgt, NULL); return (ret < 0) ? ret : 1; } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -2511,7 +2594,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, return ret; } - if (fgt->eof_out[ofp->index]) { + if (fgt->eof_out[ofp->ofilter.index]) { av_frame_unref(frame); return 0; } @@ -2592,25 +2675,6 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt, while (fgp->nb_outputs_done < fg->nb_outputs) { int ret; - ret = avfilter_graph_request_oldest(fgt->graph); - if (ret == AVERROR(EAGAIN)) { - fgt->next_in = choose_input(fg, fgt); - break; - } else if (ret < 0) { - if (ret == AVERROR_EOF) - av_log(fg, AV_LOG_VERBOSE, "Filtergraph returned EOF, finishing\n"); - else - av_log(fg, AV_LOG_ERROR, - "Error requesting a frame from the filtergraph: %s\n", - av_err2str(ret)); - return ret; - } - fgt->next_in = fg->nb_inputs; - - // return after one iteration, so that scheduler can rate-control us - if (did_step && fgp->have_sources) - return 0; - /* Reap all buffers present in the buffer sinks */ for (int i = 0; i < fg->nb_outputs; i++) { OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[i]); @@ -2622,10 +2686,30 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt, return ret; } } + + // return after one iteration, so that scheduler can rate-control us + if (did_step && fgp->have_sources) + return 0; + + ret = avfilter_graph_request_oldest(fgt->graph); + if (ret == AVERROR(EAGAIN)) { + fgt->next_in = choose_input(fg, fgt); + return 0; + } else if (ret < 0) { + if (ret == AVERROR_EOF) + av_log(fg, AV_LOG_VERBOSE, "Filtergraph returned EOF, finishing\n"); + else + av_log(fg, AV_LOG_ERROR, + "Error requesting a frame from the filtergraph: %s\n", + av_err2str(ret)); + return ret; + } + fgt->next_in = fg->nb_inputs; + did_step = 1; } - return (fgp->nb_outputs_done == fg->nb_outputs) ? AVERROR_EOF : 0; + return AVERROR_EOF; } static void sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational tb) @@ -2644,7 +2728,7 @@ static void sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational tb if (pts2 >= ifp->sub2video.end_pts || ifp->sub2video.initialize) /* if we have hit the end of the current displayed subpicture, or if we need to initialize the system, update the - overlayed subpicture and its start/end times */ + overlaid subpicture and its start/end times */ sub2video_update(ifp, pts2 + 1, NULL); else sub2video_push_ref(ifp, pts2); @@ -2686,7 +2770,7 @@ static int sub2video_frame(InputFilter *ifilter, AVFrame *frame, int buffer) if (ifp->sub2video.end_pts < INT64_MAX) sub2video_update(ifp, INT64_MAX, NULL); - return av_buffersrc_add_frame(ifp->filter, NULL); + return av_buffersrc_add_frame(ifilter->filter, NULL); } ifp->width = frame->width ? frame->width : ifp->width; @@ -2703,16 +2787,16 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter, InputFilterPriv *ifp = ifp_from_ifilter(ifilter); int ret; - if (fgt->eof_in[ifp->index]) + if (fgt->eof_in[ifilter->index]) return 0; - fgt->eof_in[ifp->index] = 1; + fgt->eof_in[ifilter->index] = 1; - if (ifp->filter) { + if (ifilter->filter) { pts = av_rescale_q_rnd(pts, tb, ifp->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); - ret = av_buffersrc_close(ifp->filter, pts, AV_BUFFERSRC_FLAG_PUSH); + ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH); if (ret < 0) return ret; } else { @@ -2732,17 +2816,24 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter, if (ret < 0) return ret; + av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data); + ret = clone_side_data(&ifp->side_data, &ifp->nb_side_data, + ifp->opts.fallback->side_data, + ifp->opts.fallback->nb_side_data, 0); + if (ret < 0) + return ret; + if (ifilter_has_all_input_formats(ifilter->graph)) { ret = configure_filtergraph(ifilter->graph, fgt); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error initializing filters!\n"); + av_log(ifilter->graph, AV_LOG_ERROR, "Error initializing filters!\n"); return ret; } } } if (ifp->format < 0) { - av_log(NULL, AV_LOG_ERROR, + av_log(ifilter->graph, AV_LOG_ERROR, "Cannot determine format of input %s after EOF\n", ifp->opts.name); return AVERROR_INVALIDDATA; @@ -2756,7 +2847,8 @@ enum ReinitReason { VIDEO_CHANGED = (1 << 0), AUDIO_CHANGED = (1 << 1), MATRIX_CHANGED = (1 << 2), - HWACCEL_CHANGED = (1 << 3) + DOWNMIX_CHANGED = (1 << 3), + HWACCEL_CHANGED = (1 << 4) }; static const char *unknown_if_null(const char *str) @@ -2773,7 +2865,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, int need_reinit = 0, ret; /* determine if the parameters for this input changed */ - switch (ifp->type) { + switch (ifilter->type) { case AVMEDIA_TYPE_AUDIO: if (ifp->format != frame->format || ifp->sample_rate != frame->sample_rate || @@ -2797,6 +2889,20 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, } else if (ifp->displaymatrix_present) need_reinit |= MATRIX_CHANGED; + if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO)) { + if (!ifp->downmixinfo_present || + memcmp(sd->data, &ifp->downmixinfo, sizeof(ifp->downmixinfo))) + need_reinit |= DOWNMIX_CHANGED; + } else if (ifp->downmixinfo_present) + need_reinit |= DOWNMIX_CHANGED; + + if (need_reinit && fgt->graph && (ifp->opts.flags & IFILTER_FLAG_DROPCHANGED)) { + ifp->nb_dropped++; + av_log_once(fg, AV_LOG_WARNING, AV_LOG_DEBUG, &ifp->drop_warned, "Avoiding reinit; dropping frame pts: %s bound for %s\n", av_ts2str(frame->pts), ifilter->name); + av_frame_unref(frame); + return 0; + } + if (!(ifp->opts.flags & IFILTER_FLAG_REINIT) && fgt->graph) need_reinit = 0; @@ -2851,6 +2957,8 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, } if (need_reinit & MATRIX_CHANGED) av_bprintf(&reason, "display matrix changed, "); + if (need_reinit & DOWNMIX_CHANGED) + av_bprintf(&reason, "downmix medatata changed, "); if (need_reinit & HWACCEL_CHANGED) av_bprintf(&reason, "hwaccel changed, "); if (reason.len > 1) @@ -2877,7 +2985,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, return AVERROR(ENOMEM); fd->wallclock[LATENCY_PROBE_FILTER_PRE] = av_gettime_relative(); - ret = av_buffersrc_add_frame_flags(ifp->filter, frame, + ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, AV_BUFFERSRC_FLAG_PUSH); if (ret < 0) { av_frame_unref(frame); @@ -2896,7 +3004,7 @@ static void fg_thread_set_name(const FilterGraph *fg) OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[0]); snprintf(name, sizeof(name), "%cf%s", av_get_media_type_string(ofp->ofilter.type)[0], - ofp->name); + ofp->ofilter.output_name); } else { snprintf(name, sizeof(name), "fc%d", fg->index); } @@ -2975,7 +3083,7 @@ static int filter_thread(void *arg) while (1) { InputFilter *ifilter; - InputFilterPriv *ifp; + InputFilterPriv *ifp = NULL; enum FrameOpaque o; unsigned input_idx = fgt.next_in; @@ -3033,10 +3141,12 @@ static int filter_thread(void *arg) goto finish; read_frames: - // retrieve all newly avalable frames + // retrieve all newly available frames ret = read_frames(fg, &fgt, fgt.frame); if (ret == AVERROR_EOF) { av_log(fg, AV_LOG_VERBOSE, "All consumers returned EOF\n"); + if (ifp && ifp->opts.flags & IFILTER_FLAG_DROPCHANGED) + av_log(fg, AV_LOG_INFO, "Total changed input frames dropped : %"PRId64"\n", ifp->nb_dropped); break; } else if (ret < 0) { av_log(fg, AV_LOG_ERROR, "Error sending frames to consumers: %s\n", @@ -3057,6 +3167,10 @@ read_frames: } finish: + + if (print_graphs || print_graphs_file) + print_filtergraph(fg, fgt.graph); + // EOF is normal termination if (ret == AVERROR_EOF) ret = 0; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 71ff9b45ab..25f66dd185 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -581,9 +581,9 @@ static int bsf_init(MuxStream *ms) int ret; if (!ctx) - return avcodec_parameters_copy(ost->st->codecpar, ost->par_in); + return avcodec_parameters_copy(ost->st->codecpar, ms->par_in); - ret = avcodec_parameters_copy(ctx->par_in, ost->par_in); + ret = avcodec_parameters_copy(ctx->par_in, ms->par_in); if (ret < 0) return ret; @@ -608,12 +608,29 @@ static int bsf_init(MuxStream *ms) return 0; } -int of_stream_init(OutputFile *of, OutputStream *ost) +int of_stream_init(OutputFile *of, OutputStream *ost, + const AVCodecContext *enc_ctx) { Muxer *mux = mux_from_of(of); MuxStream *ms = ms_from_ost(ost); int ret; + if (enc_ctx) { + // use upstream time base unless it has been overridden previously + if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) + ost->st->time_base = av_add_q(enc_ctx->time_base, (AVRational){0, 1}); + + ost->st->avg_frame_rate = enc_ctx->framerate; + ost->st->sample_aspect_ratio = enc_ctx->sample_aspect_ratio; + + ret = avcodec_parameters_from_context(ms->par_in, enc_ctx); + if (ret < 0) { + av_log(ost, AV_LOG_FATAL, + "Error initializing the output stream codec parameters.\n"); + return ret; + } + } + /* initialize bitstream filters for the output stream * needs to be done here, because the codec id for streamcopy is not * known until now */ @@ -644,8 +661,8 @@ static int check_written(OutputFile *of) total_packets_written += packets_written; - if (ost->enc_ctx && - (ost->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) + if (ost->enc && + (ost->enc->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) != AV_CODEC_FLAG_PASS1) pass1_used = 0; @@ -706,9 +723,9 @@ static void mux_final_stats(Muxer *mux) of->index, j, av_get_media_type_string(type)); if (ost->enc) { av_log(of, AV_LOG_VERBOSE, "%"PRIu64" frames encoded", - ost->frames_encoded); + ost->enc->frames_encoded); if (type == AVMEDIA_TYPE_AUDIO) - av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded); + av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->enc->samples_encoded); av_log(of, AV_LOG_VERBOSE, "; "); } @@ -806,7 +823,7 @@ static void ost_free(OutputStream **post) ost->logfile = NULL; } - avcodec_parameters_free(&ost->par_in); + avcodec_parameters_free(&ms->par_in); av_bsf_free(&ms->bsf_ctx); av_packet_free(&ms->bsf_pkt); @@ -820,10 +837,6 @@ static void ost_free(OutputStream **post) av_freep(&ost->attachment_filename); - if (ost->enc_ctx) - av_freep(&ost->enc_ctx->stats_in); - avcodec_free_context(&ost->enc_ctx); - enc_stats_uninit(&ost->enc_stats_pre); enc_stats_uninit(&ost->enc_stats_post); enc_stats_uninit(&ms->stats); diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h index 22d728a919..4ca8ab73a4 100644 --- a/fftools/ffmpeg_mux.h +++ b/fftools/ffmpeg_mux.h @@ -36,6 +36,12 @@ typedef struct MuxStream { OutputStream ost; + /** + * Codec parameters for packets submitted to the muxer (i.e. before + * bitstream filtering, if any). + */ + AVCodecParameters *par_in; + // name used for logging char log_name[32]; @@ -79,6 +85,10 @@ typedef struct MuxStream { int ts_drop; #endif + AVRational frame_rate; + AVRational max_frame_rate; + int force_fps; + const char *apad; } MuxStream; @@ -113,7 +123,7 @@ typedef struct Muxer { int mux_check_init(void *arg); -static MuxStream *ms_from_ost(OutputStream *ost) +static inline MuxStream *ms_from_ost(OutputStream *ost) { return (MuxStream*)ost; } diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 8afb018de8..17977eb07f 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -67,8 +67,9 @@ static int check_opt_bitexact(void *ctx, const AVDictionary *opts, } static int choose_encoder(const OptionsContext *o, AVFormatContext *s, - OutputStream *ost, const AVCodec **enc) + MuxStream *ms, const AVCodec **enc) { + OutputStream *ost = &ms->ost; enum AVMediaType type = ost->type; const char *codec_name = NULL; @@ -90,20 +91,20 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s, } if (!codec_name) { - ost->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); - *enc = avcodec_find_encoder(ost->par_in->codec_id); + ms->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); + *enc = avcodec_find_encoder(ms->par_in->codec_id); if (!*enc) { av_log(ost, AV_LOG_FATAL, "Automatic encoder selection failed " "Default encoder for format %s (codec %s) is " "probably disabled. Please choose an encoder manually.\n", - s->oformat->name, avcodec_get_name(ost->par_in->codec_id)); + s->oformat->name, avcodec_get_name(ms->par_in->codec_id)); return AVERROR_ENCODER_NOT_FOUND; } } else if (strcmp(codec_name, "copy")) { int ret = find_codec(ost, codec_name, ost->type, 1, enc); if (ret < 0) return ret; - ost->par_in->codec_id = (*enc)->id; + ms->par_in->codec_id = (*enc)->id; } return 0; @@ -423,27 +424,6 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, #endif opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters); - if (!ost->enc) { - if ( -#if FFMPEG_OPT_FILTER_SCRIPT - filters_script || -#endif - filters) { - av_log(ost, AV_LOG_ERROR, - "%s '%s' was specified, but codec copy was selected. " - "Filtering and streamcopy cannot be used together.\n", -#if FFMPEG_OPT_FILTER_SCRIPT - filters ? "Filtergraph" : "Filtergraph script", - filters ? filters : filters_script -#else - "Filtergraph", filters -#endif - ); - return AVERROR(ENOSYS); - } - return 0; - } - if (!ost->ist) { if ( #if FFMPEG_OPT_FILTER_SCRIPT @@ -554,7 +534,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) return AV_PIX_FMT_NONE; } - ret = avcodec_get_supported_config(ost->enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, + ret = avcodec_get_supported_config(ost->enc->enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, 0, (const void **) &fmts, NULL); if (ret < 0) return AV_PIX_FMT_NONE; @@ -586,7 +566,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) } if (fmts && !fmt_in_list(fmts, fmt)) - fmt = choose_pixel_fmt(ost->enc_ctx, fmt); + fmt = choose_pixel_fmt(ost->enc->enc_ctx, fmt); return fmt; } @@ -604,13 +584,13 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, st = ost->st; opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate); - if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) { + if (frame_rate && av_parse_video_rate(&ms->frame_rate, frame_rate) < 0) { av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate); return AVERROR(EINVAL); } opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate); - if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) { + if (max_frame_rate && av_parse_video_rate(&ms->max_frame_rate, max_frame_rate) < 0) { av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate); return AVERROR(EINVAL); } @@ -631,8 +611,8 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, ost->frame_aspect_ratio = q; } - if (ost->enc_ctx) { - AVCodecContext *video_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *video_enc = ost->enc->enc_ctx; const char *p = NULL, *fps_mode = NULL; const char *frame_size = NULL; const char *frame_pix_fmt = NULL; @@ -745,10 +725,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, ost->logfile_prefix ? ost->logfile_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX, ost_idx); - if (!strcmp(ost->enc_ctx->codec->name, "libx264") || !strcmp(ost->enc_ctx->codec->name, "libvvenc")) { - if (av_opt_is_set_to_default_by_name(ost->enc_ctx, "stats", + if (!strcmp(video_enc->codec->name, "libx264") || !strcmp(video_enc->codec->name, "libvvenc")) { + if (av_opt_is_set_to_default_by_name(video_enc, "stats", AV_OPT_SEARCH_CHILDREN) > 0) - av_opt_set(ost->enc_ctx, "stats", logfilename, + av_opt_set(video_enc, "stats", logfilename, AV_OPT_SEARCH_CHILDREN); } else { if (video_enc->flags & AV_CODEC_FLAG_PASS2) { @@ -774,7 +754,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } } - opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps); + opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps); #if FFMPEG_OPT_TOP ost->top_field_first = -1; @@ -795,7 +775,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, return ret; } - if ((ost->frame_rate.num || ost->max_frame_rate.num) && + if ((ms->frame_rate.num || ms->max_frame_rate.num) && !(*vsync_method == VSYNC_AUTO || *vsync_method == VSYNC_CFR || *vsync_method == VSYNC_VSCFR)) { av_log(ost, AV_LOG_FATAL, "One of -r/-fpsmax was specified " @@ -804,7 +784,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } if (*vsync_method == VSYNC_AUTO) { - if (ost->frame_rate.num || ost->max_frame_rate.num) { + if (ms->frame_rate.num || ms->max_frame_rate.num) { *vsync_method = VSYNC_CFR; } else if (!strcmp(oc->oformat->name, "avi")) { *vsync_method = VSYNC_VFR; @@ -841,8 +821,8 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o, AVFormatContext *oc = mux->fc; AVStream *st = ost->st; - if (ost->enc_ctx) { - AVCodecContext *audio_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *audio_enc = ost->enc->enc_ctx; int channels = 0; const char *layout = NULL; const char *sample_fmt = NULL; @@ -880,8 +860,8 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, st = ost->st; - if (ost->enc_ctx) { - AVCodecContext *subtitle_enc = ost->enc_ctx; + if (ost->enc) { + AVCodecContext *subtitle_enc = ost->enc->enc_ctx; AVCodecDescriptor const *input_descriptor = avcodec_descriptor_get(ost->ist->par->codec_id); @@ -916,14 +896,16 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, static int ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, - const OptionsContext *o, char *filters, + const OptionsContext *o, AVRational enc_tb, enum VideoSyncMethod vsync_method, int keep_pix_fmt, int autoscale, int threads_manual, - const ViewSpecifier *vs) + const ViewSpecifier *vs, + SchedulerNode *src) { OutputStream *ost = &ms->ost; - AVCodecContext *enc_ctx = ost->enc_ctx; + AVCodecContext *enc_ctx = ost->enc->enc_ctx; char name[16]; + char *filters = NULL; int ret; OutputFilterOptions opts = { @@ -936,6 +918,8 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, .color_space = enc_ctx->colorspace, .color_range = enc_ctx->color_range, .vsync_method = vsync_method, + .frame_rate = ms->frame_rate, + .max_frame_rate = ms->max_frame_rate, .sample_rate = enc_ctx->sample_rate, .ch_layout = enc_ctx->ch_layout, .sws_opts = o->g->sws_dict, @@ -946,6 +930,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, .ts_offset = mux->of.start_time == AV_NOPTS_VALUE ? 0 : mux->of.start_time, .vs = vs, + .nb_threads = -1, .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt | OFILTER_FLAG_AUTOSCALE * !!autoscale | @@ -962,7 +947,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, if (ret < 0) return ret; } - if (!ost->force_fps) { + if (!ms->force_fps) { ret = avcodec_get_supported_config(enc_ctx, NULL, AV_CODEC_CONFIG_FRAME_RATE, 0, (const void **) &opts.frame_rates, NULL); @@ -998,46 +983,77 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, } if (threads_manual) { - ret = av_opt_get(enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); + ret = av_opt_get_int(enc_ctx, "threads", 0, &opts.nb_threads); if (ret < 0) return ret; } + ret = ost_get_filters(o, mux->fc, ost, &filters); + if (ret < 0) + return ret; + if (ofilter) { + av_assert0(!filters); ost->filter = ofilter; - ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc, &opts); + ret = ofilter_bind_enc(ofilter, ms->sch_idx_enc, &opts); } else { - ret = init_simple_filtergraph(ost->ist, ost, filters, - mux->sch, ms->sch_idx_enc, &opts); + ret = fg_create_simple(&ost->fg_simple, ost->ist, filters, + mux->sch, ms->sch_idx_enc, &opts); + if (ret >= 0) + ost->filter = ost->fg_simple->outputs[0]; + } - av_freep(&opts.nb_threads); if (ret < 0) return ret; - ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), - SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); - if (ret < 0) - return ret; + *src = SCH_ENC(ms->sch_idx_enc); - return ret; + return 0; } -static int streamcopy_init(const Muxer *mux, OutputStream *ost, AVDictionary **encoder_opts) +static int streamcopy_init(const OptionsContext *o, const Muxer *mux, + OutputStream *ost, AVDictionary **encoder_opts) { MuxStream *ms = ms_from_ost(ost); const InputStream *ist = ost->ist; const InputFile *ifile = ist->file; - AVCodecParameters *par = ost->par_in; + AVCodecParameters *par = ms->par_in; uint32_t codec_tag = par->codec_tag; AVCodecContext *codec_ctx = NULL; - AVRational fr = ost->frame_rate; + AVRational fr = ms->frame_rate; int ret = 0; + const char *filters = NULL; +#if FFMPEG_OPT_FILTER_SCRIPT + const char *filters_script = NULL; + + opt_match_per_stream_str(ost, &o->filter_scripts, mux->fc, ost->st, &filters_script); +#endif + opt_match_per_stream_str(ost, &o->filters, mux->fc, ost->st, &filters); + + if ( +#if FFMPEG_OPT_FILTER_SCRIPT + filters_script || +#endif + filters) { + av_log(ost, AV_LOG_ERROR, + "%s '%s' was specified, but codec copy was selected. " + "Filtering and streamcopy cannot be used together.\n", +#if FFMPEG_OPT_FILTER_SCRIPT + filters ? "Filtergraph" : "Filtergraph script", + filters ? filters : filters_script +#else + "Filtergraph", filters +#endif + ); + return AVERROR(EINVAL); + } + codec_ctx = avcodec_alloc_context3(NULL); if (!codec_ctx) return AVERROR(ENOMEM); @@ -1139,6 +1155,28 @@ fail: return ret; } +static int set_encoder_id(OutputStream *ost, const AVCodec *codec) +{ + const char *cname = codec->name; + uint8_t *encoder_string; + int encoder_string_len; + + encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; + encoder_string = av_mallocz(encoder_string_len); + if (!encoder_string) + return AVERROR(ENOMEM); + + if (!ost->file->bitexact && !ost->bitexact) + av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); + else + av_strlcpy(encoder_string, "Lavc ", encoder_string_len); + av_strlcat(encoder_string, cname, encoder_string_len); + av_dict_set(&ost->st->metadata, "encoder", encoder_string, + AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); + + return 0; +} + static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, InputStream *ist, OutputFilter *ofilter, const ViewSpecifier *vs, OutputStream **post) @@ -1148,13 +1186,14 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, OutputStream *ost; const AVCodec *enc; AVStream *st; + SchedulerNode src = { .type = SCH_NODE_TYPE_NONE }; AVDictionary *encoder_opts = NULL; int ret = 0, keep_pix_fmt = 0, autoscale = 1; int threads_manual = 0; AVRational enc_tb = { 0, 0 }; enum VideoSyncMethod vsync_method = VSYNC_AUTO; const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL; - char *filters = NULL, *next; + char *next; double qscale = -1; st = avformat_new_stream(oc, NULL); @@ -1198,8 +1237,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, } } - ost->par_in = avcodec_parameters_alloc(); - if (!ost->par_in) + ms->par_in = avcodec_parameters_alloc(); + if (!ms->par_in) return AVERROR(ENOMEM); ms->last_mux_dts = AV_NOPTS_VALUE; @@ -1207,27 +1246,23 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ost->st = st; ost->ist = ist; ost->kf.ref_pts = AV_NOPTS_VALUE; - ost->par_in->codec_type = type; + ms->par_in->codec_type = type; st->codecpar->codec_type = type; - ret = choose_encoder(o, oc, ost, &enc); + ret = choose_encoder(o, oc, ms, &enc); if (ret < 0) { av_log(ost, AV_LOG_FATAL, "Error selecting an encoder\n"); return ret; } if (enc) { - ost->enc_ctx = avcodec_alloc_context3(enc); - if (!ost->enc_ctx) - return AVERROR(ENOMEM); - ret = sch_add_enc(mux->sch, encoder_thread, ost, ost->type == AVMEDIA_TYPE_SUBTITLE ? NULL : enc_open); if (ret < 0) return ret; ms->sch_idx_enc = ret; - ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc); + ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc, ost); if (ret < 0) return ret; @@ -1262,21 +1297,21 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (!ms->pkt) return AVERROR(ENOMEM); - if (ost->enc_ctx) { + if (ost->enc) { AVIOContext *s = NULL; char *buf = NULL, *arg = NULL; const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL; const char *enc_time_base = NULL, *preset = NULL; - ret = filter_codec_opts(o->g->codec_opts, ost->enc_ctx->codec_id, - oc, st, ost->enc_ctx->codec, &encoder_opts, + ret = filter_codec_opts(o->g->codec_opts, enc->id, + oc, st, enc, &encoder_opts, &mux->enc_opts_used); if (ret < 0) goto fail; opt_match_per_stream_str(ost, &o->presets, oc, st, &preset); opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale); - if (preset && (!(ret = get_preset_file_2(preset, ost->enc_ctx->codec->name, &s)))) { + if (preset && (!(ret = get_preset_file_2(preset, enc->name, &s)))) { AVBPrint bprint; av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); do { @@ -1376,7 +1411,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); - ret = av_opt_set_dict2(ost->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set_dict2(ost->enc->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", av_err2str(ret)); @@ -1389,7 +1424,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, // default to automatic thread count if (!threads_manual) - ost->enc_ctx->thread_count = 0; + ost->enc->enc_ctx->thread_count = 0; } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL, &encoder_opts, @@ -1401,8 +1436,14 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (o->bitexact) { ost->bitexact = 1; - } else if (ost->enc_ctx) { - ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); + } else if (ost->enc) { + ost->bitexact = !!(ost->enc->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); + } + + if (enc) { + ret = set_encoder_id(ost, enc); + if (ret < 0) + return ret; } opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base); @@ -1447,15 +1488,15 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, tag = AV_RL32(buf); } ost->st->codecpar->codec_tag = tag; - ost->par_in->codec_tag = tag; - if (ost->enc_ctx) - ost->enc_ctx->codec_tag = tag; + ms->par_in->codec_tag = tag; + if (ost->enc) + ost->enc->enc_ctx->codec_tag = tag; } opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale); - if (ost->enc_ctx && qscale >= 0) { - ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; - ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; + if (ost->enc && qscale >= 0) { + ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; + ost->enc->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; } if (ms->sch_idx >= 0) { @@ -1477,8 +1518,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat, oc, st, &ost->fix_sub_duration_heartbeat); - if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc_ctx) - ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc) + ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes, oc, st, &ms->copy_initial_nonkeyframes); @@ -1490,48 +1531,43 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (ret < 0) goto fail; - if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { - ret = ost_get_filters(o, oc, ost, &filters); - if (ret < 0) - goto fail; - } - if (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { - ret = ost_bind_filter(mux, ms, ofilter, o, filters, enc_tb, vsync_method, - keep_pix_fmt, autoscale, threads_manual, vs); + ret = ost_bind_filter(mux, ms, ofilter, o, enc_tb, vsync_method, + keep_pix_fmt, autoscale, threads_manual, vs, &src); if (ret < 0) goto fail; } else if (ost->ist) { - int sched_idx = ist_output_add(ost->ist, ost); - if (sched_idx < 0) { + ret = ist_use(ost->ist, !!ost->enc, NULL, &src); + if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error binding an input stream\n"); - ret = sched_idx; goto fail; } - ms->sch_idx_src = sched_idx; + ms->sch_idx_src = src.idx; + // src refers to a decoder for transcoding, demux stream otherwise if (ost->enc) { - ret = sch_connect(mux->sch, SCH_DEC_OUT(sched_idx, 0), - SCH_ENC(ms->sch_idx_enc)); - if (ret < 0) - goto fail; - - ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), - SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); - if (ret < 0) - goto fail; - } else { - ret = sch_connect(mux->sch, SCH_DSTREAM(ost->ist->file->index, sched_idx), - SCH_MSTREAM(ost->file->index, ms->sch_idx)); + ret = sch_connect(mux->sch, + src, SCH_ENC(ms->sch_idx_enc)); if (ret < 0) goto fail; + src = SCH_ENC(ms->sch_idx_enc); } } + if (src.type != SCH_NODE_TYPE_NONE) { + ret = sch_connect(mux->sch, + src, SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); + if (ret < 0) + goto fail; + } else { + // only attachment streams don't have a source + av_assert0(type == AVMEDIA_TYPE_ATTACHMENT && ms->sch_idx < 0); + } + if (ost->ist && !ost->enc) { - ret = streamcopy_init(mux, ost, &encoder_opts); + ret = streamcopy_init(o, mux, ost, &encoder_opts); if (ret < 0) goto fail; } @@ -1557,7 +1593,7 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) { AVFormatContext *oc = mux->fc; InputStream *best_ist = NULL; - int best_score = 0; + int64_t best_score = 0; int qcr; /* video: highest resolution */ @@ -1568,16 +1604,16 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) for (int j = 0; j < nb_input_files; j++) { InputFile *ifile = input_files[j]; InputStream *file_best_ist = NULL; - int file_best_score = 0; + int64_t file_best_score = 0; for (int i = 0; i < ifile->nb_streams; i++) { InputStream *ist = ifile->streams[i]; - int score; + int64_t score; if (ist->user_set_discard == AVDISCARD_ALL || ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) continue; - score = ist->st->codecpar->width * ist->st->codecpar->height + score = ist->st->codecpar->width * (int64_t)ist->st->codecpar->height + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) @@ -1799,6 +1835,7 @@ loop_end: static int of_add_attachments(Muxer *mux, const OptionsContext *o) { + MuxStream *ms; OutputStream *ost; int err; @@ -1866,9 +1903,11 @@ read_fail: return err; } + ms = ms_from_ost(ost); + ost->attachment_filename = attachment_filename; - ost->par_in->extradata = attachment; - ost->par_in->extradata_size = len; + ms->par_in->extradata = attachment; + ms->par_in->extradata_size = len; p = strrchr(o->attachments[i], '/'); av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE); @@ -2009,7 +2048,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int limit_frames = 0, limit_frames_av_enc = 0; #define IS_AV_ENC(ost, type) \ - (ost->enc_ctx && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) + (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) #define IS_INTERLEAVED(type) (type != AVMEDIA_TYPE_ATTACHMENT) for (int i = 0; i < oc->nb_streams; i++) { @@ -2021,8 +2060,8 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, nb_interleaved += IS_INTERLEAVED(type); nb_av_enc += IS_AV_ENC(ost, type); - nb_audio_fs += (ost->enc_ctx && type == AVMEDIA_TYPE_AUDIO && - !(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); + nb_audio_fs += (ost->enc && type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); limit_frames |= ms->max_frames < INT64_MAX; limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); @@ -2977,9 +3016,6 @@ static int copy_meta(Muxer *mux, const OptionsContext *o) if (!ost->ist) /* this is true e.g. for attached files */ continue; av_dict_copy(&ost->st->metadata, ost->ist->st->metadata, AV_DICT_DONT_OVERWRITE); - if (ost->enc_ctx) { - av_dict_set(&ost->st->metadata, "encoder", NULL, 0); - } } return 0; @@ -3056,7 +3092,7 @@ finish: return ret; } -const char *const forced_keyframes_const_names[] = { +static const char *const forced_keyframes_const_names[] = { "n", "n_forced", "prev_forced_n", @@ -3158,7 +3194,7 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) mux->fc, ost->st, &forced_keyframes); if (!(ost->type == AVMEDIA_TYPE_VIDEO && - ost->enc_ctx && forced_keyframes)) + ost->enc && forced_keyframes)) continue; if (!strncmp(forced_keyframes, "expr:", 5)) { @@ -3385,7 +3421,7 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) OutputStream *ost = of->streams[i]; if (!ost->enc) { - err = of_stream_init(of, ost); + err = of_stream_init(of, ost, NULL); if (err < 0) return err; } diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index f639a1cf0a..d714a1523a 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -47,12 +47,12 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/stereo3d.h" +#include "graph/graphprint.h" HWDevice *filter_hw_device; char *vstats_filename; -float audio_drift_threshold = 0.1; float dts_delta_threshold = 10; float dts_error_threshold = 3600*30; @@ -75,7 +75,11 @@ int stdin_interaction = 1; float max_error_rate = 2.0/3; char *filter_nbthreads; int filter_complex_nbthreads = 0; +int filter_buffered_frames = 0; int vstats_version = 2; +int print_graphs = 0; +char *print_graphs_file = NULL; +char *print_graphs_format = NULL; int auto_conversion_filters = 1; int64_t stats_period = 500000; @@ -86,6 +90,15 @@ int ignore_unknown_streams = 0; int copy_unknown_streams = 0; int recast_media = 0; +// this struct is passed as the optctx argument +// to func_arg() for global options +typedef struct GlobalOptionsContext { + Scheduler *sch; + + char **filtergraphs; + int nb_filtergraphs; +} GlobalOptionsContext; + static void uninit_options(OptionsContext *o) { /* all OPT_SPEC and OPT_TYPE_STRING can be freed in generic way */ @@ -345,7 +358,7 @@ static void correct_input_start_times(void) if (copy_ts && start_at_zero) ifile->ts_offset = -new_start_time; else if (!copy_ts) { - abs_start_seek = is->start_time + (ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0; + abs_start_seek = is->start_time + ((ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0); ifile->ts_offset = abs_start_seek > new_start_time ? -abs_start_seek : -new_start_time; } else if (copy_ts) ifile->ts_offset = 0; @@ -611,8 +624,8 @@ static int opt_attach(void *optctx, const char *opt, const char *arg) static int opt_sdp_file(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - return sch_sdp_filename(sch, arg); + GlobalOptionsContext *go = optctx; + return sch_sdp_filename(go->sch, arg); } #if CONFIG_VAAPI @@ -1150,26 +1163,46 @@ static int opt_audio_qscale(void *optctx, const char *opt, const char *arg) static int opt_filter_complex(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - char *graph_desc = av_strdup(arg); + GlobalOptionsContext *go = optctx; + char *graph_desc; + int ret; + + graph_desc = av_strdup(arg); if (!graph_desc) return AVERROR(ENOMEM); - return fg_create(NULL, graph_desc, sch); + ret = GROW_ARRAY(go->filtergraphs, go->nb_filtergraphs); + if (ret < 0) { + av_freep(&graph_desc); + return ret; + } + go->filtergraphs[go->nb_filtergraphs - 1] = graph_desc; + + return 0; } #if FFMPEG_OPT_FILTER_SCRIPT static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg) { - Scheduler *sch = optctx; - char *graph_desc = file_read(arg); + GlobalOptionsContext *go = optctx; + char *graph_desc; + int ret; + + graph_desc = file_read(arg); if (!graph_desc) return AVERROR(EINVAL); av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -/filter_complex %s instead\n", opt, arg); - return fg_create(NULL, graph_desc, sch); + ret = GROW_ARRAY(go->filtergraphs, go->nb_filtergraphs); + if (ret < 0) { + av_freep(&graph_desc); + return ret; + } + go->filtergraphs[go->nb_filtergraphs - 1] = graph_desc; + + return 0; } #endif @@ -1346,6 +1379,7 @@ static int open_files(OptionGroupList *l, const char *inout, Scheduler *sch, int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) { + GlobalOptionsContext go = { .sch = sch }; OptionParseContext octx; const char *errmsg = NULL; int ret; @@ -1361,7 +1395,7 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) } /* apply global options */ - ret = parse_optgroup(sch, &octx.global_opts, options); + ret = parse_optgroup(&go, &octx.global_opts, options); if (ret < 0) { errmsg = "parsing global options"; goto fail; @@ -1370,6 +1404,14 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) /* configure terminal and setup signal handlers */ term_init(); + /* create complex filtergraphs */ + for (int i = 0; i < go.nb_filtergraphs; i++) { + ret = fg_create(NULL, go.filtergraphs[i], sch); + go.filtergraphs[i] = NULL; + if (ret < 0) + goto fail; + } + /* open input files */ ret = open_files(&octx.groups[GROUP_INFILE], "input", sch, ifile_open); if (ret < 0) { @@ -1405,6 +1447,10 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) goto fail; fail: + for (int i = 0; i < go.nb_filtergraphs; i++) + av_freep(&go.filtergraphs[i]); + av_freep(&go.filtergraphs); + uninit_parse_context(&octx); if (ret < 0 && ret != AVERROR_EXIT) { av_log(NULL, AV_LOG_FATAL, "Error %s: %s\n", @@ -1466,7 +1512,6 @@ static int opt_adrift_threshold(void *optctx, const char *opt, const char *arg) } #endif -static const char *const alt_bsf[] = { "absf", "vbsf", NULL }; static const char *const alt_channel_layout[] = { "ch_layout", NULL}; static const char *const alt_codec[] = { "c", "acodec", "vcodec", "scodec", "dcodec", NULL }; static const char *const alt_filter[] = { "af", "vf", NULL }; @@ -1598,6 +1643,9 @@ const OptionDef options[] = { { "readrate_initial_burst", OPT_TYPE_DOUBLE, OPT_OFFSET | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(readrate_initial_burst) }, "The initial amount of input to burst read before imposing any readrate", "seconds" }, + { "readrate_catchup", OPT_TYPE_FLOAT, OPT_OFFSET | OPT_EXPERT | OPT_INPUT, + { .off = OFFSET(readrate_catchup) }, + "Temporary readrate used to catch up if an input lags behind the specified readrate", "speed" }, { "target", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_PERFILE | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_target }, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" " @@ -1667,6 +1715,9 @@ const OptionDef options[] = { { "filter_threads", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_filter_threads }, "number of non-complex filter threads" }, + { "filter_buffered_frames", OPT_TYPE_INT, OPT_EXPERT, + { &filter_buffered_frames }, + "maximum number of buffered frames in a filter graph" }, #if FFMPEG_OPT_FILTER_SCRIPT { "filter_script", OPT_TYPE_STRING, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(filter_scripts) }, @@ -1675,6 +1726,9 @@ const OptionDef options[] = { { "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, { .off = OFFSET(reinit_filters) }, "reinit filtergraph on input parameter changes", "" }, + { "drop_changed", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, + { .off = OFFSET(drop_changed) }, + "drop frame instead of reiniting filtergraph on input parameter changes", "" }, { "filter_complex", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex }, "create a complex filtergraph", "graph_description" }, @@ -1689,6 +1743,15 @@ const OptionDef options[] = { { .func_arg = opt_filter_complex_script }, "deprecated, use -/filter_complex instead", "filename" }, #endif + { "print_graphs", OPT_TYPE_BOOL, 0, + { &print_graphs }, + "print execution graph data to stderr" }, + { "print_graphs_file", OPT_TYPE_STRING, 0, + { &print_graphs_file }, + "write execution graph data to the specified file", "filename" }, + { "print_graphs_format", OPT_TYPE_STRING, 0, + { &print_graphs_format }, + "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml)", "format" }, { "auto_conversion_filters", OPT_TYPE_BOOL, OPT_EXPERT, { &auto_conversion_filters }, "enable automatic conversion filters globally" }, diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c index ef0b6e2897..3180367576 100644 --- a/fftools/ffmpeg_sched.c +++ b/fftools/ffmpeg_sched.c @@ -285,8 +285,9 @@ struct Scheduler { pthread_mutex_t mux_ready_lock; unsigned nb_mux_done; - pthread_mutex_t mux_done_lock; - pthread_cond_t mux_done_cond; + unsigned task_failed; + pthread_mutex_t finish_lock; + pthread_cond_t finish_cond; SchDec *dec; @@ -306,7 +307,6 @@ struct Scheduler { enum SchedulerState state; atomic_int terminate; - atomic_int task_failed; pthread_mutex_t schedule_lock; @@ -375,7 +375,6 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si enum QueueType type) { ThreadQueue *tq; - ObjPool *op; if (queue_size <= 0) { if (type == QUEUE_FRAMES) @@ -393,18 +392,11 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si av_assert0(queue_size == DEFAULT_FRAME_THREAD_QUEUE_SIZE); } - op = (type == QUEUE_PACKETS) ? objpool_alloc_packets() : - objpool_alloc_frames(); - if (!op) + tq = tq_alloc(nb_streams, queue_size, + (type == QUEUE_PACKETS) ? THREAD_QUEUE_PACKETS : THREAD_QUEUE_FRAMES); + if (!tq) return AVERROR(ENOMEM); - tq = tq_alloc(nb_streams, queue_size, op, - (type == QUEUE_PACKETS) ? pkt_move : frame_move); - if (!tq) { - objpool_free(&op); - return AVERROR(ENOMEM); - } - *ptq = tq; return 0; } @@ -571,8 +563,8 @@ void sch_free(Scheduler **psch) pthread_mutex_destroy(&sch->mux_ready_lock); - pthread_mutex_destroy(&sch->mux_done_lock); - pthread_cond_destroy(&sch->mux_done_cond); + pthread_mutex_destroy(&sch->finish_lock); + pthread_cond_destroy(&sch->finish_cond); av_freep(psch); } @@ -602,11 +594,11 @@ Scheduler *sch_alloc(void) if (ret) goto fail; - ret = pthread_mutex_init(&sch->mux_done_lock, NULL); + ret = pthread_mutex_init(&sch->finish_lock, NULL); if (ret) goto fail; - ret = pthread_cond_init(&sch->mux_done_cond, NULL); + ret = pthread_cond_init(&sch->finish_cond, NULL); if (ret) goto fail; @@ -1111,22 +1103,52 @@ static int mux_task_start(SchMux *mux) return ret; /* flush the pre-muxing queues */ - for (unsigned i = 0; i < mux->nb_streams; i++) { - SchMuxStream *ms = &mux->streams[i]; + while (1) { + int min_stream = -1; + Timestamp min_ts = { .ts = AV_NOPTS_VALUE }; + AVPacket *pkt; - while (av_fifo_read(ms->pre_mux_queue.fifo, &pkt, 1) >= 0) { + // find the stream with the earliest dts or EOF in pre-muxing queue + for (unsigned i = 0; i < mux->nb_streams; i++) { + SchMuxStream *ms = &mux->streams[i]; + + if (av_fifo_peek(ms->pre_mux_queue.fifo, &pkt, 1, 0) < 0) + continue; + + if (!pkt || pkt->dts == AV_NOPTS_VALUE) { + min_stream = i; + break; + } + + if (min_ts.ts == AV_NOPTS_VALUE || + av_compare_ts(min_ts.ts, min_ts.tb, pkt->dts, pkt->time_base) > 0) { + min_stream = i; + min_ts = (Timestamp){ .ts = pkt->dts, .tb = pkt->time_base }; + } + } + + if (min_stream >= 0) { + SchMuxStream *ms = &mux->streams[min_stream]; + + ret = av_fifo_read(ms->pre_mux_queue.fifo, &pkt, 1); + av_assert0(ret >= 0); + if (pkt) { if (!ms->init_eof) - ret = tq_send(mux->queue, i, pkt); + ret = tq_send(mux->queue, min_stream, pkt); av_packet_free(&pkt); if (ret == AVERROR_EOF) ms->init_eof = 1; else if (ret < 0) return ret; } else - tq_send_finish(mux->queue, i); + tq_send_finish(mux->queue, min_stream); + + continue; } + + break; } atomic_store(&mux->mux_started, 1); @@ -1634,29 +1656,27 @@ fail: int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts) { - int ret, err; + int ret; // convert delay to absolute timestamp timeout_us += av_gettime(); - pthread_mutex_lock(&sch->mux_done_lock); + pthread_mutex_lock(&sch->finish_lock); if (sch->nb_mux_done < sch->nb_mux) { struct timespec tv = { .tv_sec = timeout_us / 1000000, .tv_nsec = (timeout_us % 1000000) * 1000 }; - pthread_cond_timedwait(&sch->mux_done_cond, &sch->mux_done_lock, &tv); + pthread_cond_timedwait(&sch->finish_cond, &sch->finish_lock, &tv); } - ret = sch->nb_mux_done == sch->nb_mux; + // abort transcoding if any task failed + ret = sch->nb_mux_done == sch->nb_mux || sch->task_failed; - pthread_mutex_unlock(&sch->mux_done_lock); + pthread_mutex_unlock(&sch->finish_lock); *transcode_ts = atomic_load(&sch->last_dts); - // abort transcoding if any task failed - err = atomic_load(&sch->task_failed); - - return ret || err; + return ret; } static int enc_open(Scheduler *sch, SchEnc *enc, const AVFrame *frame) @@ -1816,7 +1836,7 @@ static int mux_queue_packet(SchMux *mux, SchMuxStream *ms, AVPacket *pkt) if (new_size <= packets) { av_log(mux, AV_LOG_ERROR, "Too many packets buffered for output stream.\n"); - return AVERROR(ENOSPC); + return AVERROR_BUFFER_TOO_SMALL; } ret = av_fifo_grow2(q->fifo, new_size - packets); if (ret < 0) @@ -1879,7 +1899,7 @@ static int send_to_mux(Scheduler *sch, SchMux *mux, unsigned stream_idx, update_schedule: // TODO: use atomics to check whether this changes trailing dts - // to avoid locking unnecesarily + // to avoid locking unnecessarily if (dts != AV_NOPTS_VALUE || !pkt) { pthread_mutex_lock(&sch->schedule_lock); @@ -2122,14 +2142,14 @@ static int mux_done(Scheduler *sch, unsigned mux_idx) pthread_mutex_unlock(&sch->schedule_lock); - pthread_mutex_lock(&sch->mux_done_lock); + pthread_mutex_lock(&sch->finish_lock); av_assert0(sch->nb_mux_done < sch->nb_mux); sch->nb_mux_done++; - pthread_cond_signal(&sch->mux_done_cond); + pthread_cond_signal(&sch->finish_cond); - pthread_mutex_unlock(&sch->mux_done_lock); + pthread_mutex_unlock(&sch->finish_lock); return 0; } @@ -2522,8 +2542,12 @@ static void *task_wrapper(void *arg) // EOF is considered normal termination if (ret == AVERROR_EOF) ret = 0; - if (ret < 0) - atomic_store(&sch->task_failed, 1); + if (ret < 0) { + pthread_mutex_lock(&sch->finish_lock); + sch->task_failed = 1; + pthread_cond_signal(&sch->finish_cond); + pthread_mutex_unlock(&sch->finish_lock); + } av_log(task->func_arg, ret < 0 ? AV_LOG_ERROR : AV_LOG_VERBOSE, "Terminating thread with return code %d (%s)\n", ret, diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h index 3062c4a6ec..fb7a77ddfc 100644 --- a/fftools/ffmpeg_sched.h +++ b/fftools/ffmpeg_sched.h @@ -355,7 +355,7 @@ enum DemuxSendFlags { * @retval "non-negative value" success * @retval AVERROR_EOF all consumers for the stream are done * @retval AVERROR_EXIT all consumers are done, should terminate demuxing - * @retval "anoter negative error code" other failure + * @retval "another negative error code" other failure */ int sch_demux_send(Scheduler *sch, unsigned demux_idx, struct AVPacket *pkt, unsigned flags); @@ -436,7 +436,7 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx) * * @retval "non-negative value" success * @retval AVERROR_EOF all consumers are done - * @retval "anoter negative error code" other failure + * @retval "another negative error code" other failure */ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, struct AVFrame *frame); diff --git a/fftools/ffmpeg_utils.h b/fftools/ffmpeg_utils.h index 7939e44cdc..9ca3afffa0 100644 --- a/fftools/ffmpeg_utils.h +++ b/fftools/ffmpeg_utils.h @@ -44,14 +44,20 @@ static inline int err_merge(int err0, int err1) return (err0 < 0) ? err0 : FFMIN(err1, 0); } -static inline void pkt_move(void *dst, void *src) +/** + * Wrapper calling av_frame_side_data_clone() in a loop for all source entries. + * It does not clear dst beforehand. */ +static inline int clone_side_data(AVFrameSideData ***dst, int *nb_dst, + AVFrameSideData * const *src, int nb_src, + unsigned int flags) { - av_packet_move_ref(dst, src); -} + for (int i = 0; i < nb_src; i++) { + int ret = av_frame_side_data_clone(dst, nb_dst, src[i], flags); + if (ret < 0) + return ret; + } -static inline void frame_move(void *dst, void *src) -{ - av_frame_move_ref(dst, src); + return 0; } #endif // FFTOOLS_FFMPEG_UTILS_H diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 60d8874eab..2a572fc3aa 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -388,7 +388,6 @@ static const struct TextureFormatEntry { { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY }, - { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_UNKNOWN }, }; static int opt_add_vfilter(void *optctx, const char *opt, const char *arg) @@ -895,7 +894,7 @@ static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_B format == AV_PIX_FMT_BGR32 || format == AV_PIX_FMT_BGR32_1) *sdl_blendmode = SDL_BLENDMODE_BLEND; - for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; i++) { + for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map); i++) { if (format == sdl_texture_format_map[i].format) { *sdl_pix_fmt = sdl_texture_format_map[i].texture_fmt; return; @@ -941,7 +940,6 @@ static enum AVColorSpace sdl_supported_color_spaces[] = { AVCOL_SPC_BT709, AVCOL_SPC_BT470BG, AVCOL_SPC_SMPTE170M, - AVCOL_SPC_UNSPECIFIED, }; static void set_sdl_yuv_conversion_mode(AVFrame *frame) @@ -1861,7 +1859,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c { enum AVPixelFormat pix_fmts[FF_ARRAY_ELEMS(sdl_texture_format_map)]; char sws_flags_str[512] = ""; - char buffersrc_args[256]; int ret; AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecParameters *codecpar = is->video_st->codecpar; @@ -1875,14 +1872,13 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c return AVERROR(ENOMEM); for (i = 0; i < renderer_info.num_texture_formats; i++) { - for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; j++) { + for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map); 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_iterate(sws_dict, e))) { if (!strcmp(e->key, "sws_flags")) { @@ -1895,36 +1891,49 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c graph->scale_sws_opts = av_strdup(sws_flags_str); - snprintf(buffersrc_args, sizeof(buffersrc_args), - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:" - "colorspace=%d:range=%d", - frame->width, frame->height, frame->format, - is->video_st->time_base.num, is->video_st->time_base.den, - codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1), - frame->colorspace, frame->color_range); - if (fr.num && fr.den) - av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den); - if ((ret = avfilter_graph_create_filter(&filt_src, - avfilter_get_by_name("buffer"), - "ffplay_buffer", buffersrc_args, NULL, - graph)) < 0) + filt_src = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffer"), + "ffplay_buffer"); + if (!filt_src) { + ret = AVERROR(ENOMEM); goto fail; + } + + par->format = frame->format; + par->time_base = is->video_st->time_base; + par->width = frame->width; + par->height = frame->height; + par->sample_aspect_ratio = codecpar->sample_aspect_ratio; + par->color_space = frame->colorspace; + par->color_range = frame->color_range; + par->frame_rate = fr; par->hw_frames_ctx = frame->hw_frames_ctx; ret = av_buffersrc_parameters_set(filt_src, par); if (ret < 0) goto fail; - ret = avfilter_graph_create_filter(&filt_out, - avfilter_get_by_name("buffersink"), - "ffplay_buffersink", NULL, NULL, graph); + ret = avfilter_init_dict(filt_src, NULL); if (ret < 0) goto fail; - if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) + filt_out = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffersink"), + "ffplay_buffersink"); + if (!filt_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_opt_set_array(filt_out, "pixel_formats", AV_OPT_SEARCH_CHILDREN, + 0, nb_pix_fmts, AV_OPT_TYPE_PIXEL_FMT, pix_fmts)) < 0) goto fail; if (!vk_renderer && - (ret = av_opt_set_int_list(filt_out, "color_spaces", sdl_supported_color_spaces, AVCOL_SPC_UNSPECIFIED, AV_OPT_SEARCH_CHILDREN)) < 0) + (ret = av_opt_set_array(filt_out, "colorspaces", AV_OPT_SEARCH_CHILDREN, + 0, FF_ARRAY_ELEMS(sdl_supported_color_spaces), + AV_OPT_TYPE_INT, sdl_supported_color_spaces)) < 0) + goto fail; + + ret = avfilter_init_dict(filt_out, NULL); + if (ret < 0) goto fail; last_filter = filt_out; @@ -1994,8 +2003,6 @@ fail: static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format) { - static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; - int sample_rates[2] = { 0, -1 }; AVFilterContext *filt_asrc = NULL, *filt_asink = NULL; char aresample_swr_opts[512] = ""; const AVDictionaryEntry *e = NULL; @@ -2029,30 +2036,28 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for if (ret < 0) goto end; - - ret = avfilter_graph_create_filter(&filt_asink, - avfilter_get_by_name("abuffersink"), "ffplay_abuffersink", - NULL, NULL, is->agraph); - if (ret < 0) + filt_asink = avfilter_graph_alloc_filter(is->agraph, avfilter_get_by_name("abuffersink"), + "ffplay_abuffersink"); + if (!filt_asink) { + ret = AVERROR(ENOMEM); goto end; + } - if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) - goto end; - if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set(filt_asink, "sample_formats", "s16", AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if (force_output_format) { - av_bprint_clear(&bp); - av_channel_layout_describe_bprint(&is->audio_tgt.ch_layout, &bp); - sample_rates [0] = is->audio_tgt.freq; - if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set_array(filt_asink, "channel_layouts", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_CHLAYOUT, &is->audio_tgt.ch_layout)) < 0) goto end; - if ((ret = av_opt_set(filt_asink, "ch_layouts", bp.str, AV_OPT_SEARCH_CHILDREN)) < 0) - goto end; - if ((ret = av_opt_set_int_list(filt_asink, "sample_rates" , sample_rates , -1, AV_OPT_SEARCH_CHILDREN)) < 0) + if ((ret = av_opt_set_array(filt_asink, "samplerates", AV_OPT_SEARCH_CHILDREN, + 0, 1, AV_OPT_TYPE_INT, &is->audio_tgt.freq)) < 0) goto end; } + ret = avfilter_init_dict(filt_asink, NULL); + if (ret < 0) + goto end; if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0) goto end; @@ -2607,6 +2612,11 @@ static int create_hwaccel(AVBufferRef **device_ctx) if (type == AV_HWDEVICE_TYPE_NONE) return AVERROR(ENOTSUP); + if (!vk_renderer) { + av_log(NULL, AV_LOG_ERROR, "Vulkan renderer is not available\n"); + return AVERROR(ENOTSUP); + } + ret = vk_renderer_get_hw_dev(vk_renderer, &vk_dev); if (ret < 0) return ret; diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c index f272cb46f1..699cd6ecd0 100644 --- a/fftools/ffplay_renderer.c +++ b/fftools/ffplay_renderer.c @@ -259,8 +259,8 @@ static int create_vk_by_hwcontext(VkRenderer *renderer, ctx->get_proc_addr = hwctx->get_proc_addr; ctx->inst = hwctx->inst; - ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, - pl_vulkan_import_params( + + struct pl_vulkan_import_params import_params = { .instance = hwctx->inst, .get_proc_addr = hwctx->get_proc_addr, .phys_device = hwctx->phys_dev, @@ -272,18 +272,36 @@ static int create_vk_by_hwcontext(VkRenderer *renderer, .unlock_queue = hwctx_unlock_queue, .queue_ctx = dev, .queue_graphics = { - .index = hwctx->queue_family_index, - .count = hwctx->nb_graphics_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, .queue_compute = { - .index = hwctx->queue_family_comp_index, - .count = hwctx->nb_comp_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, .queue_transfer = { - .index = hwctx->queue_family_tx_index, - .count = hwctx->nb_tx_queues, + .index = VK_QUEUE_FAMILY_IGNORED, + .count = 0, }, - )); + }; + for (int i = 0; i < hwctx->nb_qf; i++) { + const AVVulkanDeviceQueueFamily *qf = &hwctx->qf[i]; + + if (qf->flags & VK_QUEUE_GRAPHICS_BIT) { + import_params.queue_graphics.index = qf->idx; + import_params.queue_graphics.count = qf->num; + } + if (qf->flags & VK_QUEUE_COMPUTE_BIT) { + import_params.queue_compute.index = qf->idx; + import_params.queue_compute.count = qf->num; + } + if (qf->flags & VK_QUEUE_TRANSFER_BIT) { + import_params.queue_transfer.index = qf->idx; + import_params.queue_transfer.count = qf->num; + } + } + + ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, &import_params); if (!ctx->placebo_vulkan) return AVERROR_EXTERNAL; @@ -391,8 +409,8 @@ static int create_vk_by_placebo(VkRenderer *renderer, device_ctx->user_opaque = ctx; vk_dev_ctx = device_ctx->hwctx; - vk_dev_ctx->lock_queue = placebo_lock_queue, - vk_dev_ctx->unlock_queue = placebo_unlock_queue; + vk_dev_ctx->lock_queue = placebo_lock_queue; + vk_dev_ctx->unlock_queue = placebo_unlock_queue; vk_dev_ctx->get_proc_addr = ctx->placebo_instance->get_proc_addr; @@ -408,21 +426,38 @@ static int create_vk_by_placebo(VkRenderer *renderer, vk_dev_ctx->enabled_dev_extensions = ctx->placebo_vulkan->extensions; vk_dev_ctx->nb_enabled_dev_extensions = ctx->placebo_vulkan->num_extensions; - vk_dev_ctx->queue_family_index = ctx->placebo_vulkan->queue_graphics.index; - vk_dev_ctx->nb_graphics_queues = ctx->placebo_vulkan->queue_graphics.count; - - vk_dev_ctx->queue_family_tx_index = ctx->placebo_vulkan->queue_transfer.index; - vk_dev_ctx->nb_tx_queues = ctx->placebo_vulkan->queue_transfer.count; - - vk_dev_ctx->queue_family_comp_index = ctx->placebo_vulkan->queue_compute.index; - vk_dev_ctx->nb_comp_queues = ctx->placebo_vulkan->queue_compute.count; + int nb_qf = 0; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_graphics.index, + .num = ctx->placebo_vulkan->queue_graphics.count, + .flags = VK_QUEUE_GRAPHICS_BIT, + }; + nb_qf++; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_transfer.index, + .num = ctx->placebo_vulkan->queue_transfer.count, + .flags = VK_QUEUE_TRANSFER_BIT, + }; + nb_qf++; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = ctx->placebo_vulkan->queue_compute.index, + .num = ctx->placebo_vulkan->queue_compute.count, + .flags = VK_QUEUE_COMPUTE_BIT, + }; + nb_qf++; ret = get_decode_queue(renderer, &decode_index, &decode_count); if (ret < 0) return ret; - vk_dev_ctx->queue_family_decode_index = decode_index; - vk_dev_ctx->nb_decode_queues = decode_count; + vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) { + .idx = decode_index, + .num = decode_count, + .flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + }; + nb_qf++; + + vk_dev_ctx->nb_qf = nb_qf; ret = av_hwdevice_ctx_init(ctx->hw_device_ref); if (ret < 0) @@ -697,6 +732,7 @@ static int display(VkRenderer *renderer, AVFrame *frame) struct pl_frame target = {0}; RendererContext *ctx = (RendererContext *) renderer; int ret = 0; + struct pl_color_space hint = {0}; ret = convert_frame(renderer, frame); if (ret < 0) @@ -709,6 +745,8 @@ static int display(VkRenderer *renderer, AVFrame *frame) return AVERROR_EXTERNAL; } + pl_color_space_from_avframe(&hint, frame); + pl_swapchain_colorspace_hint(ctx->swapchain, &hint); if (!pl_swapchain_start_frame(ctx->swapchain, &swap_frame)) { av_log(NULL, AV_LOG_ERROR, "start frame failed\n"); ret = AVERROR_EXTERNAL; diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 14b98d22a1..b8d51071e6 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -36,11 +36,11 @@ #include "libavutil/ambient_viewing_environment.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/avutil.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/display.h" #include "libavutil/film_grain_params.h" -#include "libavutil/hash.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/iamf.h" #include "libavutil/mastering_display_metadata.h" @@ -63,25 +63,13 @@ #include "libswscale/version.h" #include "libswresample/swresample.h" #include "libswresample/version.h" -#include "libpostproc/postprocess.h" -#include "libpostproc/version.h" #include "libavfilter/version.h" +#include "textformat/avtextformat.h" #include "cmdutils.h" #include "opt_common.h" #include "libavutil/thread.h" -#if !HAVE_THREADS -# ifdef pthread_mutex_lock -# undef pthread_mutex_lock -# endif -# define pthread_mutex_lock(a) do{}while(0) -# ifdef pthread_mutex_unlock -# undef pthread_mutex_unlock -# endif -# define pthread_mutex_unlock(a) do{}while(0) -#endif - // attached as opaque_ref to packets/frames typedef struct FrameData { int64_t pkt_pos; @@ -104,6 +92,7 @@ typedef struct InputFile { const char program_name[] = "ffprobe"; const int program_birth_year = 2007; +static int do_analyze_frames = 0; static int do_bitexact = 0; static int do_count_frames = 0; static int do_count_packets = 0; @@ -142,6 +131,11 @@ static int use_byte_value_binary_prefix = 0; static int use_value_sexagesimal_format = 0; static int show_private_data = 1; +static const char *audio_codec_name = NULL; +static const char *data_codec_name = NULL; +static const char *subtitle_codec_name = NULL; +static const char *video_codec_name = NULL; + #define SHOW_OPTIONAL_FIELDS_AUTO -1 #define SHOW_OPTIONAL_FIELDS_NEVER 0 #define SHOW_OPTIONAL_FIELDS_ALWAYS 1 @@ -166,10 +160,7 @@ static int find_stream_info = 1; /* section structure definition */ -#define SECTION_MAX_NB_CHILDREN 11 - typedef enum { - SECTION_ID_NONE = -1, SECTION_ID_CHAPTER, SECTION_ID_CHAPTER_TAGS, SECTION_ID_CHAPTERS, @@ -238,25 +229,6 @@ typedef enum { SECTION_ID_SUBTITLE, } SectionID; -struct section { - int id; ///< unique id identifying a section - const char *name; - -#define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level -#define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type -#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys. - /// For these sections the element_name field is mandatory. -#define SECTION_FLAG_HAS_TYPE 8 ///< the section contains a type to distinguish multiple nested elements - - int flags; - const SectionID children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1 - const char *element_name; ///< name of the contained element, if provided - const char *unique_name; ///< unique section name, in case the name is ambiguous - AVDictionary *entries_to_show; - const char *(* get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined - int show_all_entries; -}; - static const char *get_packet_side_data_type(const void *data) { const AVPacketSideData *sd = (const AVPacketSideData *)data; @@ -280,75 +252,75 @@ static const char *get_stream_group_type(const void *data) return av_x_if_null(avformat_stream_group_name(stg->type), "unknown"); } -static struct section sections[] = { - [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } }, +static struct AVTextFormatSection sections[] = { + [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } }, [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } }, - [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" }, + [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" }, [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } }, [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } }, - [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" }, - [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, + [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" }, + [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } }, - [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, - [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, - [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = "frame_side_data", .element_name = "side_datum", .get_type = get_frame_side_data_type }, - [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, + [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, + [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, + [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = "frame_side_data", .element_name = "side_datum", .get_type = get_frame_side_data_type }, + [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } }, - [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 }, .element_name = "component", .unique_name = "frame_side_data_components" }, - [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 }, .unique_name = "frame_side_data_component", .element_name = "component_entry", .get_type = get_raw_string_type }, - [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 }, .element_name = "piece", .unique_name = "frame_side_data_pieces" }, - [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "piece_entry", .unique_name = "frame_side_data_piece", .get_type = get_raw_string_type }, - [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, + [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 }, .element_name = "component", .unique_name = "frame_side_data_components" }, + [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 }, .unique_name = "frame_side_data_component", .element_name = "component_entry", .get_type = get_raw_string_type }, + [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 }, .element_name = "piece", .unique_name = "frame_side_data_pieces" }, + [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "piece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "piece_entry", .unique_name = "frame_side_data_piece", .get_type = get_raw_string_type }, + [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, }, - [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, + [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } }, - [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, - [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, + [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, + [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE, { SECTION_ID_PACKET, -1} }, [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } }, - [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" }, - [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" }, - [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .unique_name = "packet_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, - [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } }, + [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" }, + [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" }, + [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .unique_name = "packet_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, + [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } }, [SECTION_ID_PIXEL_FORMAT] = { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } }, [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" }, - [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" }, + [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" }, [SECTION_ID_PIXEL_FORMAT_COMPONENT] = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } }, [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" }, - [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" }, + [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" }, [SECTION_ID_PROGRAM] = { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } }, - [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" }, + [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" }, [SECTION_ID_PROGRAM_STREAM] = { SECTION_ID_PROGRAM_STREAM, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = "program_stream" }, - [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, + [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } }, - [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } }, + [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } }, [SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION] = { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_stream_disposition" }, - [SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" }, + [SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" }, [SECTION_ID_STREAM_GROUP] = { SECTION_ID_STREAM_GROUP, "stream_group", 0, { SECTION_ID_STREAM_GROUP_TAGS, SECTION_ID_STREAM_GROUP_DISPOSITION, SECTION_ID_STREAM_GROUP_COMPONENTS, SECTION_ID_STREAM_GROUP_STREAMS, -1 } }, - [SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" }, - [SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type }, - [SECTION_ID_STREAM_GROUP_SUBCOMPONENTS] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, "subcomponents", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, -1 }, .element_name = "component" }, - [SECTION_ID_STREAM_GROUP_SUBCOMPONENT] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, "subcomponent", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_PIECES, -1 }, .element_name = "subcomponent_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" }, - [SECTION_ID_STREAM_GROUP_PIECE] = { SECTION_ID_STREAM_GROUP_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBPIECES, -1 }, .unique_name = "stream_group_piece", .element_name = "piece_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_SUBPIECES] = { SECTION_ID_STREAM_GROUP_SUBPIECES, "subpieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBPIECE, -1 }, .element_name = "subpiece" }, - [SECTION_ID_STREAM_GROUP_SUBPIECE] = { SECTION_ID_STREAM_GROUP_SUBPIECE, "subpiece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_BLOCKS, -1 }, .element_name = "subpiece_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_BLOCKS] = { SECTION_ID_STREAM_GROUP_BLOCKS, "blocks", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_BLOCK, -1 }, .element_name = "block" }, - [SECTION_ID_STREAM_GROUP_BLOCK] = { SECTION_ID_STREAM_GROUP_BLOCK, "block", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "block_entry", .get_type = get_raw_string_type }, - [SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" }, + [SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" }, + [SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type }, + [SECTION_ID_STREAM_GROUP_SUBCOMPONENTS] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, "subcomponents", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, -1 }, .element_name = "component" }, + [SECTION_ID_STREAM_GROUP_SUBCOMPONENT] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, "subcomponent", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_PIECES, -1 }, .element_name = "subcomponent_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" }, + [SECTION_ID_STREAM_GROUP_PIECE] = { SECTION_ID_STREAM_GROUP_PIECE, "piece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBPIECES, -1 }, .unique_name = "stream_group_piece", .element_name = "piece_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_SUBPIECES] = { SECTION_ID_STREAM_GROUP_SUBPIECES, "subpieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBPIECE, -1 }, .element_name = "subpiece" }, + [SECTION_ID_STREAM_GROUP_SUBPIECE] = { SECTION_ID_STREAM_GROUP_SUBPIECE, "subpiece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_BLOCKS, -1 }, .element_name = "subpiece_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_BLOCKS] = { SECTION_ID_STREAM_GROUP_BLOCKS, "blocks", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_BLOCK, -1 }, .element_name = "block" }, + [SECTION_ID_STREAM_GROUP_BLOCK] = { SECTION_ID_STREAM_GROUP_BLOCK, "block", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "block_entry", .get_type = get_raw_string_type }, + [SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" }, [SECTION_ID_STREAM_GROUP_STREAM] = { SECTION_ID_STREAM_GROUP_STREAM, "stream", 0, { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAM_TAGS, -1 }, .unique_name = "stream_group_stream" }, [SECTION_ID_STREAM_GROUP_DISPOSITION] = { SECTION_ID_STREAM_GROUP_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_disposition" }, - [SECTION_ID_STREAM_GROUP_TAGS] = { SECTION_ID_STREAM_GROUP_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" }, - [SECTION_ID_STREAM_GROUPS] = { SECTION_ID_STREAM_GROUPS, "stream_groups", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP, -1 } }, - [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER, + [SECTION_ID_STREAM_GROUP_TAGS] = { SECTION_ID_STREAM_GROUP_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" }, + [SECTION_ID_STREAM_GROUPS] = { SECTION_ID_STREAM_GROUPS, "stream_groups", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP, -1 } }, + [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAM_GROUPS, SECTION_ID_STREAMS, SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, SECTION_ID_PIXEL_FORMATS, -1} }, - [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } }, + [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } }, [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } }, [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" }, - [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, - [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" }, - [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", SECTION_FLAG_HAS_TYPE|SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, + [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, + [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" }, + [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE|AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type }, [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } }, }; @@ -360,22 +332,6 @@ static const char *print_input_filename; static const AVInputFormat *iformat = NULL; static const char *output_filename = NULL; -static struct AVHashContext *hash; - -static const struct { - double bin_val; - double dec_val; - const char *bin_str; - const char *dec_str; -} si_prefixes[] = { - { 1.0, 1.0, "", "" }, - { 1.024e3, 1e3, "Ki", "K" }, - { 1.048576e6, 1e6, "Mi", "M" }, - { 1.073741824e9, 1e9, "Gi", "G" }, - { 1.099511627776e12, 1e12, "Ti", "T" }, - { 1.125899906842624e15, 1e15, "Pi", "P" }, -}; - static const char unit_second_str[] = "s" ; static const char unit_hertz_str[] = "Hz" ; static const char unit_byte_str[] = "byte" ; @@ -385,10 +341,11 @@ static int nb_streams; static uint64_t *nb_streams_packets; static uint64_t *nb_streams_frames; static int *selected_streams; +static int *streams_with_closed_captions; +static int *streams_with_film_grain; + +static AVMutex log_mutex = AV_MUTEX_INITIALIZER; -#if HAVE_THREADS -pthread_mutex_t log_mutex; -#endif typedef struct LogBuffer { char *context_name; int log_level; @@ -415,7 +372,7 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl) va_end(vl2); #if HAVE_THREADS - pthread_mutex_lock(&log_mutex); + ff_mutex_lock(&log_mutex); new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer)); if (new_log_buffer) { @@ -446,1558 +403,15 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl) log_buffer_size ++; } - pthread_mutex_unlock(&log_mutex); + ff_mutex_unlock(&log_mutex); #endif } -struct unit_value { - union { double d; int64_t i; } val; - const char *unit; -}; - -static char *value_string(char *buf, int buf_size, struct unit_value uv) -{ - double vald; - int64_t vali; - int show_float = 0; - - if (uv.unit == unit_second_str) { - vald = uv.val.d; - show_float = 1; - } else { - vald = vali = uv.val.i; - } - - if (uv.unit == unit_second_str && use_value_sexagesimal_format) { - double secs; - int hours, mins; - secs = vald; - mins = (int)secs / 60; - secs = secs - mins * 60; - hours = mins / 60; - mins %= 60; - snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs); - } else { - const char *prefix_string = ""; - - if (use_value_prefix && vald > 1) { - int64_t index; - - if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) { - index = (int64_t) (log2(vald)) / 10; - index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); - vald /= si_prefixes[index].bin_val; - prefix_string = si_prefixes[index].bin_str; - } else { - index = (int64_t) (log10(vald)) / 3; - index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); - vald /= si_prefixes[index].dec_val; - prefix_string = si_prefixes[index].dec_str; - } - vali = vald; - } - - if (show_float || (use_value_prefix && vald != (int64_t)vald)) - snprintf(buf, buf_size, "%f", vald); - else - snprintf(buf, buf_size, "%"PRId64, vali); - av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "", - prefix_string, show_value_unit ? uv.unit : ""); - } - - return buf; -} - -/* WRITERS API */ - -typedef struct WriterContext WriterContext; - -#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1 -#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2 - -typedef enum { - WRITER_STRING_VALIDATION_FAIL, - WRITER_STRING_VALIDATION_REPLACE, - WRITER_STRING_VALIDATION_IGNORE, - WRITER_STRING_VALIDATION_NB -} StringValidation; - -typedef struct Writer { - const AVClass *priv_class; ///< private class of the writer, if any - int priv_size; ///< private size for the writer context - const char *name; - - int (*init) (WriterContext *wctx); - void (*uninit)(WriterContext *wctx); - - void (*print_section_header)(WriterContext *wctx, const void *data); - void (*print_section_footer)(WriterContext *wctx); - void (*print_integer) (WriterContext *wctx, const char *, int64_t); - void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep); - void (*print_string) (WriterContext *wctx, const char *, const char *); - int flags; ///< a combination or WRITER_FLAG_* -} Writer; - -#define SECTION_MAX_NB_LEVELS 12 - -struct WriterContext { - const AVClass *class; ///< class of the writer - const Writer *writer; ///< the Writer of which this is an instance - AVIOContext *avio; ///< the I/O context used to write - - void (* writer_w8)(WriterContext *wctx, int b); - void (* writer_put_str)(WriterContext *wctx, const char *str); - void (* writer_printf)(WriterContext *wctx, const char *fmt, ...); - - char *name; ///< name of this writer instance - void *priv; ///< private data for use by the filter - - const struct section *sections; ///< array containing all sections - int nb_sections; ///< number of sections - - int level; ///< current level, starting from 0 - - /** number of the item printed in the given section, starting from 0 */ - unsigned int nb_item[SECTION_MAX_NB_LEVELS]; - - /** section per each level */ - const struct section *section[SECTION_MAX_NB_LEVELS]; - AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, - /// used by various writers - - unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section - unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section - unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames - - int string_validation; - char *string_validation_replacement; - unsigned int string_validation_utf8_flags; -}; - -static const char *writer_get_name(void *p) -{ - WriterContext *wctx = p; - return wctx->writer->name; -} - -#define OFFSET(x) offsetof(WriterContext, x) - -static const AVOption writer_options[] = { - { "string_validation", "set string validation mode", - OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, - { "sv", "set string validation mode", - OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, - { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" }, - { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" }, - { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" }, - { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}}, - { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}}, - { NULL } -}; - -static void *writer_child_next(void *obj, void *prev) -{ - WriterContext *ctx = obj; - if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv) - return ctx->priv; - return NULL; -} - -static const AVClass writer_class = { - .class_name = "Writer", - .item_name = writer_get_name, - .option = writer_options, - .version = LIBAVUTIL_VERSION_INT, - .child_next = writer_child_next, -}; - -static int writer_close(WriterContext **wctx) -{ - int i; - int ret = 0; - - if (!*wctx) - return -1; - - if ((*wctx)->writer->uninit) - (*wctx)->writer->uninit(*wctx); - for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) - av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL); - if ((*wctx)->writer->priv_class) - av_opt_free((*wctx)->priv); - av_freep(&((*wctx)->priv)); - av_opt_free(*wctx); - if ((*wctx)->avio) { - avio_flush((*wctx)->avio); - ret = avio_close((*wctx)->avio); - } - av_freep(wctx); - return ret; -} - -static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) -{ - int i; - av_bprintf(bp, "0X"); - for (i = 0; i < ubuf_size; i++) - av_bprintf(bp, "%02X", ubuf[i]); -} - -static inline void writer_w8_avio(WriterContext *wctx, int b) -{ - avio_w8(wctx->avio, b); -} - -static inline void writer_put_str_avio(WriterContext *wctx, const char *str) -{ - avio_write(wctx->avio, str, strlen(str)); -} - -static inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - avio_vprintf(wctx->avio, fmt, ap); - va_end(ap); -} - -static inline void writer_w8_printf(WriterContext *wctx, int b) -{ - printf("%c", b); -} - -static inline void writer_put_str_printf(WriterContext *wctx, const char *str) -{ - printf("%s", str); -} - -static inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); -} - -static int writer_open(WriterContext **wctx, const Writer *writer, const char *args, - const struct section *sections, int nb_sections, const char *output) -{ - int i, ret = 0; - - if (!(*wctx = av_mallocz(sizeof(WriterContext)))) { - ret = AVERROR(ENOMEM); - goto fail; - } - - if (!((*wctx)->priv = av_mallocz(writer->priv_size))) { - ret = AVERROR(ENOMEM); - goto fail; - } - - (*wctx)->class = &writer_class; - (*wctx)->writer = writer; - (*wctx)->level = -1; - (*wctx)->sections = sections; - (*wctx)->nb_sections = nb_sections; - - av_opt_set_defaults(*wctx); - - if (writer->priv_class) { - void *priv_ctx = (*wctx)->priv; - *((const AVClass **)priv_ctx) = writer->priv_class; - av_opt_set_defaults(priv_ctx); - } - - /* convert options to dictionary */ - if (args) { - AVDictionary *opts = NULL; - const AVDictionaryEntry *opt = NULL; - - if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) { - av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args); - av_dict_free(&opts); - goto fail; - } - - while ((opt = av_dict_iterate(opts, opt))) { - if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) { - av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n", - opt->key, opt->value); - av_dict_free(&opts); - goto fail; - } - } - - av_dict_free(&opts); - } - - /* validate replace string */ - { - const uint8_t *p = (*wctx)->string_validation_replacement; - const uint8_t *endp = p + strlen(p); - while (*p) { - const uint8_t *p0 = p; - int32_t code; - ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags); - if (ret < 0) { - AVBPrint bp; - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); - bprint_bytes(&bp, p0, p-p0), - av_log(wctx, AV_LOG_ERROR, - "Invalid UTF8 sequence %s found in string validation replace '%s'\n", - bp.str, (*wctx)->string_validation_replacement); - return ret; - } - } - } - - if (!output_filename) { - (*wctx)->writer_w8 = writer_w8_printf; - (*wctx)->writer_put_str = writer_put_str_printf; - (*wctx)->writer_printf = writer_printf_printf; - } else { - if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) { - av_log(*wctx, AV_LOG_ERROR, - "Failed to open output '%s' with error: %s\n", output, av_err2str(ret)); - goto fail; - } - (*wctx)->writer_w8 = writer_w8_avio; - (*wctx)->writer_put_str = writer_put_str_avio; - (*wctx)->writer_printf = writer_printf_avio; - } - - for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) - av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED); - - if ((*wctx)->writer->init) - ret = (*wctx)->writer->init(*wctx); - if (ret < 0) - goto fail; - - return 0; - -fail: - writer_close(wctx); - return ret; -} - -static inline void writer_print_section_header(WriterContext *wctx, - const void *data, - int section_id) -{ - int parent_section_id; - wctx->level++; - av_assert0(wctx->level < SECTION_MAX_NB_LEVELS); - parent_section_id = wctx->level ? - (wctx->section[wctx->level-1])->id : SECTION_ID_NONE; - - wctx->nb_item[wctx->level] = 0; - wctx->section[wctx->level] = &wctx->sections[section_id]; - - if (section_id == SECTION_ID_PACKETS_AND_FRAMES) { - wctx->nb_section_packet = wctx->nb_section_frame = - wctx->nb_section_packet_frame = 0; - } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { - wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ? - wctx->nb_section_packet : wctx->nb_section_frame; - } - - if (wctx->writer->print_section_header) - wctx->writer->print_section_header(wctx, data); -} - -static inline void writer_print_section_footer(WriterContext *wctx) -{ - int section_id = wctx->section[wctx->level]->id; - int parent_section_id = wctx->level ? - wctx->section[wctx->level-1]->id : SECTION_ID_NONE; - - if (parent_section_id != SECTION_ID_NONE) - wctx->nb_item[wctx->level-1]++; - if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { - if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++; - else wctx->nb_section_frame++; - } - if (wctx->writer->print_section_footer) - wctx->writer->print_section_footer(wctx); - wctx->level--; -} - -static inline void writer_print_integer(WriterContext *wctx, - const char *key, int64_t val) -{ - const struct section *section = wctx->section[wctx->level]; - - if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { - wctx->writer->print_integer(wctx, key, val); - wctx->nb_item[wctx->level]++; - } -} - -static inline int validate_string(WriterContext *wctx, char **dstp, const char *src) -{ - const uint8_t *p, *endp; - AVBPrint dstbuf; - int invalid_chars_nb = 0, ret = 0; - - av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); - - endp = src + strlen(src); - for (p = src; *p;) { - uint32_t code; - int invalid = 0; - const uint8_t *p0 = p; - - if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) { - AVBPrint bp; - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); - bprint_bytes(&bp, p0, p-p0); - av_log(wctx, AV_LOG_DEBUG, - "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src); - invalid = 1; - } - - if (invalid) { - invalid_chars_nb++; - - switch (wctx->string_validation) { - case WRITER_STRING_VALIDATION_FAIL: - av_log(wctx, AV_LOG_ERROR, - "Invalid UTF-8 sequence found in string '%s'\n", src); - ret = AVERROR_INVALIDDATA; - goto end; - break; - - case WRITER_STRING_VALIDATION_REPLACE: - av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement); - break; - } - } - - if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE) - av_bprint_append_data(&dstbuf, p0, p-p0); - } - - if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) { - av_log(wctx, AV_LOG_WARNING, - "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n", - invalid_chars_nb, src, wctx->string_validation_replacement); - } - -end: - av_bprint_finalize(&dstbuf, dstp); - return ret; -} - -#define PRINT_STRING_OPT 1 -#define PRINT_STRING_VALIDATE 2 - -static inline int writer_print_string(WriterContext *wctx, - const char *key, const char *val, int flags) -{ - const struct section *section = wctx->section[wctx->level]; - int ret = 0; - - if (show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER || - (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO - && (flags & PRINT_STRING_OPT) - && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))) - return 0; - - if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { - if (flags & PRINT_STRING_VALIDATE) { - char *key1 = NULL, *val1 = NULL; - ret = validate_string(wctx, &key1, key); - if (ret < 0) goto end; - ret = validate_string(wctx, &val1, val); - if (ret < 0) goto end; - wctx->writer->print_string(wctx, key1, val1); - end: - if (ret < 0) { - av_log(wctx, AV_LOG_ERROR, - "Invalid key=value string combination %s=%s in section %s\n", - key, val, section->unique_name); - } - av_free(key1); - av_free(val1); - } else { - wctx->writer->print_string(wctx, key, val); - } - - wctx->nb_item[wctx->level]++; - } - - return ret; -} - -static inline void writer_print_rational(WriterContext *wctx, - const char *key, AVRational q, char sep) -{ - AVBPrint buf; - av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); - av_bprintf(&buf, "%d%c%d", q.num, sep, q.den); - writer_print_string(wctx, key, buf.str, 0); -} - -static void writer_print_time(WriterContext *wctx, const char *key, - int64_t ts, const AVRational *time_base, int is_duration) -{ - char buf[128]; - - if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { - writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); - } else { - double d = ts * av_q2d(*time_base); - struct unit_value uv; - uv.val.d = d; - uv.unit = unit_second_str; - value_string(buf, sizeof(buf), uv); - writer_print_string(wctx, key, buf, 0); - } -} - -static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration) -{ - if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { - writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); - } else { - writer_print_integer(wctx, key, ts); - } -} - -static void writer_print_data(WriterContext *wctx, const char *name, - const uint8_t *data, int size) -{ - AVBPrint bp; - int offset = 0, l, i; - - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); - av_bprintf(&bp, "\n"); - while (size) { - av_bprintf(&bp, "%08x: ", offset); - l = FFMIN(size, 16); - for (i = 0; i < l; i++) { - av_bprintf(&bp, "%02x", data[i]); - if (i & 1) - av_bprintf(&bp, " "); - } - av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2); - for (i = 0; i < l; i++) - av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1); - av_bprintf(&bp, "\n"); - offset += l; - data += l; - size -= l; - } - writer_print_string(wctx, name, bp.str, 0); - av_bprint_finalize(&bp, NULL); -} - -static void writer_print_data_hash(WriterContext *wctx, const char *name, - const uint8_t *data, int size) -{ - char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; - - if (!hash) - return; - av_hash_init(hash); - av_hash_update(hash, data, size); - snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash)); - p = buf + strlen(buf); - av_hash_final_hex(hash, p, buf + sizeof(buf) - p); - writer_print_string(wctx, name, buf, 0); -} - -static void writer_print_integers(WriterContext *wctx, const char *name, - uint8_t *data, int size, const char *format, - int columns, int bytes, int offset_add) -{ - AVBPrint bp; - int offset = 0, l, i; - - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); - av_bprintf(&bp, "\n"); - while (size) { - av_bprintf(&bp, "%08x: ", offset); - l = FFMIN(size, columns); - for (i = 0; i < l; i++) { - if (bytes == 1) av_bprintf(&bp, format, *data); - else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data)); - else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data)); - data += bytes; - size --; - } - av_bprintf(&bp, "\n"); - offset += offset_add; - } - writer_print_string(wctx, name, bp.str, 0); - av_bprint_finalize(&bp, NULL); -} - -#define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_) -#define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_) -#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__) - -#define MAX_REGISTERED_WRITERS_NB 64 - -static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1]; - -static int writer_register(const Writer *writer) -{ - static int next_registered_writer_idx = 0; - - if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB) - return AVERROR(ENOMEM); - - registered_writers[next_registered_writer_idx++] = writer; - return 0; -} - -static const Writer *writer_get_by_name(const char *name) -{ - int i; - - for (i = 0; registered_writers[i]; i++) - if (!strcmp(registered_writers[i]->name, name)) - return registered_writers[i]; - - return NULL; -} - - -/* WRITERS */ - -#define DEFINE_WRITER_CLASS(name) \ -static const char *name##_get_name(void *ctx) \ -{ \ - return #name ; \ -} \ -static const AVClass name##_class = { \ - .class_name = #name, \ - .item_name = name##_get_name, \ - .option = name##_options \ -} - -/* Default output */ - -typedef struct DefaultContext { - const AVClass *class; - int nokey; - int noprint_wrappers; - int nested_section[SECTION_MAX_NB_LEVELS]; -} DefaultContext; - -#undef OFFSET -#define OFFSET(x) offsetof(DefaultContext, x) - -static const AVOption default_options[] = { - { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(default); - -/* lame uppercasing routine, assumes the string is lower case ASCII */ -static inline char *upcase_string(char *dst, size_t dst_size, const char *src) -{ - int i; - for (i = 0; src[i] && i < dst_size-1; i++) - dst[i] = av_toupper(src[i]); - dst[i] = 0; - return dst; -} - -static void default_print_section_header(WriterContext *wctx, const void *data) -{ - DefaultContext *def = wctx->priv; - char buf[32]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - av_bprint_clear(&wctx->section_pbuf[wctx->level]); - if (parent_section && - !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) { - def->nested_section[wctx->level] = 1; - av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", - wctx->section_pbuf[wctx->level-1].str, - upcase_string(buf, sizeof(buf), - av_x_if_null(section->element_name, section->name))); - } - - if (def->noprint_wrappers || def->nested_section[wctx->level]) - return; - - if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name)); -} - -static void default_print_section_footer(WriterContext *wctx) -{ - DefaultContext *def = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - char buf[32]; - - if (def->noprint_wrappers || def->nested_section[wctx->level]) - return; - - if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name)); -} - -static void default_print_str(WriterContext *wctx, const char *key, const char *value) -{ - DefaultContext *def = wctx->priv; - - if (!def->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%s\n", value); -} - -static void default_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - DefaultContext *def = wctx->priv; - - if (!def->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%"PRId64"\n", value); -} - -static const Writer default_writer = { - .name = "default", - .priv_size = sizeof(DefaultContext), - .print_section_header = default_print_section_header, - .print_section_footer = default_print_section_footer, - .print_integer = default_print_int, - .print_string = default_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &default_class, -}; - -/* Compact output */ - -/** - * Apply C-language-like string escaping. - */ -static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - const char *p; - - for (p = src; *p; p++) { - switch (*p) { - case '\b': av_bprintf(dst, "%s", "\\b"); break; - case '\f': av_bprintf(dst, "%s", "\\f"); break; - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\\': av_bprintf(dst, "%s", "\\\\"); break; - default: - if (*p == sep) - av_bprint_chars(dst, '\\', 1); - av_bprint_chars(dst, *p, 1); - } - } - return dst->str; -} - -/** - * Quote fields containing special characters, check RFC4180. - */ -static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - char meta_chars[] = { sep, '"', '\n', '\r', '\0' }; - int needs_quoting = !!src[strcspn(src, meta_chars)]; - - if (needs_quoting) - av_bprint_chars(dst, '"', 1); - - for (; *src; src++) { - if (*src == '"') - av_bprint_chars(dst, '"', 1); - av_bprint_chars(dst, *src, 1); - } - if (needs_quoting) - av_bprint_chars(dst, '"', 1); - return dst->str; -} - -static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) -{ - return src; -} - -typedef struct CompactContext { - const AVClass *class; - char *item_sep_str; - char item_sep; - int nokey; - int print_section; - char *escape_mode_str; - const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); - int nested_section[SECTION_MAX_NB_LEVELS]; - int has_nested_elems[SECTION_MAX_NB_LEVELS]; - int terminate_line[SECTION_MAX_NB_LEVELS]; -} CompactContext; - -#undef OFFSET -#define OFFSET(x) offsetof(CompactContext, x) - -static const AVOption compact_options[]= { - {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, - {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, - {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, - {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, - {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(compact); - -static av_cold int compact_init(WriterContext *wctx) -{ - CompactContext *compact = wctx->priv; - - if (strlen(compact->item_sep_str) != 1) { - av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", - compact->item_sep_str); - return AVERROR(EINVAL); - } - compact->item_sep = compact->item_sep_str[0]; - - if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str; - else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str; - else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str; - else { - av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str); - return AVERROR(EINVAL); - } - - return 0; -} - -static void compact_print_section_header(WriterContext *wctx, const void *data) -{ - CompactContext *compact = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - compact->terminate_line[wctx->level] = 1; - compact->has_nested_elems[wctx->level] = 0; - - av_bprint_clear(&wctx->section_pbuf[wctx->level]); - if (parent_section && - (section->flags & SECTION_FLAG_HAS_TYPE || - (!(section->flags & SECTION_FLAG_IS_ARRAY) && - !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))))) { - - /* define a prefix for elements not contained in an array or - in a wrapper, or for array elements with a type */ - const char *element_name = (char *)av_x_if_null(section->element_name, section->name); - AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level]; - - compact->nested_section[wctx->level] = 1; - compact->has_nested_elems[wctx->level-1] = 1; - - av_bprintf(section_pbuf, "%s%s", - wctx->section_pbuf[wctx->level-1].str, element_name); - - if (section->flags & SECTION_FLAG_HAS_TYPE) { - // add /TYPE to prefix - av_bprint_chars(section_pbuf, '/', 1); - - // normalize section type, replace special characters and lower case - for (const char *p = section->get_type(data); *p; p++) { - char c = - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_'; - av_bprint_chars(section_pbuf, c, 1); - } - } - av_bprint_chars(section_pbuf, ':', 1); - - wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1]; - } else { - if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) && - wctx->level && wctx->nb_item[wctx->level-1]) - writer_w8(wctx, compact->item_sep); - if (compact->print_section && - !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_printf(wctx, "%s%c", section->name, compact->item_sep); - } -} - -static void compact_print_section_footer(WriterContext *wctx) -{ - CompactContext *compact = wctx->priv; - - if (!compact->nested_section[wctx->level] && - compact->terminate_line[wctx->level] && - !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) - writer_w8(wctx, '\n'); -} - -static void compact_print_str(WriterContext *wctx, const char *key, const char *value) -{ - CompactContext *compact = wctx->priv; - AVBPrint buf; - - if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep); - if (!compact->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx)); - av_bprint_finalize(&buf, NULL); -} - -static void compact_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - CompactContext *compact = wctx->priv; - - if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep); - if (!compact->nokey) - writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); - writer_printf(wctx, "%"PRId64, value); -} - -static const Writer compact_writer = { - .name = "compact", - .priv_size = sizeof(CompactContext), - .init = compact_init, - .print_section_header = compact_print_section_header, - .print_section_footer = compact_print_section_footer, - .print_integer = compact_print_int, - .print_string = compact_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &compact_class, -}; - -/* CSV output */ - -#undef OFFSET -#define OFFSET(x) offsetof(CompactContext, x) - -static const AVOption csv_options[] = { - {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, - {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, - {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, - {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, - {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(csv); - -static const Writer csv_writer = { - .name = "csv", - .priv_size = sizeof(CompactContext), - .init = compact_init, - .print_section_header = compact_print_section_header, - .print_section_footer = compact_print_section_footer, - .print_integer = compact_print_int, - .print_string = compact_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, - .priv_class = &csv_class, -}; - -/* Flat output */ - -typedef struct FlatContext { - const AVClass *class; - const char *sep_str; - char sep; - int hierarchical; -} FlatContext; - -#undef OFFSET -#define OFFSET(x) offsetof(FlatContext, x) - -static const AVOption flat_options[]= { - {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, - {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, - {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(flat); - -static av_cold int flat_init(WriterContext *wctx) -{ - FlatContext *flat = wctx->priv; - - if (strlen(flat->sep_str) != 1) { - av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", - flat->sep_str); - return AVERROR(EINVAL); - } - flat->sep = flat->sep_str[0]; - - return 0; -} - -static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep) -{ - const char *p; - - for (p = src; *p; p++) { - if (!((*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z'))) - av_bprint_chars(dst, '_', 1); - else - av_bprint_chars(dst, *p, 1); - } - return dst->str; -} - -static const char *flat_escape_value_str(AVBPrint *dst, const char *src) -{ - const char *p; - - for (p = src; *p; p++) { - switch (*p) { - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\\': av_bprintf(dst, "%s", "\\\\"); break; - case '"': av_bprintf(dst, "%s", "\\\""); break; - case '`': av_bprintf(dst, "%s", "\\`"); break; - case '$': av_bprintf(dst, "%s", "\\$"); break; - default: av_bprint_chars(dst, *p, 1); break; - } - } - return dst->str; -} - -static void flat_print_section_header(WriterContext *wctx, const void *data) -{ - FlatContext *flat = wctx->priv; - AVBPrint *buf = &wctx->section_pbuf[wctx->level]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - /* build section header */ - av_bprint_clear(buf); - if (!parent_section) - return; - av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); - - if (flat->hierarchical || - !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { - av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str); - - if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { - int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? - wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; - av_bprintf(buf, "%d%s", n, flat->sep_str); - } - } -} - -static void flat_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value); -} - -static void flat_print_str(WriterContext *wctx, const char *key, const char *value) -{ - FlatContext *flat = wctx->priv; - AVBPrint buf; - - writer_put_str(wctx, wctx->section_pbuf[wctx->level].str); - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep)); - av_bprint_clear(&buf); - writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value)); - av_bprint_finalize(&buf, NULL); -} - -static const Writer flat_writer = { - .name = "flat", - .priv_size = sizeof(FlatContext), - .init = flat_init, - .print_section_header = flat_print_section_header, - .print_integer = flat_print_int, - .print_string = flat_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &flat_class, -}; - -/* INI format output */ - -typedef struct INIContext { - const AVClass *class; - int hierarchical; -} INIContext; - -#undef OFFSET -#define OFFSET(x) offsetof(INIContext, x) - -static const AVOption ini_options[] = { - {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(ini); - -static char *ini_escape_str(AVBPrint *dst, const char *src) -{ - int i = 0; - char c = 0; - - while (c = src[i++]) { - switch (c) { - case '\b': av_bprintf(dst, "%s", "\\b"); break; - case '\f': av_bprintf(dst, "%s", "\\f"); break; - case '\n': av_bprintf(dst, "%s", "\\n"); break; - case '\r': av_bprintf(dst, "%s", "\\r"); break; - case '\t': av_bprintf(dst, "%s", "\\t"); break; - case '\\': - case '#' : - case '=' : - case ':' : av_bprint_chars(dst, '\\', 1); - default: - if ((unsigned char)c < 32) - av_bprintf(dst, "\\x00%02x", c & 0xff); - else - av_bprint_chars(dst, c, 1); - break; - } - } - return dst->str; -} - -static void ini_print_section_header(WriterContext *wctx, const void *data) -{ - INIContext *ini = wctx->priv; - AVBPrint *buf = &wctx->section_pbuf[wctx->level]; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - av_bprint_clear(buf); - if (!parent_section) { - writer_put_str(wctx, "# ffprobe output\n\n"); - return; - } - - if (wctx->nb_item[wctx->level-1]) - writer_w8(wctx, '\n'); - - av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); - if (ini->hierarchical || - !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { - av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name); - - if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { - int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? - wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; - av_bprintf(buf, ".%d", n); - } - } - - if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) - writer_printf(wctx, "[%s]\n", buf->str); -} - -static void ini_print_str(WriterContext *wctx, const char *key, const char *value) -{ - AVBPrint buf; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "%s=", ini_escape_str(&buf, key)); - av_bprint_clear(&buf); - writer_printf(wctx, "%s\n", ini_escape_str(&buf, value)); - av_bprint_finalize(&buf, NULL); -} - -static void ini_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - writer_printf(wctx, "%s=%"PRId64"\n", key, value); -} - -static const Writer ini_writer = { - .name = "ini", - .priv_size = sizeof(INIContext), - .print_section_header = ini_print_section_header, - .print_integer = ini_print_int, - .print_string = ini_print_str, - .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &ini_class, -}; - -/* JSON output */ - -typedef struct JSONContext { - const AVClass *class; - int indent_level; - int compact; - const char *item_sep, *item_start_end; -} JSONContext; - -#undef OFFSET -#define OFFSET(x) offsetof(JSONContext, x) - -static const AVOption json_options[]= { - { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - { NULL } -}; - -DEFINE_WRITER_CLASS(json); - -static av_cold int json_init(WriterContext *wctx) -{ - JSONContext *json = wctx->priv; - - json->item_sep = json->compact ? ", " : ",\n"; - json->item_start_end = json->compact ? " " : "\n"; - - return 0; -} - -static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) -{ - static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0}; - static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0}; - const char *p; - - for (p = src; *p; p++) { - char *s = strchr(json_escape, *p); - if (s) { - av_bprint_chars(dst, '\\', 1); - av_bprint_chars(dst, json_subst[s - json_escape], 1); - } else if ((unsigned char)*p < 32) { - av_bprintf(dst, "\\u00%02x", *p & 0xff); - } else { - av_bprint_chars(dst, *p, 1); - } - } - return dst->str; -} - -#define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ') - -static void json_print_section_header(WriterContext *wctx, const void *data) -{ - JSONContext *json = wctx->priv; - AVBPrint buf; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->level && wctx->nb_item[wctx->level-1]) - writer_put_str(wctx, ",\n"); - - if (section->flags & SECTION_FLAG_IS_WRAPPER) { - writer_put_str(wctx, "{\n"); - json->indent_level++; - } else { - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - json_escape_str(&buf, section->name, wctx); - JSON_INDENT(); - - json->indent_level++; - if (section->flags & SECTION_FLAG_IS_ARRAY) { - writer_printf(wctx, "\"%s\": [\n", buf.str); - } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) { - writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end); - } else { - writer_printf(wctx, "{%s", json->item_start_end); - - /* this is required so the parser can distinguish between packets and frames */ - if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) { - if (!json->compact) - JSON_INDENT(); - writer_printf(wctx, "\"type\": \"%s\"", section->name); - wctx->nb_item[wctx->level]++; - } - } - av_bprint_finalize(&buf, NULL); - } -} - -static void json_print_section_footer(WriterContext *wctx) -{ - JSONContext *json = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - if (wctx->level == 0) { - json->indent_level--; - writer_put_str(wctx, "\n}\n"); - } else if (section->flags & SECTION_FLAG_IS_ARRAY) { - writer_w8(wctx, '\n'); - json->indent_level--; - JSON_INDENT(); - writer_w8(wctx, ']'); - } else { - writer_put_str(wctx, json->item_start_end); - json->indent_level--; - if (!json->compact) - JSON_INDENT(); - writer_w8(wctx, '}'); - } -} - -static inline void json_print_item_str(WriterContext *wctx, - const char *key, const char *value) -{ - AVBPrint buf; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx)); - av_bprint_clear(&buf); - writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx)); - av_bprint_finalize(&buf, NULL); -} - -static void json_print_str(WriterContext *wctx, const char *key, const char *value) -{ - JSONContext *json = wctx->priv; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) - writer_put_str(wctx, json->item_sep); - if (!json->compact) - JSON_INDENT(); - json_print_item_str(wctx, key, value); -} - -static void json_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - JSONContext *json = wctx->priv; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - AVBPrint buf; - - if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) - writer_put_str(wctx, json->item_sep); - if (!json->compact) - JSON_INDENT(); - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value); - av_bprint_finalize(&buf, NULL); -} - -static const Writer json_writer = { - .name = "json", - .priv_size = sizeof(JSONContext), - .init = json_init, - .print_section_header = json_print_section_header, - .print_section_footer = json_print_section_footer, - .print_integer = json_print_int, - .print_string = json_print_str, - .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &json_class, -}; - -/* XML output */ - -typedef struct XMLContext { - const AVClass *class; - int within_tag; - int indent_level; - int fully_qualified; - int xsd_strict; -} XMLContext; - -#undef OFFSET -#define OFFSET(x) offsetof(XMLContext, x) - -static const AVOption xml_options[] = { - {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, - {NULL}, -}; - -DEFINE_WRITER_CLASS(xml); - -static av_cold int xml_init(WriterContext *wctx) -{ - XMLContext *xml = wctx->priv; - - if (xml->xsd_strict) { - xml->fully_qualified = 1; -#define CHECK_COMPLIANCE(opt, opt_name) \ - if (opt) { \ - av_log(wctx, AV_LOG_ERROR, \ - "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \ - "You need to disable such option with '-no%s'\n", opt_name, opt_name); \ - return AVERROR(EINVAL); \ - } - CHECK_COMPLIANCE(show_private_data, "private"); - CHECK_COMPLIANCE(show_value_unit, "unit"); - CHECK_COMPLIANCE(use_value_prefix, "prefix"); - } - - return 0; -} - -#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ') - -static void xml_print_section_header(WriterContext *wctx, const void *data) -{ - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - const struct section *parent_section = wctx->level ? - wctx->section[wctx->level-1] : NULL; - - if (wctx->level == 0) { - const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " - "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" " - "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\""; - - writer_put_str(wctx, "\n"); - writer_printf(wctx, "<%sffprobe%s>\n", - xml->fully_qualified ? "ffprobe:" : "", - xml->fully_qualified ? qual : ""); - return; - } - - if (xml->within_tag) { - xml->within_tag = 0; - writer_put_str(wctx, ">\n"); - } - - if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) && - wctx->level && wctx->nb_item[wctx->level-1]) - writer_w8(wctx, '\n'); - xml->indent_level++; - - if (section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_HAS_VARIABLE_FIELDS)) { - XML_INDENT(); writer_printf(wctx, "<%s", section->name); - - if (section->flags & SECTION_FLAG_HAS_TYPE) { - AVBPrint buf; - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - av_bprint_escape(&buf, section->get_type(data), NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, " type=\"%s\"", buf.str); - } - writer_printf(wctx, ">\n", section->name); - } else { - XML_INDENT(); writer_printf(wctx, "<%s ", section->name); - xml->within_tag = 1; - } -} - -static void xml_print_section_footer(WriterContext *wctx) -{ - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - if (wctx->level == 0) { - writer_printf(wctx, "\n", xml->fully_qualified ? "ffprobe:" : ""); - } else if (xml->within_tag) { - xml->within_tag = 0; - writer_put_str(wctx, "/>\n"); - xml->indent_level--; - } else { - XML_INDENT(); writer_printf(wctx, "\n", section->name); - xml->indent_level--; - } -} - -static void xml_print_value(WriterContext *wctx, const char *key, - const char *str, int64_t num, const int is_int) -{ - AVBPrint buf; - XMLContext *xml = wctx->priv; - const struct section *section = wctx->section[wctx->level]; - - av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); - - if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { - xml->indent_level++; - XML_INDENT(); - av_bprint_escape(&buf, key, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, "<%s key=\"%s\"", - section->element_name, buf.str); - av_bprint_clear(&buf); - - if (is_int) { - writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num); - } else { - av_bprint_escape(&buf, str, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, " value=\"%s\"/>\n", buf.str); - } - xml->indent_level--; - } else { - if (wctx->nb_item[wctx->level]) - writer_w8(wctx, ' '); - - if (is_int) { - writer_printf(wctx, "%s=\"%"PRId64"\"", key, num); - } else { - av_bprint_escape(&buf, str, NULL, - AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); - writer_printf(wctx, "%s=\"%s\"", key, buf.str); - } - } - - av_bprint_finalize(&buf, NULL); -} - -static inline void xml_print_str(WriterContext *wctx, const char *key, const char *value) { - xml_print_value(wctx, key, value, 0, 0); -} - -static void xml_print_int(WriterContext *wctx, const char *key, int64_t value) -{ - xml_print_value(wctx, key, NULL, value, 1); -} - -static Writer xml_writer = { - .name = "xml", - .priv_size = sizeof(XMLContext), - .init = xml_init, - .print_section_header = xml_print_section_header, - .print_section_footer = xml_print_section_footer, - .print_integer = xml_print_int, - .print_string = xml_print_str, - .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, - .priv_class = &xml_class, -}; - -static void writer_register_all(void) -{ - static int initialized; - - if (initialized) - return; - initialized = 1; - - writer_register(&default_writer); - writer_register(&compact_writer); - writer_register(&csv_writer); - writer_register(&flat_writer); - writer_register(&ini_writer); - writer_register(&json_writer); - writer_register(&xml_writer); -} #define print_fmt(k, f, ...) do { \ av_bprint_clear(&pbuf); \ av_bprintf(&pbuf, f, __VA_ARGS__); \ - writer_print_string(w, k, pbuf.str, 0); \ + avtext_print_string(tfc, k, pbuf.str, 0); \ } while (0) #define print_list_fmt(k, f, n, m, ...) do { \ @@ -2009,28 +423,19 @@ static void writer_register_all(void) av_bprintf(&pbuf, f, __VA_ARGS__); \ } \ } \ - writer_print_string(w, k, pbuf.str, 0); \ + avtext_print_string(tfc, k, pbuf.str, 0); \ } while (0) -#define print_int(k, v) writer_print_integer(w, k, v) -#define print_q(k, v, s) writer_print_rational(w, k, v, s) -#define print_str(k, v) writer_print_string(w, k, v, 0) -#define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT) -#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE) -#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0) -#define print_ts(k, v) writer_print_ts(w, k, v, 0) -#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1) -#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1) -#define print_val(k, v, u) do { \ - struct unit_value uv; \ - uv.val.i = v; \ - uv.unit = u; \ - writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \ -} while (0) - -#define print_section_header(s) writer_print_section_header(w, NULL, s) -#define print_section_header_data(s, d) writer_print_section_header(w, d, s) -#define print_section_footer(s) writer_print_section_footer(w, s) +#define print_int(k, v) avtext_print_integer(tfc, k, v, 0) +#define print_q(k, v, s) avtext_print_rational(tfc, k, v, s) +#define print_str(k, v) avtext_print_string(tfc, k, v, 0) +#define print_str_opt(k, v) avtext_print_string(tfc, k, v, AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) +#define print_str_validate(k, v) avtext_print_string(tfc, k, v, AV_TEXTFORMAT_PRINT_STRING_VALIDATE) +#define print_time(k, v, tb) avtext_print_time(tfc, k, v, tb, 0) +#define print_ts(k, v) avtext_print_ts(tfc, k, v, 0) +#define print_duration_time(k, v, tb) avtext_print_time(tfc, k, v, tb, 1) +#define print_duration_ts(k, v) avtext_print_ts(tfc, k, v, 1) +#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u) #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \ { \ @@ -2040,25 +445,62 @@ static void writer_register_all(void) memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \ } -static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id) +static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int section_id) { const AVDictionaryEntry *tag = NULL; int ret = 0; if (!tags) return 0; - writer_print_section_header(w, NULL, section_id); + avtext_print_section_header(tfc, NULL, section_id); while ((tag = av_dict_iterate(tags, tag))) { if ((ret = print_str_validate(tag->key, tag->value)) < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) +static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9]) +{ + double rotation = av_display_rotation_get(matrix); + if (isnan(rotation)) + rotation = 0; + avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1); + print_int("rotation", rotation); +} + +static void print_mastering_display_metadata(AVTextFormatContext *tfc, + const AVMasteringDisplayMetadata *metadata) +{ + if (metadata->has_primaries) { + print_q("red_x", metadata->display_primaries[0][0], '/'); + print_q("red_y", metadata->display_primaries[0][1], '/'); + print_q("green_x", metadata->display_primaries[1][0], '/'); + print_q("green_y", metadata->display_primaries[1][1], '/'); + print_q("blue_x", metadata->display_primaries[2][0], '/'); + print_q("blue_y", metadata->display_primaries[2][1], '/'); + + print_q("white_point_x", metadata->white_point[0], '/'); + print_q("white_point_y", metadata->white_point[1], '/'); + } + + if (metadata->has_luminance) { + print_q("min_luminance", metadata->min_luminance, '/'); + print_q("max_luminance", metadata->max_luminance, '/'); + } +} + +static void print_context_light_level(AVTextFormatContext *tfc, + const AVContentLightMetadata *metadata) +{ + print_int("max_content", metadata->MaxCLL); + print_int("max_average", metadata->MaxFALL); +} + +static void print_dovi_metadata(AVTextFormatContext *tfc, const AVDOVIMetadata *dovi) { if (!dovi) return; @@ -2113,15 +555,15 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) print_int("num_x_partitions", mapping->num_x_partitions); print_int("num_y_partitions", mapping->num_y_partitions); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); for (int c = 0; c < 3; c++) { const AVDOVIReshapingCurve *curve = &mapping->curves[c]; - writer_print_section_header(w, "Reshaping curve", SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, "Reshaping curve", SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_list_fmt("pivots", "%"PRIu16, curve->num_pivots, 1, curve->pivots[idx]); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); for (int i = 0; i < curve->num_pivots - 1; i++) { AVBPrint piece_buf; @@ -2139,7 +581,7 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } av_bprintf(&piece_buf, " mapping"); - writer_print_section_header(w, piece_buf.str, SECTION_ID_FRAME_SIDE_DATA_PIECE); + avtext_print_section_header(tfc, piece_buf.str, SECTION_ID_FRAME_SIDE_DATA_PIECE); print_int("mapping_idc", curve->mapping_idc[i]); switch (curve->mapping_idc[i]) { case AV_DOVI_MAPPING_POLYNOMIAL: @@ -2163,11 +605,11 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } // SECTION_ID_FRAME_SIDE_DATA_PIECE - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { const AVDOVINLQParams *nlq = &mapping->nlq[c]; @@ -2183,11 +625,11 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); // color metadata print_int("dm_metadata_id", color->dm_metadata_id); @@ -2220,7 +662,7 @@ static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi) } } -static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata) +static void print_dynamic_hdr10_plus(AVTextFormatContext *tfc, const AVDynamicHDRPlus *metadata) { if (!metadata) return; @@ -2319,7 +761,7 @@ static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *m } } -static void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *metadata) +static void print_dynamic_hdr_vivid(AVTextFormatContext *tfc, const AVDynamicHDRVivid *metadata) { if (!metadata) return; @@ -2389,7 +831,7 @@ static void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *m } } -static void print_ambient_viewing_environment(WriterContext *w, +static void print_ambient_viewing_environment(AVTextFormatContext *tfc, const AVAmbientViewingEnvironment *env) { if (!env) @@ -2400,7 +842,7 @@ static void print_ambient_viewing_environment(WriterContext *w, print_q("ambient_light_y", env->ambient_light_y, '/'); } -static void print_film_grain_params(WriterContext *w, +static void print_film_grain_params(AVTextFormatContext *tfc, const AVFilmGrainParams *fgp) { const char *color_range, *color_primaries, *color_trc, *color_space; @@ -2446,10 +888,10 @@ static void print_film_grain_params(WriterContext *w, print_int("overlap_flag", aom->overlap_flag); print_int("limit_output_range", aom->limit_output_range); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); if (aom->num_y_points) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int("bit_depth_luma", fgp->bit_depth_luma); print_list_fmt("y_points_value", "%"PRIu8, aom->num_y_points, 1, aom->y_points[idx][0]); @@ -2457,14 +899,14 @@ static void print_film_grain_params(WriterContext *w, print_list_fmt("ar_coeffs_y", "%"PRId8, num_ar_coeffs_y, 1, aom->ar_coeffs_y[idx]); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } for (int uv = 0; uv < 2; uv++) { if (!aom->num_uv_points[uv] && !aom->chroma_scaling_from_luma) continue; - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int("bit_depth_chroma", fgp->bit_depth_chroma); print_list_fmt("uv_points_value", "%"PRIu8, aom->num_uv_points[uv], 1, aom->uv_points[uv][idx][0]); @@ -2475,11 +917,11 @@ static void print_film_grain_params(WriterContext *w, print_int("uv_offset", aom->uv_offset[uv]); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); break; } case AV_FILM_GRAIN_PARAMS_H274: { @@ -2488,36 +930,36 @@ static void print_film_grain_params(WriterContext *w, print_int("blending_mode_id", h274->blending_mode_id); print_int("log2_scale_factor", h274->log2_scale_factor); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST); for (int c = 0; c < 3; c++) { if (!h274->component_model_present[c]) continue; - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_COMPONENT); print_int(c ? "bit_depth_chroma" : "bit_depth_luma", c ? fgp->bit_depth_chroma : fgp->bit_depth_luma); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST); for (int i = 0; i < h274->num_intensity_intervals[c]; i++) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_PIECE); print_int("intensity_interval_lower_bound", h274->intensity_interval_lower_bound[c][i]); print_int("intensity_interval_upper_bound", h274->intensity_interval_upper_bound[c][i]); print_list_fmt("comp_model_value", "%"PRId16, h274->num_model_values[c], 1, h274->comp_model_value[c][i][idx]); // SECTION_ID_FRAME_SIDE_DATA_PIECE - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); // SECTION_ID_FRAME_SIDE_DATA_COMPONENT - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST - writer_print_section_footer(w); + avtext_print_section_footer(tfc); break; } } @@ -2525,129 +967,106 @@ static void print_film_grain_params(WriterContext *w, av_bprint_finalize(&pbuf, NULL); } -static void print_pkt_side_data(WriterContext *w, +static void print_pkt_side_data(AVTextFormatContext *tfc, AVCodecParameters *par, const AVPacketSideData *sd, SectionID id_data) { - const char *name = av_packet_side_data_name(sd->type); + const char *name = av_packet_side_data_name(sd->type); - writer_print_section_header(w, sd, id_data); - print_str("side_data_type", name ? name : "unknown"); - if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) { - double rotation = av_display_rotation_get((int32_t *)sd->data); - if (isnan(rotation)) - rotation = 0; - writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); - print_int("rotation", rotation); - } else if (sd->type == AV_PKT_DATA_STEREO3D) { - const AVStereo3D *stereo = (AVStereo3D *)sd->data; - print_str("type", av_stereo3d_type_name(stereo->type)); - print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT)); - print_str("view", av_stereo3d_view_name(stereo->view)); - print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye)); - print_int("baseline", stereo->baseline); - print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/'); - print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/'); - } else if (sd->type == AV_PKT_DATA_SPHERICAL) { - const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; - print_str("projection", av_spherical_projection_name(spherical->projection)); - if (spherical->projection == AV_SPHERICAL_CUBEMAP) { - print_int("padding", spherical->padding); - } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { - size_t l, t, r, b; - av_spherical_tile_bounds(spherical, par->width, par->height, - &l, &t, &r, &b); - print_int("bound_left", l); - print_int("bound_top", t); - print_int("bound_right", r); - print_int("bound_bottom", b); - } - - print_int("yaw", (double) spherical->yaw / (1 << 16)); - print_int("pitch", (double) spherical->pitch / (1 << 16)); - print_int("roll", (double) spherical->roll / (1 << 16)); - } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) { - print_int("skip_samples", AV_RL32(sd->data)); - print_int("discard_padding", AV_RL32(sd->data + 4)); - print_int("skip_reason", AV_RL8(sd->data + 8)); - print_int("discard_reason", AV_RL8(sd->data + 9)); - } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) { - AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; - - if (metadata->has_primaries) { - print_q("red_x", metadata->display_primaries[0][0], '/'); - print_q("red_y", metadata->display_primaries[0][1], '/'); - print_q("green_x", metadata->display_primaries[1][0], '/'); - print_q("green_y", metadata->display_primaries[1][1], '/'); - print_q("blue_x", metadata->display_primaries[2][0], '/'); - print_q("blue_y", metadata->display_primaries[2][1], '/'); - - print_q("white_point_x", metadata->white_point[0], '/'); - print_q("white_point_y", metadata->white_point[1], '/'); - } - - if (metadata->has_luminance) { - print_q("min_luminance", metadata->min_luminance, '/'); - print_q("max_luminance", metadata->max_luminance, '/'); - } - } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) { - AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; - print_int("max_content", metadata->MaxCLL); - print_int("max_average", metadata->MaxFALL); - } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) { - print_ambient_viewing_environment( - w, (const AVAmbientViewingEnvironment *)sd->data); - } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) { - AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; - print_dynamic_hdr10_plus(w, metadata); - } else if (sd->type == AV_PKT_DATA_DOVI_CONF) { - AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; - const char *comp = "unknown"; - print_int("dv_version_major", dovi->dv_version_major); - print_int("dv_version_minor", dovi->dv_version_minor); - print_int("dv_profile", dovi->dv_profile); - print_int("dv_level", dovi->dv_level); - print_int("rpu_present_flag", dovi->rpu_present_flag); - print_int("el_present_flag", dovi->el_present_flag); - print_int("bl_present_flag", dovi->bl_present_flag); - print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id); - switch (dovi->dv_md_compression) - { - case AV_DOVI_COMPRESSION_NONE: comp = "none"; break; - case AV_DOVI_COMPRESSION_LIMITED: comp = "limited"; break; - case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break; - case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break; - } - print_str("dv_md_compression", comp); - } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) { - enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data; - print_int("service_type", *t); - } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) { - print_int("id", *sd->data); - } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) { - const AVCPBProperties *prop = (AVCPBProperties *)sd->data; - print_int("max_bitrate", prop->max_bitrate); - print_int("min_bitrate", prop->min_bitrate); - print_int("avg_bitrate", prop->avg_bitrate); - print_int("buffer_size", prop->buffer_size); - print_int("vbv_delay", prop->vbv_delay); - } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER || - sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) { - if (do_show_data) - writer_print_data(w, "data", sd->data, sd->size); - writer_print_data_hash(w, "data_hash", sd->data, sd->size); - } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) { - print_int("crop_top", AV_RL32(sd->data)); - print_int("crop_bottom", AV_RL32(sd->data + 4)); - print_int("crop_left", AV_RL32(sd->data + 8)); - print_int("crop_right", AV_RL32(sd->data + 12)); - } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) { - print_int("active_format", *sd->data); + avtext_print_section_header(tfc, sd, id_data); + print_str("side_data_type", name ? name : "unknown"); + if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) { + print_displaymatrix(tfc, (const int32_t*)sd->data); + } else if (sd->type == AV_PKT_DATA_STEREO3D) { + const AVStereo3D *stereo = (AVStereo3D *)sd->data; + print_str("type", av_stereo3d_type_name(stereo->type)); + print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT)); + print_str("view", av_stereo3d_view_name(stereo->view)); + print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye)); + print_int("baseline", stereo->baseline); + print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/'); + print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/'); + } else if (sd->type == AV_PKT_DATA_SPHERICAL) { + const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; + print_str("projection", av_spherical_projection_name(spherical->projection)); + if (spherical->projection == AV_SPHERICAL_CUBEMAP) { + print_int("padding", spherical->padding); + } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { + size_t l, t, r, b; + av_spherical_tile_bounds(spherical, par->width, par->height, + &l, &t, &r, &b); + print_int("bound_left", l); + print_int("bound_top", t); + print_int("bound_right", r); + print_int("bound_bottom", b); } + + print_int("yaw", (double) spherical->yaw / (1 << 16)); + print_int("pitch", (double) spherical->pitch / (1 << 16)); + print_int("roll", (double) spherical->roll / (1 << 16)); + } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) { + print_int("skip_samples", AV_RL32(sd->data)); + print_int("discard_padding", AV_RL32(sd->data + 4)); + print_int("skip_reason", AV_RL8(sd->data + 8)); + print_int("discard_reason", AV_RL8(sd->data + 9)); + } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) { + print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data); + } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) { + print_context_light_level(tfc, (AVContentLightMetadata *)sd->data); + } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) { + print_ambient_viewing_environment( + tfc, (const AVAmbientViewingEnvironment *)sd->data); + } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) { + AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; + print_dynamic_hdr10_plus(tfc, metadata); + } else if (sd->type == AV_PKT_DATA_DOVI_CONF) { + AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; + const char *comp = "unknown"; + print_int("dv_version_major", dovi->dv_version_major); + print_int("dv_version_minor", dovi->dv_version_minor); + print_int("dv_profile", dovi->dv_profile); + print_int("dv_level", dovi->dv_level); + print_int("rpu_present_flag", dovi->rpu_present_flag); + print_int("el_present_flag", dovi->el_present_flag); + print_int("bl_present_flag", dovi->bl_present_flag); + print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id); + switch (dovi->dv_md_compression) + { + case AV_DOVI_COMPRESSION_NONE: comp = "none"; break; + case AV_DOVI_COMPRESSION_LIMITED: comp = "limited"; break; + case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break; + case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break; + } + print_str("dv_md_compression", comp); + } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) { + enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data; + print_int("service_type", *t); + } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) { + print_int("id", *sd->data); + } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) { + const AVCPBProperties *prop = (AVCPBProperties *)sd->data; + print_int("max_bitrate", prop->max_bitrate); + print_int("min_bitrate", prop->min_bitrate); + print_int("avg_bitrate", prop->avg_bitrate); + print_int("buffer_size", prop->buffer_size); + print_int("vbv_delay", prop->vbv_delay); + } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER || + sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) { + if (do_show_data) + avtext_print_data(tfc, "data", sd->data, sd->size); + avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size); + } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) { + print_int("crop_top", AV_RL32(sd->data)); + print_int("crop_bottom", AV_RL32(sd->data + 4)); + print_int("crop_left", AV_RL32(sd->data + 8)); + print_int("crop_right", AV_RL32(sd->data + 12)); + } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) { + print_int("active_format", *sd->data); + } } -static void print_private_data(WriterContext *w, void *priv_data) +static void print_private_data(AVTextFormatContext *tfc, void *priv_data) { const AVOption *opt = NULL; while (opt = av_opt_next(priv_data, opt)) { @@ -2660,7 +1079,32 @@ static void print_private_data(WriterContext *w, void *priv_data) } } -static void print_color_range(WriterContext *w, enum AVColorRange color_range) +static void print_pixel_format(AVTextFormatContext *tfc, enum AVPixelFormat pix_fmt) +{ + const char *s = av_get_pix_fmt_name(pix_fmt); + enum AVPixelFormat swapped_pix_fmt; + + if (!s) { + print_str_opt("pix_fmt", "unknown"); + } else if (!do_bitexact || + (swapped_pix_fmt = av_pix_fmt_swap_endianness(pix_fmt)) == AV_PIX_FMT_NONE) { + print_str ("pix_fmt", s); + } else { + const char *s2 = av_get_pix_fmt_name(swapped_pix_fmt); + char buf[128]; + size_t i = 0; + + while (s[i] && s[i] == s2[i] && i < sizeof(buf) - 1) { + buf[i] = s[i]; + i++; + } + buf[i] = '\0'; + + print_str ("pix_fmt", buf); + } +} + +static void print_color_range(AVTextFormatContext *tfc, enum AVColorRange color_range) { const char *val = av_color_range_name(color_range); if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) { @@ -2670,7 +1114,7 @@ static void print_color_range(WriterContext *w, enum AVColorRange color_range) } } -static void print_color_space(WriterContext *w, enum AVColorSpace color_space) +static void print_color_space(AVTextFormatContext *tfc, enum AVColorSpace color_space) { const char *val = av_color_space_name(color_space); if (!val || color_space == AVCOL_SPC_UNSPECIFIED) { @@ -2680,7 +1124,7 @@ static void print_color_space(WriterContext *w, enum AVColorSpace color_space) } } -static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries) +static void print_primaries(AVTextFormatContext *tfc, enum AVColorPrimaries color_primaries) { const char *val = av_color_primaries_name(color_primaries); if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) { @@ -2690,7 +1134,7 @@ static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primar } } -static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc) +static void print_color_trc(AVTextFormatContext *tfc, enum AVColorTransferCharacteristic color_trc) { const char *val = av_color_transfer_name(color_trc); if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) { @@ -2700,7 +1144,7 @@ static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic } } -static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location) +static void print_chroma_location(AVTextFormatContext *tfc, enum AVChromaLocation chroma_location) { const char *val = av_chroma_location_name(chroma_location); if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) { @@ -2715,7 +1159,7 @@ static void clear_log(int need_lock) int i; if (need_lock) - pthread_mutex_lock(&log_mutex); + ff_mutex_lock(&log_mutex); for (i=0; istreams[pkt->stream_index].st; AVBPrint pbuf; const char *s; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_PACKET); + avtext_print_section_header(tfc, NULL, SECTION_ID_PACKET); s = av_get_media_type_string(st->codecpar->codec_type); if (s) print_str ("codec_type", s); @@ -2789,8 +1232,8 @@ static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int p pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_', pkt->flags & AV_PKT_FLAG_CORRUPT ? 'C' : '_'); if (do_show_data) - writer_print_data(w, "data", pkt->data, pkt->size); - writer_print_data_hash(w, "data_hash", pkt->data, pkt->size); + avtext_print_data(tfc, "data", pkt->data, pkt->size); + avtext_print_data_hash(tfc, "data_hash", pkt->data, pkt->size); if (pkt->side_data_elems) { size_t size; @@ -2800,33 +1243,33 @@ static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int p if (side_metadata && size && do_show_packet_tags) { AVDictionary *dict = NULL; if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0) - show_tags(w, dict, SECTION_ID_PACKET_TAGS); + show_tags(tfc, dict, SECTION_ID_PACKET_TAGS); av_dict_free(&dict); } - writer_print_section_header(w, NULL, SECTION_ID_PACKET_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_PACKET_SIDE_DATA_LIST); for (int i = 0; i < pkt->side_data_elems; i++) { - print_pkt_side_data(w, st->codecpar, &pkt->side_data[i], + print_pkt_side_data(tfc, st->codecpar, &pkt->side_data[i], SECTION_ID_PACKET_SIDE_DATA); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, +static void show_subtitle(AVTextFormatContext *tfc, AVSubtitle *sub, AVStream *stream, AVFormatContext *fmt_ctx) { AVBPrint pbuf; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_SUBTITLE); + avtext_print_section_header(tfc, NULL, SECTION_ID_SUBTITLE); print_str ("media_type", "subtitle"); print_ts ("pts", sub->pts); @@ -2836,31 +1279,27 @@ static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, print_int ("end_display_time", sub->end_display_time); print_int ("num_rects", sub->num_rects); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static void print_frame_side_data(WriterContext *w, +static void print_frame_side_data(AVTextFormatContext *tfc, const AVFrame *frame, const AVStream *stream) { - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_LIST); for (int i = 0; i < frame->nb_side_data; i++) { const AVFrameSideData *sd = frame->side_data[i]; const char *name; - writer_print_section_header(w, sd, SECTION_ID_FRAME_SIDE_DATA); + avtext_print_section_header(tfc, sd, SECTION_ID_FRAME_SIDE_DATA); name = av_frame_side_data_name(sd->type); print_str("side_data_type", name ? name : "unknown"); if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) { - double rotation = av_display_rotation_get((int32_t *)sd->data); - if (isnan(rotation)) - rotation = 0; - writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); - print_int("rotation", rotation); + print_displaymatrix(tfc, (const int32_t*)sd->data); } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) { print_int("active_format", *sd->data); } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) { @@ -2870,65 +1309,46 @@ static void print_frame_side_data(WriterContext *w, } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) { uint32_t *tc = (uint32_t*)sd->data; int m = FFMIN(tc[0],3); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); for (int j = 1; j <= m ; j++) { char tcbuf[AV_TIMECODE_STR_SIZE]; av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0); - writer_print_section_header(w, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); print_str("value", tcbuf); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) { - AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; - - if (metadata->has_primaries) { - print_q("red_x", metadata->display_primaries[0][0], '/'); - print_q("red_y", metadata->display_primaries[0][1], '/'); - print_q("green_x", metadata->display_primaries[1][0], '/'); - print_q("green_y", metadata->display_primaries[1][1], '/'); - print_q("blue_x", metadata->display_primaries[2][0], '/'); - print_q("blue_y", metadata->display_primaries[2][1], '/'); - - print_q("white_point_x", metadata->white_point[0], '/'); - print_q("white_point_y", metadata->white_point[1], '/'); - } - - if (metadata->has_luminance) { - print_q("min_luminance", metadata->min_luminance, '/'); - print_q("max_luminance", metadata->max_luminance, '/'); - } + print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) { AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; - print_dynamic_hdr10_plus(w, metadata); + print_dynamic_hdr10_plus(tfc, metadata); } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) { - AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; - print_int("max_content", metadata->MaxCLL); - print_int("max_average", metadata->MaxFALL); + print_context_light_level(tfc, (AVContentLightMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) { const AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE); if (tag) print_str(tag->key, tag->value); print_int("size", sd->size); } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) { - print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data); + print_dovi_metadata(tfc, (const AVDOVIMetadata *)sd->data); } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) { AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data; - print_dynamic_hdr_vivid(w, metadata); + print_dynamic_hdr_vivid(tfc, metadata); } else if (sd->type == AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT) { - print_ambient_viewing_environment(w, (const AVAmbientViewingEnvironment *)sd->data); + print_ambient_viewing_environment(tfc, (const AVAmbientViewingEnvironment *)sd->data); } else if (sd->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) { AVFilmGrainParams *fgp = (AVFilmGrainParams *)sd->data; - print_film_grain_params(w, fgp); + print_film_grain_params(tfc, fgp); } else if (sd->type == AV_FRAME_DATA_VIEW_ID) { print_int("view_id", *(int*)sd->data); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } -static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, +static void show_frame(AVTextFormatContext *tfc, AVFrame *frame, AVStream *stream, AVFormatContext *fmt_ctx) { FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL; @@ -2938,7 +1358,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_FRAME); + avtext_print_section_header(tfc, NULL, SECTION_ID_FRAME); s = av_get_media_type_string(stream->codecpar->codec_type); if (s) print_str ("media_type", s); @@ -2968,9 +1388,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, print_int("crop_bottom", frame->crop_bottom); print_int("crop_left", frame->crop_left); print_int("crop_right", frame->crop_right); - s = av_get_pix_fmt_name(frame->format); - if (s) print_str ("pix_fmt", s); - else print_str_opt("pix_fmt", "unknown"); + print_pixel_format(tfc, frame->format); sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame); if (sar.num) { print_q("sample_aspect_ratio", sar, ':'); @@ -2980,13 +1398,14 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type)); print_int("interlaced_frame", !!(frame->flags & AV_FRAME_FLAG_INTERLACED)); print_int("top_field_first", !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + print_int("lossless", !!(frame->flags & AV_FRAME_FLAG_LOSSLESS)); print_int("repeat_pict", frame->repeat_pict); - print_color_range(w, frame->color_range); - print_color_space(w, frame->colorspace); - print_primaries(w, frame->color_primaries); - print_color_trc(w, frame->color_trc); - print_chroma_location(w, frame->chroma_location); + print_color_range(tfc, frame->color_range); + print_color_space(tfc, frame->colorspace); + print_primaries(tfc, frame->color_primaries); + print_color_trc(tfc, frame->color_trc); + print_chroma_location(tfc, frame->chroma_location); break; case AVMEDIA_TYPE_AUDIO: @@ -3003,19 +1422,19 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, break; } if (do_show_frame_tags) - show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS); + show_tags(tfc, frame->metadata, SECTION_ID_FRAME_TAGS); if (do_show_log) - show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log); + show_log(tfc, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log); if (frame->nb_side_data) - print_frame_side_data(w, frame, stream); + print_frame_side_data(tfc, frame, stream); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); } -static av_always_inline int process_frame(WriterContext *w, +static av_always_inline int process_frame(AVTextFormatContext *tfc, InputFile *ifile, AVFrame *frame, const AVPacket *pkt, int *packet_new) @@ -3069,9 +1488,19 @@ static av_always_inline int process_frame(WriterContext *w, nb_streams_frames[pkt->stream_index]++; if (do_show_frames) if (is_sub) - show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx); + show_subtitle(tfc, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx); else - show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx); + show_frame(tfc, frame, ifile->streams[pkt->stream_index].st, fmt_ctx); + + if (!is_sub && do_analyze_frames) { + for (int i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC) + streams_with_closed_captions[pkt->stream_index] = 1; + else if (frame->side_data[i]->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) + streams_with_film_grain[pkt->stream_index] = 1; + } + } + if (is_sub) avsubtitle_free(&sub); } @@ -3102,7 +1531,7 @@ static void log_read_interval(const ReadInterval *interval, void *log_ctx, int l av_log(log_ctx, log_level, "\n"); } -static int read_interval_packets(WriterContext *w, InputFile *ifile, +static int read_interval_packets(AVTextFormatContext *tfc, InputFile *ifile, const ReadInterval *interval, int64_t *cur_ts) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; @@ -3154,6 +1583,8 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_closed_captions, nb_streams, fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_film_grain, nb_streams, fmt_ctx->nb_streams); nb_streams = fmt_ctx->nb_streams; } if (selected_streams[pkt->stream_index]) { @@ -3183,7 +1614,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, frame_count++; if (do_read_packets) { if (do_show_packets) - show_packet(w, ifile, pkt, i++); + show_packet(tfc, ifile, pkt, i++); nb_streams_packets[pkt->stream_index]++; } if (do_read_frames) { @@ -3199,7 +1630,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, fd->pkt_pos = pkt->pos; fd->pkt_size = pkt->size; - while (process_frame(w, ifile, frame, pkt, &packet_new) > 0); + while (process_frame(tfc, ifile, frame, pkt, &packet_new) > 0); } } av_packet_unref(pkt); @@ -3209,7 +1640,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, for (i = 0; i < ifile->nb_streams; i++) { pkt->stream_index = i; if (do_read_frames) { - while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0); + while (process_frame(tfc, ifile, frame, pkt, &(int){1}) > 0); if (ifile->streams[i].dec_ctx) avcodec_flush_buffers(ifile->streams[i].dec_ctx); } @@ -3225,7 +1656,7 @@ end: return ret; } -static int read_packets(WriterContext *w, InputFile *ifile) +static int read_packets(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; @@ -3233,10 +1664,10 @@ static int read_packets(WriterContext *w, InputFile *ifile) if (read_intervals_nb == 0) { ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 }; - ret = read_interval_packets(w, ifile, &interval, &cur_ts); + ret = read_interval_packets(tfc, ifile, &interval, &cur_ts); } else { for (i = 0; i < read_intervals_nb; i++) { - ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts); + ret = read_interval_packets(tfc, ifile, &read_intervals[i], &cur_ts); if (ret < 0) break; } @@ -3245,22 +1676,22 @@ static int read_packets(WriterContext *w, InputFile *ifile) return ret; } -static void print_dispositions(WriterContext *w, uint32_t disposition, SectionID section_id) +static void print_dispositions(AVTextFormatContext *tfc, uint32_t disposition, SectionID section_id) { - writer_print_section_header(w, NULL, section_id); + avtext_print_section_header(tfc, NULL, section_id); for (int i = 0; i < sizeof(disposition) * CHAR_BIT; i++) { const char *disposition_str = av_disposition_to_string(1U << i); if (disposition_str) print_int(disposition_str, !!(disposition & (1U << i))); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } #define IN_PROGRAM 1 #define IN_STREAM_GROUP 2 -static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container) +static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container) { AVStream *stream = ist->st; AVCodecParameters *par; @@ -3292,7 +1723,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, section_header[container]); + avtext_print_section_header(tfc, NULL, section_header[container]); print_int("index", stream->index); @@ -3337,8 +1768,11 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (dec_ctx) { print_int("coded_width", dec_ctx->coded_width); print_int("coded_height", dec_ctx->coded_height); - print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS)); - print_int("film_grain", !!(dec_ctx->properties & FF_CODEC_PROPERTY_FILM_GRAIN)); + + if (do_analyze_frames) { + print_int("closed_captions", streams_with_closed_captions[stream->index]); + print_int("film_grain", streams_with_film_grain[stream->index]); + } } print_int("has_b_frames", par->video_delay); sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL); @@ -3353,16 +1787,14 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id print_str_opt("sample_aspect_ratio", "N/A"); print_str_opt("display_aspect_ratio", "N/A"); } - s = av_get_pix_fmt_name(par->format); - if (s) print_str ("pix_fmt", s); - else print_str_opt("pix_fmt", "unknown"); + print_pixel_format(tfc, par->format); print_int("level", par->level); - print_color_range(w, par->color_range); - print_color_space(w, par->color_space); - print_color_trc(w, par->color_trc); - print_primaries(w, par->color_primaries); - print_chroma_location(w, par->chroma_location); + print_color_range(tfc, par->color_range); + print_color_space(tfc, par->color_space); + print_color_trc(tfc, par->color_trc); + print_primaries(tfc, par->color_primaries); + print_chroma_location(tfc, par->chroma_location); if (par->field_order == AV_FIELD_PROGRESSIVE) print_str("field_order", "progressive"); @@ -3414,9 +1846,9 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (show_private_data) { if (dec_ctx && dec_ctx->codec->priv_class) - print_private_data(w, dec_ctx->priv_data); + print_private_data(tfc, dec_ctx->priv_data); if (fmt_ctx->iformat->priv_class) - print_private_data(w, fmt_ctx->priv_data); + print_private_data(tfc, fmt_ctx->priv_data); } if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id); @@ -3443,113 +1875,113 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]); else print_str_opt("nb_read_packets", "N/A"); if (do_show_data) - writer_print_data(w, "extradata", par->extradata, + avtext_print_data(tfc, "extradata", par->extradata, par->extradata_size); if (par->extradata_size > 0) { print_int("extradata_size", par->extradata_size); - writer_print_data_hash(w, "extradata_hash", par->extradata, + avtext_print_data_hash(tfc, "extradata_hash", par->extradata, par->extradata_size); } /* Print disposition information */ if (do_show_stream_disposition) { av_assert0(container < FF_ARRAY_ELEMS(section_disposition)); - print_dispositions(w, stream->disposition, section_disposition[container]); + print_dispositions(tfc, stream->disposition, section_disposition[container]); } if (do_show_stream_tags) { av_assert0(container < FF_ARRAY_ELEMS(section_tags)); - ret = show_tags(w, stream->metadata, section_tags[container]); + ret = show_tags(tfc, stream->metadata, section_tags[container]); } if (stream->codecpar->nb_coded_side_data) { - writer_print_section_header(w, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST); for (int i = 0; i < stream->codecpar->nb_coded_side_data; i++) { - print_pkt_side_data(w, stream->codecpar, &stream->codecpar->coded_side_data[i], + print_pkt_side_data(tfc, stream->codecpar, &stream->codecpar->coded_side_data[i], SECTION_ID_STREAM_SIDE_DATA); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); fflush(stdout); return ret; } -static int show_streams(WriterContext *w, InputFile *ifile) +static int show_streams(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMS); for (i = 0; i < ifile->nb_streams; i++) if (selected_streams[i]) { - ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0); + ret = show_stream(tfc, fmt_ctx, i, &ifile->streams[i], 0); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program) +static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *program) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM); print_int("program_id", program->id); print_int("program_num", program->program_num); print_int("nb_streams", program->nb_stream_indexes); print_int("pmt_pid", program->pmt_pid); print_int("pcr_pid", program->pcr_pid); if (do_show_program_tags) - ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS); + ret = show_tags(tfc, program->metadata, SECTION_ID_PROGRAM_TAGS); if (ret < 0) goto end; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_STREAMS); for (i = 0; i < program->nb_stream_indexes; i++) { if (selected_streams[program->stream_index[i]]) { - ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM); + ret = show_stream(tfc, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM); if (ret < 0) break; } } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); end: - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_programs(WriterContext *w, InputFile *ifile) +static int show_programs(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_PROGRAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAMS); for (i = 0; i < fmt_ctx->nb_programs; i++) { AVProgram *program = fmt_ctx->programs[i]; if (!program) continue; - ret = show_program(w, ifile, program); + ret = show_program(tfc, ifile, program); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static void print_tile_grid_params(WriterContext *w, const AVStreamGroup *stg, +static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVStreamGroupTileGrid *tile_grid) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_tiles", tile_grid->nb_tiles); print_int("coded_width", tile_grid->coded_width); print_int("coded_height", tile_grid->coded_height); @@ -3557,19 +1989,19 @@ static void print_tile_grid_params(WriterContext *w, const AVStreamGroup *stg, print_int("vertical_offset", tile_grid->vertical_offset); print_int("width", tile_grid->width); print_int("height", tile_grid->height); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); for (int i = 0; i < tile_grid->nb_tiles; i++) { - writer_print_section_header(w, "tile_offset", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "tile_offset", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); print_int("stream_index", tile_grid->offsets[i].idx); print_int("tile_horizontal_offset", tile_grid->offsets[i].horizontal); print_int("tile_vertical_offset", tile_grid->offsets[i].vertical); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); + avtext_print_section_footer(tfc); } -static void print_iamf_param_definition(WriterContext *w, const char *name, +static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *name, const AVIAMFParamDefinition *param, SectionID section_id) { SectionID subsection_id, parameter_section_id; @@ -3577,7 +2009,7 @@ static void print_iamf_param_definition(WriterContext *w, const char *name, av_assert0(subsection_id != -1); parameter_section_id = sections[subsection_id].children_ids[0]; av_assert0(parameter_section_id != -1); - writer_print_section_header(w, "IAMF Param Definition", section_id); + avtext_print_section_header(tfc, "IAMF Param Definition", section_id); print_str("name", name); print_int("nb_subblocks", param->nb_subblocks); print_int("type", param->type); @@ -3586,56 +2018,56 @@ static void print_iamf_param_definition(WriterContext *w, const char *name, print_int("duration", param->duration); print_int("constant_subblock_duration", param->constant_subblock_duration); if (param->nb_subblocks > 0) - writer_print_section_header(w, NULL, subsection_id); + avtext_print_section_header(tfc, NULL, subsection_id); for (int i = 0; i < param->nb_subblocks; i++) { const void *subblock = av_iamf_param_definition_get_subblock(param, i); switch(param->type) { case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { const AVIAMFMixGain *mix = subblock; - writer_print_section_header(w, "IAMF Mix Gain Parameters", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Mix Gain Parameters", parameter_section_id); print_int("subblock_duration", mix->subblock_duration); print_int("animation_type", mix->animation_type); print_q("start_point_value", mix->start_point_value, '/'); print_q("end_point_value", mix->end_point_value, '/'); print_q("control_point_value", mix->control_point_value, '/'); print_q("control_point_relative_time", mix->control_point_relative_time, '/'); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { const AVIAMFDemixingInfo *demix = subblock; - writer_print_section_header(w, "IAMF Demixing Info", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Demixing Info", parameter_section_id); print_int("subblock_duration", demix->subblock_duration); print_int("dmixp_mode", demix->dmixp_mode); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { const AVIAMFReconGain *recon = subblock; - writer_print_section_header(w, "IAMF Recon Gain", parameter_section_id); + avtext_print_section_header(tfc, "IAMF Recon Gain", parameter_section_id); print_int("subblock_duration", recon->subblock_duration); - writer_print_section_footer(w); // parameter_section_id + avtext_print_section_footer(tfc); // parameter_section_id break; } } } if (param->nb_subblocks > 0) - writer_print_section_footer(w); // subsection_id - writer_print_section_footer(w); // section_id + avtext_print_section_footer(tfc); // subsection_id + avtext_print_section_footer(tfc); // section_id } -static void print_iamf_audio_element_params(WriterContext *w, const AVStreamGroup *stg, +static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVIAMFAudioElement *audio_element) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_layers", audio_element->nb_layers); print_int("audio_element_type", audio_element->audio_element_type); print_int("default_w", audio_element->default_w); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); for (int i = 0; i < audio_element->nb_layers; i++) { const AVIAMFLayer *layer = audio_element->layers[i]; char val_str[128]; - writer_print_section_header(w, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); av_channel_layout_describe(&layer->ch_layout, val_str, sizeof(val_str)); print_str("channel_layout", val_str); if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL) { @@ -3643,52 +2075,52 @@ static void print_iamf_audio_element_params(WriterContext *w, const AVStreamGrou print_q("output_gain", layer->output_gain, '/'); } else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) print_int("ambisonics_mode", layer->ambisonics_mode); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } if (audio_element->demixing_info) - print_iamf_param_definition(w, "demixing_info", audio_element->demixing_info, + print_iamf_param_definition(tfc, "demixing_info", audio_element->demixing_info, SECTION_ID_STREAM_GROUP_SUBCOMPONENT); if (audio_element->recon_gain_info) - print_iamf_param_definition(w, "recon_gain_info", audio_element->recon_gain_info, + print_iamf_param_definition(tfc, "recon_gain_info", audio_element->recon_gain_info, SECTION_ID_STREAM_GROUP_SUBCOMPONENT); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT } -static void print_iamf_submix_params(WriterContext *w, const AVIAMFSubmix *submix) +static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmix *submix) { - writer_print_section_header(w, "IAMF Submix", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Submix", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); print_int("nb_elements", submix->nb_elements); print_int("nb_layouts", submix->nb_layouts); print_q("default_mix_gain", submix->default_mix_gain, '/'); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_PIECES); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_PIECES); for (int i = 0; i < submix->nb_elements; i++) { const AVIAMFSubmixElement *element = submix->elements[i]; - writer_print_section_header(w, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE); + avtext_print_section_header(tfc, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE); print_int("stream_id", element->audio_element_id); print_q("default_mix_gain", element->default_mix_gain, '/'); print_int("headphones_rendering_mode", element->headphones_rendering_mode); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBPIECES); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBPIECES); if (element->annotations) { const AVDictionaryEntry *annotation = NULL; - writer_print_section_header(w, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBPIECE); + avtext_print_section_header(tfc, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBPIECE); while (annotation = av_dict_iterate(element->annotations, annotation)) print_str(annotation->key, annotation->value); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBPIECE } if (element->element_mix_config) - print_iamf_param_definition(w, "element_mix_config", element->element_mix_config, + print_iamf_param_definition(tfc, "element_mix_config", element->element_mix_config, SECTION_ID_STREAM_GROUP_SUBPIECE); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECES - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBPIECES + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECE } if (submix->output_mix_config) - print_iamf_param_definition(w, "output_mix_config", submix->output_mix_config, + print_iamf_param_definition(tfc, "output_mix_config", submix->output_mix_config, SECTION_ID_STREAM_GROUP_PIECE); for (int i = 0; i < submix->nb_layouts; i++) { const AVIAMFSubmixLayout *layout = submix->layouts[i]; char val_str[128]; - writer_print_section_header(w, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE); + avtext_print_section_header(tfc, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE); av_channel_layout_describe(&layout->sound_system, val_str, sizeof(val_str)); print_str("sound_system", val_str); print_q("integrated_loudness", layout->integrated_loudness, '/'); @@ -3696,51 +2128,51 @@ static void print_iamf_submix_params(WriterContext *w, const AVIAMFSubmix *submi print_q("true_peak", layout->true_peak, '/'); print_q("dialogue_anchored_loudness", layout->dialogue_anchored_loudness, '/'); print_q("album_anchored_loudness", layout->album_anchored_loudness, '/'); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECE } - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECES - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_PIECES + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } -static void print_iamf_mix_presentation_params(WriterContext *w, const AVStreamGroup *stg, +static void print_iamf_mix_presentation_params(AVTextFormatContext *tfc, const AVStreamGroup *stg, const AVIAMFMixPresentation *mix_presentation) { - writer_print_section_header(w, stg, SECTION_ID_STREAM_GROUP_COMPONENT); + avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT); print_int("nb_submixes", mix_presentation->nb_submixes); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS); if (mix_presentation->annotations) { const AVDictionaryEntry *annotation = NULL; - writer_print_section_header(w, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); + avtext_print_section_header(tfc, "IAMF Annotations", SECTION_ID_STREAM_GROUP_SUBCOMPONENT); while (annotation = av_dict_iterate(mix_presentation->annotations, annotation)) print_str(annotation->key, annotation->value); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT } for (int i = 0; i < mix_presentation->nb_submixes; i++) - print_iamf_submix_params(w, mix_presentation->submixes[i]); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT + print_iamf_submix_params(tfc, mix_presentation->submixes[i]); + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT } -static void print_stream_group_params(WriterContext *w, AVStreamGroup *stg) +static void print_stream_group_params(AVTextFormatContext *tfc, AVStreamGroup *stg) { - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_COMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_COMPONENTS); if (stg->type == AV_STREAM_GROUP_PARAMS_TILE_GRID) - print_tile_grid_params(w, stg, stg->params.tile_grid); + print_tile_grid_params(tfc, stg, stg->params.tile_grid); else if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) - print_iamf_audio_element_params(w, stg, stg->params.iamf_audio_element); + print_iamf_audio_element_params(tfc, stg, stg->params.iamf_audio_element); else if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) - print_iamf_mix_presentation_params(w, stg, stg->params.iamf_mix_presentation); - writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENTS + print_iamf_mix_presentation_params(tfc, stg, stg->params.iamf_mix_presentation); + avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENTS } -static int show_stream_group(WriterContext *w, InputFile *ifile, AVStreamGroup *stg) +static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStreamGroup *stg) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; AVBPrint pbuf; int i, ret = 0; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP); print_int("index", stg->index); if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%"PRIx64, stg->id); else print_str_opt("id", "N/A"); @@ -3750,60 +2182,60 @@ static int show_stream_group(WriterContext *w, InputFile *ifile, AVStreamGroup * else print_str_opt("type", "unknown"); if (do_show_stream_group_components) - print_stream_group_params(w, stg); + print_stream_group_params(tfc, stg); /* Print disposition information */ if (do_show_stream_group_disposition) - print_dispositions(w, stg->disposition, SECTION_ID_STREAM_GROUP_DISPOSITION); + print_dispositions(tfc, stg->disposition, SECTION_ID_STREAM_GROUP_DISPOSITION); if (do_show_stream_group_tags) - ret = show_tags(w, stg->metadata, SECTION_ID_STREAM_GROUP_TAGS); + ret = show_tags(tfc, stg->metadata, SECTION_ID_STREAM_GROUP_TAGS); if (ret < 0) goto end; - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_STREAMS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_STREAMS); for (i = 0; i < stg->nb_streams; i++) { if (selected_streams[stg->streams[i]->index]) { - ret = show_stream(w, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP); + ret = show_stream(tfc, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP); if (ret < 0) break; } } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); end: av_bprint_finalize(&pbuf, NULL); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_stream_groups(WriterContext *w, InputFile *ifile) +static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUPS); + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUPS); for (i = 0; i < fmt_ctx->nb_stream_groups; i++) { AVStreamGroup *stg = fmt_ctx->stream_groups[i]; - ret = show_stream_group(w, ifile, stg); + ret = show_stream_group(tfc, ifile, stg); if (ret < 0) break; } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_chapters(WriterContext *w, InputFile *ifile) +static int show_chapters(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; int i, ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_CHAPTERS); + avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTERS); for (i = 0; i < fmt_ctx->nb_chapters; i++) { AVChapter *chapter = fmt_ctx->chapters[i]; - writer_print_section_header(w, NULL, SECTION_ID_CHAPTER); + avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTER); print_int("id", chapter->id); print_q ("time_base", chapter->time_base, '/'); print_int("start", chapter->start); @@ -3811,22 +2243,21 @@ static int show_chapters(WriterContext *w, InputFile *ifile) print_int("end", chapter->end); print_time("end_time", chapter->end, &chapter->time_base); if (do_show_chapter_tags) - ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS); - writer_print_section_footer(w); + ret = show_tags(tfc, chapter->metadata, SECTION_ID_CHAPTER_TAGS); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); return ret; } -static int show_format(WriterContext *w, InputFile *ifile) +static int show_format(AVTextFormatContext *tfc, InputFile *ifile) { AVFormatContext *fmt_ctx = ifile->fmt_ctx; - char val_str[128]; int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1; int ret = 0; - writer_print_section_header(w, NULL, SECTION_ID_FORMAT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FORMAT); print_str_validate("filename", fmt_ctx->url); print_int("nb_streams", fmt_ctx->nb_streams); print_int("nb_programs", fmt_ctx->nb_programs); @@ -3844,19 +2275,78 @@ static int show_format(WriterContext *w, InputFile *ifile) else print_str_opt("bit_rate", "N/A"); print_int("probe_score", fmt_ctx->probe_score); if (do_show_format_tags) - ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); + ret = show_tags(tfc, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); fflush(stdout); return ret; } -static void show_error(WriterContext *w, int err) +static void show_error(AVTextFormatContext *tfc, int err) { - writer_print_section_header(w, NULL, SECTION_ID_ERROR); + avtext_print_section_header(tfc, NULL, SECTION_ID_ERROR); print_int("code", err); print_str("string", av_err2str(err)); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); +} + +static int get_decoder_by_name(const char *codec_name, const AVCodec **codec) +{ + if (codec_name == NULL) + return 0; + + *codec = avcodec_find_decoder_by_name(codec_name); + if (*codec == NULL) { + av_log(NULL, AV_LOG_ERROR, + "No codec could be found with name '%s'\n", codec_name); + return AVERROR(EINVAL); + } + return 0; +} + +static int set_decoders(AVFormatContext *fmt_ctx) +{ + int ret; + +#define GET_DECODER(type_) \ + ret = get_decoder_by_name(type_##_codec_name, &fmt_ctx->type_##_codec); \ + if (ret < 0) return ret; + + GET_DECODER(audio); + GET_DECODER(data); + GET_DECODER(subtitle); + GET_DECODER(video); + return 0; +} + +static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream *stream) +{ + const AVCodec *codec = NULL; + switch (stream->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: codec = fmt_ctx->video_codec; break; + case AVMEDIA_TYPE_AUDIO: codec = fmt_ctx->audio_codec; break; + case AVMEDIA_TYPE_SUBTITLE: codec = fmt_ctx->subtitle_codec; break; + case AVMEDIA_TYPE_DATA: codec = fmt_ctx->data_codec; break; + } + + if (codec != NULL) + return codec; + + if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { + av_log(NULL, AV_LOG_WARNING, + "Failed to probe codec for input stream %d\n", stream->index); + return NULL; + } + + codec = avcodec_find_decoder(stream->codecpar->codec_id); + if (codec == NULL) { + av_log(NULL, AV_LOG_WARNING, + "Unsupported codec with id %d for input stream %d\n", + stream->codecpar->codec_id, stream->index); + return NULL; + } + + return codec; } static int open_input_file(InputFile *ifile, const char *filename, @@ -3871,6 +2361,9 @@ static int open_input_file(InputFile *ifile, const char *filename, if (!fmt_ctx) return AVERROR(ENOMEM); + err = set_decoders(fmt_ctx); + if (err < 0) + return err; 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; @@ -3925,20 +2418,10 @@ static int open_input_file(InputFile *ifile, const char *filename, ist->st = stream; - if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { - av_log(NULL, AV_LOG_WARNING, - "Failed to probe codec for input stream %d\n", - stream->index); + codec = get_decoder_for_stream(fmt_ctx, stream); + if (!codec) continue; - } - codec = avcodec_find_decoder(stream->codecpar->codec_id); - if (!codec) { - av_log(NULL, AV_LOG_WARNING, - "Unsupported codec with id %d for input stream %d\n", - stream->codecpar->codec_id, stream->index); - continue; - } { AVDictionary *opts; @@ -3956,7 +2439,7 @@ static int open_input_file(InputFile *ifile, const char *filename, exit(1); if (do_show_log) { - // For loging it is needed to disable at least frame threads as otherwise + // For logging it is needed to disable at least frame threads as otherwise // the log information would need to be reordered and matches up to contexts and frames // That is in fact possible but not trivial av_dict_set(&codec_opts, "threads", "1", 0); @@ -3998,14 +2481,15 @@ static void close_input_file(InputFile *ifile) avformat_close_input(&ifile->fmt_ctx); } -static int probe_file(WriterContext *wctx, const char *filename, +static int probe_file(AVTextFormatContext *tfc, const char *filename, const char *print_filename) { InputFile ifile = { 0 }; int ret, i; int section_id; - do_read_frames = do_show_frames || do_count_frames; + do_analyze_frames = do_analyze_frames && do_show_streams; + do_read_frames = do_show_frames || do_count_frames || do_analyze_frames; do_read_packets = do_show_packets || do_count_packets; ret = open_input_file(&ifile, filename, print_filename); @@ -4018,6 +2502,8 @@ static int probe_file(WriterContext *wctx, const char *filename, REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams); REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_closed_captions,0,ifile.fmt_ctx->nb_streams); + REALLOCZ_ARRAY_STREAM(streams_with_film_grain,0,ifile.fmt_ctx->nb_streams); for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) { if (stream_specifier) { @@ -4037,40 +2523,40 @@ static int probe_file(WriterContext *wctx, const char *filename, if (do_read_frames || do_read_packets) { if (do_show_frames && do_show_packets && - wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER) + tfc->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT) section_id = SECTION_ID_PACKETS_AND_FRAMES; else if (do_show_packets && !do_show_frames) section_id = SECTION_ID_PACKETS; else // (!do_show_packets && do_show_frames) section_id = SECTION_ID_FRAMES; if (do_show_frames || do_show_packets) - writer_print_section_header(wctx, NULL, section_id); - ret = read_packets(wctx, &ifile); + avtext_print_section_header(tfc, NULL, section_id); + ret = read_packets(tfc, &ifile); if (do_show_frames || do_show_packets) - writer_print_section_footer(wctx); + avtext_print_section_footer(tfc); CHECK_END; } if (do_show_programs) { - ret = show_programs(wctx, &ifile); + ret = show_programs(tfc, &ifile); CHECK_END; } if (do_show_stream_groups) { - ret = show_stream_groups(wctx, &ifile); + ret = show_stream_groups(tfc, &ifile); CHECK_END; } if (do_show_streams) { - ret = show_streams(wctx, &ifile); + ret = show_streams(tfc, &ifile); CHECK_END; } if (do_show_chapters) { - ret = show_chapters(wctx, &ifile); + ret = show_chapters(tfc, &ifile); CHECK_END; } if (do_show_format) { - ret = show_format(wctx, &ifile); + ret = show_format(tfc, &ifile); CHECK_END; } @@ -4080,6 +2566,12 @@ end: av_freep(&nb_streams_frames); av_freep(&nb_streams_packets); av_freep(&selected_streams); + av_freep(&streams_with_closed_captions); + av_freep(&streams_with_film_grain); + av_freep(&audio_codec_name); + av_freep(&data_codec_name); + av_freep(&subtitle_codec_name); + av_freep(&video_codec_name); return ret; } @@ -4091,18 +2583,18 @@ static void show_usage(void) av_log(NULL, AV_LOG_INFO, "\n"); } -static void ffprobe_show_program_version(WriterContext *w) +static void ffprobe_show_program_version(AVTextFormatContext *tfc) { AVBPrint pbuf; av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); - writer_print_section_header(w, NULL, SECTION_ID_PROGRAM_VERSION); + avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_VERSION); print_str("version", FFMPEG_VERSION); print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers", program_birth_year, CONFIG_THIS_YEAR); print_str("compiler_ident", CC_IDENT); print_str("configuration", FFMPEG_CONFIGURATION); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); av_bprint_finalize(&pbuf, NULL); } @@ -4111,20 +2603,20 @@ static void ffprobe_show_program_version(WriterContext *w) do { \ if (CONFIG_##LIBNAME) { \ unsigned int version = libname##_version(); \ - writer_print_section_header(w, NULL, SECTION_ID_LIBRARY_VERSION); \ + avtext_print_section_header(tfc, NULL, SECTION_ID_LIBRARY_VERSION); \ print_str("name", "lib" #libname); \ print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \ print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \ print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \ print_int("version", version); \ print_str("ident", LIB##LIBNAME##_IDENT); \ - writer_print_section_footer(w); \ + avtext_print_section_footer(tfc); \ } \ } while (0) -static void ffprobe_show_library_versions(WriterContext *w) +static void ffprobe_show_library_versions(AVTextFormatContext *tfc) { - writer_print_section_header(w, NULL, SECTION_ID_LIBRARY_VERSIONS); + avtext_print_section_header(tfc, NULL, SECTION_ID_LIBRARY_VERSIONS); SHOW_LIB_VERSION(avutil, AVUTIL); SHOW_LIB_VERSION(avcodec, AVCODEC); SHOW_LIB_VERSION(avformat, AVFORMAT); @@ -4132,8 +2624,7 @@ static void ffprobe_show_library_versions(WriterContext *w) SHOW_LIB_VERSION(avfilter, AVFILTER); SHOW_LIB_VERSION(swscale, SWSCALE); SHOW_LIB_VERSION(swresample, SWRESAMPLE); - SHOW_LIB_VERSION(postproc, POSTPROC); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } #define PRINT_PIX_FMT_FLAG(flagname, name) \ @@ -4141,14 +2632,14 @@ static void ffprobe_show_library_versions(WriterContext *w) print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \ } while (0) -static void ffprobe_show_pixel_formats(WriterContext *w) +static void ffprobe_show_pixel_formats(AVTextFormatContext *tfc) { const AVPixFmtDescriptor *pixdesc = NULL; int i, n; - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMATS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMATS); while (pixdesc = av_pix_fmt_desc_next(pixdesc)) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT); print_str("name", pixdesc->name); print_int("nb_components", pixdesc->nb_components); if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) { @@ -4162,7 +2653,7 @@ static void ffprobe_show_pixel_formats(WriterContext *w) if (n) print_int ("bits_per_pixel", n); else print_str_opt("bits_per_pixel", "N/A"); if (do_show_pixel_format_flags) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_FLAGS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_FLAGS); PRINT_PIX_FMT_FLAG(BE, "big_endian"); PRINT_PIX_FMT_FLAG(PAL, "palette"); PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream"); @@ -4170,21 +2661,21 @@ static void ffprobe_show_pixel_formats(WriterContext *w) PRINT_PIX_FMT_FLAG(PLANAR, "planar"); PRINT_PIX_FMT_FLAG(RGB, "rgb"); PRINT_PIX_FMT_FLAG(ALPHA, "alpha"); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENTS); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENTS); for (i = 0; i < pixdesc->nb_components; i++) { - writer_print_section_header(w, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENT); + avtext_print_section_header(tfc, NULL, SECTION_ID_PIXEL_FORMAT_COMPONENT); print_int("index", i + 1); print_int("bit_depth", pixdesc->comp[i].depth); - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } - writer_print_section_footer(w); + avtext_print_section_footer(tfc); } static int opt_show_optional_fields(void *optctx, const char *opt, const char *arg) @@ -4217,11 +2708,11 @@ static int opt_format(void *optctx, const char *opt, const char *arg) static inline void mark_section_show_entries(SectionID section_id, int show_all_entries, AVDictionary *entries) { - struct section *section = §ions[section_id]; + struct AVTextFormatSection *section = §ions[section_id]; section->show_all_entries = show_all_entries; if (show_all_entries) { - for (const SectionID *id = section->children_ids; *id != -1; id++) + for (const int *id = section->children_ids; *id != -1; id++) mark_section_show_entries(*id, show_all_entries, entries); } else { av_dict_copy(§ion->entries_to_show, entries, 0); @@ -4234,7 +2725,7 @@ static int match_section(const char *section_name, int i, ret = 0; for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) { - const struct section *section = §ions[i]; + const struct AVTextFormatSection *section = §ions[i]; if (!strcmp(section_name, section->name) || (section->unique_name && !strcmp(section_name, section->unique_name))) { av_log(NULL, AV_LOG_DEBUG, @@ -4506,13 +2997,13 @@ static int opt_pretty(void *optctx, const char *opt, const char *arg) static void print_section(SectionID id, int level) { - const SectionID *pid; - const struct section *section = §ions[id]; + const int *pid; + const struct AVTextFormatSection *section = §ions[id]; printf("%c%c%c%c", - section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.', - section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.', - section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.', - section->flags & SECTION_FLAG_HAS_TYPE ? 'T' : '.'); + section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER ? 'W' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY ? 'A' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.', + section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE ? 'T' : '.'); printf("%*c %s", level * 4, ' ', section->name); if (section->unique_name) printf("/%s", section->unique_name); @@ -4535,6 +3026,36 @@ static int opt_sections(void *optctx, const char *opt, const char *arg) return 0; } +static int opt_codec(void *optctx, const char *opt, const char *arg) +{ + const char *spec = strchr(opt, ':'); + const char **name; + if (!spec) { + av_log(NULL, AV_LOG_ERROR, + "No media specifier was specified for '%s' in option '%s'. Use -%s: " + "where can be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n", + arg, opt, opt); + return AVERROR(EINVAL); + } + spec++; + + switch (spec[0]) { + case 'a' : name = &audio_codec_name; break; + case 'd' : name = &data_codec_name; break; + case 's' : name = &subtitle_codec_name; break; + case 'v' : name = &video_codec_name; break; + default: + av_log(NULL, AV_LOG_ERROR, + "Invalid media specifier '%s' in option '%s'. " + "Must be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n", spec, opt); + return AVERROR(EINVAL); + } + + av_freep(name); + *name = av_strdup(arg); + return *name ? 0 : AVERROR(ENOMEM); +} + static int opt_show_versions(void *optctx, const char *opt, const char *arg) { mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL); @@ -4602,6 +3123,7 @@ static const OptionDef real_options[] = { { "show_optional_fields", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = &opt_show_optional_fields }, "show optional fields" }, { "show_private_data", OPT_TYPE_BOOL, 0, { &show_private_data }, "show private data" }, { "private", OPT_TYPE_BOOL, 0, { &show_private_data }, "same as show_private_data" }, + { "analyze_frames", OPT_TYPE_BOOL, 0, { &do_analyze_frames }, "analyze frames to provide additional stream-level information" }, { "bitexact", OPT_TYPE_BOOL, 0, {&do_bitexact}, "force bitexact output" }, { "read_intervals", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" }, { "i", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"}, @@ -4609,15 +3131,17 @@ static const OptionDef real_options[] = { { "print_filename", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_print_filename}, "override the printed input filename", "print_file"}, { "find_stream_info", OPT_TYPE_BOOL, OPT_INPUT | OPT_EXPERT, { &find_stream_info }, "read and decode the streams to fill missing information with heuristics" }, + { "c", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" }, + { "codec", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "alias for -c (force decoder)", "decoder_name" }, { NULL, }, }; static inline int check_section_show_entries(int section_id) { - struct section *section = §ions[section_id]; + struct AVTextFormatSection *section = §ions[section_id]; if (sections[section_id].show_all_entries || sections[section_id].entries_to_show) return 1; - for (const SectionID *id = section->children_ids; *id != -1; id++) + for (const int *id = section->children_ids; *id != -1; id++) if (check_section_show_entries(*id)) return 1; return 0; @@ -4630,20 +3154,17 @@ static inline int check_section_show_entries(int section_id) int main(int argc, char **argv) { - const Writer *w; - WriterContext *wctx; + const AVTextFormatter *f; + AVTextFormatContext *tctx; + AVTextWriterContext *wctx; char *buf; - char *w_name = NULL, *w_args = NULL; + char *f_name = NULL, *f_args = NULL; int ret, input_ret, i; init_dynload(); -#if HAVE_THREADS - ret = pthread_mutex_init(&log_mutex, NULL); - if (ret != 0) { - goto end; - } -#endif + setvbuf(stderr, NULL, _IONBF, 0); /* win32 runtime needs this */ + av_log_set_flags(AV_LOG_SKIP_REPEATED); options = real_options; @@ -4701,58 +3222,56 @@ int main(int argc, char **argv) goto end; } - writer_register_all(); - if (!output_format) output_format = av_strdup("default"); if (!output_format) { ret = AVERROR(ENOMEM); goto end; } - w_name = av_strtok(output_format, "=", &buf); - if (!w_name) { + f_name = av_strtok(output_format, "=", &buf); + if (!f_name) { av_log(NULL, AV_LOG_ERROR, "No name specified for the output format\n"); ret = AVERROR(EINVAL); goto end; } - w_args = buf; + f_args = buf; - if (show_data_hash) { - if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) { - if (ret == AVERROR(EINVAL)) { - const char *n; - av_log(NULL, AV_LOG_ERROR, - "Unknown hash algorithm '%s'\nKnown algorithms:", - show_data_hash); - for (i = 0; (n = av_hash_names(i)); i++) - av_log(NULL, AV_LOG_ERROR, " %s", n); - av_log(NULL, AV_LOG_ERROR, "\n"); - } - goto end; - } - } - - w = writer_get_by_name(w_name); - if (!w) { - av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name); + f = avtext_get_formatter_by_name(f_name); + if (!f) { + av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", f_name); ret = AVERROR(EINVAL); goto end; } - if ((ret = writer_open(&wctx, w, w_args, - sections, FF_ARRAY_ELEMS(sections), output_filename)) >= 0) { - if (w == &xml_writer) - wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES; + if (output_filename) { + ret = avtextwriter_create_file(&wctx, output_filename); + } else + ret = avtextwriter_create_stdout(&wctx); - writer_print_section_header(wctx, NULL, SECTION_ID_ROOT); + if (ret < 0) + goto end; + + AVTextFormatOptions tf_options = { + .show_optional_fields = show_optional_fields, + .show_value_unit = show_value_unit, + .use_value_prefix = use_value_prefix, + .use_byte_value_binary_prefix = use_byte_value_binary_prefix, + .use_value_sexagesimal_format = use_value_sexagesimal_format, + }; + + if ((ret = avtext_context_open(&tctx, f, wctx, f_args, sections, FF_ARRAY_ELEMS(sections), tf_options, show_data_hash)) >= 0) { + if (f == &avtextformatter_xml) + tctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES; + + avtext_print_section_header(tctx, NULL, SECTION_ID_ROOT); if (do_show_program_version) - ffprobe_show_program_version(wctx); + ffprobe_show_program_version(tctx); if (do_show_library_versions) - ffprobe_show_library_versions(wctx); + ffprobe_show_library_versions(tctx); if (do_show_pixel_formats) - ffprobe_show_pixel_formats(wctx); + ffprobe_show_pixel_formats(tctx); if (!input_filename && ((do_show_format || do_show_programs || do_show_stream_groups || do_show_streams || do_show_chapters || do_show_packets || do_show_error) || @@ -4762,17 +3281,22 @@ int main(int argc, char **argv) av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name); ret = AVERROR(EINVAL); } else if (input_filename) { - ret = probe_file(wctx, input_filename, print_input_filename); + ret = probe_file(tctx, input_filename, print_input_filename); if (ret < 0 && do_show_error) - show_error(wctx, ret); + show_error(tctx, ret); } input_ret = ret; - writer_print_section_footer(wctx); - ret = writer_close(&wctx); + avtext_print_section_footer(tctx); + + ret = avtextwriter_context_close(&wctx); if (ret < 0) - av_log(NULL, AV_LOG_ERROR, "Writing output failed: %s\n", av_err2str(ret)); + av_log(NULL, AV_LOG_ERROR, "Writing output failed (closing writer): %s\n", av_err2str(ret)); + + ret = avtext_context_close(&tctx); + if (ret < 0) + av_log(NULL, AV_LOG_ERROR, "Writing output failed (closing formatter): %s\n", av_err2str(ret)); ret = FFMIN(ret, input_ret); } @@ -4783,7 +3307,6 @@ end: av_freep(&input_filename); av_freep(&print_input_filename); av_freep(&read_intervals); - av_hash_freep(&hash); uninit_opts(); for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) @@ -4791,9 +3314,5 @@ end: avformat_network_deinit(); -#if HAVE_THREADS - pthread_mutex_destroy(&log_mutex); -#endif - return ret < 0; } diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c new file mode 100644 index 0000000000..242eaf8ba1 --- /dev/null +++ b/fftools/graph/graphprint.c @@ -0,0 +1,1098 @@ +/* + * Copyright (c) 2018-2025 - softworkz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * output writers for filtergraph details + */ + +#include +#include + +#include "graphprint.h" + +#include "fftools/ffmpeg.h" +#include "fftools/ffmpeg_mux.h" + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/pixdesc.h" +#include "libavutil/dict.h" +#include "libavutil/common.h" +#include "libavfilter/avfilter.h" +#include "libavutil/buffer.h" +#include "libavutil/hwcontext.h" +#include "fftools/textformat/avtextformat.h" +#include "fftools/textformat/tf_mermaid.h" +#include "fftools/resources/resman.h" + +typedef enum { + SECTION_ID_ROOT, + SECTION_ID_FILTERGRAPHS, + SECTION_ID_FILTERGRAPH, + SECTION_ID_GRAPH_INPUTS, + SECTION_ID_GRAPH_INPUT, + SECTION_ID_GRAPH_OUTPUTS, + SECTION_ID_GRAPH_OUTPUT, + SECTION_ID_FILTERS, + SECTION_ID_FILTER, + SECTION_ID_FILTER_INPUTS, + SECTION_ID_FILTER_INPUT, + SECTION_ID_FILTER_OUTPUTS, + SECTION_ID_FILTER_OUTPUT, + SECTION_ID_HWFRAMESCONTEXT, + SECTION_ID_INPUTFILES, + SECTION_ID_INPUTFILE, + SECTION_ID_INPUTSTREAMS, + SECTION_ID_INPUTSTREAM, + SECTION_ID_OUTPUTFILES, + SECTION_ID_OUTPUTFILE, + SECTION_ID_OUTPUTSTREAMS, + SECTION_ID_OUTPUTSTREAM, + SECTION_ID_STREAMLINKS, + SECTION_ID_STREAMLINK, + SECTION_ID_DECODERS, + SECTION_ID_DECODER, + SECTION_ID_ENCODERS, + SECTION_ID_ENCODER, +} SectionID; + +static struct AVTextFormatSection sections[] = { + [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_FILTERGRAPHS, SECTION_ID_INPUTFILES, SECTION_ID_OUTPUTFILES, SECTION_ID_DECODERS, SECTION_ID_ENCODERS, SECTION_ID_STREAMLINKS, -1 } }, + + [SECTION_ID_FILTERGRAPHS] = { SECTION_ID_FILTERGRAPHS, "graphs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTERGRAPH, -1 } }, + [SECTION_ID_FILTERGRAPH] = { SECTION_ID_FILTERGRAPH, "graph", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { SECTION_ID_GRAPH_INPUTS, SECTION_ID_GRAPH_OUTPUTS, SECTION_ID_FILTERS, -1 }, .element_name = "graph_info" }, + + [SECTION_ID_GRAPH_INPUTS] = { SECTION_ID_GRAPH_INPUTS, "graph_inputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_GRAPH_INPUT, -1 }, .id_key = "id" }, + [SECTION_ID_GRAPH_INPUT] = { SECTION_ID_GRAPH_INPUT, "graph_input", 0, { -1 }, .id_key = "filter_id" }, + + [SECTION_ID_GRAPH_OUTPUTS] = { SECTION_ID_GRAPH_OUTPUTS, "graph_outputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_GRAPH_OUTPUT, -1 }, .id_key = "id" }, + [SECTION_ID_GRAPH_OUTPUT] = { SECTION_ID_GRAPH_OUTPUT, "graph_output", 0, { -1 }, .id_key = "filter_id" }, + + [SECTION_ID_FILTERS] = { SECTION_ID_FILTERS, "filters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_FILTER, -1 }, .id_key = "graph_id" }, + [SECTION_ID_FILTER] = { SECTION_ID_FILTER, "filter", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { SECTION_ID_FILTER_INPUTS, SECTION_ID_FILTER_OUTPUTS, -1 }, .id_key = "filter_id" }, + + [SECTION_ID_FILTER_INPUTS] = { SECTION_ID_FILTER_INPUTS, "filter_inputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTER_INPUT, -1 } }, + [SECTION_ID_FILTER_INPUT] = { SECTION_ID_FILTER_INPUT, "filter_input", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { SECTION_ID_HWFRAMESCONTEXT, -1 }, .id_key = "filter_id", .src_id_key = "source_filter_id", .dest_id_key = "filter_id" }, + + [SECTION_ID_FILTER_OUTPUTS] = { SECTION_ID_FILTER_OUTPUTS, "filter_outputs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTER_OUTPUT, -1 } }, + [SECTION_ID_FILTER_OUTPUT] = { SECTION_ID_FILTER_OUTPUT, "filter_output", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { SECTION_ID_HWFRAMESCONTEXT, -1 }, .id_key = "filter_id", .src_id_key = "filter_id", .dest_id_key = "dest_filter_id" }, + + [SECTION_ID_HWFRAMESCONTEXT] = { SECTION_ID_HWFRAMESCONTEXT, "hw_frames_context", 0, { -1 }, }, + + [SECTION_ID_INPUTFILES] = { SECTION_ID_INPUTFILES, "inputfiles", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTFILE, -1 }, .id_key = "id" }, + [SECTION_ID_INPUTFILE] = { SECTION_ID_INPUTFILE, "inputfile", AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTSTREAMS, -1 }, .id_key = "id" }, + + [SECTION_ID_INPUTSTREAMS] = { SECTION_ID_INPUTSTREAMS, "inputstreams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_INPUTSTREAM, -1 }, .id_key = "id" }, + [SECTION_ID_INPUTSTREAM] = { SECTION_ID_INPUTSTREAM, "inputstream", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { -1 }, .id_key = "id" }, + + [SECTION_ID_OUTPUTFILES] = { SECTION_ID_OUTPUTFILES, "outputfiles", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTFILE, -1 }, .id_key = "id" }, + [SECTION_ID_OUTPUTFILE] = { SECTION_ID_OUTPUTFILE, "outputfile", AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTSTREAMS, -1 }, .id_key = "id" }, + + [SECTION_ID_OUTPUTSTREAMS] = { SECTION_ID_OUTPUTSTREAMS, "outputstreams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_OUTPUTSTREAM, -1 }, .id_key = "id" }, + [SECTION_ID_OUTPUTSTREAM] = { SECTION_ID_OUTPUTSTREAM, "outputstream", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS, { -1 }, .id_key = "id", }, + + [SECTION_ID_STREAMLINKS] = { SECTION_ID_STREAMLINKS, "streamlinks", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAMLINK, -1 } }, + [SECTION_ID_STREAMLINK] = { SECTION_ID_STREAMLINK, "streamlink", AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .src_id_key = "source_stream_id", .dest_id_key = "dest_stream_id" }, + + [SECTION_ID_DECODERS] = { SECTION_ID_DECODERS, "decoders", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_DECODER, -1 } }, + [SECTION_ID_DECODER] = { SECTION_ID_DECODER, "decoder", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS | AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .id_key = "id", .src_id_key = "source_id", .dest_id_key = "id" }, + + [SECTION_ID_ENCODERS] = { SECTION_ID_ENCODERS, "encoders", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH, { SECTION_ID_ENCODER, -1 } }, + [SECTION_ID_ENCODER] = { SECTION_ID_ENCODER, "encoder", AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS | AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS, { -1 }, .id_key = "id", .src_id_key = "id", .dest_id_key = "dest_id" }, +}; + +typedef struct GraphPrintContext { + AVTextFormatContext *tfc; + AVTextWriterContext *wctx; + AVDiagramConfig diagram_config; + + int id_prefix_num; + int is_diagram; + int opt_flags; + int skip_buffer_filters; + AVBPrint pbuf; + +} GraphPrintContext; + +/* Text Format API Shortcuts */ +#define print_id(k, v) print_sanizied_id(gpc, k, v, 0) +#define print_id_noprefix(k, v) print_sanizied_id(gpc, k, v, 1) +#define print_int(k, v) avtext_print_integer(tfc, k, v, 0) +#define print_int_opt(k, v) avtext_print_integer(tfc, k, v, gpc->opt_flags) +#define print_q(k, v, s) avtext_print_rational(tfc, k, v, s) +#define print_str(k, v) avtext_print_string(tfc, k, v, 0) +#define print_str_opt(k, v) avtext_print_string(tfc, k, v, gpc->opt_flags) +#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u) + +#define print_fmt(k, f, ...) do { \ + av_bprint_clear(&gpc->pbuf); \ + av_bprintf(&gpc->pbuf, f, __VA_ARGS__); \ + avtext_print_string(tfc, k, gpc->pbuf.str, 0); \ +} while (0) + +#define print_fmt_opt(k, f, ...) do { \ + av_bprint_clear(&gpc->pbuf); \ + av_bprintf(&gpc->pbuf, f, __VA_ARGS__); \ + avtext_print_string(tfc, k, gpc->pbuf.str, gpc->opt_flags); \ +} while (0) + + +static atomic_int prefix_num = 0; + +static inline char *upcase_string(char *dst, size_t dst_size, const char *src) +{ + unsigned i; + for (i = 0; src[i] && i < dst_size - 1; i++) + dst[i] = (char)av_toupper(src[i]); + dst[i] = 0; + return dst; +} + +static char *get_extension(const char *url) +{ + const char *dot = NULL; + const char *sep = NULL; + const char *end; + + if (!url) + return NULL; + + /* Stop at the first query ('?') or fragment ('#') delimiter so they + * are not considered part of the path. */ + end = strpbrk(url, "?#"); + if (!end) + end = url + strlen(url); + + /* Scan the path component only. */ + for (const char *p = url; p < end; p++) { + if (*p == '.') + dot = p; + else if (*p == '/' || *p == '\\') + sep = p; + } + + /* Validate that we have a proper extension. */ + if (dot && dot != url && (!sep || dot > sep + 1) && (dot + 1) < end) { + /* Use FFmpeg helper to duplicate the substring. */ + return av_strndup(dot + 1, end - (dot + 1)); + } + + return NULL; +} + +static void print_hwdevicecontext(const GraphPrintContext *gpc, const AVHWDeviceContext *hw_device_context) +{ + AVTextFormatContext *tfc = gpc->tfc; + + if (!hw_device_context) + return; + + print_int_opt("has_hw_device_context", 1); + print_str_opt("hw_device_type", av_hwdevice_get_type_name(hw_device_context->type)); +} + +static void print_hwframescontext(const GraphPrintContext *gpc, const AVHWFramesContext *hw_frames_context) +{ + AVTextFormatContext *tfc = gpc->tfc; + const AVPixFmtDescriptor *pix_desc_hw; + const AVPixFmtDescriptor *pix_desc_sw; + + if (!hw_frames_context || !hw_frames_context->device_ctx) + return; + + avtext_print_section_header(tfc, NULL, SECTION_ID_HWFRAMESCONTEXT); + + print_int_opt("has_hw_frames_context", 1); + print_str("hw_device_type", av_hwdevice_get_type_name(hw_frames_context->device_ctx->type)); + + pix_desc_hw = av_pix_fmt_desc_get(hw_frames_context->format); + if (pix_desc_hw) { + print_str("hw_pixel_format", pix_desc_hw->name); + if (pix_desc_hw->alias) + print_str_opt("hw_pixel_format_alias", pix_desc_hw->alias); + } + + pix_desc_sw = av_pix_fmt_desc_get(hw_frames_context->sw_format); + if (pix_desc_sw) { + print_str("sw_pixel_format", pix_desc_sw->name); + if (pix_desc_sw->alias) + print_str_opt("sw_pixel_format_alias", pix_desc_sw->alias); + } + + print_int_opt("width", hw_frames_context->width); + print_int_opt("height", hw_frames_context->height); + print_int_opt("initial_pool_size", hw_frames_context->initial_pool_size); + + avtext_print_section_footer(tfc); // SECTION_ID_HWFRAMESCONTEXT +} + +static void print_link(GraphPrintContext *gpc, AVFilterLink *link) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBufferRef *hw_frames_ctx; + char layout_string[64]; + + if (!link) + return; + + hw_frames_ctx = avfilter_link_get_hw_frames_ctx(link); + + print_str_opt("media_type", av_get_media_type_string(link->type)); + + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + + if (hw_frames_ctx && hw_frames_ctx->data) { + AVHWFramesContext * hwfctx = (AVHWFramesContext *)hw_frames_ctx->data; + const AVPixFmtDescriptor *pix_desc_hw = av_pix_fmt_desc_get(hwfctx->format); + const AVPixFmtDescriptor *pix_desc_sw = av_pix_fmt_desc_get(hwfctx->sw_format); + if (pix_desc_hw && pix_desc_sw) + print_fmt("format", "%s | %s", pix_desc_hw->name, pix_desc_sw->name); + } else { + print_str("format", av_x_if_null(av_get_pix_fmt_name(link->format), "?")); + } + + if (link->w && link->h) { + if (tfc->show_value_unit) { + print_fmt("size", "%dx%d", link->w, link->h); + } else { + print_int("width", link->w); + print_int("height", link->h); + } + } + + print_q("sar", link->sample_aspect_ratio, ':'); + + if (link->color_range != AVCOL_RANGE_UNSPECIFIED) + print_str_opt("color_range", av_color_range_name(link->color_range)); + + if (link->colorspace != AVCOL_SPC_UNSPECIFIED) + print_str("color_space", av_color_space_name(link->colorspace)); + break; + + case AVMEDIA_TYPE_SUBTITLE: + ////print_str("format", av_x_if_null(av_get_subtitle_fmt_name(link->format), "?")); + + if (link->w && link->h) { + if (tfc->show_value_unit) { + print_fmt("size", "%dx%d", link->w, link->h); + } else { + print_int("width", link->w); + print_int("height", link->h); + } + } + + break; + + case AVMEDIA_TYPE_AUDIO: + av_channel_layout_describe(&link->ch_layout, layout_string, sizeof(layout_string)); + print_str("channel_layout", layout_string); + print_val("channels", link->ch_layout.nb_channels, "ch"); + if (tfc->show_value_unit) + print_fmt("sample_rate", "%d.1 kHz", link->sample_rate / 1000); + else + print_val("sample_rate", link->sample_rate, "Hz"); + + break; + } + + print_fmt_opt("sample_rate", "%d/%d", link->time_base.num, link->time_base.den); + + if (hw_frames_ctx && hw_frames_ctx->data) + print_hwframescontext(gpc, (AVHWFramesContext *)hw_frames_ctx->data); + av_buffer_unref(&hw_frames_ctx); +} + +static char sanitize_char(const char c) +{ + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return c; + return '_'; +} + +static void print_sanizied_id(const GraphPrintContext *gpc, const char *key, const char *id_str, int skip_prefix) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBPrint buf; + + if (!key || !id_str) + return; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + if (!skip_prefix) + av_bprintf(&buf, "G%d_", gpc->id_prefix_num); + + // sanizize section id + for (const char *p = id_str; *p; p++) + av_bprint_chars(&buf, sanitize_char(*p), 1); + + print_str(key, buf.str); + + av_bprint_finalize(&buf, NULL); +} + +static void print_section_header_id(const GraphPrintContext *gpc, int section_id, const char *id_str, int skip_prefix) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVTextFormatSectionContext sec_ctx = { 0 }; + AVBPrint buf; + + if (!id_str) + return; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + if (!skip_prefix) + av_bprintf(&buf, "G%d_", gpc->id_prefix_num); + + // sanizize section id + for (const char *p = id_str; *p; p++) + av_bprint_chars(&buf, sanitize_char(*p), 1); + + sec_ctx.context_id = buf.str; + + avtext_print_section_header(tfc, &sec_ctx, section_id); + + av_bprint_finalize(&buf, NULL); +} + +static const char *get_filterpad_name(const AVFilterPad *pad) +{ + return pad ? avfilter_pad_get_name(pad, 0) : "pad"; +} + +static void print_filter(GraphPrintContext *gpc, const AVFilterContext *filter, AVDictionary *input_map, AVDictionary *output_map) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVTextFormatSectionContext sec_ctx = { 0 }; + + print_section_header_id(gpc, SECTION_ID_FILTER, filter->name, 0); + + ////print_id("filter_id", filter->name); + + if (filter->filter) { + print_str("filter_name", filter->filter->name); + print_str_opt("description", filter->filter->description); + print_int_opt("nb_inputs", filter->nb_inputs); + print_int_opt("nb_outputs", filter->nb_outputs); + } + + if (filter->hw_device_ctx) { + AVHWDeviceContext *device_context = (AVHWDeviceContext *)filter->hw_device_ctx->data; + print_hwdevicecontext(gpc, device_context); + if (filter->extra_hw_frames > 0) + print_int("extra_hw_frames", filter->extra_hw_frames); + } + + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTER_INPUTS); + + for (unsigned i = 0; i < filter->nb_inputs; i++) { + AVDictionaryEntry *dic_entry; + AVFilterLink *link = filter->inputs[i]; + + sec_ctx.context_type = av_get_media_type_string(link->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTER_INPUT); + sec_ctx.context_type = NULL; + + print_int_opt("input_index", i); + print_str_opt("pad_name", get_filterpad_name(link->dstpad));; + + dic_entry = av_dict_get(input_map, link->src->name, NULL, 0); + if (dic_entry) { + char buf[256]; + (void)snprintf(buf, sizeof(buf), "in_%s", dic_entry->value); + print_id_noprefix("source_filter_id", buf); + } else { + print_id("source_filter_id", link->src->name); + } + + print_str_opt("source_pad_name", get_filterpad_name(link->srcpad)); + print_id("filter_id", filter->name); + + print_link(gpc, link); + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_INPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_INPUTS + + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTER_OUTPUTS); + + for (unsigned i = 0; i < filter->nb_outputs; i++) { + AVDictionaryEntry *dic_entry; + AVFilterLink *link = filter->outputs[i]; + char buf[256]; + + sec_ctx.context_type = av_get_media_type_string(link->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTER_OUTPUT); + sec_ctx.context_type = NULL; + + dic_entry = av_dict_get(output_map, link->dst->name, NULL, 0); + if (dic_entry) { + (void)snprintf(buf, sizeof(buf), "out_%s", dic_entry->value); + print_id_noprefix("dest_filter_id", buf); + } else { + print_id("dest_filter_id", link->dst->name); + } + + print_int_opt("output_index", i); + print_str_opt("pad_name", get_filterpad_name(link->srcpad)); + ////print_id("dest_filter_id", link->dst->name); + print_str_opt("dest_pad_name", get_filterpad_name(link->dstpad)); + print_id("filter_id", filter->name); + + print_link(gpc, link); + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_OUTPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER_OUTPUTS + + avtext_print_section_footer(tfc); // SECTION_ID_FILTER +} + +static void init_sections(void) +{ + for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++) + sections[i].show_all_entries = 1; +} + +static void print_filtergraph_single(GraphPrintContext *gpc, FilterGraph *fg, AVFilterGraph *graph) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVDictionary *input_map = NULL; + AVDictionary *output_map = NULL; + + print_int("graph_index", fg->index); + print_fmt("name", "Graph %d.%d", gpc->id_prefix_num, fg->index); + print_fmt("id", "Graph_%d_%d", gpc->id_prefix_num, fg->index); + print_str("description", fg->graph_desc); + + print_section_header_id(gpc, SECTION_ID_GRAPH_INPUTS, "Input_File", 0); + + for (int i = 0; i < fg->nb_inputs; i++) { + InputFilter *ifilter = fg->inputs[i]; + enum AVMediaType media_type = ifilter->type; + + avtext_print_section_header(tfc, NULL, SECTION_ID_GRAPH_INPUT); + + print_int("input_index", ifilter->index); + + if (ifilter->linklabel) + print_str("link_label", (const char*)ifilter->linklabel); + + if (ifilter->filter) { + print_id("filter_id", ifilter->filter->name); + print_str("filter_name", ifilter->filter->filter->name); + } + + if (ifilter->linklabel && ifilter->filter) + av_dict_set(&input_map, ifilter->filter->name, (const char *)ifilter->linklabel, 0); + else if (ifilter->input_name && ifilter->filter) + av_dict_set(&input_map, ifilter->filter->name, (const char *)ifilter->input_name, 0); + + print_str("media_type", av_get_media_type_string(media_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_INPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_INPUTS + + print_section_header_id(gpc, SECTION_ID_GRAPH_OUTPUTS, "Output_File", 0); + + for (int i = 0; i < fg->nb_outputs; i++) { + OutputFilter *ofilter = fg->outputs[i]; + + avtext_print_section_header(tfc, NULL, SECTION_ID_GRAPH_OUTPUT); + + print_int("output_index", ofilter->index); + + print_str("name", ofilter->output_name); + + if (fg->outputs[i]->linklabel) + print_str("link_label", (const char*)fg->outputs[i]->linklabel); + + if (ofilter->filter) { + print_id("filter_id", ofilter->filter->name); + print_str("filter_name", ofilter->filter->filter->name); + } + + if (ofilter->output_name && ofilter->filter) + av_dict_set(&output_map, ofilter->filter->name, ofilter->output_name, 0); + + + print_str("media_type", av_get_media_type_string(ofilter->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_OUTPUT + } + + avtext_print_section_footer(tfc); // SECTION_ID_GRAPH_OUTPUTS + + if (graph) { + AVTextFormatSectionContext sec_ctx = { 0 }; + + sec_ctx.context_id = av_asprintf("Graph_%d_%d", gpc->id_prefix_num, fg->index); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTERS); + + if (gpc->is_diagram) { + print_fmt("name", "Graph %d.%d", gpc->id_prefix_num, fg->index); + print_str("description", fg->graph_desc); + print_str("id", sec_ctx.context_id); + } + + av_freep(&sec_ctx.context_id); + + for (unsigned i = 0; i < graph->nb_filters; i++) { + AVFilterContext *filter = graph->filters[i]; + + if (gpc->skip_buffer_filters) { + if (av_dict_get(input_map, filter->name, NULL, 0)) + continue; + if (av_dict_get(output_map, filter->name, NULL, 0)) + continue; + } + + sec_ctx.context_id = filter->name; + + print_filter(gpc, filter, input_map, output_map); + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTERS + } + + // Clean up dictionaries + av_dict_free(&input_map); + av_dict_free(&output_map); +} + +static int print_streams(GraphPrintContext *gpc, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + AVTextFormatContext *tfc = gpc->tfc; + AVBPrint buf; + AVTextFormatSectionContext sec_ctx = { 0 }; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + print_section_header_id(gpc, SECTION_ID_INPUTFILES, "Inputs", 0); + + for (int n = nb_ifiles - 1; n >= 0; n--) { + InputFile *ifi = ifiles[n]; + AVFormatContext *fc = ifi->ctx; + + sec_ctx.context_id = av_asprintf("Input_%d", n); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTFILE); + av_freep(&sec_ctx.context_id); + + print_fmt("index", "%d", ifi->index); + + if (fc) { + print_str("demuxer_name", fc->iformat->name); + if (fc->url) { + char *extension = get_extension(fc->url); + if (extension) { + print_str("file_extension", extension); + av_freep(&extension); + } + print_str("url", fc->url); + } + } + + sec_ctx.context_id = av_asprintf("InputStreams_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTSTREAMS); + + av_freep(&sec_ctx.context_id); + + for (int i = 0; i < ifi->nb_streams; i++) { + InputStream *ist = ifi->streams[i]; + const AVCodecDescriptor *codec_desc; + + if (!ist || !ist->par) + continue; + + codec_desc = avcodec_descriptor_get(ist->par->codec_id); + + sec_ctx.context_id = av_asprintf("r_in_%d_%d", n, i); + + sec_ctx.context_type = av_get_media_type_string(ist->par->codec_type); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_INPUTSTREAM); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + + av_bprint_clear(&buf); + + print_fmt("id", "r_in_%d_%d", n, i); + + if (codec_desc && codec_desc->name) { + ////av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), codec_desc->long_name)); + av_bprintf(&buf, "%s", codec_desc->long_name); + } else if (ist->dec) { + char char_buf[256]; + av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), ist->dec->name)); + } else if (ist->par->codec_type == AVMEDIA_TYPE_ATTACHMENT) { + av_bprintf(&buf, "%s", "Attachment"); + } else if (ist->par->codec_type == AVMEDIA_TYPE_DATA) { + av_bprintf(&buf, "%s", "Data"); + } + + print_fmt("name", "%s", buf.str); + print_fmt("index", "%d", ist->index); + + if (ist->dec) + print_str_opt("media_type", av_get_media_type_string(ist->par->codec_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTSTREAM + } + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTSTREAMS + avtext_print_section_footer(tfc); // SECTION_ID_INPUTFILE + } + + avtext_print_section_footer(tfc); // SECTION_ID_INPUTFILES + + + print_section_header_id(gpc, SECTION_ID_DECODERS, "Decoders", 0); + + for (int n = 0; n < nb_ifiles; n++) { + InputFile *ifi = ifiles[n]; + + for (int i = 0; i < ifi->nb_streams; i++) { + InputStream *ist = ifi->streams[i]; + + if (!ist->decoder) + continue; + + sec_ctx.context_id = av_asprintf("in_%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ist->par->codec_type); + sec_ctx.context_flags = 2; + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_DECODER); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + sec_ctx.context_flags = 0; + + av_bprint_clear(&buf); + + print_fmt("source_id", "r_in_%d_%d", n, i); + print_fmt("id", "in_%d_%d", n, i); + + ////av_bprintf(&buf, "%s", upcase_string(char_buf, sizeof(char_buf), ist->dec->name)); + print_fmt("name", "%s", ist->dec->name); + + print_str_opt("media_type", av_get_media_type_string(ist->par->codec_type)); + + avtext_print_section_footer(tfc); // SECTION_ID_DECODER + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_DECODERS + + + print_section_header_id(gpc, SECTION_ID_ENCODERS, "Encoders", 0); + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + ////const AVCodecDescriptor *codec_desc; + + if (!ost || !ost->st || !ost->st->codecpar || !ost->enc) + continue; + + ////codec_desc = avcodec_descriptor_get(ost->st->codecpar->codec_id); + + sec_ctx.context_id = av_asprintf("out__%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ost->type); + sec_ctx.context_flags = 2; + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_ENCODER); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + sec_ctx.context_flags = 0; + + av_bprint_clear(&buf); + + print_fmt("id", "out__%d_%d", n, i); + print_fmt("dest_id", "r_out__%d_%d", n, i); + + print_fmt("name", "%s", ost->enc->enc_ctx->av_class->item_name(ost->enc->enc_ctx)); + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_ENCODER + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_ENCODERS + + + print_section_header_id(gpc, SECTION_ID_OUTPUTFILES, "Outputs", 0); + + for (int n = nb_ofiles - 1; n >= 0; n--) { + OutputFile *of = ofiles[n]; + Muxer *muxer = (Muxer *)of; + + if (!muxer->fc) + continue; + + sec_ctx.context_id = av_asprintf("Output_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTFILE); + + av_freep(&sec_ctx.context_id); + + ////print_str_opt("index", av_get_media_type_string(of->index)); + print_fmt("index", "%d", of->index); + ////print_str("url", of->url); + print_str("muxer_name", muxer->fc->oformat->name); + if (of->url) { + char *extension = get_extension(of->url); + if (extension) { + print_str("file_extension", extension); + av_freep(&extension); + } + print_str("url", of->url); + } + + sec_ctx.context_id = av_asprintf("OutputStreams_%d", n); + + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTSTREAMS); + + av_freep(&sec_ctx.context_id); + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + const AVCodecDescriptor *codec_desc = avcodec_descriptor_get(ost->st->codecpar->codec_id); + + sec_ctx.context_id = av_asprintf("r_out__%d_%d", n, i); + sec_ctx.context_type = av_get_media_type_string(ost->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_OUTPUTSTREAM); + av_freep(&sec_ctx.context_id); + sec_ctx.context_type = NULL; + + av_bprint_clear(&buf); + + print_fmt("id", "r_out__%d_%d", n, i); + + if (codec_desc && codec_desc->name) { + av_bprintf(&buf, "%s", codec_desc->long_name); + } else { + av_bprintf(&buf, "%s", "unknown"); + } + + print_fmt("name", "%s", buf.str); + print_fmt("index", "%d", ost->index); + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTSTREAM + } + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTSTREAMS + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTFILE + } + + avtext_print_section_footer(tfc); // SECTION_ID_OUTPUTFILES + + + avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMLINKS); + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + + if (ost->ist && !ost->filter) { + sec_ctx.context_type = av_get_media_type_string(ost->type); + avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_STREAMLINK); + sec_ctx.context_type = NULL; + + if (ost->enc) { + print_fmt("dest_stream_id", "out__%d_%d", n, i); + print_fmt("source_stream_id", "in_%d_%d", ost->ist->file->index, ost->ist->index); + print_str("operation", "Transcode"); + } else { + print_fmt("dest_stream_id", "r_out__%d_%d", n, i); + print_fmt("source_stream_id", "r_in_%d_%d", ost->ist->file->index, ost->ist->index); + print_str("operation", "Stream Copy"); + } + + print_str_opt("media_type", av_get_media_type_string(ost->type)); + + avtext_print_section_footer(tfc); // SECTION_ID_STREAMLINK + } + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_STREAMLINKS + + av_bprint_finalize(&buf, NULL); + return 0; +} + + +static void uninit_graphprint(GraphPrintContext *gpc) +{ + if (gpc->tfc) + avtext_context_close(&gpc->tfc); + + if (gpc->wctx) + avtextwriter_context_close(&gpc->wctx); + + // Finalize the print buffer if it was initialized + av_bprint_finalize(&gpc->pbuf, NULL); + + av_freep(&gpc); +} + +static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf) +{ + const AVTextFormatter *text_formatter; + AVTextFormatContext *tfc = NULL; + AVTextWriterContext *wctx = NULL; + GraphPrintContext *gpc = NULL; + int ret; + + init_sections(); + *pgpc = NULL; + + av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + const char *w_name = print_graphs_format ? print_graphs_format : "json"; + + text_formatter = avtext_get_formatter_by_name(w_name); + if (!text_formatter) { + av_log(NULL, AV_LOG_ERROR, "Unknown filter graph output format with name '%s'\n", w_name); + ret = AVERROR(EINVAL); + goto fail; + } + + ret = avtextwriter_create_buffer(&wctx, target_buf); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "avtextwriter_create_buffer failed. Error code %d\n", ret); + ret = AVERROR(EINVAL); + goto fail; + } + + AVTextFormatOptions tf_options = { .show_optional_fields = -1 }; + const char *w_args = print_graphs_format ? strchr(print_graphs_format, '=') : NULL; + if (w_args) + ++w_args; // consume '=' + ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), tf_options, NULL); + if (ret < 0) { + goto fail; + } + + gpc = av_mallocz(sizeof(GraphPrintContext)); + if (!gpc) { + ret = AVERROR(ENOMEM); + goto fail; + } + + gpc->wctx = wctx; + gpc->tfc = tfc; + av_bprint_init(&gpc->pbuf, 0, AV_BPRINT_SIZE_UNLIMITED); + + gpc->id_prefix_num = atomic_fetch_add(&prefix_num, 1); + gpc->is_diagram = !!(tfc->formatter->flags & AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER); + if (gpc->is_diagram) { + tfc->show_value_unit = 1; + tfc->show_optional_fields = -1; + gpc->opt_flags = AV_TEXTFORMAT_PRINT_STRING_OPTIONAL; + gpc->skip_buffer_filters = 1; + ////} else { + //// gpc->opt_flags = AV_TEXTFORMAT_PRINT_STRING_OPTIONAL; + } + + if (!strcmp(text_formatter->name, "mermaid") || !strcmp(text_formatter->name, "mermaidhtml")) { + gpc->diagram_config.diagram_css = ff_resman_get_string(FF_RESOURCE_GRAPH_CSS); + + if (!strcmp(text_formatter->name, "mermaidhtml")) + gpc->diagram_config.html_template = ff_resman_get_string(FF_RESOURCE_GRAPH_HTML); + + av_diagram_init(tfc, &gpc->diagram_config); + } + + *pgpc = gpc; + + return 0; + +fail: + if (tfc) + avtext_context_close(&tfc); + if (wctx && !tfc) // Only free wctx if tfc didn't take ownership of it + avtextwriter_context_close(&wctx); + av_freep(&gpc); + + return ret; +} + + +int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph) +{ + GraphPrintContext *gpc = NULL; + AVTextFormatContext *tfc; + AVBPrint *target_buf = &fg->graph_print_buf; + int ret; + + if (!fg) { + av_log(NULL, AV_LOG_ERROR, "Invalid filter graph provided\n"); + return AVERROR(EINVAL); + } + + if (target_buf->len) + av_bprint_finalize(target_buf, NULL); + + ret = init_graphprint(&gpc, target_buf); + if (ret) + return ret; + + if (!gpc) { + av_log(NULL, AV_LOG_ERROR, "Failed to initialize graph print context\n"); + return AVERROR(ENOMEM); + } + + tfc = gpc->tfc; + + // Due to the threading model each graph needs to print itself into a buffer + // from its own thread. The actual printing happens short before cleanup in ffmpeg.c + // where all graphs are assembled together. To make this work, we need to put the + // formatting context into the same state like it would be when printing all at once, + // so here we print the section headers and clear the buffer to get into the right state. + avtext_print_section_header(tfc, NULL, SECTION_ID_ROOT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPHS); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + + av_bprint_clear(target_buf); + + print_filtergraph_single(gpc, fg, graph); + + if (gpc->is_diagram) { + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPHS + } + + uninit_graphprint(gpc); + + return 0; +} + +static int print_filtergraphs_priv(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + GraphPrintContext *gpc = NULL; + AVTextFormatContext *tfc; + AVBPrint target_buf; + int ret; + + ret = init_graphprint(&gpc, &target_buf); + if (ret) + goto cleanup; + + if (!gpc) { + ret = AVERROR(ENOMEM); + goto cleanup; + } + + tfc = gpc->tfc; + + avtext_print_section_header(tfc, NULL, SECTION_ID_ROOT); + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPHS); + + for (int i = 0; i < nb_graphs; i++) { + AVBPrint *graph_buf = &graphs[i]->graph_print_buf; + + if (graph_buf->len > 0) { + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + av_bprint_append_data(&target_buf, graph_buf->str, graph_buf->len); + av_bprint_finalize(graph_buf, NULL); + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + } + } + + for (int n = 0; n < nb_ofiles; n++) { + OutputFile *of = ofiles[n]; + + for (int i = 0; i < of->nb_streams; i++) { + OutputStream *ost = of->streams[i]; + + if (ost->fg_simple) { + AVBPrint *graph_buf = &ost->fg_simple->graph_print_buf; + + if (graph_buf->len > 0) { + avtext_print_section_header(tfc, NULL, SECTION_ID_FILTERGRAPH); + av_bprint_append_data(&target_buf, graph_buf->str, graph_buf->len); + av_bprint_finalize(graph_buf, NULL); + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPH + } + } + } + } + + avtext_print_section_footer(tfc); // SECTION_ID_FILTERGRAPHS + + print_streams(gpc, ifiles, nb_ifiles, ofiles, nb_ofiles); + + avtext_print_section_footer(tfc); // SECTION_ID_ROOT + + if (print_graphs_file) { + AVIOContext *avio = NULL; + + if (!strcmp(print_graphs_file, "-")) { + printf("%s", target_buf.str); + } else { + ret = avio_open2(&avio, print_graphs_file, AVIO_FLAG_WRITE, NULL, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open graph output file, \"%s\": %s\n", print_graphs_file, av_err2str(ret)); + goto cleanup; + } + + avio_write(avio, (const unsigned char *)target_buf.str, FFMIN(target_buf.len, target_buf.size - 1)); + + if ((ret = avio_closep(&avio)) < 0) + av_log(NULL, AV_LOG_ERROR, "Error closing graph output file, loss of information possible: %s\n", av_err2str(ret)); + } + } + + if (print_graphs) + av_log(NULL, AV_LOG_INFO, "%s %c", target_buf.str, '\n'); + +cleanup: + // Properly clean up resources + if (gpc) + uninit_graphprint(gpc); + + // Ensure the target buffer is properly finalized + av_bprint_finalize(&target_buf, NULL); + + return ret; +} + +int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles) +{ + int ret = print_filtergraphs_priv(graphs, nb_graphs, ifiles, nb_ifiles, ofiles, nb_ofiles); + ff_resman_uninit(); + return ret; +} diff --git a/fftools/graph/graphprint.h b/fftools/graph/graphprint.h new file mode 100644 index 0000000000..9f043cc273 --- /dev/null +++ b/fftools/graph/graphprint.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025 - softworkz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_GRAPH_GRAPHPRINT_H +#define FFTOOLS_GRAPH_GRAPHPRINT_H + +#include "fftools/ffmpeg.h" + +int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles); + +int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph); + +#endif /* FFTOOLS_GRAPH_GRAPHPRINT_H */ diff --git a/fftools/objpool.c b/fftools/objpool.c deleted file mode 100644 index 87237cf724..0000000000 --- a/fftools/objpool.c +++ /dev/null @@ -1,131 +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 "libavcodec/packet.h" - -#include "libavutil/common.h" -#include "libavutil/error.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" - -#include "objpool.h" - -struct ObjPool { - void *pool[32]; - unsigned int pool_count; - - ObjPoolCBAlloc alloc; - ObjPoolCBReset reset; - ObjPoolCBFree free; -}; - -ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset, - ObjPoolCBFree cb_free) -{ - ObjPool *op = av_mallocz(sizeof(*op)); - - if (!op) - return NULL; - - op->alloc = cb_alloc; - op->reset = cb_reset; - op->free = cb_free; - - return op; -} - -void objpool_free(ObjPool **pop) -{ - ObjPool *op = *pop; - - if (!op) - return; - - for (unsigned int i = 0; i < op->pool_count; i++) - op->free(&op->pool[i]); - - av_freep(pop); -} - -int objpool_get(ObjPool *op, void **obj) -{ - if (op->pool_count) { - *obj = op->pool[--op->pool_count]; - op->pool[op->pool_count] = NULL; - } else - *obj = op->alloc(); - - return *obj ? 0 : AVERROR(ENOMEM); -} - -void objpool_release(ObjPool *op, void **obj) -{ - if (!*obj) - return; - - op->reset(*obj); - - if (op->pool_count < FF_ARRAY_ELEMS(op->pool)) - op->pool[op->pool_count++] = *obj; - else - op->free(obj); - - *obj = NULL; -} - -static void *alloc_packet(void) -{ - return av_packet_alloc(); -} -static void *alloc_frame(void) -{ - return av_frame_alloc(); -} - -static void reset_packet(void *obj) -{ - av_packet_unref(obj); -} -static void reset_frame(void *obj) -{ - av_frame_unref(obj); -} - -static void free_packet(void **obj) -{ - AVPacket *pkt = *obj; - av_packet_free(&pkt); - *obj = NULL; -} -static void free_frame(void **obj) -{ - AVFrame *frame = *obj; - av_frame_free(&frame); - *obj = NULL; -} - -ObjPool *objpool_alloc_packets(void) -{ - return objpool_alloc(alloc_packet, reset_packet, free_packet); -} -ObjPool *objpool_alloc_frames(void) -{ - return objpool_alloc(alloc_frame, reset_frame, free_frame); -} diff --git a/fftools/opt_common.c b/fftools/opt_common.c index 021ed75272..c2f6b9de2a 100644 --- a/fftools/opt_common.c +++ b/fftools/opt_common.c @@ -60,8 +60,6 @@ #include "libswresample/swresample.h" #include "libswresample/version.h" -#include "libpostproc/postprocess.h" -#include "libpostproc/version.h" enum show_muxdemuxers { SHOW_DEFAULT, @@ -191,7 +189,6 @@ static void print_all_libs_info(int flags, int level) PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); PRINT_LIB_INFO(swscale, SWSCALE, flags, level); PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); - PRINT_LIB_INFO(postproc, POSTPROC, flags, level); } static void print_program_info(int flags, int level) @@ -808,7 +805,6 @@ int show_filters(void *optctx, const char *opt, const char *arg) printf("Filters:\n" " T.. = Timeline support\n" " .S. = Slice threading\n" - " ..C = Command support\n" " A = Audio input/output\n" " V = Video input/output\n" " N = Dynamic number and/or type of input/output\n" @@ -833,10 +829,9 @@ int show_filters(void *optctx, const char *opt, const char *arg) ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|'; } *descr_cur = 0; - printf(" %c%c%c %-17s %-10s %s\n", + printf(" %c%c %-17s %-10s %s\n", filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.', filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.', - filter->process_command ? 'C' : '.', filter->name, descr, filter->description); } #else @@ -1294,6 +1289,18 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) } else { flags |= AV_LOG_PRINT_LEVEL; } + } else if (av_strstart(token, "time", &arg)) { + if (cmd == '-') { + flags &= ~AV_LOG_PRINT_TIME; + } else { + flags |= AV_LOG_PRINT_TIME; + } + } else if (av_strstart(token, "datetime", &arg)) { + if (cmd == '-') { + flags &= ~AV_LOG_PRINT_DATETIME; + } else { + flags |= AV_LOG_PRINT_DATETIME; + } } else { break; } @@ -1320,6 +1327,11 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) "Possible levels are numbers or:\n", arg); for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); + av_log(NULL, AV_LOG_FATAL, "Possible flags are:\n"); + av_log(NULL, AV_LOG_FATAL, "\"repeat\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"level\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"time\"\n"); + av_log(NULL, AV_LOG_FATAL, "\"datetime\"\n"); return AVERROR(EINVAL); } diff --git a/fftools/resources/.gitignore b/fftools/resources/.gitignore new file mode 100644 index 0000000000..cc742817b5 --- /dev/null +++ b/fftools/resources/.gitignore @@ -0,0 +1,5 @@ +*.html.c +*.css.c +*.html.gz +*.css.min +*.css.min.gz diff --git a/fftools/resources/Makefile b/fftools/resources/Makefile new file mode 100644 index 0000000000..3c936484d1 --- /dev/null +++ b/fftools/resources/Makefile @@ -0,0 +1,19 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=fftools/resources/%) + +vpath %.html $(SRC_PATH) +vpath %.css $(SRC_PATH) + +OBJS-resman += \ + fftools/resources/resman.o \ + + +RESOBJS += \ + fftools/resources/graph.html.o \ + fftools/resources/graph.css.o \ + + +$(RESOBJS): CCDEP = +$(RESOBJS): CC_DEPFLAGS = + +.SECONDARY: $(RESOBJS:.o=.gz) $(RESOBJS:.o=.c) $(RESOBJS:%.css.o=%.css.min) $(RESOBJS:%.css.o=%.css.min.gz) $(RESOBJS:%.html.o=%.html.gz) $(RESOBJS:.o=) diff --git a/fftools/resources/graph.css b/fftools/resources/graph.css new file mode 100644 index 0000000000..ab480673ab --- /dev/null +++ b/fftools/resources/graph.css @@ -0,0 +1,353 @@ +/* Variables */ +.root { + --ff-colvideo: #6eaa7b; + --ff-colaudio: #477fb3; + --ff-colsubtitle: #ad76ab; + --ff-coltext: #666; +} + +/* Common & Misc */ +.ff-inputfiles rect, .ff-outputfiles rect, .ff-inputstreams rect, .ff-outputstreams rect, .ff-decoders rect, .ff-encoders rect { + stroke-width: 0; + stroke: transparent; + filter: none !important; + fill: transparent !important; + display: none !important; +} + +.cluster span { + color: var(--ff-coltext); +} + +.cluster rect { + stroke: #dfdfdf !important; + transform: translateY(-2.3rem); + filter: drop-shadow(1px 2px 2px rgba(185,185,185,0.2)) !important; + rx: 8; + ry: 8; +} + +.cluster-label { + font-size: 1.1rem; +} + + .cluster-label .nodeLabel { + display: block; + font-weight: 500; + color: var(--ff-coltext); + } + + .cluster-label div { + max-width: unset !important; + padding: 3px; + } + + .cluster-label foreignObject { + transform: translateY(-0.7rem); + } + +/* Input and output files */ +.node.ff-inputfile .label foreignObject, .node.ff-outputfile .label foreignObject { + overflow: visible; +} + +.cluster.ff-inputfile .cluster-label foreignObject div:not(foreignObject div div), .cluster.ff-outputfile .cluster-label foreignObject div:not(foreignObject div div) { + display: table !important; +} + +.nodeLabel div.ff-inputfile, .nodeLabel div.ff-outputfile { + font-size: 1.1rem; + font-weight: 500; + min-width: 14rem; + width: 100%; + display: flex; + color: var(--ff-coltext); + margin-top: 0.1rem; + line-height: 1.35; + padding-bottom: 1.9rem; +} + +.nodeLabel div.ff-outputfile { + flex-direction: row-reverse; +} + +.ff-inputfile .index, .ff-outputfile .index { + order: 2; + color: var(--ff-coltext); + text-align: center; + border-radius: 0.45rem; + border: 0.18em solid #666666db; + font-weight: 600; + padding: 0 0.3em; + opacity: 0.8; +} + + .ff-inputfile .index::before { + content: 'In '; + } + + .ff-outputfile .index::before { + content: 'Out '; + } + +.ff-inputfile .demuxer_name, .ff-outputfile .muxer_name { + flex: 1; + order: 1; + font-size: 0.9rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: center; + max-width: 8rem; + align-content: center; + margin: 0.2rem 0.4rem 0 0.4rem; +} + +.ff-inputfile .file_extension, .ff-outputfile .file_extension { + order: 0; + background-color: #888; + color: white; + text-align: center; + border-radius: 0.45rem; + font-weight: 600; + padding: 0 0.4em; + align-content: center; + opacity: 0.8; +} + +.ff-inputfile .url, .ff-outputfile .url { + order: 4; + text-align: center; + position: absolute; + left: 0; + right: 0; + bottom: 0.75rem; + font-size: 0.7rem; + font-weight: 400; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0 0.3rem; + direction: rtl; + color: #999; +} + +.cluster.ff-inputfile rect, .cluster.ff-outputfile rect { + transform: translateY(-1.8rem); + fill: url(#ff-radgradient); +} + +/* Input and output streams */ +.node.ff-inputstream rect, .node.ff-outputstream rect { + padding: 0 !important; + margin: 0 !important; + border: none !important; + fill: white; + stroke: #e5e5e5 !important; + height: 2.7rem; + transform: translateY(0.2rem); + filter: none; + rx: 3; + ry: 3; +} + +.node.ff-inputstream .label foreignObject, .node.ff-outputstream .label foreignObject { + transform: translateY(-0.2%); + overflow: visible; +} + + .node.ff-inputstream .label foreignObject div:not(foreignObject div div), .node.ff-outputstream .label foreignObject div:not(foreignObject div div) { + display: block !important; + line-height: 1.5 !important; + } + +.nodeLabel div.ff-inputstream, .nodeLabel div.ff-outputstream { + font-size: 1.0rem; + font-weight: 500; + min-width: 12rem; + width: 100%; + display: flex; +} + +.nodeLabel div.ff-outputstream { + flex-direction: row-reverse; +} + +.ff-inputstream .name, .ff-outputstream .name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + align-content: center; + margin-bottom: -0.15rem; +} + +.ff-inputstream .index, .ff-outputstream .index { + flex: 0 0 1.4rem; + background-color: #888; + color: white; + text-align: center; + border-radius: 0.3rem; + font-weight: 600; + margin-right: -0.3rem; + margin-left: 0.4rem; + opacity: 0.8; +} + +.ff-outputstream .index { + margin-right: 0.6rem; + margin-left: -0.4rem; +} + +.ff-inputstream::before, .ff-outputstream::before { + font-variant-emoji: text; + flex: 0 0 2rem; + margin-left: -0.8rem; + margin-right: 0.2rem; +} + +.ff-outputstream::before { + margin-left: 0.2rem; + margin-right: -0.6rem; +} + +.ff-inputstream.video::before, .ff-outputstream.video::before { + content: '\239A'; + color: var(--ff-colvideo); + font-size: 2.25rem; + line-height: 0.5; + font-weight: bold; +} + +.ff-inputstream.audio::before, .ff-outputstream.audio::before { + content: '\1F39D'; + color: var(--ff-colaudio); + font-size: 1.75rem; + line-height: 0.9; +} + +.ff-inputstream.subtitle::before, .ff-outputstream.subtitle::before { + content: '\1AC'; + color: var(--ff-colsubtitle); + font-size: 1.2rem; + line-height: 1.1; + transform: scaleX(1.5); + margin-top: 0.050rem; +} + +.ff-inputstream.attachment::before, .ff-outputstream.attachment::before { + content: '\1F4CE'; + font-size: 1.3rem; + line-height: 1.15; +} + +.ff-inputstream.data::before, .ff-outputstream.data::before { + content: '\27E8\2219\2219\2219\27E9'; + font-size: 1.15rem; + line-height: 1.17; + letter-spacing: -0.3px; +} + +/* Filter Graphs */ +.cluster.ff-filters rect { + stroke-dasharray: 6 !important; + stroke-width: 1.3px; + stroke: #d1d1d1 !important; + filter: none !important; +} + +.cluster.ff-filters div.ff-filters .id { + display: none; +} + +.cluster.ff-filters div.ff-filters .name { + margin-right: 0.5rem; + font-size: 0.9rem; +} + +.cluster.ff-filters div.ff-filters .description { + font-weight: 400; + font-size: 0.75rem; + vertical-align: middle; + color: #777; + font-family: Cascadia Code, Lucida Console, monospace; +} + +/* Filter Shapes */ +.node.ff-filter rect { + rx: 10; + ry: 10; + stroke-width: 1px; + stroke: #d3d3d3; + fill: url(#ff-filtergradient); + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.1)); +} + +.node.ff-filter .label foreignObject { + transform: translateY(-0.4rem); + overflow: visible; +} + +.nodeLabel div.ff-filter { + font-size: 1.0rem; + font-weight: 500; + text-transform: uppercase; + min-width: 5.5rem; + margin-bottom: 0.5rem; +} + + .nodeLabel div.ff-filter span { + color: inherit; + } + +/* Decoders & Encoders */ +.node.ff-decoder rect, .node.ff-encoder rect { + stroke-width: 1px; + stroke: #d3d3d3; + fill: url(#ff-filtergradient); + filter: drop-shadow(1px 1px 2px rgba(0, 0, 0, 0.1)); +} + +.nodeLabel div.ff-decoder, .nodeLabel div.ff-encoder { + font-size: 0.85rem; + font-weight: 500; + min-width: 3.5rem; +} + +/* Links and Arrows */ +path.flowchart-link[id|='video'] { + stroke: var(--ff-colvideo); +} + +path.flowchart-link[id|='audio'] { + stroke: var(--ff-colaudio); +} + +path.flowchart-link[id|='subtitle'] { + stroke: var(--ff-colsubtitle); +} + +marker.marker path { + fill: context-stroke; +} + +.edgeLabel foreignObject { + transform: translateY(-1rem); +} + +.edgeLabel p { + background: transparent; + white-space: nowrap; + margin: 1rem 0.5rem !important; + font-weight: 500; + color: var(--ff-coltext); +} + +.edgeLabel, .labelBkg { + background: transparent; +} + +.edgeLabels .edgeLabel * { + font-size: 0.8rem; +} diff --git a/fftools/resources/graph.html b/fftools/resources/graph.html new file mode 100644 index 0000000000..8906f939a9 --- /dev/null +++ b/fftools/resources/graph.html @@ -0,0 +1,86 @@ + + + + + FFmpeg Graph + + + + +
+__###__
+
+ + + diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c new file mode 100644 index 0000000000..aa53e96bf4 --- /dev/null +++ b/fftools/resources/resman.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025 - softworkz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * output writers for filtergraph details + */ + +#include "config.h" + +#include + +#if CONFIG_RESOURCE_COMPRESSION +#include +#endif + +#include "resman.h" +#include "libavutil/avassert.h" +#include "libavutil/pixdesc.h" +#include "libavutil/dict.h" +#include "libavutil/common.h" + +extern const unsigned char ff_graph_html_data[]; +extern const unsigned int ff_graph_html_len; + +extern const unsigned char ff_graph_css_data[]; +extern const unsigned ff_graph_css_len; + +static const FFResourceDefinition resource_definitions[] = { + [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, "graph.css", &ff_graph_css_data[0], &ff_graph_css_len }, + [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, "graph.html", &ff_graph_html_data[0], &ff_graph_html_len }, +}; + + +static const AVClass resman_class = { + .class_name = "ResourceManager", +}; + +typedef struct ResourceManagerContext { + const AVClass *class; + AVDictionary *resource_dic; +} ResourceManagerContext; + +static AVMutex mutex = AV_MUTEX_INITIALIZER; + +static ResourceManagerContext resman_ctx = { .class = &resman_class }; + + +#if CONFIG_RESOURCE_COMPRESSION + +static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in_len, char **out, size_t *out_len) +{ + z_stream strm; + unsigned chunk = 65534; + int ret; + uint8_t *buf; + + *out = NULL; + memset(&strm, 0, sizeof(strm)); + + // Allocate output buffer with extra byte for null termination + buf = (uint8_t *)av_mallocz(chunk + 1); + if (!buf) { + av_log(ctx, AV_LOG_ERROR, "Failed to allocate decompression buffer\n"); + return AVERROR(ENOMEM); + } + + // 15 + 16 tells zlib to detect GZIP or zlib automatically + ret = inflateInit2(&strm, 15 + 16); + if (ret != Z_OK) { + av_log(ctx, AV_LOG_ERROR, "Error during zlib initialization: %s\n", strm.msg); + av_free(buf); + return AVERROR(ENOSYS); + } + + strm.avail_in = in_len; + strm.next_in = in; + strm.avail_out = chunk; + strm.next_out = buf; + + ret = inflate(&strm, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) { + av_log(ctx, AV_LOG_ERROR, "Inflate failed: %d, %s\n", ret, strm.msg); + inflateEnd(&strm); + av_free(buf); + return (ret == Z_STREAM_END) ? Z_OK : ((ret == Z_OK) ? Z_BUF_ERROR : ret); + } + + if (strm.avail_out == 0) { + // TODO: Error or loop decoding? + av_log(ctx, AV_LOG_WARNING, "Decompression buffer may be too small\n"); + } + + *out_len = chunk - strm.avail_out; + buf[*out_len] = 0; // Ensure null termination + + inflateEnd(&strm); + *out = (char *)buf; + return Z_OK; +} +#endif + +void ff_resman_uninit(void) +{ + ff_mutex_lock(&mutex); + + av_dict_free(&resman_ctx.resource_dic); + + ff_mutex_unlock(&mutex); +} + + +char *ff_resman_get_string(FFResourceId resource_id) +{ + ResourceManagerContext *ctx = &resman_ctx; + FFResourceDefinition resource_definition = { 0 }; + AVDictionaryEntry *dic_entry; + char *res = NULL; + + for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { + FFResourceDefinition def = resource_definitions[i]; + if (def.resource_id == resource_id) { + resource_definition = def; + break; + } + } + + av_assert1(resource_definition.name); + + ff_mutex_lock(&mutex); + + dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + + if (!dic_entry) { + int dict_ret; + +#if CONFIG_RESOURCE_COMPRESSION + + char *out = NULL; + size_t out_len; + + int ret = decompress_gzip(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len); + + if (ret) { + av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); + goto end; + } + + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, out, 0); + if (dict_ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret); + av_freep(&out); + goto end; + } + + av_freep(&out); +#else + + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, (const char *)resource_definition.data, 0); + if (dict_ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret); + goto end; + } + +#endif + dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + + if (!dic_entry) { + av_log(ctx, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n"); + goto end; + } + } + + res = dic_entry->value; + +end: + ff_mutex_unlock(&mutex); + return res; +} diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h new file mode 100644 index 0000000000..6485db5091 --- /dev/null +++ b/fftools/resources/resman.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 - softworkz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_RESOURCES_RESMAN_H +#define FFTOOLS_RESOURCES_RESMAN_H + +#include + +#include "config.h" +#include "fftools/ffmpeg.h" +#include "libavutil/avutil.h" +#include "libavutil/bprint.h" +#include "fftools/textformat/avtextformat.h" + +typedef enum { + FF_RESOURCE_GRAPH_CSS, + FF_RESOURCE_GRAPH_HTML, +} FFResourceId; + +typedef struct FFResourceDefinition { + FFResourceId resource_id; + const char *name; + + const unsigned char *data; + const unsigned *data_len; + +} FFResourceDefinition; + +void ff_resman_uninit(void); + +char *ff_resman_get_string(FFResourceId resource_id); + +#endif /* FFTOOLS_RESOURCES_RESMAN_H */ diff --git a/fftools/sync_queue.c b/fftools/sync_queue.c index 0e35b5b1cb..fbf288c6d1 100644 --- a/fftools/sync_queue.c +++ b/fftools/sync_queue.c @@ -20,16 +20,15 @@ #include #include "libavutil/avassert.h" +#include "libavutil/container_fifo.h" #include "libavutil/channel_layout.h" #include "libavutil/cpu.h" #include "libavutil/error.h" -#include "libavutil/fifo.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" #include "libavutil/samplefmt.h" #include "libavutil/timestamp.h" -#include "objpool.h" #include "sync_queue.h" /* @@ -67,8 +66,11 @@ * frame from stream 1, and all 4 frames from stream 2. */ +#define SQPTR(sq, frame) ((sq->type == SYNC_QUEUE_FRAMES) ? \ + (void*)frame.f : (void*)frame.p) + typedef struct SyncQueueStream { - AVFifo *fifo; + AVContainerFifo *fifo; AVRational tb; /* number of audio samples in fifo */ @@ -104,23 +106,11 @@ struct SyncQueue { SyncQueueStream *streams; unsigned int nb_streams; - // pool of preallocated frames to avoid constant allocations - ObjPool *pool; - int have_limiting; uintptr_t align_mask; }; -static void frame_move(const SyncQueue *sq, SyncQueueFrame dst, - SyncQueueFrame src) -{ - if (sq->type == SYNC_QUEUE_PACKETS) - av_packet_move_ref(dst.p, src.p); - else - av_frame_move_ref(dst.f, src.f); -} - /** * Compute the end timestamp of a frame. If nb_samples is provided, consider * the frame to have this number of audio samples, otherwise use frame duration. @@ -160,7 +150,7 @@ static void tb_update(const SyncQueue *sq, SyncQueueStream *st, return; // timebase should not change after the first frame - av_assert0(!av_fifo_can_read(st->fifo)); + av_assert0(!av_container_fifo_can_read(st->fifo)); if (st->head_ts != AV_NOPTS_VALUE) st->head_ts = av_rescale_q(st->head_ts, st->tb, tb); @@ -308,7 +298,7 @@ static int overflow_heartbeat(SyncQueue *sq, int stream_idx) /* get the chosen stream's tail timestamp */ for (size_t i = 0; tail_ts == AV_NOPTS_VALUE && - av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++) + av_container_fifo_peek(st->fifo, (void**)&frame, i) >= 0; i++) tail_ts = frame_end(sq, frame, 0); /* overflow triggers when the tail is over specified duration behind the head */ @@ -343,7 +333,6 @@ static int overflow_heartbeat(SyncQueue *sq, int stream_idx) int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) { SyncQueueStream *st; - SyncQueueFrame dst; int64_t ts; int ret, nb_samples; @@ -360,31 +349,22 @@ int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) tb_update(sq, st, frame); - ret = objpool_get(sq->pool, (void**)&dst); - if (ret < 0) - return ret; - - frame_move(sq, dst, frame); - - nb_samples = frame_samples(sq, dst); + nb_samples = frame_samples(sq, frame); // make sure frame duration is consistent with sample count if (nb_samples) { - av_assert0(dst.f->sample_rate > 0); - dst.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, dst.f->sample_rate }, - dst.f->time_base); + av_assert0(frame.f->sample_rate > 0); + frame.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, frame.f->sample_rate }, + frame.f->time_base); } - ts = frame_end(sq, dst, 0); + ts = frame_end(sq, frame, 0); av_log(sq->logctx, AV_LOG_DEBUG, "sq: send %u ts %s\n", stream_idx, av_ts2timestr(ts, &st->tb)); - ret = av_fifo_write(st->fifo, &dst, 1); - if (ret < 0) { - frame_move(sq, frame, dst); - objpool_release(sq->pool, (void**)&dst); + ret = av_container_fifo_write(st->fifo, SQPTR(sq, frame), 0); + if (ret < 0) return ret; - } stream_update_ts(sq, stream_idx, ts); @@ -453,7 +433,7 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, av_assert0(st->samples_queued >= nb_samples); - ret = av_fifo_peek(st->fifo, &src, 1, 0); + ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); av_assert0(ret >= 0); // peeked frame has enough samples and its data is aligned @@ -490,7 +470,7 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, while (dst->nb_samples < nb_samples) { int to_copy; - ret = av_fifo_peek(st->fifo, &src, 1, 0); + ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); av_assert0(ret >= 0); to_copy = FFMIN(nb_samples - dst->nb_samples, src.f->nb_samples); @@ -500,11 +480,9 @@ static int receive_samples(SyncQueue *sq, SyncQueueStream *st, if (to_copy < src.f->nb_samples) offset_audio(src.f, to_copy); - else { - av_frame_unref(src.f); - objpool_release(sq->pool, (void**)&src); - av_fifo_drain2(st->fifo, 1); - } + else + av_container_fifo_drain(st->fifo, 1); + st->samples_queued -= to_copy; dst->nb_samples += to_copy; @@ -531,7 +509,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, av_assert0(stream_idx < sq->nb_streams); st = &sq->streams[stream_idx]; - if (av_fifo_can_read(st->fifo) && + if (av_container_fifo_can_read(st->fifo) && (st->frame_samples <= st->samples_queued || st->finished)) { int nb_samples = st->frame_samples; SyncQueueFrame peek; @@ -541,7 +519,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, if (st->finished) nb_samples = FFMIN(nb_samples, st->samples_queued); - av_fifo_peek(st->fifo, &peek, 1, 0); + av_container_fifo_peek(st->fifo, (void**)&peek, 0); ts = frame_end(sq, peek, nb_samples); /* check if this stream's tail timestamp does not overtake @@ -560,9 +538,9 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, if (ret < 0) return ret; } else { - frame_move(sq, frame, peek); - objpool_release(sq->pool, (void**)&peek); - av_fifo_drain2(st->fifo, 1); + int ret = av_container_fifo_read(st->fifo, SQPTR(sq, frame), 0); + av_assert0(ret >= 0); + av_assert0(st->samples_queued >= frame_samples(sq, frame)); st->samples_queued -= frame_samples(sq, frame); } @@ -577,7 +555,7 @@ static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, } } - return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ? + return (sq->finished || (st->finished && !av_container_fifo_can_read(st->fifo))) ? AVERROR_EOF : AVERROR(EAGAIN); } @@ -629,7 +607,8 @@ int sq_add_stream(SyncQueue *sq, int limiting) st = &sq->streams[sq->nb_streams]; memset(st, 0, sizeof(*st)); - st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW); + st->fifo = (sq->type == SYNC_QUEUE_FRAMES) ? + av_container_fifo_alloc_avframe(0) : av_container_fifo_alloc_avpacket(0); if (!st->fifo) return AVERROR(ENOMEM); @@ -686,13 +665,6 @@ SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us, void *logctx) sq->head_stream = -1; sq->head_finished_stream = -1; - sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() : - objpool_alloc_frames(); - if (!sq->pool) { - av_freep(&sq); - return NULL; - } - return sq; } @@ -703,17 +675,10 @@ void sq_free(SyncQueue **psq) if (!sq) return; - for (unsigned int i = 0; i < sq->nb_streams; i++) { - SyncQueueFrame frame; - while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0) - objpool_release(sq->pool, (void**)&frame); - - av_fifo_freep2(&sq->streams[i].fifo); - } + for (unsigned int i = 0; i < sq->nb_streams; i++) + av_container_fifo_free(&sq->streams[i].fifo); av_freep(&sq->streams); - objpool_free(&sq->pool); - av_freep(psq); } diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c new file mode 100644 index 0000000000..651a84578c --- /dev/null +++ b/fftools/textformat/avtextformat.c @@ -0,0 +1,702 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "libavutil/mem.h" +#include "libavutil/avassert.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/hash.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/macros.h" +#include "libavutil/opt.h" +#include "avtextformat.h" + +#define SECTION_ID_NONE (-1) + +#define SHOW_OPTIONAL_FIELDS_AUTO (-1) +#define SHOW_OPTIONAL_FIELDS_NEVER 0 +#define SHOW_OPTIONAL_FIELDS_ALWAYS 1 + +static const struct { + double bin_val; + double dec_val; + char bin_str[4]; + char dec_str[4]; +} si_prefixes[] = { + { 1.0, 1.0, "", "" }, + { 1.024e3, 1e3, "Ki", "K" }, + { 1.048576e6, 1e6, "Mi", "M" }, + { 1.073741824e9, 1e9, "Gi", "G" }, + { 1.099511627776e12, 1e12, "Ti", "T" }, + { 1.125899906842624e15, 1e15, "Pi", "P" }, +}; + +static const char *textcontext_get_formatter_name(void *p) +{ + AVTextFormatContext *tctx = p; + return tctx->formatter->name; +} + +#define OFFSET(x) offsetof(AVTextFormatContext, x) + +static const AVOption textcontext_options[] = { + { "string_validation", "set string validation mode", + OFFSET(string_validation), AV_OPT_TYPE_INT, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, 0, AV_TEXTFORMAT_STRING_VALIDATION_NB - 1, .unit = "sv" }, + { "sv", "set string validation mode", + OFFSET(string_validation), AV_OPT_TYPE_INT, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, 0, AV_TEXTFORMAT_STRING_VALIDATION_NB - 1, .unit = "sv" }, + { "ignore", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_IGNORE }, .unit = "sv" }, + { "replace", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_REPLACE }, .unit = "sv" }, + { "fail", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_TEXTFORMAT_STRING_VALIDATION_FAIL }, .unit = "sv" }, + { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, { .str = "" } }, + { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, { .str = "\xEF\xBF\xBD" } }, + { NULL } +}; + +static void *textcontext_child_next(void *obj, void *prev) +{ + AVTextFormatContext *ctx = obj; + if (!prev && ctx->formatter && ctx->formatter->priv_class && ctx->priv) + return ctx->priv; + return NULL; +} + +static const AVClass textcontext_class = { + .class_name = "AVTextContext", + .item_name = textcontext_get_formatter_name, + .option = textcontext_options, + .version = LIBAVUTIL_VERSION_INT, + .child_next = textcontext_child_next, +}; + +static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) +{ + av_bprintf(bp, "0X"); + for (unsigned i = 0; i < ubuf_size; i++) + av_bprintf(bp, "%02X", ubuf[i]); +} + +int avtext_context_close(AVTextFormatContext **ptctx) +{ + AVTextFormatContext *tctx = *ptctx; + int ret = 0; + + if (!tctx) + return AVERROR(EINVAL); + + av_hash_freep(&tctx->hash); + + if (tctx->formatter) { + if (tctx->formatter->uninit) + ret = tctx->formatter->uninit(tctx); + if (tctx->formatter->priv_class) + av_opt_free(tctx->priv); + } + for (int i = 0; i < SECTION_MAX_NB_LEVELS; i++) + av_bprint_finalize(&tctx->section_pbuf[i], NULL); + av_freep(&tctx->priv); + av_opt_free(tctx); + av_freep(ptctx); + return ret; +} + + +int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, + const AVTextFormatSection *sections, int nb_sections, AVTextFormatOptions options, char *show_data_hash) +{ + AVTextFormatContext *tctx; + int ret = 0; + + av_assert0(ptctx && formatter); + + if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + for (int i = 0; i < SECTION_MAX_NB_LEVELS; i++) + av_bprint_init(&tctx->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED); + + tctx->class = &textcontext_class; + av_opt_set_defaults(tctx); + + if (!(tctx->priv = av_mallocz(formatter->priv_size))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + tctx->show_value_unit = options.show_value_unit; + tctx->use_value_prefix = options.use_value_prefix; + tctx->use_byte_value_binary_prefix = options.use_byte_value_binary_prefix; + tctx->use_value_sexagesimal_format = options.use_value_sexagesimal_format; + tctx->show_optional_fields = options.show_optional_fields; + + if (nb_sections > SECTION_MAX_NB_SECTIONS) { + av_log(tctx, AV_LOG_ERROR, "The number of section definitions (%d) is larger than the maximum allowed (%d)\n", nb_sections, SECTION_MAX_NB_SECTIONS); + ret = AVERROR(EINVAL); + goto fail; + } + + tctx->formatter = formatter; + tctx->level = -1; + tctx->sections = sections; + tctx->nb_sections = nb_sections; + tctx->writer = writer_context; + + if (formatter->priv_class) { + void *priv_ctx = tctx->priv; + *(const AVClass **)priv_ctx = formatter->priv_class; + av_opt_set_defaults(priv_ctx); + } + + /* convert options to dictionary */ + if (args) { + AVDictionary *opts = NULL; + const AVDictionaryEntry *opt = NULL; + + if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) { + av_log(tctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to textformat context\n", args); + av_dict_free(&opts); + goto fail; + } + + while ((opt = av_dict_iterate(opts, opt))) { + if ((ret = av_opt_set(tctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) { + av_log(tctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to textformat context\n", + opt->key, opt->value); + av_dict_free(&opts); + goto fail; + } + } + + av_dict_free(&opts); + } + + if (show_data_hash) { + if ((ret = av_hash_alloc(&tctx->hash, show_data_hash)) < 0) { + if (ret == AVERROR(EINVAL)) { + const char *n; + av_log(NULL, AV_LOG_ERROR, "Unknown hash algorithm '%s'\nKnown algorithms:", show_data_hash); + for (unsigned i = 0; (n = av_hash_names(i)); i++) + av_log(NULL, AV_LOG_ERROR, " %s", n); + av_log(NULL, AV_LOG_ERROR, "\n"); + } + goto fail; + } + } + + /* validate replace string */ + { + const uint8_t *p = (uint8_t *)tctx->string_validation_replacement; + const uint8_t *endp = p + strlen((const char *)p); + while (*p) { + const uint8_t *p0 = p; + int32_t code; + ret = av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags); + if (ret < 0) { + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + bprint_bytes(&bp, p0, p - p0); + av_log(tctx, AV_LOG_ERROR, + "Invalid UTF8 sequence %s found in string validation replace '%s'\n", + bp.str, tctx->string_validation_replacement); + goto fail; + } + } + } + + if (tctx->formatter->init) + ret = tctx->formatter->init(tctx); + if (ret < 0) + goto fail; + + *ptctx = tctx; + + return 0; + +fail: + avtext_context_close(&tctx); + return ret; +} + +/* Temporary definitions during refactoring */ +static const char unit_second_str[] = "s"; +static const char unit_hertz_str[] = "Hz"; +static const char unit_byte_str[] = "byte"; +static const char unit_bit_per_second_str[] = "bit/s"; + + +void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id) +{ + if (section_id < 0 || section_id >= tctx->nb_sections) { + av_log(tctx, AV_LOG_ERROR, "Invalid section_id for section_header: %d\n", section_id); + return; + } + + tctx->level++; + av_assert0(tctx->level < SECTION_MAX_NB_LEVELS); + + tctx->nb_item[tctx->level] = 0; + memset(tctx->nb_item_type[tctx->level], 0, sizeof(tctx->nb_item_type[tctx->level])); + tctx->section[tctx->level] = &tctx->sections[section_id]; + + if (tctx->formatter->print_section_header) + tctx->formatter->print_section_header(tctx, data); +} + +void avtext_print_section_footer(AVTextFormatContext *tctx) +{ + if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) { + av_log(tctx, AV_LOG_ERROR, "Invalid level for section_footer: %d\n", tctx->level); + return; + } + + int section_id = tctx->section[tctx->level]->id; + int parent_section_id = tctx->level ? + tctx->section[tctx->level - 1]->id : SECTION_ID_NONE; + + if (parent_section_id != SECTION_ID_NONE) { + tctx->nb_item[tctx->level - 1]++; + tctx->nb_item_type[tctx->level - 1][section_id]++; + } + + if (tctx->formatter->print_section_footer) + tctx->formatter->print_section_footer(tctx); + tctx->level--; +} + +void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags) +{ + const AVTextFormatSection *section; + + av_assert0(tctx); + + if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER) + return; + + if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO + && (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) + && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS)) + return; + + av_assert0(key && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + section = tctx->section[tctx->level]; + + if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { + tctx->formatter->print_integer(tctx, key, val); + tctx->nb_item[tctx->level]++; + } +} + +static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const char *src) +{ + const uint8_t *p, *endp, *srcp = (const uint8_t *)src; + AVBPrint dstbuf; + AVBPrint invalid_seq; + int invalid_chars_nb = 0, ret = 0; + + *dstp = NULL; + av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_init(&invalid_seq, 0, AV_BPRINT_SIZE_UNLIMITED); + + endp = srcp + strlen(src); + for (p = srcp; *p;) { + int32_t code; + int invalid = 0; + const uint8_t *p0 = p; + + if (av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags) < 0) { + + av_bprint_clear(&invalid_seq); + + bprint_bytes(&invalid_seq, p0, p - p0); + + av_log(tctx, AV_LOG_DEBUG, "Invalid UTF-8 sequence '%s' found in string '%s'\n", invalid_seq.str, src); + invalid = 1; + } + + if (invalid) { + invalid_chars_nb++; + + switch (tctx->string_validation) { + case AV_TEXTFORMAT_STRING_VALIDATION_FAIL: + av_log(tctx, AV_LOG_ERROR, "Invalid UTF-8 sequence found in string '%s'\n", src); + ret = AVERROR_INVALIDDATA; + goto end; + + case AV_TEXTFORMAT_STRING_VALIDATION_REPLACE: + av_bprintf(&dstbuf, "%s", tctx->string_validation_replacement); + break; + } + } + + if (!invalid || tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_IGNORE) + av_bprint_append_data(&dstbuf, p0, p-p0); + } + + if (invalid_chars_nb && tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_REPLACE) + av_log(tctx, AV_LOG_WARNING, + "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n", + invalid_chars_nb, src, tctx->string_validation_replacement); + +end: + av_bprint_finalize(&dstbuf, dstp); + av_bprint_finalize(&invalid_seq, NULL); + return ret; +} + +struct unit_value { + union { + double d; + int64_t i; + } val; + + const char *unit; +}; + +static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv) +{ + double vald; + int64_t vali = 0; + int show_float = 0; + + if (uv.unit == unit_second_str) { + vald = uv.val.d; + show_float = 1; + } else { + vald = (double)uv.val.i; + vali = uv.val.i; + } + + if (uv.unit == unit_second_str && tctx->use_value_sexagesimal_format) { + double secs; + int hours, mins; + secs = vald; + mins = (int)secs / 60; + secs = secs - mins * 60; + hours = mins / 60; + mins %= 60; + snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs); + } else { + const char *prefix_string = ""; + + if (tctx->use_value_prefix && vald > 1) { + int64_t index; + + if (uv.unit == unit_byte_str && tctx->use_byte_value_binary_prefix) { + index = (int64_t)(log2(vald) / 10); + index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); + vald /= si_prefixes[index].bin_val; + prefix_string = si_prefixes[index].bin_str; + } else { + index = (int64_t)(log10(vald) / 3); + index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); + vald /= si_prefixes[index].dec_val; + prefix_string = si_prefixes[index].dec_str; + } + vali = (int64_t)vald; + } + + if (show_float || (tctx->use_value_prefix && vald != (int64_t)vald)) + snprintf(buf, buf_size, "%f", vald); + else + snprintf(buf, buf_size, "%"PRId64, vali); + + av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || tctx->show_value_unit ? " " : "", + prefix_string, tctx->show_value_unit ? uv.unit : ""); + } + + return buf; +} + + +void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit) +{ + char val_str[128]; + struct unit_value uv; + uv.val.i = val; + uv.unit = unit; + avtext_print_string(tctx, key, value_string(tctx, val_str, sizeof(val_str), uv), 0); +} + + +int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags) +{ + const AVTextFormatSection *section; + int ret = 0; + + av_assert0(key && val && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + section = tctx->section[tctx->level]; + + if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER) + return 0; + + if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO + && (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL) + && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS)) + return 0; + + if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { + if (flags & AV_TEXTFORMAT_PRINT_STRING_VALIDATE) { + char *key1 = NULL, *val1 = NULL; + ret = validate_string(tctx, &key1, key); + if (ret < 0) goto end; + ret = validate_string(tctx, &val1, val); + if (ret < 0) goto end; + tctx->formatter->print_string(tctx, key1, val1); + end: + if (ret < 0) + av_log(tctx, AV_LOG_ERROR, + "Invalid key=value string combination %s=%s in section %s\n", + key, val, section->unique_name); + av_free(key1); + av_free(val1); + } else { + tctx->formatter->print_string(tctx, key, val); + } + + tctx->nb_item[tctx->level]++; + } + + return ret; +} + +void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep) +{ + char buf[44]; + snprintf(buf, sizeof(buf), "%d%c%d", q.num, sep, q.den); + avtext_print_string(tctx, key, buf, 0); +} + +void avtext_print_time(AVTextFormatContext *tctx, const char *key, + int64_t ts, const AVRational *time_base, int is_duration) +{ + if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { + avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL); + } else { + char buf[128]; + double d = av_q2d(*time_base) * ts; + struct unit_value uv; + uv.val.d = d; + uv.unit = unit_second_str; + value_string(tctx, buf, sizeof(buf), uv); + avtext_print_string(tctx, key, buf, 0); + } +} + +void avtext_print_ts(AVTextFormatContext *tctx, const char *key, int64_t ts, int is_duration) +{ + if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) + avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL); + else + avtext_print_integer(tctx, key, ts, 0); +} + +void avtext_print_data(AVTextFormatContext *tctx, const char *key, + const uint8_t *data, int size) +{ + AVBPrint bp; + unsigned offset = 0; + int i; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&bp, "\n"); + while (size) { + av_bprintf(&bp, "%08x: ", offset); + int l = FFMIN(size, 16); + for (i = 0; i < l; i++) { + av_bprintf(&bp, "%02x", data[i]); + if (i & 1) + av_bprintf(&bp, " "); + } + av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2); + for (i = 0; i < l; i++) + av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1); + av_bprintf(&bp, "\n"); + offset += l; + data += l; + size -= l; + } + avtext_print_string(tctx, key, bp.str, 0); + av_bprint_finalize(&bp, NULL); +} + +void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, + const uint8_t *data, int size) +{ + char buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; + int len; + + if (!tctx->hash) + return; + + av_hash_init(tctx->hash); + av_hash_update(tctx->hash, data, size); + len = snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(tctx->hash)); + av_hash_final_hex(tctx->hash, (uint8_t *)&buf[len], (int)sizeof(buf) - len); + avtext_print_string(tctx, key, buf, 0); +} + +void avtext_print_integers(AVTextFormatContext *tctx, const char *key, + uint8_t *data, int size, const char *format, + int columns, int bytes, int offset_add) +{ + AVBPrint bp; + unsigned offset = 0; + + if (!key || !data || !format || columns <= 0 || bytes <= 0) + return; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&bp, "\n"); + while (size) { + av_bprintf(&bp, "%08x: ", offset); + for (int i = 0, l = FFMIN(size, columns); i < l; i++) { + if (bytes == 1) av_bprintf(&bp, format, *data); + else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data)); + else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data)); + data += bytes; + size--; + } + av_bprintf(&bp, "\n"); + offset += offset_add; + } + avtext_print_string(tctx, key, bp.str, 0); + av_bprint_finalize(&bp, NULL); +} + +static const char *writercontext_get_writer_name(void *p) +{ + AVTextWriterContext *wctx = p; + return wctx->writer->name; +} + +static void *writercontext_child_next(void *obj, void *prev) +{ + AVTextFormatContext *ctx = obj; + if (!prev && ctx->formatter && ctx->formatter->priv_class && ctx->priv) + return ctx->priv; + return NULL; +} + +static const AVClass textwriter_class = { + .class_name = "AVTextWriterContext", + .item_name = writercontext_get_writer_name, + .version = LIBAVUTIL_VERSION_INT, + .child_next = writercontext_child_next, +}; + + +int avtextwriter_context_close(AVTextWriterContext **pwctx) +{ + AVTextWriterContext *wctx = *pwctx; + int ret = 0; + + if (!wctx) + return AVERROR(EINVAL); + + if (wctx->writer) { + if (wctx->writer->uninit) + ret = wctx->writer->uninit(wctx); + if (wctx->writer->priv_class) + av_opt_free(wctx->priv); + } + av_freep(&wctx->priv); + av_freep(pwctx); + return ret; +} + + +int avtextwriter_context_open(AVTextWriterContext **pwctx, const AVTextWriter *writer) +{ + AVTextWriterContext *wctx; + int ret = 0; + + if (!pwctx || !writer) + return AVERROR(EINVAL); + + if (!((wctx = av_mallocz(sizeof(AVTextWriterContext))))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (writer->priv_size && !((wctx->priv = av_mallocz(writer->priv_size)))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (writer->priv_class) { + void *priv_ctx = wctx->priv; + *(const AVClass **)priv_ctx = writer->priv_class; + av_opt_set_defaults(priv_ctx); + } + + wctx->class = &textwriter_class; + wctx->writer = writer; + + av_opt_set_defaults(wctx); + + + if (wctx->writer->init) + ret = wctx->writer->init(wctx); + if (ret < 0) + goto fail; + + *pwctx = wctx; + + return 0; + +fail: + avtextwriter_context_close(&wctx); + return ret; +} + +static const AVTextFormatter *const registered_formatters[] = +{ + &avtextformatter_default, + &avtextformatter_compact, + &avtextformatter_csv, + &avtextformatter_flat, + &avtextformatter_ini, + &avtextformatter_json, + &avtextformatter_xml, + &avtextformatter_mermaid, + &avtextformatter_mermaidhtml, + NULL +}; + +const AVTextFormatter *avtext_get_formatter_by_name(const char *name) +{ + for (int i = 0; registered_formatters[i]; i++) { + const char *end; + if (av_strstart(name, registered_formatters[i]->name, &end) && + (*end == '\0' || *end == '=')) + return registered_formatters[i]; + } + + return NULL; +} diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h new file mode 100644 index 0000000000..d9c14069eb --- /dev/null +++ b/fftools/textformat/avtextformat.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_TEXTFORMAT_AVTEXTFORMAT_H +#define FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H + +#include +#include "libavutil/dict.h" +#include "libavformat/avio.h" +#include "libavutil/bprint.h" +#include "libavutil/rational.h" +#include "libavutil/hash.h" +#include "avtextwriters.h" + +#define SECTION_MAX_NB_CHILDREN 11 + +typedef struct AVTextFormatSectionContext { + char *context_id; + const char *context_type; + int context_flags; +} AVTextFormatSectionContext; + + +typedef struct AVTextFormatSection { + int id; ///< unique id identifying a section + const char *name; + +#define AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level +#define AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys. + /// For these sections the element_name field is mandatory. +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE 8 ///< the section contains a type to distinguish multiple nested elements +#define AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE 16 ///< the items in this array section should be numbered individually by type +#define AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE 32 ///< ... +#define AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS 64 ///< ... +#define AV_TEXTFORMAT_SECTION_PRINT_TAGS 128 ///< ... +#define AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH 256 ///< ... + + int flags; + const int children_ids[SECTION_MAX_NB_CHILDREN + 1]; ///< list of children section IDS, terminated by -1 + const char *element_name; ///< name of the contained element, if provided + const char *unique_name; ///< unique section name, in case the name is ambiguous + AVDictionary *entries_to_show; + const char *(*get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined + int show_all_entries; + const char *id_key; ///< name of the key to be used as the id + const char *src_id_key; ///< name of the key to be used as the source id for diagram connections + const char *dest_id_key; ///< name of the key to be used as the target id for diagram connections + const char *linktype_key; ///< name of the key to be used as the link type for diagram connections (AVTextFormatLinkType) +} AVTextFormatSection; + +typedef struct AVTextFormatContext AVTextFormatContext; + +#define AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS 1 +#define AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT 2 +#define AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER 4 + +typedef enum { + AV_TEXTFORMAT_STRING_VALIDATION_FAIL, + AV_TEXTFORMAT_STRING_VALIDATION_REPLACE, + AV_TEXTFORMAT_STRING_VALIDATION_IGNORE, + AV_TEXTFORMAT_STRING_VALIDATION_NB +} StringValidation; + +typedef enum { + AV_TEXTFORMAT_LINKTYPE_SRCDEST, + AV_TEXTFORMAT_LINKTYPE_DESTSRC, + AV_TEXTFORMAT_LINKTYPE_BIDIR, + AV_TEXTFORMAT_LINKTYPE_NONDIR, + AV_TEXTFORMAT_LINKTYPE_HIDDEN, + AV_TEXTFORMAT_LINKTYPE_ONETOMANY = AV_TEXTFORMAT_LINKTYPE_SRCDEST, + AV_TEXTFORMAT_LINKTYPE_MANYTOONE = AV_TEXTFORMAT_LINKTYPE_DESTSRC, + AV_TEXTFORMAT_LINKTYPE_ONETOONE = AV_TEXTFORMAT_LINKTYPE_BIDIR, + AV_TEXTFORMAT_LINKTYPE_MANYTOMANY = AV_TEXTFORMAT_LINKTYPE_NONDIR, +} AVTextFormatLinkType; + +typedef struct AVTextFormatter { + const AVClass *priv_class; ///< private class of the formatter, if any + int priv_size; ///< private size for the formatter context + const char *name; + + int (*init) (AVTextFormatContext *tctx); + int (*uninit)(AVTextFormatContext *tctx); + + void (*print_section_header)(AVTextFormatContext *tctx, const void *data); + void (*print_section_footer)(AVTextFormatContext *tctx); + void (*print_integer) (AVTextFormatContext *tctx, const char *, int64_t); + void (*print_string) (AVTextFormatContext *tctx, const char *, const char *); + int flags; ///< a combination or AV_TEXTFORMAT__FLAG_* +} AVTextFormatter; + +#define SECTION_MAX_NB_LEVELS 12 +#define SECTION_MAX_NB_SECTIONS 100 + +struct AVTextFormatContext { + const AVClass *class; ///< class of the formatter + const AVTextFormatter *formatter; ///< the AVTextFormatter of which this is an instance + AVTextWriterContext *writer; ///< the AVTextWriterContext + + char *name; ///< name of this formatter instance + void *priv; ///< private data for use by the filter + + const AVTextFormatSection *sections; ///< array containing all sections + int nb_sections; ///< number of sections + + int level; ///< current level, starting from 0 + + /** number of the item printed in the given section, starting from 0 */ + unsigned int nb_item[SECTION_MAX_NB_LEVELS]; + unsigned int nb_item_type[SECTION_MAX_NB_LEVELS][SECTION_MAX_NB_SECTIONS]; + + /** section per each level */ + const AVTextFormatSection *section[SECTION_MAX_NB_LEVELS]; + AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, + /// used by various formatters + + int show_optional_fields; + int show_value_unit; + int use_value_prefix; + int use_byte_value_binary_prefix; + int use_value_sexagesimal_format; + + struct AVHashContext *hash; + + int string_validation; + char *string_validation_replacement; + unsigned int string_validation_utf8_flags; +}; + +typedef struct AVTextFormatOptions { + int show_optional_fields; + int show_value_unit; + int use_value_prefix; + int use_byte_value_binary_prefix; + int use_value_sexagesimal_format; +} AVTextFormatOptions; + +#define AV_TEXTFORMAT_PRINT_STRING_OPTIONAL 1 +#define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2 + +int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, + const AVTextFormatSection *sections, int nb_sections, AVTextFormatOptions options, char *show_data_hash); + +int avtext_context_close(AVTextFormatContext **tctx); + + +void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id); + +void avtext_print_section_footer(AVTextFormatContext *tctx); + +void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags); + +int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags); + +void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit); + +void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep); + +void avtext_print_time(AVTextFormatContext *tctx, const char *key, int64_t ts, const AVRational *time_base, int is_duration); + +void avtext_print_ts(AVTextFormatContext *tctx, const char *key, int64_t ts, int is_duration); + +void avtext_print_data(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size); + +void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size); + +void avtext_print_integers(AVTextFormatContext *tctx, const char *key, uint8_t *data, int size, + const char *format, int columns, int bytes, int offset_add); + +const AVTextFormatter *avtext_get_formatter_by_name(const char *name); + +extern const AVTextFormatter avtextformatter_default; +extern const AVTextFormatter avtextformatter_compact; +extern const AVTextFormatter avtextformatter_csv; +extern const AVTextFormatter avtextformatter_flat; +extern const AVTextFormatter avtextformatter_ini; +extern const AVTextFormatter avtextformatter_json; +extern const AVTextFormatter avtextformatter_xml; +extern const AVTextFormatter avtextformatter_mermaid; +extern const AVTextFormatter avtextformatter_mermaidhtml; + +#endif /* FFTOOLS_TEXTFORMAT_AVTEXTFORMAT_H */ diff --git a/fftools/textformat/avtextwriters.h b/fftools/textformat/avtextwriters.h new file mode 100644 index 0000000000..8457d7a6ea --- /dev/null +++ b/fftools/textformat/avtextwriters.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_TEXTFORMAT_AVTEXTWRITERS_H +#define FFTOOLS_TEXTFORMAT_AVTEXTWRITERS_H + +#include +#include "libavformat/avio.h" +#include "libavutil/bprint.h" + +typedef struct AVTextWriterContext AVTextWriterContext; + +typedef struct AVTextWriter { + const AVClass *priv_class; ///< private class of the writer, if any + int priv_size; ///< private size for the writer private class + const char *name; + + int (*init)(AVTextWriterContext *wctx); + int (*uninit)(AVTextWriterContext *wctx); + void (*writer_w8)(AVTextWriterContext *wctx, int b); + void (*writer_put_str)(AVTextWriterContext *wctx, const char *str); + void (*writer_vprintf)(AVTextWriterContext *wctx, const char *fmt, va_list vl); +} AVTextWriter; + +typedef struct AVTextWriterContext { + const AVClass *class; ///< class of the writer + const AVTextWriter *writer; + const char *name; + void *priv; ///< private data for use by the writer +} AVTextWriterContext; + + +int avtextwriter_context_open(AVTextWriterContext **pwctx, const AVTextWriter *writer); + +int avtextwriter_context_close(AVTextWriterContext **pwctx); + +int avtextwriter_create_stdout(AVTextWriterContext **pwctx); + +int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit); + +int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename); + +int avtextwriter_create_buffer(AVTextWriterContext **pwctx, AVBPrint *buffer); + +#endif /* FFTOOLS_TEXTFORMAT_AVTEXTWRITERS_H */ diff --git a/fftools/textformat/tf_compact.c b/fftools/textformat/tf_compact.c new file mode 100644 index 0000000000..c6311b5dea --- /dev/null +++ b/fftools/textformat/tf_compact.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + + +/* Compact output */ + +/** + * Apply C-language-like string escaping. + */ +static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + const char *p; + + for (p = src; *p; p++) { + switch (*p) { + case '\b': av_bprintf(dst, "%s", "\\b"); break; + case '\f': av_bprintf(dst, "%s", "\\f"); break; + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\\': av_bprintf(dst, "%s", "\\\\"); break; + default: + if (*p == sep) + av_bprint_chars(dst, '\\', 1); + av_bprint_chars(dst, *p, 1); + } + } + return dst->str; +} + +/** + * Quote fields containing special characters, check RFC4180. + */ +static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + char meta_chars[] = { sep, '"', '\n', '\r', '\0' }; + + int needs_quoting = !!src[strcspn(src, meta_chars)]; + + if (needs_quoting) + av_bprint_chars(dst, '"', 1); + + for (; *src; src++) { + if (*src == '"') + av_bprint_chars(dst, '"', 1); + av_bprint_chars(dst, *src, 1); + } + if (needs_quoting) + av_bprint_chars(dst, '"', 1); + return dst->str; +} + +static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) +{ + return src; +} + +typedef struct CompactContext { + const AVClass *class; + char *item_sep_str; + char item_sep; + int nokey; + int print_section; + char *escape_mode_str; + const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); + int nested_section[SECTION_MAX_NB_LEVELS]; + int has_nested_elems[SECTION_MAX_NB_LEVELS]; + int terminate_line[SECTION_MAX_NB_LEVELS]; +} CompactContext; + +#undef OFFSET +#define OFFSET(x) offsetof(CompactContext, x) + +static const AVOption compact_options[] = { + { "item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "|" }, 0, 0 }, + { "s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "|" }, 0, 0 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "c" }, 0, 0 }, + { "e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "c" }, 0, 0 }, + { "print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(compact); + +static av_cold int compact_init(AVTextFormatContext *wctx) +{ + CompactContext *compact = wctx->priv; + + if (strlen(compact->item_sep_str) != 1) { + av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", + compact->item_sep_str); + return AVERROR(EINVAL); + } + compact->item_sep = compact->item_sep_str[0]; + + if (!strcmp(compact->escape_mode_str, "none")) { + compact->escape_str = none_escape_str; + } else if (!strcmp(compact->escape_mode_str, "c" )) { + compact->escape_str = c_escape_str; + } else if (!strcmp(compact->escape_mode_str, "csv" )) { + compact->escape_str = csv_escape_str; + } else { + av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str); + return AVERROR(EINVAL); + } + + return 0; +} + +static void compact_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + CompactContext *compact = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + compact->terminate_line[wctx->level] = 1; + compact->has_nested_elems[wctx->level] = 0; + + av_bprint_clear(&wctx->section_pbuf[wctx->level]); + if (parent_section && + (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE || + (!(section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) && + !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))))) { + + /* define a prefix for elements not contained in an array or + in a wrapper, or for array elements with a type */ + const char *element_name = (char *)av_x_if_null(section->element_name, section->name); + AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level]; + + compact->nested_section[wctx->level] = 1; + compact->has_nested_elems[wctx->level - 1] = 1; + + av_bprintf(section_pbuf, "%s%s", + wctx->section_pbuf[wctx->level - 1].str, element_name); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + // add /TYPE to prefix + av_bprint_chars(section_pbuf, '/', 1); + + // normalize section type, replace special characters and lower case + for (const char *p = section->get_type(data); *p; p++) { + char c = + (*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_'; + av_bprint_chars(section_pbuf, c, 1); + } + } + av_bprint_chars(section_pbuf, ':', 1); + + wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level - 1]; + } else { + if (parent_section && !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) && + wctx->level && wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, compact->item_sep); + if (compact->print_section && + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "%s%c", section->name, compact->item_sep); + } +} + +static void compact_print_section_footer(AVTextFormatContext *wctx) +{ + CompactContext *compact = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + if (!compact->nested_section[wctx->level] && + compact->terminate_line[wctx->level] && + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_w8(wctx, '\n'); +} + +static void compact_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + CompactContext *compact = wctx->priv; + AVBPrint buf; + + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, compact->item_sep); + + if (!compact->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx)); + av_bprint_finalize(&buf, NULL); +} + +static void compact_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + CompactContext *compact = wctx->priv; + + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, compact->item_sep); + + if (!compact->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + + writer_printf(wctx, "%"PRId64, value); +} + +const AVTextFormatter avtextformatter_compact = { + .name = "compact", + .priv_size = sizeof(CompactContext), + .init = compact_init, + .print_section_header = compact_print_section_header, + .print_section_footer = compact_print_section_footer, + .print_integer = compact_print_int, + .print_string = compact_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &compact_class, +}; + +/* CSV output */ + +#undef OFFSET +#define OFFSET(x) offsetof(CompactContext, x) + +static const AVOption csv_options[] = { + { "item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "," }, 0, 0 }, + { "s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, { .str = "," }, 0, 0 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "csv" }, 0, 0 }, + { "e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, { .str = "csv" }, 0, 0 }, + { "print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(csv); + +const AVTextFormatter avtextformatter_csv = { + .name = "csv", + .priv_size = sizeof(CompactContext), + .init = compact_init, + .print_section_header = compact_print_section_header, + .print_section_footer = compact_print_section_footer, + .print_integer = compact_print_int, + .print_string = compact_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &csv_class, +}; diff --git a/fftools/textformat/tf_default.c b/fftools/textformat/tf_default.c new file mode 100644 index 0000000000..019bda9d44 --- /dev/null +++ b/fftools/textformat/tf_default.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Default output */ + +typedef struct DefaultContext { + const AVClass *class; + int nokey; + int noprint_wrappers; + int nested_section[SECTION_MAX_NB_LEVELS]; +} DefaultContext; + +#undef OFFSET +#define OFFSET(x) offsetof(DefaultContext, x) + +static const AVOption default_options[] = { + { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(default); + +/* lame uppercasing routine, assumes the string is lower case ASCII */ +static inline char *upcase_string(char *dst, size_t dst_size, const char *src) +{ + unsigned i; + + for (i = 0; src[i] && i < dst_size - 1; i++) + dst[i] = (char)av_toupper(src[i]); + dst[i] = 0; + return dst; +} + +static void default_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + DefaultContext *def = wctx->priv; + char buf[32]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_clear(&wctx->section_pbuf[wctx->level]); + if (parent_section && + !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) { + def->nested_section[wctx->level] = 1; + av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", + wctx->section_pbuf[wctx->level - 1].str, + upcase_string(buf, sizeof(buf), + av_x_if_null(section->element_name, section->name))); + } + + if (def->noprint_wrappers || def->nested_section[wctx->level]) + return; + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name)); +} + +static void default_print_section_footer(AVTextFormatContext *wctx) +{ + DefaultContext *def = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + char buf[32]; + + if (!section) + return; + + if (def->noprint_wrappers || def->nested_section[wctx->level]) + return; + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER | AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY))) + writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name)); +} + +static void default_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + DefaultContext *def = wctx->priv; + + if (!def->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + writer_printf(wctx, "%s\n", value); +} + +static void default_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + DefaultContext *def = wctx->priv; + + if (!def->nokey) + writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key); + writer_printf(wctx, "%"PRId64"\n", value); +} + +const AVTextFormatter avtextformatter_default = { + .name = "default", + .priv_size = sizeof(DefaultContext), + .print_section_header = default_print_section_header, + .print_section_footer = default_print_section_footer, + .print_integer = default_print_int, + .print_string = default_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS, + .priv_class = &default_class, +}; diff --git a/fftools/textformat/tf_flat.c b/fftools/textformat/tf_flat.c new file mode 100644 index 0000000000..d5517f109b --- /dev/null +++ b/fftools/textformat/tf_flat.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Flat output */ + +typedef struct FlatContext { + const AVClass *class; + const char *sep_str; + char sep; + int hierarchical; +} FlatContext; + +#undef OFFSET +#define OFFSET(x) offsetof(FlatContext, x) + +static const AVOption flat_options[] = { + { "sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 }, + { "s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, { .str = "." }, 0, 0 }, + { "hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(flat); + +static av_cold int flat_init(AVTextFormatContext *wctx) +{ + FlatContext *flat = wctx->priv; + + if (strlen(flat->sep_str) != 1) { + av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", + flat->sep_str); + return AVERROR(EINVAL); + } + flat->sep = flat->sep_str[0]; + + return 0; +} + +static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep) +{ + const char *p; + + for (p = src; *p; p++) { + if (!((*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z'))) + av_bprint_chars(dst, '_', 1); + else + av_bprint_chars(dst, *p, 1); + } + return dst->str; +} + +static const char *flat_escape_value_str(AVBPrint *dst, const char *src) +{ + const char *p; + + for (p = src; *p; p++) { + switch (*p) { + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\\': av_bprintf(dst, "%s", "\\\\"); break; + case '"': av_bprintf(dst, "%s", "\\\""); break; + case '`': av_bprintf(dst, "%s", "\\`"); break; + case '$': av_bprintf(dst, "%s", "\\$"); break; + default: av_bprint_chars(dst, *p, 1); break; + } + } + return dst->str; +} + +static void flat_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + FlatContext *flat = wctx->priv; + AVBPrint *buf = &wctx->section_pbuf[wctx->level]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + /* build section header */ + av_bprint_clear(buf); + if (!parent_section) + return; + + av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level - 1].str); + + if (flat->hierarchical || + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) { + av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str); + + if (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + int n = parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE + ? wctx->nb_item_type[wctx->level - 1][section->id] + : wctx->nb_item[wctx->level - 1]; + + av_bprintf(buf, "%d%s", n, flat->sep_str); + } + } +} + +static void flat_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value); +} + +static void flat_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + FlatContext *flat = wctx->priv; + AVBPrint buf; + + writer_put_str(wctx, wctx->section_pbuf[wctx->level].str); + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep)); + av_bprint_clear(&buf); + writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value)); + av_bprint_finalize(&buf, NULL); +} + +const AVTextFormatter avtextformatter_flat = { + .name = "flat", + .priv_size = sizeof(FlatContext), + .init = flat_init, + .print_section_header = flat_print_section_header, + .print_integer = flat_print_int, + .print_string = flat_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS | AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &flat_class, +}; diff --git a/fftools/textformat/tf_ini.c b/fftools/textformat/tf_ini.c new file mode 100644 index 0000000000..8959785295 --- /dev/null +++ b/fftools/textformat/tf_ini.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" + +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* Default output */ + +typedef struct DefaultContext { + const AVClass *class; + int nokey; + int noprint_wrappers; + int nested_section[SECTION_MAX_NB_LEVELS]; +} DefaultContext; + +/* INI format output */ + +typedef struct INIContext { + const AVClass *class; + int hierarchical; +} INIContext; + +#undef OFFSET +#define OFFSET(x) offsetof(INIContext, x) + +static const AVOption ini_options[] = { + { "hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { "h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(ini); + +static char *ini_escape_str(AVBPrint *dst, const char *src) +{ + int i = 0; + char c; + + while ((c = src[i++])) { + switch (c) { + case '\b': av_bprintf(dst, "%s", "\\b"); break; + case '\f': av_bprintf(dst, "%s", "\\f"); break; + case '\n': av_bprintf(dst, "%s", "\\n"); break; + case '\r': av_bprintf(dst, "%s", "\\r"); break; + case '\t': av_bprintf(dst, "%s", "\\t"); break; + case '\\': + case '#': + case '=': + case ':': + av_bprint_chars(dst, '\\', 1); + /* fallthrough */ + default: + if ((unsigned char)c < 32) + av_bprintf(dst, "\\x00%02x", (unsigned char)c); + else + av_bprint_chars(dst, c, 1); + break; + } + } + return dst->str; +} + +static void ini_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + INIContext *ini = wctx->priv; + AVBPrint *buf = &wctx->section_pbuf[wctx->level]; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_clear(buf); + if (!parent_section) { + writer_put_str(wctx, "# ffprobe output\n\n"); + return; + } + + if (wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, '\n'); + + av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level - 1].str); + if (ini->hierarchical || + !(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) { + av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name); + + if (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + unsigned n = parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE + ? wctx->nb_item_type[wctx->level - 1][section->id] + : wctx->nb_item[wctx->level - 1]; + av_bprintf(buf, ".%u", n); + } + } + + if (!(section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER))) + writer_printf(wctx, "[%s]\n", buf->str); +} + +static void ini_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + AVBPrint buf; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "%s=", ini_escape_str(&buf, key)); + av_bprint_clear(&buf); + writer_printf(wctx, "%s\n", ini_escape_str(&buf, value)); + av_bprint_finalize(&buf, NULL); +} + +static void ini_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + writer_printf(wctx, "%s=%"PRId64"\n", key, value); +} + +const AVTextFormatter avtextformatter_ini = { + .name = "ini", + .priv_size = sizeof(INIContext), + .print_section_header = ini_print_section_header, + .print_integer = ini_print_int, + .print_string = ini_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS | AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &ini_class, +}; diff --git a/fftools/textformat/tf_internal.h b/fftools/textformat/tf_internal.h new file mode 100644 index 0000000000..484886b7a7 --- /dev/null +++ b/fftools/textformat/tf_internal.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Internal utilities for text formatters. + */ + +#ifndef FFTOOLS_TEXTFORMAT_TF_INTERNAL_H +#define FFTOOLS_TEXTFORMAT_TF_INTERNAL_H + +#include "avtextformat.h" + +#define DEFINE_FORMATTER_CLASS(name) \ +static const AVClass name##_class = { \ + .class_name = #name, \ + .item_name = av_default_item_name, \ + .option = name##_options \ +} + + +/** + * Safely validate and access a section at a given level + */ +static inline const AVTextFormatSection *tf_get_section(AVTextFormatContext *tfc, int level) +{ + if (!tfc || level < 0 || level >= SECTION_MAX_NB_LEVELS || !tfc->section[level]) { + if (tfc) + av_log(tfc, AV_LOG_ERROR, "Invalid section access at level %d\n", level); + return NULL; + } + return tfc->section[level]; +} + +/** + * Safely access the parent section + */ +static inline const AVTextFormatSection *tf_get_parent_section(AVTextFormatContext *tfc, int level) +{ + if (level <= 0) + return NULL; + + return tf_get_section(tfc, level - 1); +} + +static inline void writer_w8(AVTextFormatContext *wctx, int b) +{ + wctx->writer->writer->writer_w8(wctx->writer, b); +} + +static inline void writer_put_str(AVTextFormatContext *wctx, const char *str) +{ + wctx->writer->writer->writer_put_str(wctx->writer, str); +} + +static inline void writer_printf(AVTextFormatContext *wctx, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + wctx->writer->writer->writer_vprintf(wctx->writer, fmt, args); + va_end(args); +} + +#endif /* FFTOOLS_TEXTFORMAT_TF_INTERNAL_H */ diff --git a/fftools/textformat/tf_json.c b/fftools/textformat/tf_json.c new file mode 100644 index 0000000000..78ea5dc21f --- /dev/null +++ b/fftools/textformat/tf_json.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* JSON output */ + +typedef struct JSONContext { + const AVClass *class; + int indent_level; + int compact; + const char *item_sep, *item_start_end; +} JSONContext; + +#undef OFFSET +#define OFFSET(x) offsetof(JSONContext, x) + +static const AVOption json_options[] = { + { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL } +}; + +DEFINE_FORMATTER_CLASS(json); + +static av_cold int json_init(AVTextFormatContext *wctx) +{ + JSONContext *json = wctx->priv; + + json->item_sep = json->compact ? ", " : ",\n"; + json->item_start_end = json->compact ? " " : "\n"; + + return 0; +} + +static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) +{ + static const char json_escape[] = { '"', '\\', '\b', '\f', '\n', '\r', '\t', 0 }; + static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 }; + const char *p; + + if (!src) { + av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n"); + return NULL; + } + + for (p = src; *p; p++) { + char *s = strchr(json_escape, *p); + if (s) { + av_bprint_chars(dst, '\\', 1); + av_bprint_chars(dst, json_subst[s - json_escape], 1); + } else if ((unsigned char)*p < 32) { + av_bprintf(dst, "\\u00%02x", (unsigned char)*p); + } else { + av_bprint_chars(dst, *p, 1); + } + } + return dst->str; +} + +#define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ') + +static void json_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + AVBPrint buf; + + if (!section) + return; + + if (wctx->level && wctx->nb_item[wctx->level - 1]) + writer_put_str(wctx, ",\n"); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) { + writer_put_str(wctx, "{\n"); + json->indent_level++; + } else { + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + json_escape_str(&buf, section->name, wctx); + JSON_INDENT(); + + json->indent_level++; + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + writer_printf(wctx, "\"%s\": [\n", buf.str); + } else if (parent_section && !(parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) { + writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end); + } else { + writer_printf(wctx, "{%s", json->item_start_end); + + /* this is required so the parser can distinguish between packets and frames */ + if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE) { + if (!json->compact) + JSON_INDENT(); + writer_printf(wctx, "\"type\": \"%s\"", section->name); + wctx->nb_item[wctx->level]++; + } + } + av_bprint_finalize(&buf, NULL); + } +} + +static void json_print_section_footer(AVTextFormatContext *wctx) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + + if (!section) + return; + + if (wctx->level == 0) { + json->indent_level--; + writer_put_str(wctx, "\n}\n"); + } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) { + writer_w8(wctx, '\n'); + json->indent_level--; + JSON_INDENT(); + writer_w8(wctx, ']'); + } else { + writer_put_str(wctx, json->item_start_end); + json->indent_level--; + if (!json->compact) + JSON_INDENT(); + writer_w8(wctx, '}'); + } +} + +static inline void json_print_item_str(AVTextFormatContext *wctx, + const char *key, const char *value) +{ + AVBPrint buf; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx)); + av_bprint_clear(&buf); + writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx)); + av_bprint_finalize(&buf, NULL); +} + +static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + + if (!section) + return; + + if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) + writer_put_str(wctx, json->item_sep); + if (!json->compact) + JSON_INDENT(); + json_print_item_str(wctx, key, value); +} + +static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + JSONContext *json = wctx->priv; + AVBPrint buf; + + if (!section) + return; + + if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) + writer_put_str(wctx, json->item_sep); + if (!json->compact) + JSON_INDENT(); + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value); + av_bprint_finalize(&buf, NULL); +} + +const AVTextFormatter avtextformatter_json = { + .name = "json", + .priv_size = sizeof(JSONContext), + .init = json_init, + .print_section_header = json_print_section_header, + .print_section_footer = json_print_section_footer, + .print_integer = json_print_int, + .print_string = json_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &json_class, +}; diff --git a/fftools/textformat/tf_mermaid.c b/fftools/textformat/tf_mermaid.c new file mode 100644 index 0000000000..6af58d58c2 --- /dev/null +++ b/fftools/textformat/tf_mermaid.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "tf_internal.h" +#include "tf_mermaid.h" +#include +#include +#include +#include + + +static const char *init_directive = "" + "%%{init: {" + "\"theme\": \"base\"," + "\"curve\": \"monotoneX\"," + "\"rankSpacing\": 10," + "\"nodeSpacing\": 10," + "\"themeCSS\": \"__###__\"," + "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\"," + "\"themeVariables\": { " + "\"clusterBkg\": \"white\", " + "\"primaryBorderColor\": \"gray\", " + "\"lineColor\": \"gray\", " + "\"secondaryTextColor\": \"gray\", " + "\"tertiaryBorderColor\": \"gray\", " + "\"primaryTextColor\": \"#666\", " + "\"secondaryTextColor\": \"red\" " + "}," + "\"flowchart\": { " + "\"subGraphTitleMargin\": { \"top\": -15, \"bottom\": 20 }, " + "\"diagramPadding\": 20, " + "\"curve\": \"monotoneX\" " + "}" + " }}%%\n\n"; + +static const char* init_directive_er = "" + "%%{init: {" + "\"theme\": \"base\"," + "\"layout\": \"elk\"," + "\"curve\": \"monotoneX\"," + "\"rankSpacing\": 65," + "\"nodeSpacing\": 60," + "\"themeCSS\": \"__###__\"," + "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\"," + "\"themeVariables\": { " + "\"clusterBkg\": \"white\", " + "\"primaryBorderColor\": \"gray\", " + "\"lineColor\": \"gray\", " + "\"secondaryTextColor\": \"gray\", " + "\"tertiaryBorderColor\": \"gray\", " + "\"primaryTextColor\": \"#666\", " + "\"secondaryTextColor\": \"red\" " + "}," + "\"er\": { " + "\"diagramPadding\": 12, " + "\"entityPadding\": 4, " + "\"minEntityWidth\": 150, " + "\"minEntityHeight\": 20, " + "\"curve\": \"monotoneX\" " + "}" + " }}%%\n\n"; + +static const char *theme_css_er = "" + + // Variables + ".root { " + "--ff-colvideo: #6eaa7b; " + "--ff-colaudio: #477fb3; " + "--ff-colsubtitle: #ad76ab; " + "--ff-coltext: #666; " + "} " + " g.nodes g.node.default rect.basic.label-container, " + " g.nodes g.node.default path { " + " rx: 1; " + " ry: 1; " + " stroke-width: 1px !important; " + " stroke: #e9e9e9 !important; " + " fill: url(#ff-filtergradient) !important; " + " filter: drop-shadow(0px 0px 5.5px rgba(0, 0, 0, 0.05)); " + " fill: white !important; " + " } " + " " + " .relationshipLine { " + " stroke: gray; " + " stroke-width: 1; " + " fill: none; " + " filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.2)); " + " } " + " " + " g.node.default g.label.name foreignObject > div > span > p, " + " g.nodes g.node.default g.label:not(.attribute-name, .attribute-keys, .attribute-type, .attribute-comment) foreignObject > div > span > p { " + " font-size: 0.95rem; " + " font-weight: 500; " + " text-transform: uppercase; " + " min-width: 5.5rem; " + " margin-bottom: 0.5rem; " + " " + " } " + " " + " .edgePaths path { " + " marker-end: none; " + " marker-start: none; " + " " + "} "; + + +/* Mermaid Graph output */ + +typedef struct MermaidContext { + const AVClass *class; + AVDiagramConfig *diagram_config; + int subgraph_count; + int within_tag; + int indent_level; + int create_html; + + // Options + int enable_link_colors; // Requires Mermaid 11.5 + + struct section_data { + const char *section_id; + const char *section_type; + const char *src_id; + const char *dest_id; + AVTextFormatLinkType link_type; + int current_is_textblock; + int current_is_stadium; + int subgraph_start_incomplete; + } section_data[SECTION_MAX_NB_LEVELS]; + + unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, + AVBPrint link_buf; ///< print buffer for writing diagram links + AVDictionary *link_dict; +} MermaidContext; + +#undef OFFSET +#define OFFSET(x) offsetof(MermaidContext, x) + +static const AVOption mermaid_options[] = { + { "link_coloring", "enable colored links (requires Mermaid >= 11.5)", OFFSET(enable_link_colors), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 }, + ////{"diagram_css", "CSS for the diagram", OFFSET(diagram_css), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 }, + ////{"html_template", "Template HTML", OFFSET(html_template), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(mermaid); + +void av_diagram_init(AVTextFormatContext *tfc, AVDiagramConfig *diagram_config) +{ + MermaidContext *mmc = tfc->priv; + mmc->diagram_config = diagram_config; +} + +static av_cold int has_link_pair(const AVTextFormatContext *tfc, const char *src, const char *dest) +{ + MermaidContext *mmc = tfc->priv; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&buf, "%s--%s", src, dest); + + if (mmc->link_dict && av_dict_get(mmc->link_dict, buf.str, NULL, 0)) + return 1; + + av_dict_set(&mmc->link_dict, buf.str, buf.str, 0); + + return 0; +} + +static av_cold int mermaid_init(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + av_bprint_init(&mmc->link_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + ////mmc->enable_link_colors = 1; // Requires Mermaid 11.5 + return 0; +} + +static av_cold int mermaid_init_html(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + int ret = mermaid_init(tfc); + + if (ret < 0) + return ret; + + mmc->create_html = 1; + + return 0; +} + +static av_cold int mermaid_uninit(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + + av_bprint_finalize(&mmc->link_buf, NULL); + av_dict_free(&mmc->link_dict); + + for (unsigned i = 0; i < SECTION_MAX_NB_LEVELS; i++) { + av_freep(&mmc->section_data[i].dest_id); + av_freep(&mmc->section_data[i].section_id); + av_freep(&mmc->section_data[i].src_id); + av_freep(&mmc->section_data[i].section_type); + } + + return 0; +} + +static void set_str(const char **dst, const char *src) +{ + if (*dst) + av_freep(dst); + + if (src) + *dst = av_strdup(src); +} + +#define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ') + +static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data) +{ + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(tfc, tfc->level); + + if (!section) + return; + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + MermaidContext *mmc = tfc->priv; + const AVTextFormatSectionContext *sec_ctx = data; + + if (tfc->level == 0) { + char *directive; + AVBPrint css_buf; + const char *diag_directive = mmc->diagram_config->diagram_type == AV_DIAGRAMTYPE_ENTITYRELATIONSHIP ? init_directive_er : init_directive; + char *single_line_css = av_strireplace(mmc->diagram_config->diagram_css, "\n", " "); + (void)theme_css_er; + ////char *single_line_css = av_strireplace(theme_css_er, "\n", " "); + av_bprint_init(&css_buf, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_escape(&css_buf, single_line_css, "'\\", AV_ESCAPE_MODE_BACKSLASH, AV_ESCAPE_FLAG_STRICT); + av_freep(&single_line_css); + + directive = av_strireplace(diag_directive, "__###__", css_buf.str); + if (mmc->create_html) { + uint64_t length; + char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__"); + if (!token_pos) { + av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template."); + return; + } + + length = token_pos - mmc->diagram_config->html_template; + for (uint64_t i = 0; i < length; i++) + writer_w8(tfc, mmc->diagram_config->html_template[i]); + } + + writer_put_str(tfc, directive); + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + writer_put_str(tfc, "flowchart LR\n"); + ////writer_put_str(tfc, " gradient_def@{ shape: text, label: \"\" }\n"); + writer_put_str(tfc, " gradient_def@{ shape: text, label: \"\" }\n"); + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + writer_put_str(tfc, "erDiagram\n"); + break; + } + + av_bprint_finalize(&css_buf, NULL); + av_freep(&directive); + return; + } + + if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { + + struct section_data parent_sec_data = mmc->section_data[tfc->level - 1]; + AVBPrint *parent_buf = &tfc->section_pbuf[tfc->level - 1]; + + if (parent_sec_data.subgraph_start_incomplete) { + + if (parent_buf->len > 0) + writer_printf(tfc, "%s", parent_buf->str); + + writer_put_str(tfc, "\"]\n"); + + mmc->section_data[tfc->level - 1].subgraph_start_incomplete = 0; + } + } + + av_freep(&mmc->section_data[tfc->level].section_id); + av_freep(&mmc->section_data[tfc->level].section_type); + av_freep(&mmc->section_data[tfc->level].src_id); + av_freep(&mmc->section_data[tfc->level].dest_id); + mmc->section_data[tfc->level].current_is_textblock = 0; + mmc->section_data[tfc->level].current_is_stadium = 0; + mmc->section_data[tfc->level].subgraph_start_incomplete = 0; + mmc->section_data[tfc->level].link_type = AV_TEXTFORMAT_LINKTYPE_SRCDEST; + + // NOTE: av_strdup() allocations aren't checked + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { + + av_bprint_clear(buf); + writer_put_str(tfc, "\n"); + + mmc->indent_level++; + + if (sec_ctx->context_id) { + MM_INDENT(); + writer_printf(tfc, "subgraph %s[\"
", sec_ctx->context_id, section->name); + } else { + av_log(tfc, AV_LOG_ERROR, "Unable to write subgraph start. Missing id field. Section: %s", section->name); + } + + mmc->section_data[tfc->level].subgraph_start_incomplete = 1; + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + } + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE) { + + av_bprint_clear(buf); + writer_put_str(tfc, "\n"); + + mmc->indent_level++; + + if (sec_ctx->context_id) { + + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + if (sec_ctx->context_flags & 1) { + + MM_INDENT(); + writer_printf(tfc, "%s@{ shape: text, label: \"", sec_ctx->context_id); + mmc->section_data[tfc->level].current_is_textblock = 1; + } else if (sec_ctx->context_flags & 2) { + + MM_INDENT(); + writer_printf(tfc, "%s([\"", sec_ctx->context_id); + mmc->section_data[tfc->level].current_is_stadium = 1; + } else { + MM_INDENT(); + writer_printf(tfc, "%s(\"", sec_ctx->context_id); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + MM_INDENT(); + writer_printf(tfc, "%s {\n", sec_ctx->context_id); + break; + } + + } else { + av_log(tfc, AV_LOG_ERROR, "Unable to write shape start. Missing id field. Section: %s", section->name); + } + + set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id); + } + + + if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) { + + if (sec_ctx && sec_ctx->context_type) + writer_printf(tfc, "
", section->name, sec_ctx->context_type); + else + writer_printf(tfc, "
", section->name); + } + + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) { + + av_bprint_clear(buf); + mmc->nb_link_captions[tfc->level] = 0; + + if (sec_ctx && sec_ctx->context_type) + set_str(&mmc->section_data[tfc->level].section_type, sec_ctx->context_type); + + ////if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + //// AVBPrint buf; + //// av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + //// av_bprint_escape(&buf, section->get_type(data), NULL, + //// AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + //// writer_printf(tfc, " type=\"%s\"", buf.str); + } +} + +static void mermaid_print_section_footer(AVTextFormatContext *tfc) +{ + MermaidContext *mmc = tfc->priv; + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + + if (!section) + return; + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + struct section_data sec_data = mmc->section_data[tfc->level]; + + if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) + writer_put_str(tfc, "
"); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE) { + + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (sec_data.current_is_textblock) { + writer_printf(tfc, "\"}\n", section->name); + + if (sec_data.section_id) { + MM_INDENT(); + writer_put_str(tfc, "class "); + writer_put_str(tfc, sec_data.section_id); + writer_put_str(tfc, " ff-"); + writer_put_str(tfc, section->name); + writer_put_str(tfc, "\n"); + } + } else if (sec_data.current_is_stadium) { + writer_printf(tfc, "\"]):::ff-%s\n", section->name); + } else { + writer_printf(tfc, "\"):::ff-%s\n", section->name); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + MM_INDENT(); + writer_put_str(tfc, "}\n\n"); + break; + } + + mmc->indent_level--; + + } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) { + + MM_INDENT(); + writer_put_str(tfc, "end\n"); + + if (sec_data.section_id) { + MM_INDENT(); + writer_put_str(tfc, "class "); + writer_put_str(tfc, sec_data.section_id); + writer_put_str(tfc, " ff-"); + writer_put_str(tfc, section->name); + writer_put_str(tfc, "\n"); + } + + mmc->indent_level--; + } + + if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS)) + if (sec_data.src_id && sec_data.dest_id + && !has_link_pair(tfc, sec_data.src_id, sec_data.dest_id)) + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (sec_data.section_type && mmc->enable_link_colors) + av_bprintf(&mmc->link_buf, "\n %s %s-%s-%s@==", sec_data.src_id, sec_data.section_type, sec_data.src_id, sec_data.dest_id); + else + av_bprintf(&mmc->link_buf, "\n %s ==", sec_data.src_id); + + if (buf->len > 0) { + av_bprintf(&mmc->link_buf, " \"%s", buf->str); + + for (unsigned i = 0; i < mmc->nb_link_captions[tfc->level]; i++) + av_bprintf(&mmc->link_buf, "
 "); + + av_bprintf(&mmc->link_buf, "\" =="); + } + + av_bprintf(&mmc->link_buf, "> %s", sec_data.dest_id); + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + + + av_bprintf(&mmc->link_buf, "\n %s", sec_data.src_id); + + switch (sec_data.link_type) { + case AV_TEXTFORMAT_LINKTYPE_ONETOMANY: + av_bprintf(&mmc->link_buf, "%s", " ||--o{ "); + break; + case AV_TEXTFORMAT_LINKTYPE_MANYTOONE: + av_bprintf(&mmc->link_buf, "%s", " }o--|| "); + break; + case AV_TEXTFORMAT_LINKTYPE_ONETOONE: + av_bprintf(&mmc->link_buf, "%s", " ||--|| "); + break; + case AV_TEXTFORMAT_LINKTYPE_MANYTOMANY: + av_bprintf(&mmc->link_buf, "%s", " }o--o{ "); + break; + default: + av_bprintf(&mmc->link_buf, "%s", " ||--|| "); + break; + } + + av_bprintf(&mmc->link_buf, "%s : \"\"", sec_data.dest_id); + + break; + } + + if (tfc->level == 0) { + + writer_put_str(tfc, "\n"); + if (mmc->create_html) { + char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__"); + if (!token_pos) { + av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template."); + return; + } + token_pos += strlen("__###__"); + writer_put_str(tfc, token_pos); + } + } + + if (tfc->level == 1) { + + if (mmc->link_buf.len > 0) { + writer_put_str(tfc, mmc->link_buf.str); + av_bprint_clear(&mmc->link_buf); + } + + writer_put_str(tfc, "\n"); + } +} + +static void mermaid_print_value(AVTextFormatContext *tfc, const char *key, + const char *str, int64_t num, const int is_int) +{ + MermaidContext *mmc = tfc->priv; + const AVTextFormatSection *section = tf_get_section(tfc, tfc->level); + + if (!section) + return; + + AVBPrint *buf = &tfc->section_pbuf[tfc->level]; + struct section_data sec_data = mmc->section_data[tfc->level]; + int exit = 0; + + if (section->id_key && !strcmp(section->id_key, key)) { + set_str(&mmc->section_data[tfc->level].section_id, str); + exit = 1; + } + + if (section->dest_id_key && !strcmp(section->dest_id_key, key)) { + set_str(&mmc->section_data[tfc->level].dest_id, str); + exit = 1; + } + + if (section->src_id_key && !strcmp(section->src_id_key, key)) { + set_str(&mmc->section_data[tfc->level].src_id, str); + exit = 1; + } + + if (section->linktype_key && !strcmp(section->linktype_key, key)) { + mmc->section_data[tfc->level].link_type = (AVTextFormatLinkType)num; + exit = 1; + } + + if (exit) + return; + + if ((section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE | AV_TEXTFORMAT_SECTION_PRINT_TAGS)) + || (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH && sec_data.subgraph_start_incomplete)) { + switch (mmc->diagram_config->diagram_type) { + case AV_DIAGRAMTYPE_GRAPH: + + if (is_int) { + writer_printf(tfc, "%s: %"PRId64"", key, key, num); + } else { + const char *tmp = av_strireplace(str, "\"", "'"); + writer_printf(tfc, "%s", key, tmp); + av_freep(&tmp); + } + + break; + case AV_DIAGRAMTYPE_ENTITYRELATIONSHIP: + + if (!is_int && str) + { + const char *col_type; + + if (key[0] == '_') + return; + + if (sec_data.section_id && !strcmp(str, sec_data.section_id)) + col_type = "PK"; + else if (sec_data.dest_id && !strcmp(str, sec_data.dest_id)) + col_type = "FK"; + else if (sec_data.src_id && !strcmp(str, sec_data.src_id)) + col_type = "FK"; + else + col_type = ""; + + MM_INDENT(); + + writer_printf(tfc, " %s %s %s\n", key, str, col_type); + } + break; + } + + } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) { + if (buf->len > 0) + av_bprintf(buf, "%s", "
"); + + av_bprintf(buf, ""); + if (is_int) + av_bprintf(buf, "%s: %"PRId64"", key, num); + else + av_bprintf(buf, "%s", str); + + mmc->nb_link_captions[tfc->level]++; + } +} + +static inline void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value) +{ + mermaid_print_value(tfc, key, value, 0, 0); +} + +static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value) +{ + mermaid_print_value(tfc, key, NULL, value, 1); +} + +const AVTextFormatter avtextformatter_mermaid = { + .name = "mermaid", + .priv_size = sizeof(MermaidContext), + .init = mermaid_init, + .uninit = mermaid_uninit, + .print_section_header = mermaid_print_section_header, + .print_section_footer = mermaid_print_section_footer, + .print_integer = mermaid_print_int, + .print_string = mermaid_print_str, + .flags = AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER, + .priv_class = &mermaid_class, +}; + + +const AVTextFormatter avtextformatter_mermaidhtml = { + .name = "mermaidhtml", + .priv_size = sizeof(MermaidContext), + .init = mermaid_init_html, + .uninit = mermaid_uninit, + .print_section_header = mermaid_print_section_header, + .print_section_footer = mermaid_print_section_footer, + .print_integer = mermaid_print_int, + .print_string = mermaid_print_str, + .flags = AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER, + .priv_class = &mermaid_class, +}; diff --git a/fftools/objpool.h b/fftools/textformat/tf_mermaid.h similarity index 57% rename from fftools/objpool.h rename to fftools/textformat/tf_mermaid.h index 1b2aea6aca..6e8f2a9b42 100644 --- a/fftools/objpool.h +++ b/fftools/textformat/tf_mermaid.h @@ -1,4 +1,6 @@ /* + * Copyright (c) The FFmpeg developers + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -16,22 +18,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef FFTOOLS_OBJPOOL_H -#define FFTOOLS_OBJPOOL_H +#ifndef FFTOOLS_TEXTFORMAT_TF_MERMAID_H +#define FFTOOLS_TEXTFORMAT_TF_MERMAID_H -typedef struct ObjPool ObjPool; +typedef enum { + AV_DIAGRAMTYPE_GRAPH, + AV_DIAGRAMTYPE_ENTITYRELATIONSHIP, +} AVDiagramType; -typedef void* (*ObjPoolCBAlloc)(void); -typedef void (*ObjPoolCBReset)(void *); -typedef void (*ObjPoolCBFree)(void **); +typedef struct AVDiagramConfig { + AVDiagramType diagram_type; + const char *diagram_css; + const char *html_template; +} AVDiagramConfig; -void objpool_free(ObjPool **op); -ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset, - ObjPoolCBFree cb_free); -ObjPool *objpool_alloc_packets(void); -ObjPool *objpool_alloc_frames(void); -int objpool_get(ObjPool *op, void **obj); -void objpool_release(ObjPool *op, void **obj); +void av_diagram_init(AVTextFormatContext *tfc, AVDiagramConfig *diagram_config); -#endif // FFTOOLS_OBJPOOL_H +void av_mermaid_set_html_template(AVTextFormatContext *tfc, const char *html_template); + + +#endif /* FFTOOLS_TEXTFORMAT_TF_MERMAID_H */ diff --git a/fftools/textformat/tf_xml.c b/fftools/textformat/tf_xml.c new file mode 100644 index 0000000000..6b09e09ab4 --- /dev/null +++ b/fftools/textformat/tf_xml.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextformat.h" +#include "libavutil/bprint.h" +#include "libavutil/error.h" +#include "libavutil/opt.h" +#include "tf_internal.h" + +/* XML output */ + +typedef struct XMLContext { + const AVClass *class; + int within_tag; + int indent_level; + int fully_qualified; + int xsd_strict; +} XMLContext; + +#undef OFFSET +#define OFFSET(x) offsetof(XMLContext, x) + +static const AVOption xml_options[] = { + { "fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { "x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 }, + { NULL }, +}; + +DEFINE_FORMATTER_CLASS(xml); + +static av_cold int xml_init(AVTextFormatContext *wctx) +{ + XMLContext *xml = wctx->priv; + + if (xml->xsd_strict) { + xml->fully_qualified = 1; +#define CHECK_COMPLIANCE(opt, opt_name) \ + if (opt) { \ + av_log(wctx, AV_LOG_ERROR, \ + "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \ + "You need to disable such option with '-no%s'\n", opt_name, opt_name); \ + return AVERROR(EINVAL); \ + } + ////CHECK_COMPLIANCE(show_private_data, "private"); + CHECK_COMPLIANCE(wctx->show_value_unit, "unit"); + CHECK_COMPLIANCE(wctx->use_value_prefix, "prefix"); + } + + return 0; +} + +#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ') + +static void xml_print_section_header(AVTextFormatContext *wctx, const void *data) +{ + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); + + if (!section) + return; + + if (wctx->level == 0) { + const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" " + "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\""; + + writer_put_str(wctx, "\n"); + writer_printf(wctx, "<%sffprobe%s>\n", + xml->fully_qualified ? "ffprobe:" : "", + xml->fully_qualified ? qual : ""); + return; + } + + if (xml->within_tag) { + xml->within_tag = 0; + writer_put_str(wctx, ">\n"); + } + + if (parent_section && (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) && + wctx->level && wctx->nb_item[wctx->level - 1]) + writer_w8(wctx, '\n'); + xml->indent_level++; + + if (section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY | AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS)) { + XML_INDENT(); + writer_printf(wctx, "<%s", section->name); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) { + AVBPrint buf; + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_escape(&buf, section->get_type(data), NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, " type=\"%s\"", buf.str); + } + writer_printf(wctx, ">\n", section->name); + } else { + XML_INDENT(); + writer_printf(wctx, "<%s ", section->name); + xml->within_tag = 1; + } +} + +static void xml_print_section_footer(AVTextFormatContext *wctx) +{ + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + if (wctx->level == 0) { + writer_printf(wctx, "\n", xml->fully_qualified ? "ffprobe:" : ""); + } else if (xml->within_tag) { + xml->within_tag = 0; + writer_put_str(wctx, "/>\n"); + xml->indent_level--; + } else { + XML_INDENT(); + writer_printf(wctx, "\n", section->name); + xml->indent_level--; + } +} + +static void xml_print_value(AVTextFormatContext *wctx, const char *key, + const char *str, int64_t num, const int is_int) +{ + AVBPrint buf; + XMLContext *xml = wctx->priv; + const AVTextFormatSection *section = tf_get_section(wctx, wctx->level); + + if (!section) + return; + + av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); + + if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS) { + xml->indent_level++; + XML_INDENT(); + av_bprint_escape(&buf, key, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, "<%s key=\"%s\"", + section->element_name, buf.str); + av_bprint_clear(&buf); + + if (is_int) { + writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num); + } else { + av_bprint_escape(&buf, str, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, " value=\"%s\"/>\n", buf.str); + } + xml->indent_level--; + } else { + if (wctx->nb_item[wctx->level]) + writer_w8(wctx, ' '); + + if (is_int) { + writer_printf(wctx, "%s=\"%"PRId64"\"", key, num); + } else { + av_bprint_escape(&buf, str, NULL, + AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES); + writer_printf(wctx, "%s=\"%s\"", key, buf.str); + } + } + + av_bprint_finalize(&buf, NULL); +} + +static inline void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value) +{ + xml_print_value(wctx, key, value, 0, 0); +} + +static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) +{ + xml_print_value(wctx, key, NULL, value, 1); +} + +const AVTextFormatter avtextformatter_xml = { + .name = "xml", + .priv_size = sizeof(XMLContext), + .init = xml_init, + .print_section_header = xml_print_section_header, + .print_section_footer = xml_print_section_footer, + .print_integer = xml_print_int, + .print_string = xml_print_str, + .flags = AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT, + .priv_class = &xml_class, +}; diff --git a/fftools/textformat/tw_avio.c b/fftools/textformat/tw_avio.c new file mode 100644 index 0000000000..21d3af27df --- /dev/null +++ b/fftools/textformat/tw_avio.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextwriters.h" +#include "libavutil/avassert.h" + +#include "libavutil/error.h" + +/* AVIO Writer */ + +# define WRITER_NAME "aviowriter" + +typedef struct IOWriterContext { + const AVClass *class; + AVIOContext *avio_context; + int close_on_uninit; +} IOWriterContext; + +static av_cold int iowriter_uninit(AVTextWriterContext *wctx) +{ + IOWriterContext *ctx = wctx->priv; + int ret = 0; + + if (ctx->close_on_uninit) + ret = avio_closep(&ctx->avio_context); + return ret; +} + +static void io_w8(AVTextWriterContext *wctx, int b) +{ + IOWriterContext *ctx = wctx->priv; + avio_w8(ctx->avio_context, b); +} + +static void io_put_str(AVTextWriterContext *wctx, const char *str) +{ + IOWriterContext *ctx = wctx->priv; + avio_write(ctx->avio_context, (const unsigned char *)str, (int)strlen(str)); +} + +static void io_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + IOWriterContext *ctx = wctx->priv; + + avio_vprintf(ctx->avio_context, fmt, vl); +} + + +const AVTextWriter avtextwriter_avio = { + .name = WRITER_NAME, + .priv_size = sizeof(IOWriterContext), + .uninit = iowriter_uninit, + .writer_put_str = io_put_str, + .writer_vprintf = io_vprintf, + .writer_w8 = io_w8 +}; + +int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename) +{ + IOWriterContext *ctx; + int ret; + + if (!output_filename || !output_filename[0]) { + av_log(NULL, AV_LOG_ERROR, "The output_filename cannot be NULL or empty\n"); + return AVERROR(EINVAL); + } + + ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + + if ((ret = avio_open(&ctx->avio_context, output_filename, AVIO_FLAG_WRITE)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Failed to open output '%s' with error: %s\n", output_filename, av_err2str(ret)); + avtextwriter_context_close(pwctx); + return ret; + } + + ctx->close_on_uninit = 1; + + return ret; +} + + +int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit) +{ + IOWriterContext *ctx; + int ret; + + av_assert0(avio_ctx); + + ret = avtextwriter_context_open(pwctx, &avtextwriter_avio); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + ctx->avio_context = avio_ctx; + ctx->close_on_uninit = close_on_uninit; + + return ret; +} diff --git a/fftools/textformat/tw_buffer.c b/fftools/textformat/tw_buffer.c new file mode 100644 index 0000000000..f6e63445d9 --- /dev/null +++ b/fftools/textformat/tw_buffer.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextwriters.h" +#include "libavutil/opt.h" +#include "libavutil/bprint.h" + +/* Buffer Writer */ + +# define WRITER_NAME "bufferwriter" + +typedef struct BufferWriterContext { + const AVClass *class; + AVBPrint *buffer; +} BufferWriterContext; + +static const char *bufferwriter_get_name(void *ctx) +{ + return WRITER_NAME; +} + +static const AVClass bufferwriter_class = { + .class_name = WRITER_NAME, + .item_name = bufferwriter_get_name, +}; + +static void buffer_w8(AVTextWriterContext *wctx, int b) +{ + BufferWriterContext *ctx = wctx->priv; + av_bprintf(ctx->buffer, "%c", b); +} + +static void buffer_put_str(AVTextWriterContext *wctx, const char *str) +{ + BufferWriterContext *ctx = wctx->priv; + av_bprintf(ctx->buffer, "%s", str); +} + +static void buffer_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + BufferWriterContext *ctx = wctx->priv; + + av_vbprintf(ctx->buffer, fmt, vl); +} + + +const AVTextWriter avtextwriter_buffer = { + .name = WRITER_NAME, + .priv_size = sizeof(BufferWriterContext), + .priv_class = &bufferwriter_class, + .writer_put_str = buffer_put_str, + .writer_vprintf = buffer_vprintf, + .writer_w8 = buffer_w8 +}; + +int avtextwriter_create_buffer(AVTextWriterContext **pwctx, AVBPrint *buffer) +{ + BufferWriterContext *ctx; + int ret; + + ret = avtextwriter_context_open(pwctx, &avtextwriter_buffer); + if (ret < 0) + return ret; + + ctx = (*pwctx)->priv; + ctx->buffer = buffer; + + return ret; +} diff --git a/fftools/textformat/tw_stdout.c b/fftools/textformat/tw_stdout.c new file mode 100644 index 0000000000..3e2a8dd0d4 --- /dev/null +++ b/fftools/textformat/tw_stdout.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) The FFmpeg developers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "avtextwriters.h" +#include "libavutil/opt.h" + +/* STDOUT Writer */ + +# define WRITER_NAME "stdoutwriter" + +typedef struct StdOutWriterContext { + const AVClass *class; +} StdOutWriterContext; + +static const char *stdoutwriter_get_name(void *ctx) +{ + return WRITER_NAME; +} + +static const AVClass stdoutwriter_class = { + .class_name = WRITER_NAME, + .item_name = stdoutwriter_get_name, +}; + +static inline void stdout_w8(AVTextWriterContext *wctx, int b) +{ + printf("%c", b); +} + +static inline void stdout_put_str(AVTextWriterContext *wctx, const char *str) +{ + printf("%s", str); +} + +static inline void stdout_vprintf(AVTextWriterContext *wctx, const char *fmt, va_list vl) +{ + vprintf(fmt, vl); +} + + +static const AVTextWriter avtextwriter_stdout = { + .name = WRITER_NAME, + .priv_size = sizeof(StdOutWriterContext), + .priv_class = &stdoutwriter_class, + .writer_put_str = stdout_put_str, + .writer_vprintf = stdout_vprintf, + .writer_w8 = stdout_w8 +}; + +int avtextwriter_create_stdout(AVTextWriterContext **pwctx) +{ + int ret; + + ret = avtextwriter_context_open(pwctx, &avtextwriter_stdout); + + return ret; +} diff --git a/fftools/thread_queue.c b/fftools/thread_queue.c index fd73cc0a9b..b035ffe11d 100644 --- a/fftools/thread_queue.c +++ b/fftools/thread_queue.c @@ -20,13 +20,16 @@ #include #include "libavutil/avassert.h" +#include "libavutil/container_fifo.h" #include "libavutil/error.h" #include "libavutil/fifo.h" +#include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/thread.h" -#include "objpool.h" +#include "libavcodec/packet.h" + #include "thread_queue.h" enum { @@ -34,19 +37,14 @@ enum { FINISHED_RECV = (1 << 1), }; -typedef struct FifoElem { - void *obj; - unsigned int stream_idx; -} FifoElem; - struct ThreadQueue { int *finished; unsigned int nb_streams; - AVFifo *fifo; + enum ThreadQueueType type; - ObjPool *obj_pool; - void (*obj_move)(void *dst, void *src); + AVContainerFifo *fifo; + AVFifo *fifo_stream_index; pthread_mutex_t lock; pthread_cond_t cond; @@ -59,14 +57,8 @@ void tq_free(ThreadQueue **ptq) if (!tq) return; - if (tq->fifo) { - FifoElem elem; - while (av_fifo_read(tq->fifo, &elem, 1) >= 0) - objpool_release(tq->obj_pool, &elem.obj); - } - av_fifo_freep2(&tq->fifo); - - objpool_free(&tq->obj_pool); + av_container_fifo_free(&tq->fifo); + av_fifo_freep2(&tq->fifo_stream_index); av_freep(&tq->finished); @@ -77,7 +69,7 @@ void tq_free(ThreadQueue **ptq) } ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, - ObjPool *obj_pool, void (*obj_move)(void *dst, void *src)) + enum ThreadQueueType type) { ThreadQueue *tq; int ret; @@ -104,12 +96,16 @@ ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, goto fail; tq->nb_streams = nb_streams; - tq->fifo = av_fifo_alloc2(queue_size, sizeof(FifoElem), 0); + tq->type = type; + + tq->fifo = (type == THREAD_QUEUE_FRAMES) ? + av_container_fifo_alloc_avframe(0) : av_container_fifo_alloc_avpacket(0); if (!tq->fifo) goto fail; - tq->obj_pool = obj_pool; - tq->obj_move = obj_move; + tq->fifo_stream_index = av_fifo_alloc2(queue_size, sizeof(unsigned), 0); + if (!tq->fifo_stream_index) + goto fail; return tq; fail: @@ -132,23 +128,21 @@ int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data) goto finish; } - while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo)) + while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo_stream_index)) pthread_cond_wait(&tq->cond, &tq->lock); if (*finished & FINISHED_RECV) { ret = AVERROR_EOF; *finished |= FINISHED_SEND; } else { - FifoElem elem = { .stream_idx = stream_idx }; - - ret = objpool_get(tq->obj_pool, &elem.obj); + ret = av_fifo_write(tq->fifo_stream_index, &stream_idx, 1); if (ret < 0) goto finish; - tq->obj_move(elem.obj, data); + ret = av_container_fifo_write(tq->fifo, data, 0); + if (ret < 0) + goto finish; - ret = av_fifo_write(tq->fifo, &elem, 1); - av_assert0(ret >= 0); pthread_cond_broadcast(&tq->cond); } @@ -161,18 +155,21 @@ finish: static int receive_locked(ThreadQueue *tq, int *stream_idx, void *data) { - FifoElem elem; unsigned int nb_finished = 0; - while (av_fifo_read(tq->fifo, &elem, 1) >= 0) { - if (tq->finished[elem.stream_idx] & FINISHED_RECV) { - objpool_release(tq->obj_pool, &elem.obj); + while (av_container_fifo_read(tq->fifo, data, 0) >= 0) { + unsigned idx; + int ret; + + ret = av_fifo_read(tq->fifo_stream_index, &idx, 1); + av_assert0(ret >= 0); + if (tq->finished[idx] & FINISHED_RECV) { + (tq->type == THREAD_QUEUE_FRAMES) ? + av_frame_unref(data) : av_packet_unref(data); continue; } - tq->obj_move(data, elem.obj); - objpool_release(tq->obj_pool, &elem.obj); - *stream_idx = elem.stream_idx; + *stream_idx = idx; return 0; } @@ -202,12 +199,12 @@ int tq_receive(ThreadQueue *tq, int *stream_idx, void *data) pthread_mutex_lock(&tq->lock); while (1) { - size_t can_read = av_fifo_can_read(tq->fifo); + size_t can_read = av_container_fifo_can_read(tq->fifo); ret = receive_locked(tq, stream_idx, data); // signal other threads if the fifo state changed - if (can_read != av_fifo_can_read(tq->fifo)) + if (can_read != av_container_fifo_can_read(tq->fifo)) pthread_cond_broadcast(&tq->cond); if (ret == AVERROR(EAGAIN)) { diff --git a/fftools/thread_queue.h b/fftools/thread_queue.h index 0cc8c71ebd..cc01c8a2c9 100644 --- a/fftools/thread_queue.h +++ b/fftools/thread_queue.h @@ -21,7 +21,10 @@ #include -#include "objpool.h" +enum ThreadQueueType { + THREAD_QUEUE_FRAMES, + THREAD_QUEUE_PACKETS, +}; typedef struct ThreadQueue ThreadQueue; @@ -32,12 +35,9 @@ typedef struct ThreadQueue ThreadQueue; * maintained * @param queue_size number of items that can be stored in the queue without * blocking - * @param obj_pool object pool that will be used to allocate items stored in the - * queue; the pool becomes owned by the queue - * @param callback that moves the contents between two data pointers */ ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size, - ObjPool *obj_pool, void (*obj_move)(void *dst, void *src)); + enum ThreadQueueType type); void tq_free(ThreadQueue **tq); /** diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index fd3a45f093..c6b2ce1230 100644 --- a/libavcodec/4xm.c +++ b/libavcodec/4xm.c @@ -337,7 +337,8 @@ static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w, } break; default: - av_assert0(0); + av_unreachable("log2w starts at 3 and gets only decremented during " + "recursive calls to decode_p_block"); } } @@ -927,8 +928,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, frame_size = buf_size - 12; } - if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) - return ret; + if ( frame_4cc == AV_RL32("ifr2") || frame_4cc == AV_RL32("ifrm") + || frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) { + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + } if (frame_4cc == AV_RL32("ifr2")) { picture->pict_type = AV_PICTURE_TYPE_I; diff --git a/libavcodec/8bps.c b/libavcodec/8bps.c index 0060c46d09..7a01633c9a 100644 --- a/libavcodec/8bps.c +++ b/libavcodec/8bps.c @@ -114,14 +114,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } if (avctx->bits_per_coded_sample <= 8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(c->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index 43567df3d7..18203ee69e 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -198,8 +198,7 @@ const FFCodec ff_eightsvx_fib_decoder = { FF_CODEC_DECODE_CB(eightsvx_decode_frame), .close = eightsvx_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P), }; #endif #if CONFIG_EIGHTSVX_EXP_DECODER @@ -213,7 +212,6 @@ const FFCodec ff_eightsvx_exp_decoder = { FF_CODEC_DECODE_CB(eightsvx_decode_frame), .close = eightsvx_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P), }; #endif diff --git a/libavcodec/Makefile b/libavcodec/Makefile index a4fcce3b42..fb22541f8d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -5,7 +5,6 @@ HEADERS = ac3_parser.h \ adts_parser.h \ avcodec.h \ avdct.h \ - avfft.h \ bsf.h \ codec.h \ codec_desc.h \ @@ -20,6 +19,7 @@ HEADERS = ac3_parser.h \ mediacodec.h \ packet.h \ qsv.h \ + smpte_436m.h \ vdpau.h \ version.h \ version_major.h \ @@ -31,7 +31,6 @@ OBJS = ac3_parser.o \ allcodecs.o \ avcodec.o \ avdct.o \ - avfft.o \ packet.o \ bitstream.o \ bitstream_filters.o \ @@ -56,7 +55,6 @@ OBJS = ac3_parser.o \ profiles.o \ qsv_api.o \ raw.o \ - refstruct.o \ threadprogress.o \ utils.o \ version.o \ @@ -64,16 +62,21 @@ OBJS = ac3_parser.o \ vorbis_parser.o \ xiph.o \ +SHLIBOBJS = float_scalarproduct.o \ + timecode_internal.o \ + # subsystems include $(SRC_PATH)/libavcodec/aac/Makefile include $(SRC_PATH)/libavcodec/hevc/Makefile include $(SRC_PATH)/libavcodec/opus/Makefile include $(SRC_PATH)/libavcodec/vvc/Makefile +include $(SRC_PATH)/libavcodec/vulkan/Makefile +-include $(SRC_PATH)/libavcodec/$(ARCH)/hevc/Makefile -include $(SRC_PATH)/libavcodec/$(ARCH)/vvc/Makefile OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio_sample_rates.o -OBJS-$(CONFIG_AMF) += amfenc.o +OBJS-$(CONFIG_AMF) += amfenc.o amfdec.o OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o OBJS-$(CONFIG_ATSC_A53) += atsc_a53.o OBJS-$(CONFIG_AUDIODSP) += audiodsp.o @@ -81,6 +84,7 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o OBJS-$(CONFIG_CABAC) += cabac.o OBJS-$(CONFIG_CBS) += cbs.o cbs_bsf.o +OBJS-$(CONFIG_CBS_APV) += cbs_apv.o OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o cbs_sei.o h2645_parse.o OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o cbs_sei.o h2645_parse.o @@ -89,6 +93,7 @@ OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o +OBJS-$(CONFIG_CELP_MATH) += celp_math.o OBJS-$(CONFIG_D3D12VA_ENCODE) += d3d12va_encode.o hw_base_encode.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o dovi_rpudec.o @@ -108,7 +113,7 @@ OBJS-$(CONFIG_H264PARSE) += h264_parse.o h264_ps.o h264data.o \ h2645data.o h2645_parse.o h2645_vui.o OBJS-$(CONFIG_H264PRED) += h264pred.o OBJS-$(CONFIG_H264QPEL) += h264qpel.o -OBJS-$(CONFIG_H264_SEI) += h264_sei.o h2645_sei.o +OBJS-$(CONFIG_H264_SEI) += h264_sei.o h2645_sei.o aom_film_grain.o OBJS-$(CONFIG_HEVCPARSE) += h2645data.o h2645_parse.o h2645_vui.o OBJS-$(CONFIG_HEVC_SEI) += h2645_sei.o aom_film_grain.o \ dynamic_hdr_vivid.o @@ -117,7 +122,6 @@ OBJS-$(CONFIG_HUFFMAN) += huffman.o OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o OBJS-$(CONFIG_HUFFYUVENCDSP) += huffyuvencdsp.o OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o -OBJS-$(CONFIG_IIRFILTER) += iirfilter.o OBJS-$(CONFIG_INFLATE_WRAPPER) += zlib_wrapper.o OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4_vc1_data.o OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o @@ -144,12 +148,13 @@ OBJS-$(CONFIG_MPEGAUDIOHEADER) += mpegaudiodecheader.o mpegaudiotabs.o OBJS-$(CONFIG_MPEG4AUDIO) += mpeg4audio.o mpeg4audio_sample_rates.o OBJS-$(CONFIG_MPEGVIDEO) += mpegvideo.o rl.o \ mpegvideo_motion.o \ + mpegvideo_unquantize.o \ mpegvideodata.o mpegpicture.o \ to_upper4.o OBJS-$(CONFIG_MPEGVIDEODEC) += mpegvideo_dec.o mpegutils.o OBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideo_enc.o mpeg12data.o \ - motion_est.o ratecontrol.o \ - mpegvideoencdsp.o + motion_est.o ratecontrol.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mpegvideoencdsp.o OBJS-$(CONFIG_MSMPEG4DEC) += msmpeg4dec.o msmpeg4.o msmpeg4data.o \ msmpeg4_vc1_data.o OBJS-$(CONFIG_MSMPEG4ENC) += msmpeg4enc.o msmpeg4.o msmpeg4data.o \ @@ -163,6 +168,7 @@ OBJS-$(CONFIG_QSVENC) += qsvenc.o OBJS-$(CONFIG_RANGECODER) += rangecoder.o OBJS-$(CONFIG_RV34DSP) += rv34dsp.o OBJS-$(CONFIG_SINEWIN) += sinewin.o +OBJS-$(CONFIG_SMPTE_436M) += smpte_436m.o OBJS-$(CONFIG_SNAPPY) += snappy.o OBJS-$(CONFIG_STARTCODE) += startcode.o OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o @@ -170,6 +176,7 @@ OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o OBJS-$(CONFIG_TPELDSP) += tpeldsp.o OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o hw_base_encode.o OBJS-$(CONFIG_AV1_AMF_ENCODER) += amfenc_av1.o +OBJS-$(CONFIG_AV1_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_VC1DSP) += vc1dsp.o OBJS-$(CONFIG_VIDEODSP) += videodsp.o OBJS-$(CONFIG_VP3DSP) += vp3dsp.o @@ -195,8 +202,6 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \ aacpsy.o aactab.o \ aacenc_is.o \ aacenc_tns.o \ - aacenc_ltp.o \ - aacenc_pred.o \ psymodel.o kbdwin.o \ mpeg4audio_sample_rates.o OBJS-$(CONFIG_AAC_MEDIACODEC_DECODER) += mediacodecdec.o @@ -210,7 +215,7 @@ OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \ ac3.o kbdwin.o OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o kbdwin.o OBJS-$(CONFIG_AC3_MF_ENCODER) += mfenc.o mf_utils.o -OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o +OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o OBJS-$(CONFIG_AGM_DECODER) += agm.o jpegquanttables.o OBJS-$(CONFIG_AIC_DECODER) += aic.o OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o @@ -219,11 +224,11 @@ OBJS-$(CONFIG_ALIAS_PIX_DECODER) += aliaspixdec.o OBJS-$(CONFIG_ALIAS_PIX_ENCODER) += aliaspixenc.o OBJS-$(CONFIG_ALS_DECODER) += alsdec.o bgmc.o mlz.o OBJS-$(CONFIG_AMRNB_DECODER) += amrnbdec.o celp_filters.o \ - celp_math.o acelp_filters.o \ + acelp_filters.o \ acelp_vectors.o \ acelp_pitch_delay.o OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \ - celp_math.o acelp_filters.o \ + acelp_filters.o \ acelp_vectors.o \ acelp_pitch_delay.o OBJS-$(CONFIG_AMRNB_MEDIACODEC_DECODER) += mediacodecdec.o @@ -241,6 +246,7 @@ OBJS-$(CONFIG_APTX_HD_DECODER) += aptxdec.o aptx.o OBJS-$(CONFIG_APTX_HD_ENCODER) += aptxenc.o aptx.o OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o +OBJS-$(CONFIG_APV_DECODER) += apv_decode.o apv_entropy.o apv_dsp.o OBJS-$(CONFIG_ARBC_DECODER) += arbc.o OBJS-$(CONFIG_ARGO_DECODER) += argo.o OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o @@ -268,6 +274,8 @@ OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o OBJS-$(CONFIG_AV1_VAAPI_ENCODER) += vaapi_encode_av1.o av1_levels.o +OBJS-$(CONFIG_AV1_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_av1.o \ + hw_base_encode.o av1_levels.o OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o @@ -347,7 +355,7 @@ OBJS-$(CONFIG_DVVIDEO_ENCODER) += dvenc.o dv.o dvdata.o OBJS-$(CONFIG_DXA_DECODER) += dxa.o OBJS-$(CONFIG_DXTORY_DECODER) += dxtory.o OBJS-$(CONFIG_DXV_DECODER) += dxv.o -OBJS-$(CONFIG_DXV_ENCODER) += dxvenc.o +OBJS-$(CONFIG_DXV_ENCODER) += dxvenc.o hashtable.o OBJS-$(CONFIG_EAC3_DECODER) += eac3_data.o OBJS-$(CONFIG_EAC3_ENCODER) += eac3enc.o eac3_data.o OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o @@ -363,11 +371,12 @@ OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER) += 8svx.o OBJS-$(CONFIG_ESCAPE124_DECODER) += escape124.o OBJS-$(CONFIG_ESCAPE130_DECODER) += escape130.o OBJS-$(CONFIG_EVRC_DECODER) += evrcdec.o acelp_vectors.o lsp.o -OBJS-$(CONFIG_EXR_DECODER) += exr.o exrdsp.o half2float.o -OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o float2half.o +OBJS-$(CONFIG_EXR_DECODER) += exr.o exrdsp.o +OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o OBJS-$(CONFIG_FASTAUDIO_DECODER) += fastaudio.o -OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o -OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o +OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1_parse.o ffv1.o +OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1_parse.o ffv1.o +OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += ffv1enc.o ffv1.o ffv1_vulkan.o ffv1enc_vulkan.o OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o OBJS-$(CONFIG_FIC_DECODER) += fic.o OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o @@ -388,10 +397,11 @@ OBJS-$(CONFIG_FRWU_DECODER) += frwu.o OBJS-$(CONFIG_FTR_DECODER) += ftr.o OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o mjpegdec_common.o OBJS-$(CONFIG_G723_1_DECODER) += g723_1dec.o g723_1.o \ - acelp_vectors.o celp_filters.o celp_math.o + acelp_vectors.o celp_filters.o OBJS-$(CONFIG_G723_1_ENCODER) += g723_1enc.o g723_1.o \ - acelp_vectors.o celp_filters.o celp_math.o -OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o + acelp_vectors.o celp_filters.o +OBJS-$(CONFIG_G728_DECODER) += g728dec.o celp_filters.o +OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o OBJS-$(CONFIG_GDV_DECODER) += gdv.o OBJS-$(CONFIG_GEM_DECODER) += gemdec.o OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o @@ -415,12 +425,15 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_refs.o \ h264_slice.o h264data.o h274.o OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o +OBJS-$(CONFIG_H264_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o +OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o +OBJS-$(CONFIG_H264_OH_ENCODER) += ohcodec.o ohenc.o OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o @@ -439,15 +452,18 @@ OBJS-$(CONFIG_HCA_DECODER) += hcadec.o OBJS-$(CONFIG_HCOM_DECODER) += hcom.o OBJS-$(CONFIG_HDR_DECODER) += hdrdec.o OBJS-$(CONFIG_HDR_ENCODER) += hdrenc.o -OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o container_fifo.o +OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o +OBJS-$(CONFIG_HEVC_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_HEVC_D3D12VA_ENCODER) += d3d12va_encode_hevc.o h265_profile_level.o \ - h2645data.o + h2645data.o hw_base_encode_h265.o OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o +OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o +OBJS-$(CONFIG_HEVC_OH_ENCODER) += ohcodec.o ohenc.o OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o @@ -460,8 +476,8 @@ OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_HEVC_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o -OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadsp.o canopus.o -OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o +OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadsp.o hq_common.o canopus.o +OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxdsp.o hq_common.o canopus.o OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o OBJS-$(CONFIG_HYMT_DECODER) += huffyuv.o huffyuvdec.o @@ -524,10 +540,10 @@ OBJS-$(CONFIG_MOVTEXT_ENCODER) += movtextenc.o ass_split.o OBJS-$(CONFIG_MP1_DECODER) += mpegaudiodec_fixed.o OBJS-$(CONFIG_MP1FLOAT_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_MP2_DECODER) += mpegaudiodec_fixed.o -OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc_float.o mpegaudio.o \ +OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc.o mpegaudio.o \ mpegaudiodata.o mpegaudiodsp_data.o \ mpegaudiotabs.o -OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \ +OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc.o mpegaudio.o \ mpegaudiodata.o mpegaudiodsp_data.o \ mpegaudiotabs.o OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o @@ -607,8 +623,8 @@ OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o OBJS-$(CONFIG_PGX_DECODER) += pgxdec.o -OBJS-$(CONFIG_PHM_DECODER) += pnmdec.o pnm.o half2float.o -OBJS-$(CONFIG_PHM_ENCODER) += pnmenc.o float2half.o +OBJS-$(CONFIG_PHM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PHM_ENCODER) += pnmenc.o OBJS-$(CONFIG_PHOTOCD_DECODER) += photocd.o OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o OBJS-$(CONFIG_PIXLET_DECODER) += pixlet.o @@ -621,6 +637,7 @@ OBJS-$(CONFIG_PRORES_DECODER) += proresdec.o proresdsp.o proresdata.o OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o proresdata.o OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o proresdata.o OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o +OBJS-$(CONFIG_PRORES_RAW_DECODER) += prores_raw.o proresdsp.o proresdata.o OBJS-$(CONFIG_PRORES_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_PROSUMER_DECODER) += prosumer.o OBJS-$(CONFIG_PSD_DECODER) += psd.o @@ -665,6 +682,7 @@ OBJS-$(CONFIG_RV20_DECODER) += rv10.o OBJS-$(CONFIG_RV20_ENCODER) += rv20enc.o OBJS-$(CONFIG_RV30_DECODER) += rv30.o rv34.o rv30dsp.o OBJS-$(CONFIG_RV40_DECODER) += rv40.o rv34.o rv40dsp.o +OBJS-$(CONFIG_RV60_DECODER) += rv60dec.o rv60dsp.o OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o htmlsubtitles.o OBJS-$(CONFIG_S302M_DECODER) += s302m.o OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o @@ -679,7 +697,7 @@ OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o OBJS-$(CONFIG_SHEERVIDEO_DECODER) += sheervideo.o OBJS-$(CONFIG_SHORTEN_DECODER) += shorten.o OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \ - celp_math.o acelp_vectors.o \ + acelp_vectors.o \ acelp_filters.o celp_filters.o \ sipr16k.o OBJS-$(CONFIG_SIREN_DECODER) += siren.o @@ -690,7 +708,8 @@ OBJS-$(CONFIG_SMC_DECODER) += smc.o OBJS-$(CONFIG_SMC_ENCODER) += smcenc.o OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \ - h263.o h263data.o ituh263enc.o + h263data.o ituh263enc.o \ + motion_est.o ratecontrol.o OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_SONIC_DECODER) += sonic.o OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o @@ -710,12 +729,11 @@ OBJS-$(CONFIG_SUBVIEWER1_DECODER) += textdec.o ass.o OBJS-$(CONFIG_SUBVIEWER_DECODER) += subviewerdec.o ass.o OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o -OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o -OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbcdec_data.o sbc.o -OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o sbcdsp_data.o +OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbc.o +OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o h263data.o OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o h263data.o \ - h263.o ituh263enc.o + h263.o ituh263enc.o motion_est.o OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o mpegutils.o h264data.o OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o OBJS-$(CONFIG_TEXT_ENCODER) += srtenc.o ass_split.o @@ -793,6 +811,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 vpx_rac.o \ vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o +OBJS-$(CONFIG_VP9_AMF_DECODER) += amfdec.o OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP9_MEDIACODEC_ENCODER) += mediacodecenc.o @@ -803,6 +822,8 @@ OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o OBJS-$(CONFIG_VP9_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_VQC_DECODER) += vqcdec.o +OBJS-$(CONFIG_VVC_DECODER) += executor.o h2645data.o +OBJS-$(CONFIG_VVC_SEI) += h2645_sei.o aom_film_grain.o h274.o OBJS-$(CONFIG_WADY_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_WAVARC_DECODER) += wavarc.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o wavpackdata.o dsd.o @@ -974,10 +995,12 @@ OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WS_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_XBOX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MTAF_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SANYO_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_4_DECODER) += adpcm.o adpcm_data.o @@ -1008,7 +1031,9 @@ OBJS-$(CONFIG_AV1_D3D12VA_HWACCEL) += dxva2_av1.o d3d12va_av1.o OBJS-$(CONFIG_AV1_NVDEC_HWACCEL) += nvdec_av1.o OBJS-$(CONFIG_AV1_VAAPI_HWACCEL) += vaapi_av1.o OBJS-$(CONFIG_AV1_VDPAU_HWACCEL) += vdpau_av1.o +OBJS-$(CONFIG_AV1_VIDEOTOOLBOX_HWACCEL) += videotoolbox_av1.o OBJS-$(CONFIG_AV1_VULKAN_HWACCEL) += vulkan_decode.o vulkan_av1.o +OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan_decode.o ffv1_vulkan.o vulkan_ffv1.o OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o @@ -1061,11 +1086,19 @@ OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o OBJS-$(CONFIG_VP9_VDPAU_HWACCEL) += vdpau_vp9.o OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) += videotoolbox_vp9.o +OBJS-$(CONFIG_VP9_VULKAN_HWACCEL) += vulkan_decode.o vulkan_vp9.o OBJS-$(CONFIG_VP8_QSV_HWACCEL) += qsvdec.o +OBJS-$(CONFIG_VVC_VAAPI_HWACCEL) += vaapi_vvc.o +OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan_decode.o vulkan_prores_raw.o # Objects duplicated from other libraries for shared builds SHLIBOBJS += log2_tab.o reverse.o +SHLIBOBJS-$(CONFIG_EXR_DECODER) += half2float.o float2half.o +SHLIBOBJS-$(CONFIG_EXR_ENCODER) += float2half.o +SHLIBOBJS-$(CONFIG_PHM_DECODER) += half2float.o +SHLIBOBJS-$(CONFIG_PHM_ENCODER) += float2half.o + # General libavformat dependencies OBJS-$(CONFIG_FITS_DEMUXER) += fits.o OBJS-$(CONFIG_TAK_DEMUXER) += tak.o @@ -1076,7 +1109,6 @@ STLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o STLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o STLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o STLIBOBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER) += jpegxl_parse.o -STLIBOBJS-$(CONFIG_JNI) += ffjni.o STLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o STLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o STLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o @@ -1135,6 +1167,7 @@ OBJS-$(CONFIG_LIBKVAZAAR_ENCODER) += libkvazaar.o OBJS-$(CONFIG_LIBLC3_ENCODER) += liblc3enc.o OBJS-$(CONFIG_LIBLC3_DECODER) += liblc3dec.o OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o +OBJS-$(CONFIG_LIBOAPV_ENCODER) += liboapvenc.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o @@ -1146,6 +1179,7 @@ OBJS-$(CONFIG_LIBOPUS_DECODER) += libopusdec.o libopus.o \ OBJS-$(CONFIG_LIBOPUS_ENCODER) += libopusenc.o libopus.o \ vorbis_data.o OBJS-$(CONFIG_LIBRAV1E_ENCODER) += librav1e.o +OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o @@ -1181,6 +1215,7 @@ OBJS-$(CONFIG_AC3_PARSER) += aac_ac3_parser.o ac3tab.o \ ac3_channel_layout_tab.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o OBJS-$(CONFIG_AMR_PARSER) += amr_parser.o +OBJS-$(CONFIG_APV_PARSER) += apv_parser.o OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o OBJS-$(CONFIG_AVS2_PARSER) += avs2.o avs2_parser.o OBJS-$(CONFIG_AVS3_PARSER) += avs3_parser.o @@ -1192,6 +1227,7 @@ OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o dca_exss.o dca.o \ dca_sample_rate_tab.o OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o OBJS-$(CONFIG_DNXHD_PARSER) += dnxhd_parser.o dnxhddata.o +OBJS-$(CONFIG_DNXUC_PARSER) += dnxuc_parser.o OBJS-$(CONFIG_DOLBY_E_PARSER) += dolby_e_parser.o dolby_e_parse.o OBJS-$(CONFIG_DPX_PARSER) += dpx_parser.o OBJS-$(CONFIG_DVAUDIO_PARSER) += dvaudio_parser.o @@ -1199,6 +1235,7 @@ OBJS-$(CONFIG_DVBSUB_PARSER) += dvbsub_parser.o OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o OBJS-$(CONFIG_EVC_PARSER) += evc_parser.o +OBJS-$(CONFIG_FFV1_PARSER) += ffv1_parser.o ffv1_parse.o ffv1.o OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o OBJS-$(CONFIG_FTR_PARSER) += ftr_parser.o OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o @@ -1224,6 +1261,7 @@ OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ OBJS-$(CONFIG_OPUS_PARSER) += vorbis_data.o OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o +OBJS-$(CONFIG_PRORES_RAW_PARSER) += prores_raw_parser.o OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o OBJS-$(CONFIG_RV34_PARSER) += rv34_parser.o OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o @@ -1256,6 +1294,10 @@ OBJS-$(HAVE_THREADS) += pthread.o pthread_slice.o pthread_fram OBJS-$(CONFIG_FRAME_THREAD_ENCODER) += frame_thread_encoder.o +# vulkan libs +OBJS-$(CONFIG_LIBGLSLANG) += vulkan_glslang.o +OBJS-$(CONFIG_LIBSHADERC) += vulkan_shaderc.o + # Windows resource file SHLIBOBJS-$(HAVE_GNU_WINDRES) += avcodecres.o @@ -1270,7 +1312,7 @@ SKIPHEADERS += %_tablegen.h \ bitstream_template.h \ $(ARCH)/vpx_arith.h \ -SKIPHEADERS-$(CONFIG_AMF) += amfenc.h +SKIPHEADERS-$(CONFIG_AMF) += amfenc.h amfdec.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h d3d12va_encode.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h @@ -1284,12 +1326,14 @@ SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surf SKIPHEADERS-$(CONFIG_MEDIAFOUNDATION) += mf_utils.h SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h +SKIPHEADERS-$(CONFIG_OHCODEC) += ohcodec.h SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_hevc.h vaapi_encode.h SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h -SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_video.h vulkan_encode.h vulkan_decode.h +SKIPHEADERS-$(CONFIG_VULKAN) += ffv1_vulkan.h vulkan_video.h \ + vulkan_encode.h vulkan_decode.h SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h SKIPHEADERS-$(CONFIG_ZLIB) += zlib_wrapper.h @@ -1297,17 +1341,18 @@ TESTPROGS = avcodec \ avpacket \ bitstream_be \ bitstream_le \ - celp_math \ codec_desc \ htmlsubtitles \ jpeg2000dwt \ mathops \ +TESTPROGS-$(CONFIG_APV_DECODER) += apv TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels TESTPROGS-$(CONFIG_CABAC) += cabac +TESTPROGS-$(CONFIG_CELP_MATH) += celp_math TESTPROGS-$(CONFIG_GOLOMB) += golomb TESTPROGS-$(CONFIG_IDCTDSP) += dct -TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter +TESTPROGS-$(CONFIG_DXV_ENCODER) += hashtable TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman TESTPROGS-$(HAVE_MMX) += motion TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index 38edbe3a77..d81718dff5 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -403,7 +403,7 @@ const FFCodec ff_a64multi_encoder = { .init = a64multi_encode_init, FF_CODEC_ENCODE_CB(a64multi_encode_frame), .close = a64multi_close_encoder, - .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -418,7 +418,7 @@ const FFCodec ff_a64multi5_encoder = { .init = a64multi_encode_init, FF_CODEC_ENCODE_CB(a64multi_encode_frame), .close = a64multi_close_encoder, - .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c index 4110bc40ca..6a2aa9dc8e 100644 --- a/libavcodec/aac/aacdec.c +++ b/libavcodec/aac/aacdec.c @@ -395,8 +395,8 @@ static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags) FFSWAP(struct elem_to_channel, e2c_vec[6], e2c_vec[4]); // FLc & FRc fifth (final), SiL & SiR seventh FFSWAP(struct elem_to_channel, e2c_vec[7], e2c_vec[6]); // LFE2 seventh (final), SiL & SiR eight (final) FFSWAP(struct elem_to_channel, e2c_vec[9], e2c_vec[8]); // TpFL & TpFR ninth (final), TFC tenth (final) - FFSWAP(struct elem_to_channel, e2c_vec[11], e2c_vec[10]); // TC eleventh (final), TpSiL & TpSiR twelth - FFSWAP(struct elem_to_channel, e2c_vec[12], e2c_vec[11]); // TpBL & TpBR twelth (final), TpSiL & TpSiR thirteenth (final) + FFSWAP(struct elem_to_channel, e2c_vec[11], e2c_vec[10]); // TC eleventh (final), TpSiL & TpSiR twelfth + FFSWAP(struct elem_to_channel, e2c_vec[12], e2c_vec[11]); // TpBL & TpBR twelfth (final), TpSiL & TpSiR thirteenth (final) } else { // For everything else, utilize the AV channel position define as a // stable sort. @@ -538,7 +538,9 @@ static av_cold void flush(AVCodecContext *avctx) } } +#if CONFIG_AAC_DECODER ff_aac_usac_reset_state(ac, &ac->oc[1]); +#endif } /** @@ -1107,6 +1109,8 @@ static av_cold int decode_close(AVCodecContext *avctx) AACUsacElemConfig *ec = &usac->elems[j]; av_freep(&ec->ext.pl_data); } + + av_channel_layout_uninit(&ac->oc[i].ch_layout); } for (int type = 0; type < FF_ARRAY_ELEMS(ac->che); type++) { @@ -1724,7 +1728,7 @@ int ff_aac_decode_ics(AACDecContext *ac, SingleChannelElement *sce, } } // 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 + // control, but this is what both reference and real implementations do if (tns->present && er_syntax) { ret = ff_aac_decode_tns(ac, tns, gb, ics); if (ret < 0) @@ -1743,6 +1747,7 @@ int ff_aac_decode_ics(AACDecContext *ac, SingleChannelElement *sce, return 0; fail: + memset(sce->sfo, 0, sizeof(sce->sfo)); tns->present = 0; return ret; } @@ -2194,6 +2199,7 @@ static int aac_decode_er_frame(AVCodecContext *avctx, AVFrame *frame, ac->frame->nb_samples = samples; ac->frame->sample_rate = avctx->sample_rate; + ac->frame->flags |= AV_FRAME_FLAG_KEY; *got_frame_ptr = 1; skip_bits_long(gb, get_bits_left(gb)); @@ -2354,6 +2360,7 @@ static int decode_frame_ga(AVCodecContext *avctx, AACDecContext *ac, if (samples) { ac->frame->nb_samples = samples; ac->frame->sample_rate = avctx->sample_rate; + ac->frame->flags |= AV_FRAME_FLAG_KEY; *got_frame_ptr = 1; } else { av_frame_unref(ac->frame); @@ -2384,7 +2391,8 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, ac->frame = frame; *got_frame_ptr = 0; - if (show_bits(gb, 12) == 0xfff) { + // USAC can't be packed into ADTS due to field size limitations. + if (show_bits(gb, 12) == 0xfff && ac->oc[1].m4ac.object_type != AOT_USAC) { if ((err = parse_adts_frame_header(ac, gb)) < 0) { av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); goto fail; @@ -2540,12 +2548,10 @@ const FFCodec ff_aac_decoder = { .init = ff_aac_decode_init_float, .close = decode_close, FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .flush = flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; @@ -2562,12 +2568,10 @@ const FFCodec ff_aac_fixed_decoder = { .init = ff_aac_decode_init_fixed, .close = decode_close, FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), .flush = flush, }; diff --git a/libavcodec/aac/aacdec_ac.c b/libavcodec/aac/aacdec_ac.c index 7e5077cd19..5104604fa5 100644 --- a/libavcodec/aac/aacdec_ac.c +++ b/libavcodec/aac/aacdec_ac.c @@ -91,10 +91,7 @@ uint32_t ff_aac_ac_get_pk(uint32_t c) void ff_aac_ac_update_context(AACArithState *state, int idx, uint16_t a, uint16_t b) { - state->cur[0] = a + b + 1; - if (state->cur[0] > 0xF) - state->cur[0] = 0xF; - + state->cur[0] = FFMIN(a + b + 1, 0xF); state->cur[3] = state->cur[2]; state->cur[2] = state->cur[1]; state->cur[1] = state->cur[0]; diff --git a/libavcodec/aac/aacdec_dsp_template.c b/libavcodec/aac/aacdec_dsp_template.c index 8d31af22f8..b64944d548 100644 --- a/libavcodec/aac/aacdec_dsp_template.c +++ b/libavcodec/aac/aacdec_dsp_template.c @@ -185,7 +185,7 @@ static void AAC_RENAME(apply_tns)(void *_coef_param, TemporalNoiseShaping *tns, continue; // tns_decode_coef - compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], order, lpc, 0, 0, 0); + compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], 0, order, lpc, 0, 0, 0, NULL); start = ics->swb_offset[FFMIN(bottom, mmm)]; end = ics->swb_offset[FFMIN( top, mmm)]; diff --git a/libavcodec/aac/aacdec_latm.h b/libavcodec/aac/aacdec_latm.h index 047c11e0fb..398d40741b 100644 --- a/libavcodec/aac/aacdec_latm.h +++ b/libavcodec/aac/aacdec_latm.h @@ -339,12 +339,10 @@ const FFCodec ff_aac_latm_decoder = { .init = latm_decode_init, .close = decode_close, FF_CODEC_DECODE_CB(latm_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, + CODEC_CH_LAYOUTS_ARRAY(ff_aac_ch_layout), .flush = flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; diff --git a/libavcodec/aac/aacdec_lpd.c b/libavcodec/aac/aacdec_lpd.c index 20bbb007ff..93be7a74d1 100644 --- a/libavcodec/aac/aacdec_lpd.c +++ b/libavcodec/aac/aacdec_lpd.c @@ -22,47 +22,11 @@ #include "aacdec_usac.h" #include "libavcodec/unary.h" -const uint8_t ff_aac_lpd_mode_tab[32][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 0, 1, 0, 0 }, - { 1, 1, 0, 0 }, - { 0, 0, 1, 0 }, - { 1, 0, 1, 0 }, - { 0, 1, 1, 0 }, - { 1, 1, 1, 0 }, - { 0, 0, 0, 1 }, - { 1, 0, 0, 1 }, - { 0, 1, 0, 1 }, - { 1, 1, 0, 1 }, - { 0, 0, 1, 1 }, - { 1, 0, 1, 1 }, - { 0, 1, 1, 1 }, - { 1, 1, 1, 1 }, - { 2, 2, 0, 0 }, - { 2, 2, 1, 0 }, - { 2, 2, 0, 1 }, - { 2, 2, 1, 1 }, - { 0, 0, 2, 2 }, - { 1, 0, 2, 2 }, - { 0, 1, 2, 2 }, - { 1, 1, 2, 2 }, - { 2, 2, 2, 2 }, - { 3, 3, 3, 3 }, - /* Larger values are reserved, but permit them for resilience */ - { 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 void parse_qn(GetBitContext *gb, int *qn, int nk_mode, int no_qn) { if (nk_mode == 1) { for (int k = 0; k < no_qn; k++) { - qn[k] = get_unary(gb, 0, INT32_MAX); // TODO: find proper ranges + qn[k] = get_unary(gb, 0, 68); // TODO: find proper ranges if (qn[k]) qn[k]++; } @@ -75,7 +39,7 @@ static void parse_qn(GetBitContext *gb, int *qn, int nk_mode, int no_qn) if (nk_mode == 2) { for (int k = 0; k < no_qn; k++) { if (qn[k] > 4) { - qn[k] = get_unary(gb, 0, INT32_MAX);; + qn[k] = get_unary(gb, 0, 65); if (qn[k]) qn[k] += 4; } @@ -85,7 +49,7 @@ static void parse_qn(GetBitContext *gb, int *qn, int nk_mode, int no_qn) for (int k = 0; k < no_qn; k++) { if (qn[k] > 4) { - int qn_ext = get_unary(gb, 0, INT32_MAX);; + int qn_ext = get_unary(gb, 0, 65); switch (qn_ext) { case 0: qn[k] = 5; break; case 1: qn[k] = 6; break; @@ -114,6 +78,9 @@ static int parse_codebook_idx(GetBitContext *gb, uint32_t *kv, } } + if (nk > 25) + return AVERROR_PATCHWELCOME; + skip_bits(gb, 4*n); if (nk > 0) @@ -145,8 +112,6 @@ int ff_aac_parse_fac_data(AACUsacElemData *ce, GetBitContext *gb, int ff_aac_ldp_parse_channel_stream(AACDecContext *ac, AACUSACConfig *usac, AACUsacElemData *ce, GetBitContext *gb) { - int k; - const uint8_t *mod; int first_ldp_flag; ce->ldp.acelp_core_mode = get_bits(gb, 3); @@ -156,35 +121,10 @@ int ff_aac_ldp_parse_channel_stream(AACDecContext *ac, AACUSACConfig *usac, ce->ldp.core_mode_last = get_bits1(gb); ce->ldp.fac_data_present = get_bits1(gb); - mod = ff_aac_lpd_mode_tab[ce->ldp.lpd_mode]; - first_ldp_flag = !ce->ldp.core_mode_last; if (first_ldp_flag) ce->ldp.last_lpd_mode = -1; /* last_ldp_mode is a **STATEFUL** value */ - k = 0; - while (k < 0) { - if (!k) { - if (ce->ldp.core_mode_last && ce->ldp.fac_data_present) - ff_aac_parse_fac_data(ce, gb, 0, usac->core_frame_len/8); - } else { - if (!ce->ldp.last_lpd_mode && mod[k] > 0 || - ce->ldp.last_lpd_mode && !mod[k]) - ff_aac_parse_fac_data(ce, gb, 0, usac->core_frame_len/8); - } - if (!mod[k]) { -// parse_acelp_coding(); - ce->ldp.last_lpd_mode = 0; - k++; - } else { -// parse_tcx_coding(); - ce->ldp.last_lpd_mode = mod[k]; - k += (1 << (mod[k] - 1)); - } - } - -// parse_lpc_data(first_lpd_flag); - if (!ce->ldp.core_mode_last && ce->ldp.fac_data_present) { uint16_t len_8 = usac->core_frame_len / 8; uint16_t len_16 = usac->core_frame_len / 16; diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c index 1b79d19a30..e03e6e015f 100644 --- a/libavcodec/aac/aacdec_usac.c +++ b/libavcodec/aac/aacdec_usac.c @@ -265,6 +265,7 @@ static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e, /* No configuration needed - fallthrough (len should be 0) */ default: skip_bits(gb, 8*ext_config_len); + e->ext.type = ID_EXT_ELE_FILL; break; }; @@ -566,15 +567,8 @@ static int decode_usac_scale_factors(AACDecContext *ac, int offset_sf = global_gain; for (int g = 0; g < ics->num_window_groups; g++) { for (int sfb = 0; sfb < ics->max_sfb; sfb++) { - /* First coefficient is just the global gain */ - if (!g && !sfb) { - /* The cannonical representation of quantized scalefactors - * in the spec is with 100 subtracted. */ - sce->sfo[0] = offset_sf - 100; - continue; - } - - offset_sf += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; + if (g || sfb) + offset_sf += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; if (offset_sf > 255U) { av_log(ac->avctx, AV_LOG_ERROR, "Scalefactor (%d) out of range.\n", offset_sf); @@ -917,8 +911,10 @@ static int decode_usac_stereo_info(AACDecContext *ac, AACUSACConfig *usac, } ret = setup_sce(ac, sce1, usac); - if (ret < 0) + if (ret < 0) { + ics2->max_sfb = 0; return ret; + } ret = setup_sce(ac, sce2, usac); if (ret < 0) @@ -1027,8 +1023,9 @@ static void apply_noise_fill(AACDecContext *ac, SingleChannelElement *sce, } } - if (band_quantized_to_zero) - sce->sfo[g*ics->max_sfb + sfb] += noise_offset; + if (band_quantized_to_zero) { + sce->sfo[g*ics->max_sfb + sfb] = FFMAX(sce->sfo[g*ics->max_sfb + sfb] + noise_offset, -200); + } } coef += g_len << 7; } @@ -1482,11 +1479,11 @@ static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac, ret = ff_aac_sbr_decode_usac_data(ac, che, ec, gb, sbr_ch, indep_flag); if (ret < 0) return ret; + } - if (ec->stereo_config_index) { - avpriv_report_missing_feature(ac->avctx, "AAC USAC Mps212"); - return AVERROR_PATCHWELCOME; - } + if (ec->stereo_config_index) { + avpriv_report_missing_feature(ac->avctx, "AAC USAC Mps212"); + return AVERROR_PATCHWELCOME; } spectrum_decode(ac, usac, che, core_nb_channels); diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c index f45631d09f..e10ce13a3b 100644 --- a/libavcodec/aac_ac3_parser.c +++ b/libavcodec/aac_ac3_parser.c @@ -40,6 +40,8 @@ int ff_aac_ac3_parse(AVCodecParserContext *s1, int new_frame_start; int got_frame = 0; + s1->key_frame = -1; + if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) { i = buf_size; got_frame = 1; @@ -145,10 +147,15 @@ get_next: } else { #if CONFIG_AAC_PARSER AACADTSHeaderInfo hdr; + GetBitContext gb; + + init_get_bits8(&gb, buf, buf_size); if (buf_size < AV_AAC_ADTS_HEADER_SIZE || - ff_adts_header_parse_buf(buf, &hdr) < 0) + ff_adts_header_parse(&gb, &hdr) < 0) return i; + avctx->profile = hdr.object_type - 1; + s1->key_frame = (avctx->profile == AV_PROFILE_AAC_USAC) ? get_bits1(&gb) : 1; bit_rate = hdr.bit_rate; #endif } diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c index 4ce54ca886..96915c9731 100644 --- a/libavcodec/aaccoder.c +++ b/libavcodec/aaccoder.c @@ -47,8 +47,6 @@ #include "aacenc_is.h" #include "aacenc_tns.h" -#include "aacenc_ltp.h" -#include "aacenc_pred.h" #include "libavcodec/aaccoder_twoloop.h" @@ -294,120 +292,6 @@ typedef struct BandCodingPath { int run; } BandCodingPath; -/** - * Encode band info for single window group bands. - */ -static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce, - int win, int group_len, const float lambda) -{ - BandCodingPath path[120][CB_TOT_ALL]; - int w, swb, cb, start, size; - int i, j; - const int max_sfb = sce->ics.max_sfb; - const int run_bits = sce->ics.num_windows == 1 ? 5 : 3; - const int run_esc = (1 << run_bits) - 1; - int idx, ppos, count; - int stackrun[120], stackcb[120], stack_len; - float next_minrd = INFINITY; - int next_mincb = 0; - - s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024); - start = win*128; - for (cb = 0; cb < CB_TOT_ALL; cb++) { - path[0][cb].cost = 0.0f; - path[0][cb].prev_idx = -1; - path[0][cb].run = 0; - } - for (swb = 0; swb < max_sfb; swb++) { - size = sce->ics.swb_sizes[swb]; - if (sce->zeroes[win*16 + swb]) { - for (cb = 0; cb < CB_TOT_ALL; cb++) { - path[swb+1][cb].prev_idx = cb; - path[swb+1][cb].cost = path[swb][cb].cost; - path[swb+1][cb].run = path[swb][cb].run + 1; - } - } else { - float minrd = next_minrd; - int mincb = next_mincb; - next_minrd = INFINITY; - next_mincb = 0; - for (cb = 0; cb < CB_TOT_ALL; cb++) { - float cost_stay_here, cost_get_here; - float rd = 0.0f; - if (cb >= 12 && sce->band_type[win*16+swb] < aac_cb_out_map[cb] || - cb < aac_cb_in_map[sce->band_type[win*16+swb]] && sce->band_type[win*16+swb] > aac_cb_out_map[cb]) { - path[swb+1][cb].prev_idx = -1; - path[swb+1][cb].cost = INFINITY; - path[swb+1][cb].run = path[swb][cb].run + 1; - continue; - } - for (w = 0; w < group_len; w++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(win+w)*16+swb]; - rd += quantize_band_cost(s, &sce->coeffs[start + w*128], - &s->scoefs[start + w*128], size, - sce->sf_idx[(win+w)*16+swb], aac_cb_out_map[cb], - lambda / band->threshold, INFINITY, NULL, NULL); - } - cost_stay_here = path[swb][cb].cost + rd; - cost_get_here = minrd + rd + run_bits + 4; - if ( run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run] - != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1]) - cost_stay_here += run_bits; - if (cost_get_here < cost_stay_here) { - path[swb+1][cb].prev_idx = mincb; - path[swb+1][cb].cost = cost_get_here; - path[swb+1][cb].run = 1; - } else { - path[swb+1][cb].prev_idx = cb; - path[swb+1][cb].cost = cost_stay_here; - path[swb+1][cb].run = path[swb][cb].run + 1; - } - if (path[swb+1][cb].cost < next_minrd) { - next_minrd = path[swb+1][cb].cost; - next_mincb = cb; - } - } - } - start += sce->ics.swb_sizes[swb]; - } - - //convert resulting path from backward-linked list - stack_len = 0; - idx = 0; - for (cb = 1; cb < CB_TOT_ALL; cb++) - if (path[max_sfb][cb].cost < path[max_sfb][idx].cost) - idx = cb; - ppos = max_sfb; - while (ppos > 0) { - av_assert1(idx >= 0); - cb = idx; - stackrun[stack_len] = path[ppos][cb].run; - stackcb [stack_len] = cb; - idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx; - ppos -= path[ppos][cb].run; - stack_len++; - } - //perform actual band info encoding - start = 0; - for (i = stack_len - 1; i >= 0; i--) { - cb = aac_cb_out_map[stackcb[i]]; - put_bits(&s->pb, 4, cb); - count = stackrun[i]; - memset(sce->zeroes + win*16 + start, !cb, count); - //XXX: memset when band_type is also uint8_t - for (j = 0; j < count; j++) { - sce->band_type[win*16 + start] = cb; - start++; - } - while (count >= run_esc) { - put_bits(&s->pb, run_bits, run_esc); - count -= run_esc; - } - put_bits(&s->pb, run_bits, count); - } -} - - typedef struct TrellisPath { float cost; int prev; @@ -455,166 +339,6 @@ static void set_special_band_scalefactors(AACEncContext *s, SingleChannelElement } } -static void search_for_quantizers_anmr(AVCodecContext *avctx, AACEncContext *s, - SingleChannelElement *sce, - const float lambda) -{ - int q, w, w2, g, start = 0; - int i, j; - int idx; - TrellisPath paths[TRELLIS_STAGES][TRELLIS_STATES]; - int bandaddr[TRELLIS_STAGES]; - int minq; - float mincost; - float q0f = FLT_MAX, q1f = 0.0f, qnrgf = 0.0f; - int q0, q1, qcnt = 0; - - for (i = 0; i < 1024; i++) { - float t = fabsf(sce->coeffs[i]); - if (t > 0.0f) { - q0f = FFMIN(q0f, t); - q1f = FFMAX(q1f, t); - qnrgf += t*t; - qcnt++; - } - } - - if (!qcnt) { - memset(sce->sf_idx, 0, sizeof(sce->sf_idx)); - memset(sce->zeroes, 1, sizeof(sce->zeroes)); - return; - } - - //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped - q0 = av_clip(coef2minsf(q0f), 0, SCALE_MAX_POS-1); - //maximum scalefactor index is when maximum coefficient after quantizing is still not zero - q1 = av_clip(coef2maxsf(q1f), 1, SCALE_MAX_POS); - if (q1 - q0 > 60) { - int q0low = q0; - int q1high = q1; - //minimum scalefactor index is when maximum nonzero coefficient after quantizing is not clipped - int qnrg = av_clip_uint8(log2f(sqrtf(qnrgf/qcnt))*4 - 31 + SCALE_ONE_POS - SCALE_DIV_512); - q1 = qnrg + 30; - q0 = qnrg - 30; - if (q0 < q0low) { - q1 += q0low - q0; - q0 = q0low; - } else if (q1 > q1high) { - q0 -= q1 - q1high; - q1 = q1high; - } - } - // q0 == q1 isn't really a legal situation - if (q0 == q1) { - // the following is indirect but guarantees q1 != q0 && q1 near q0 - q1 = av_clip(q0+1, 1, SCALE_MAX_POS); - q0 = av_clip(q1-1, 0, SCALE_MAX_POS - 1); - } - - for (i = 0; i < TRELLIS_STATES; i++) { - paths[0][i].cost = 0.0f; - paths[0][i].prev = -1; - } - for (j = 1; j < TRELLIS_STAGES; j++) { - for (i = 0; i < TRELLIS_STATES; i++) { - paths[j][i].cost = INFINITY; - paths[j][i].prev = -2; - } - } - idx = 1; - s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024); - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = w*128; - for (g = 0; g < sce->ics.num_swb; g++) { - const float *coefs = &sce->coeffs[start]; - float qmin, qmax; - int nz = 0; - - bandaddr[idx] = w * 16 + g; - qmin = INT_MAX; - qmax = 0.0f; - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - if (band->energy <= band->threshold || band->threshold == 0.0f) { - sce->zeroes[(w+w2)*16+g] = 1; - continue; - } - sce->zeroes[(w+w2)*16+g] = 0; - nz = 1; - for (i = 0; i < sce->ics.swb_sizes[g]; i++) { - float t = fabsf(coefs[w2*128+i]); - if (t > 0.0f) - qmin = FFMIN(qmin, t); - qmax = FFMAX(qmax, t); - } - } - if (nz) { - int minscale, maxscale; - float minrd = INFINITY; - float maxval; - //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped - minscale = coef2minsf(qmin); - //maximum scalefactor index is when maximum coefficient after quantizing is still not zero - maxscale = coef2maxsf(qmax); - minscale = av_clip(minscale - q0, 0, TRELLIS_STATES - 1); - maxscale = av_clip(maxscale - q0, 0, TRELLIS_STATES); - if (minscale == maxscale) { - maxscale = av_clip(minscale+1, 1, TRELLIS_STATES); - minscale = av_clip(maxscale-1, 0, TRELLIS_STATES - 1); - } - maxval = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs+start); - for (q = minscale; q < maxscale; q++) { - float dist = 0; - int cb = find_min_book(maxval, sce->sf_idx[w*16+g]); - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - dist += quantize_band_cost(s, coefs + w2*128, s->scoefs + start + w2*128, sce->ics.swb_sizes[g], - q + q0, cb, lambda / band->threshold, INFINITY, NULL, NULL); - } - minrd = FFMIN(minrd, dist); - - for (i = 0; i < q1 - q0; i++) { - float cost; - cost = paths[idx - 1][i].cost + dist - + ff_aac_scalefactor_bits[q - i + SCALE_DIFF_ZERO]; - if (cost < paths[idx][q].cost) { - paths[idx][q].cost = cost; - paths[idx][q].prev = i; - } - } - } - } else { - for (q = 0; q < q1 - q0; q++) { - paths[idx][q].cost = paths[idx - 1][q].cost + 1; - paths[idx][q].prev = q; - } - } - sce->zeroes[w*16+g] = !nz; - start += sce->ics.swb_sizes[g]; - idx++; - } - } - idx--; - mincost = paths[idx][0].cost; - minq = 0; - for (i = 1; i < TRELLIS_STATES; i++) { - if (paths[idx][i].cost < mincost) { - mincost = paths[idx][i].cost; - minq = i; - } - } - while (idx) { - sce->sf_idx[bandaddr[idx]] = minq + q0; - minq = FFMAX(paths[idx][minq].prev, 0); - idx--; - } - //set the same quantizers inside window groups - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) - for (g = 0; g < sce->ics.num_swb; g++) - for (w2 = 1; w2 < sce->ics.group_len[w]; w2++) - sce->sf_idx[(w+w2)*16+g] = sce->sf_idx[w*16+g]; -} - static void search_for_quantizers_fast(AVCodecContext *avctx, AACEncContext *s, SingleChannelElement *sce, const float lambda) @@ -1117,70 +841,30 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe) } const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = { - [AAC_CODER_ANMR] = { - search_for_quantizers_anmr, - encode_window_bands_info, - quantize_and_encode_band, - ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, - ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, - set_special_band_scalefactors, - search_for_pns, - mark_pns, - ff_aac_search_for_tns, - ff_aac_search_for_ltp, - search_for_ms, - ff_aac_search_for_is, - ff_aac_search_for_pred, - }, [AAC_CODER_TWOLOOP] = { search_for_quantizers_twoloop, codebook_trellis_rate, quantize_and_encode_band, ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, set_special_band_scalefactors, search_for_pns, mark_pns, ff_aac_search_for_tns, - ff_aac_search_for_ltp, search_for_ms, ff_aac_search_for_is, - ff_aac_search_for_pred, }, [AAC_CODER_FAST] = { search_for_quantizers_fast, codebook_trellis_rate, quantize_and_encode_band, ff_aac_encode_tns_info, - ff_aac_encode_ltp_info, - ff_aac_encode_main_pred, - ff_aac_adjust_common_pred, - ff_aac_adjust_common_ltp, - ff_aac_apply_main_pred, ff_aac_apply_tns, - ff_aac_update_ltp, - ff_aac_ltp_insert_new_frame, set_special_band_scalefactors, search_for_pns, mark_pns, ff_aac_search_for_tns, - ff_aac_search_for_ltp, search_for_ms, ff_aac_search_for_is, - ff_aac_search_for_pred, }, }; diff --git a/libavcodec/aaccoder_twoloop.h b/libavcodec/aaccoder_twoloop.h index c56abc68a7..6ac2af51cb 100644 --- a/libavcodec/aaccoder_twoloop.h +++ b/libavcodec/aaccoder_twoloop.h @@ -311,14 +311,14 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, /** * Scale uplims to match rate distortion to quality - * bu applying noisy band depriorization and tonal band priorization. + * bu applying noisy band depriorization and tonal band prioritization. * Maxval-energy ratio gives us an idea of how noisy/tonal the band is. * If maxval^2 ~ energy, then that band is mostly noise, and we can relax * rate distortion requirements. */ memcpy(euplims, uplims, sizeof(euplims)); for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - /** psy already priorizes transients to some extent */ + /** psy already prioritizes transients to some extent */ float de_psy_factor = (sce->ics.num_windows > 1) ? 8.0f / sce->ics.group_len[w] : 1.0f; start = w*128; for (g = 0; g < sce->ics.num_swb; g++) { @@ -331,7 +331,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, nzslope * cleanup_factor); energy2uplim *= de_psy_factor; if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { - /** In ABR, we need to priorize less and let rate control do its thing */ + /** In ABR, we need to prioritize less and let rate control do its thing */ energy2uplim = sqrtf(energy2uplim); } energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); @@ -345,7 +345,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, 2.0f); energy2uplim *= de_psy_factor; if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { - /** In ABR, we need to priorize less and let rate control do its thing */ + /** In ABR, we need to prioritize less and let rate control do its thing */ energy2uplim = sqrtf(energy2uplim); } energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 88037c7f87..b8df8dc530 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -502,7 +502,7 @@ static void put_ics_info(AACEncContext *s, IndividualChannelStream *info) put_bits(&s->pb, 1, info->use_kb_window[0]); if (info->window_sequence[0] != EIGHT_SHORT_SEQUENCE) { put_bits(&s->pb, 6, info->max_sfb); - put_bits(&s->pb, 1, !!info->predictor_present); + put_bits(&s->pb, 1, 0); /* No predictor present */ } else { put_bits(&s->pb, 4, info->max_sfb); for (w = 1; w < 8; w++) @@ -762,13 +762,8 @@ static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s, int common_window) { put_bits(&s->pb, 8, sce->sf_idx[0]); - if (!common_window) { + if (!common_window) put_ics_info(s, &sce->ics); - if (s->coder->encode_main_pred) - s->coder->encode_main_pred(s, sce); - if (s->coder->encode_ltp_info) - s->coder->encode_ltp_info(s, sce, 0); - } encode_band_info(s, sce); encode_scale_factors(avctx, s, sce); encode_pulses(s, &sce->pulse); @@ -850,8 +845,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } copy_input_samples(s, frame); - if (s->psypp) - ff_psy_preprocess(s->psypp, s->planar_samples, s->channels); if (!avctx->frame_num) return 0; @@ -935,12 +928,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, apply_window_and_mdct(s, sce, overlap); - if (s->options.ltp && s->coder->update_ltp) { - s->coder->update_ltp(s, sce); - apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, &sce->ltp_state[0]); - s->mdct1024_fn(s->mdct1024, sce->lcoeffs, sce->ret_buf, sizeof(float)); - } - for (k = 0; k < 1024; k++) { if (!(fabs(cpe->ch[ch].coeffs[k]) < 1E16)) { // Ensure headroom for energy calculation av_log(avctx, AV_LOG_ERROR, "Input contains (near) NaN/+-Inf\n"); @@ -976,10 +963,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, for (ch = 0; ch < chans; ch++) { sce = &cpe->ch[ch]; coeffs[ch] = sce->coeffs; - sce->ics.predictor_present = 0; - sce->ics.ltp.present = 0; - memset(sce->ics.ltp.used, 0, sizeof(sce->ics.ltp.used)); - memset(sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); memset(&sce->tns, 0, sizeof(TemporalNoiseShaping)); for (w = 0; w < 128; w++) if (sce->band_type[w] > RESERVED_BT) @@ -1032,24 +1015,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, if (cpe->is_mode) is_mode = 1; apply_intensity_stereo(cpe); } - if (s->options.pred) { /* Prediction */ - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->options.pred && s->coder->search_for_pred) - s->coder->search_for_pred(s, sce); - if (cpe->ch[ch].ics.predictor_present) pred_mode = 1; - } - if (s->coder->adjust_common_pred) - s->coder->adjust_common_pred(s, cpe); - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->options.pred && s->coder->apply_main_pred) - s->coder->apply_main_pred(s, sce); - } - s->cur_channel = start_ch; - } if (s->options.mid_side) { /* Mid/Side stereo */ if (s->options.mid_side == -1 && s->coder->search_for_ms) s->coder->search_for_ms(s, cpe); @@ -1058,26 +1023,10 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, apply_mid_side_stereo(cpe); } adjust_frame_information(cpe, chans); - if (s->options.ltp) { /* LTP */ - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - s->cur_channel = start_ch + ch; - if (s->coder->search_for_ltp) - s->coder->search_for_ltp(s, sce, cpe->common_window); - if (sce->ics.ltp.present) pred_mode = 1; - } - s->cur_channel = start_ch; - if (s->coder->adjust_common_ltp) - s->coder->adjust_common_ltp(s, cpe); - } if (chans == 2) { put_bits(&s->pb, 1, cpe->common_window); if (cpe->common_window) { put_ics_info(s, &cpe->ch[0].ics); - if (s->coder->encode_main_pred) - s->coder->encode_main_pred(s, &cpe->ch[0]); - if (s->coder->encode_ltp_info) - s->coder->encode_ltp_info(s, &cpe->ch[0], 1); encode_ms_info(&s->pb, cpe); if (cpe->ms_mode) ms_mode = 1; } @@ -1162,9 +1111,6 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } } while (1); - if (s->options.ltp && s->coder->ltp_insert_new_frame) - s->coder->ltp_insert_new_frame(s); - put_bits(&s->pb, 3, TYPE_END); flush_put_bits(&s->pb); @@ -1177,6 +1123,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, &avpkt->duration); + avpkt->flags |= AV_PKT_FLAG_KEY; + *got_packet_ptr = 1; return 0; } @@ -1191,8 +1139,6 @@ static av_cold int aac_encode_end(AVCodecContext *avctx) av_tx_uninit(&s->mdct128); ff_psy_end(&s->psy); ff_lpc_end(&s->lpc); - if (s->psypp) - ff_psy_preprocess_end(s->psypp); av_freep(&s->buffer.samples); av_freep(&s->cpe); av_freep(&s->fdsp); @@ -1285,14 +1231,13 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) } /* Samplerate */ - for (i = 0; i < 16; i++) - if (avctx->sample_rate == ff_mpeg4audio_sample_rates[i]) + for (int i = 0;; i++) { + av_assert1(i < 13); + if (avctx->sample_rate == ff_mpeg4audio_sample_rates[i]) { + s->samplerate_index = i; break; - s->samplerate_index = i; - ERROR_IF(s->samplerate_index == 16 || - s->samplerate_index >= ff_aac_swb_size_1024_len || - s->samplerate_index >= ff_aac_swb_size_128_len, - "Unsupported sample rate %d\n", avctx->sample_rate); + } + } /* Bitrate limiting */ WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels, @@ -1308,48 +1253,17 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) if (avctx->profile == aacenc_profiles[i]) break; + ERROR_IF(i == FF_ARRAY_ELEMS(aacenc_profiles), "Profile not supported!\n"); if (avctx->profile == AV_PROFILE_MPEG2_AAC_LOW) { avctx->profile = AV_PROFILE_AAC_LOW; - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"mpeg2_aac_low\" profile\n"); - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"mpeg2_aac_low\" profile\n"); WARN_IF(s->options.pns, "PNS unavailable in the \"mpeg2_aac_low\" profile, turning off\n"); s->options.pns = 0; - } else if (avctx->profile == AV_PROFILE_AAC_LTP) { - s->options.ltp = 1; - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"aac_ltp\" profile\n"); - } else if (avctx->profile == AV_PROFILE_AAC_MAIN) { - s->options.pred = 1; - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"aac_main\" profile\n"); - } else if (s->options.ltp) { - avctx->profile = AV_PROFILE_AAC_LTP; - WARN_IF(1, - "Chainging profile to \"aac_ltp\"\n"); - ERROR_IF(s->options.pred, - "Main prediction unavailable in the \"aac_ltp\" profile\n"); - } else if (s->options.pred) { - avctx->profile = AV_PROFILE_AAC_MAIN; - WARN_IF(1, - "Chainging profile to \"aac_main\"\n"); - ERROR_IF(s->options.ltp, - "LTP prediction unavailable in the \"aac_main\" profile\n"); } s->profile = avctx->profile; /* Coder limitations */ s->coder = &ff_aac_coders[s->options.coder]; - if (s->options.coder == AAC_CODER_ANMR) { - ERROR_IF(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, - "The ANMR coder is considered experimental, add -strict -2 to enable!\n"); - s->options.intensity_stereo = 0; - s->options.pns = 0; - } - ERROR_IF(s->options.ltp && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, - "The LPT profile requires experimental compliance, add -strict -2 to enable!\n"); /* M/S introduces horrible artifacts with multichannel files, this is temporary */ if (s->channels > 3) @@ -1376,7 +1290,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, s->chan_map[0], grouping)) < 0) return ret; - s->psypp = ff_psy_preprocess_init(avctx); ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON); s->random_state = 0x1f2e3d4c; @@ -1390,15 +1303,12 @@ 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, .unit = "coder"}, - {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"}, {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"}, {"fast", "Fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "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}, FF_AAC_PROFILE_OPTS {NULL} @@ -1428,9 +1338,8 @@ const FFCodec ff_aac_encoder = { FF_CODEC_ENCODE_CB(aac_encode_frame), .close = aac_encode_end, .defaults = aac_encode_defaults, - .p.supported_samplerates = ff_mpeg4audio_sample_rates, + CODEC_SAMPLERATES_ARRAY(ff_mpeg4audio_sample_rates), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &aacenc_class, }; diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index ae15f91e06..51a216e6d0 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -42,7 +42,6 @@ #define CLIP_AVOIDANCE_FACTOR 0.95f typedef enum AACCoder { - AAC_CODER_ANMR = 0, AAC_CODER_TWOLOOP, AAC_CODER_FAST, @@ -67,24 +66,11 @@ typedef struct AACEncOptions { int coder; int pns; int tns; - int ltp; int pce; - int pred; int mid_side; int intensity_stereo; } AACEncOptions; -/** - * Long Term Prediction - */ -typedef struct LongTermPrediction { - int8_t present; - int16_t lag; - int coef_idx; - float coef; - int8_t used[MAX_LTP_LONG_SFB]; -} LongTermPrediction; - /** * Individual Channel Stream */ @@ -93,17 +79,11 @@ typedef struct IndividualChannelStream { enum WindowSequence window_sequence[2]; uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sine window. uint8_t group_len[8]; - LongTermPrediction ltp; const uint16_t *swb_offset; ///< table of offsets to the lowest spectral coefficient of a scalefactor band, sfb, for a particular window const uint8_t *swb_sizes; ///< table of scalefactor band sizes for a particular window int num_swb; ///< number of scalefactor window bands int num_windows; int tns_max_bands; - int predictor_present; - int predictor_initialized; - int predictor_reset_group; - int predictor_reset_count[31]; ///< used to count prediction resets - uint8_t prediction_used[41]; uint8_t window_clipping[8]; ///< set if a certain window is near clipping float clip_avoidance_factor; ///< set if any window is near clipping to the necessary atennuation factor to avoid it } IndividualChannelStream; @@ -138,9 +118,6 @@ typedef struct SingleChannelElement { DECLARE_ALIGNED(32, float, pcoeffs)[1024]; ///< coefficients for IMDCT, pristine DECLARE_ALIGNED(32, float, coeffs)[1024]; ///< coefficients for IMDCT, maybe processed DECLARE_ALIGNED(32, float, ret_buf)[2048]; ///< PCM output buffer - DECLARE_ALIGNED(16, float, ltp_state)[3072]; ///< time signal for LTP - DECLARE_ALIGNED(32, float, lcoeffs)[1024]; ///< MDCT of LTP coefficients - DECLARE_ALIGNED(32, float, prcoeffs)[1024]; ///< Main prediction coefs PredictorState predictor_state[MAX_PREDICTORS]; } SingleChannelElement; @@ -168,22 +145,13 @@ typedef struct AACCoefficientsEncoder { void (*quantize_and_encode_band)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *out, int size, int scale_idx, int cb, const float lambda, int rtz); void (*encode_tns_info)(struct AACEncContext *s, SingleChannelElement *sce); - void (*encode_ltp_info)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); - void (*encode_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); - void (*adjust_common_pred)(struct AACEncContext *s, ChannelElement *cpe); - void (*adjust_common_ltp)(struct AACEncContext *s, ChannelElement *cpe); - void (*apply_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); void (*apply_tns_filt)(struct AACEncContext *s, SingleChannelElement *sce); - void (*update_ltp)(struct AACEncContext *s, SingleChannelElement *sce); - void (*ltp_insert_new_frame)(struct AACEncContext *s); void (*set_special_band_scalefactors)(struct AACEncContext *s, SingleChannelElement *sce); void (*search_for_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); void (*mark_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); void (*search_for_tns)(struct AACEncContext *s, SingleChannelElement *sce); - void (*search_for_ltp)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); void (*search_for_ms)(struct AACEncContext *s, ChannelElement *cpe); void (*search_for_is)(struct AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); - void (*search_for_pred)(struct AACEncContext *s, SingleChannelElement *sce); } AACCoefficientsEncoder; extern const AACCoefficientsEncoder ff_aac_coders[]; @@ -231,7 +199,6 @@ typedef struct AACEncContext { ChannelElement *cpe; ///< channel elements FFPsyContext psy; - struct FFPsyPreprocessContext* psypp; const AACCoefficientsEncoder *coder; int cur_channel; ///< current channel for coder context int random_state; diff --git a/libavcodec/aacenc_is.c b/libavcodec/aacenc_is.c index 4943b6450c..4e711382dc 100644 --- a/libavcodec/aacenc_is.c +++ b/libavcodec/aacenc_is.c @@ -30,16 +30,27 @@ #include "aacenc_is.h" #include "aacenc_quantization.h" -struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, - int start, int w, int g, float ener0, - float ener1, float ener01, - int use_pcoeffs, int phase) +/** Frequency in Hz for lower limit of intensity stereo **/ +#define INT_STEREO_LOW_LIMIT 6100 + +struct AACISError { + int pass; /* 1 if dist2 <= dist1 */ + int phase; /* -1 or +1 */ + float error; /* fabs(dist1 - dist2) */ + float dist1; /* From original coeffs */ + float dist2; /* From IS'd coeffs */ + float ener01; +}; + +static struct AACISError aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, + int start, int w, int g, float ener0, + float ener1, float ener01, int phase) { int i, w2; SingleChannelElement *sce0 = &cpe->ch[0]; SingleChannelElement *sce1 = &cpe->ch[1]; - float *L = use_pcoeffs ? sce0->pcoeffs : sce0->coeffs; - float *R = use_pcoeffs ? sce1->pcoeffs : sce1->coeffs; + float *L = sce0->coeffs; + float *R = sce1->coeffs; float *L34 = &s->scoefs[256*0], *R34 = &s->scoefs[256*1]; float *IS = &s->scoefs[256*2], *I34 = &s->scoefs[256*3]; float dist1 = 0.0f, dist2 = 0.0f; @@ -128,10 +139,10 @@ void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElemen ener01p += (coef0 - coef1)*(coef0 - coef1); } } - ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01p, 0, -1); - ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 0, +1); + ph_err1 = aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01p, -1); + ph_err2 = aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01, +1); best = (ph_err1.pass && ph_err1.error < ph_err2.error) ? &ph_err1 : &ph_err2; if (best->pass) { cpe->is_mask[w*16+g] = 1; diff --git a/libavcodec/aacenc_is.h b/libavcodec/aacenc_is.h index 269fd1a9c9..beaa70c790 100644 --- a/libavcodec/aacenc_is.h +++ b/libavcodec/aacenc_is.h @@ -30,22 +30,6 @@ #include "aacenc.h" -/** Frequency in Hz for lower limit of intensity stereo **/ -#define INT_STEREO_LOW_LIMIT 6100 - -struct AACISError { - int pass; /* 1 if dist2 <= dist1 */ - int phase; /* -1 or +1 */ - float error; /* fabs(dist1 - dist2) */ - float dist1; /* From original coeffs */ - float dist2; /* From IS'd coeffs */ - float ener01; -}; - -struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, - int start, int w, int g, float ener0, - float ener1, float ener01, - int use_pcoeffs, int phase); void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); #endif /* AVCODEC_AACENC_IS_H */ diff --git a/libavcodec/aacenc_ltp.c b/libavcodec/aacenc_ltp.c deleted file mode 100644 index 58f7921074..0000000000 --- a/libavcodec/aacenc_ltp.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * AAC encoder long term prediction extension - * Copyright (C) 2015 Rostislav Pehlivanov - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * AAC encoder long term prediction extension - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#include "aacenc_ltp.h" -#include "aacenc_quantization.h" -#include "aacenc_utils.h" - -/** - * Encode LTP data. - */ -void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce, - int common_window) -{ - int i; - IndividualChannelStream *ics = &sce->ics; - if (s->profile != AV_PROFILE_AAC_LTP || !ics->predictor_present) - return; - if (common_window) - put_bits(&s->pb, 1, 0); - put_bits(&s->pb, 1, ics->ltp.present); - if (!ics->ltp.present) - return; - put_bits(&s->pb, 11, ics->ltp.lag); - put_bits(&s->pb, 3, ics->ltp.coef_idx); - for (i = 0; i < FFMIN(ics->max_sfb, MAX_LTP_LONG_SFB); i++) - put_bits(&s->pb, 1, ics->ltp.used[i]); -} - -void ff_aac_ltp_insert_new_frame(AACEncContext *s) -{ - int i, ch, tag, chans, cur_channel, start_ch = 0; - ChannelElement *cpe; - SingleChannelElement *sce; - for (i = 0; i < s->chan_map[0]; i++) { - cpe = &s->cpe[i]; - tag = s->chan_map[i+1]; - chans = tag == TYPE_CPE ? 2 : 1; - for (ch = 0; ch < chans; ch++) { - sce = &cpe->ch[ch]; - cur_channel = start_ch + ch; - /* New sample + overlap */ - memcpy(&sce->ltp_state[0], &sce->ltp_state[1024], 1024*sizeof(sce->ltp_state[0])); - memcpy(&sce->ltp_state[1024], &s->planar_samples[cur_channel][2048], 1024*sizeof(sce->ltp_state[0])); - memcpy(&sce->ltp_state[2048], &sce->ret_buf[0], 1024*sizeof(sce->ltp_state[0])); - sce->ics.ltp.lag = 0; - } - start_ch += chans; - } -} - -static void get_lag(float *buf, const float *new, LongTermPrediction *ltp) -{ - int i, j, lag = 0, max_corr = 0; - float max_ratio = 0.0f; - for (i = 0; i < 2048; i++) { - float corr, s0 = 0.0f, s1 = 0.0f; - const int start = FFMAX(0, i - 1024); - for (j = start; j < 2048; j++) { - const int idx = j - i + 1024; - s0 += new[j]*buf[idx]; - s1 += buf[idx]*buf[idx]; - } - corr = s1 > 0.0f ? s0/sqrt(s1) : 0.0f; - if (corr > max_corr) { - max_corr = corr; - lag = i; - max_ratio = corr/(2048-start); - } - } - ltp->lag = FFMAX(av_clip_uintp2(lag, 11), 0); - ltp->coef_idx = quant_array_idx(max_ratio, ff_ltp_coef, 8); - ltp->coef = ff_ltp_coef[ltp->coef_idx]; -} - -static void generate_samples(float *buf, LongTermPrediction *ltp) -{ - int i, samples_num = 2048; - if (!ltp->lag) { - ltp->present = 0; - return; - } else if (ltp->lag < 1024) { - samples_num = ltp->lag + 1024; - } - for (i = 0; i < samples_num; i++) - buf[i] = ltp->coef*buf[i + 2048 - ltp->lag]; - memset(&buf[i], 0, (2048 - i)*sizeof(float)); -} - -/** - * Process LTP parameters - * @see Patent WO2006070265A1 - */ -void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce) -{ - float *pred_signal = &sce->ltp_state[0]; - const float *samples = &s->planar_samples[s->cur_channel][1024]; - - if (s->profile != AV_PROFILE_AAC_LTP) - return; - - /* Calculate lag */ - get_lag(pred_signal, samples, &sce->ics.ltp); - generate_samples(pred_signal, &sce->ics.ltp); -} - -void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe) -{ - int sfb, count = 0; - SingleChannelElement *sce0 = &cpe->ch[0]; - SingleChannelElement *sce1 = &cpe->ch[1]; - - if (!cpe->common_window || - sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || - sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - sce0->ics.ltp.present = 0; - return; - } - - for (sfb = 0; sfb < FFMIN(sce0->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) { - int sum = sce0->ics.ltp.used[sfb] + sce1->ics.ltp.used[sfb]; - if (sum != 2) { - sce0->ics.ltp.used[sfb] = 0; - } else { - count++; - } - } - - sce0->ics.ltp.present = !!count; - sce0->ics.predictor_present = !!count; -} - -/** - * Mark LTP sfb's - */ -void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce, - int common_window) -{ - int w, g, w2, i, start = 0, count = 0; - int saved_bits = -(15 + FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB)); - float *C34 = &s->scoefs[128*0], *PCD = &s->scoefs[128*1]; - float *PCD34 = &s->scoefs[128*2]; - const int max_ltp = FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); - - if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - if (sce->ics.ltp.lag) { - memset(&sce->ltp_state[0], 0, 3072*sizeof(sce->ltp_state[0])); - memset(&sce->ics.ltp, 0, sizeof(LongTermPrediction)); - } - return; - } - - if (!sce->ics.ltp.lag || s->lambda > 120.0f) - return; - - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce->ics.num_swb; g++) { - int bits1 = 0, bits2 = 0; - float dist1 = 0.0f, dist2 = 0.0f; - if (w*16+g > max_ltp) { - start += sce->ics.swb_sizes[g]; - continue; - } - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - int bits_tmp1, bits_tmp2; - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; - for (i = 0; i < sce->ics.swb_sizes[g]; i++) - PCD[i] = sce->coeffs[start+(w+w2)*128+i] - sce->lcoeffs[start+(w+w2)*128+i]; - s->aacdsp.abs_pow34(C34, &sce->coeffs[start+(w+w2)*128], sce->ics.swb_sizes[g]); - s->aacdsp.abs_pow34(PCD34, PCD, sce->ics.swb_sizes[g]); - dist1 += quantize_band_cost(s, &sce->coeffs[start+(w+w2)*128], C34, sce->ics.swb_sizes[g], - sce->sf_idx[(w+w2)*16+g], sce->band_type[(w+w2)*16+g], - s->lambda/band->threshold, INFINITY, &bits_tmp1, NULL); - dist2 += quantize_band_cost(s, PCD, PCD34, sce->ics.swb_sizes[g], - sce->sf_idx[(w+w2)*16+g], - sce->band_type[(w+w2)*16+g], - s->lambda/band->threshold, INFINITY, &bits_tmp2, NULL); - bits1 += bits_tmp1; - bits2 += bits_tmp2; - } - if (dist2 < dist1 && bits2 < bits1) { - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) - for (i = 0; i < sce->ics.swb_sizes[g]; i++) - sce->coeffs[start+(w+w2)*128+i] -= sce->lcoeffs[start+(w+w2)*128+i]; - sce->ics.ltp.used[w*16+g] = 1; - saved_bits += bits1 - bits2; - count++; - } - start += sce->ics.swb_sizes[g]; - } - } - - sce->ics.ltp.present = !!count && (saved_bits >= 0); - sce->ics.predictor_present = !!sce->ics.ltp.present; - - /* Reset any marked sfbs */ - if (!sce->ics.ltp.present && !!count) { - for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce->ics.num_swb; g++) { - if (sce->ics.ltp.used[w*16+g]) { - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - for (i = 0; i < sce->ics.swb_sizes[g]; i++) { - sce->coeffs[start+(w+w2)*128+i] += sce->lcoeffs[start+(w+w2)*128+i]; - } - } - } - start += sce->ics.swb_sizes[g]; - } - } - } -} diff --git a/libavcodec/aacenc_pred.c b/libavcodec/aacenc_pred.c deleted file mode 100644 index a486c44d42..0000000000 --- a/libavcodec/aacenc_pred.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * AAC encoder main-type prediction - * Copyright (C) 2015 Rostislav Pehlivanov - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * AAC encoder main-type prediction - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#include "aactab.h" -#include "aacenc_pred.h" -#include "aacenc_utils.h" -#include "aacenc_is.h" /* <- Needed for common window distortions */ -#include "aacenc_quantization.h" - -#define RESTORE_PRED(sce, sfb) \ - if (sce->ics.prediction_used[sfb]) {\ - sce->ics.prediction_used[sfb] = 0;\ - sce->band_type[sfb] = sce->band_alt[sfb];\ - } - -static inline float flt16_round(float pf) -{ - union av_intfloat32 tmp; - tmp.f = pf; - tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; - return tmp.f; -} - -static inline float flt16_even(float pf) -{ - union av_intfloat32 tmp; - tmp.f = pf; - tmp.i = (tmp.i + 0x00007FFFU + (tmp.i & 0x00010000U >> 16)) & 0xFFFF0000U; - return tmp.f; -} - -static inline float flt16_trunc(float pf) -{ - union av_intfloat32 pun; - pun.f = pf; - pun.i &= 0xFFFF0000U; - return pun.f; -} - -static inline void predict(PredictorState *ps, float *coef, float *rcoef, int set) -{ - float k2; - const float a = 0.953125; // 61.0 / 64 - const float alpha = 0.90625; // 29.0 / 32 - const float k1 = ps->k1; - const float r0 = ps->r0, r1 = ps->r1; - const float cor0 = ps->cor0, cor1 = ps->cor1; - const float var0 = ps->var0, var1 = ps->var1; - const float e0 = *coef - ps->x_est; - const float e1 = e0 - k1 * r0; - - if (set) - *coef = e0; - - ps->cor1 = flt16_trunc(alpha * cor1 + r1 * e1); - ps->var1 = flt16_trunc(alpha * var1 + 0.5f * (r1 * r1 + e1 * e1)); - ps->cor0 = flt16_trunc(alpha * cor0 + r0 * e0); - ps->var0 = flt16_trunc(alpha * var0 + 0.5f * (r0 * r0 + e0 * e0)); - ps->r1 = flt16_trunc(a * (r0 - k1 * e0)); - ps->r0 = flt16_trunc(a * e0); - - /* Prediction for next frame */ - ps->k1 = ps->var0 > 1 ? ps->cor0 * flt16_even(a / ps->var0) : 0; - k2 = ps->var1 > 1 ? ps->cor1 * flt16_even(a / ps->var1) : 0; - *rcoef = ps->x_est = flt16_round(ps->k1*ps->r0 + k2*ps->r1); -} - -static inline void reset_predict_state(PredictorState *ps) -{ - ps->r0 = 0.0f; - ps->r1 = 0.0f; - ps->k1 = 0.0f; - ps->cor0 = 0.0f; - ps->cor1 = 0.0f; - ps->var0 = 1.0f; - ps->var1 = 1.0f; - ps->x_est = 0.0f; -} - -static inline void reset_all_predictors(PredictorState *ps) -{ - int i; - for (i = 0; i < MAX_PREDICTORS; i++) - reset_predict_state(&ps[i]); -} - -static inline void reset_predictor_group(SingleChannelElement *sce, int group_num) -{ - int i; - PredictorState *ps = sce->predictor_state; - for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) - reset_predict_state(&ps[i]); -} - -void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb, k; - const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - - if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - for (sfb = 0; sfb < pmax; sfb++) { - for (k = sce->ics.swb_offset[sfb]; k < sce->ics.swb_offset[sfb + 1]; k++) { - predict(&sce->predictor_state[k], &sce->coeffs[k], &sce->prcoeffs[k], - sce->ics.predictor_present && sce->ics.prediction_used[sfb]); - } - } - if (sce->ics.predictor_reset_group) { - reset_predictor_group(sce, sce->ics.predictor_reset_group); - } - } else { - reset_all_predictors(sce->predictor_state); - } -} - -/* If inc = 0 you can check if this returns 0 to see if you can reset freely */ -static inline int update_counters(IndividualChannelStream *ics, int inc) -{ - int i; - for (i = 1; i < 31; i++) { - ics->predictor_reset_count[i] += inc; - if (ics->predictor_reset_count[i] > PRED_RESET_FRAME_MIN) - return i; /* Reset this immediately */ - } - return 0; -} - -void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe) -{ - int start, w, w2, g, i, count = 0; - SingleChannelElement *sce0 = &cpe->ch[0]; - SingleChannelElement *sce1 = &cpe->ch[1]; - const int pmax0 = FFMIN(sce0->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - const int pmax1 = FFMIN(sce1->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - const int pmax = FFMIN(pmax0, pmax1); - - if (!cpe->common_window || - sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || - sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) - return; - - for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) { - start = 0; - for (g = 0; g < sce0->ics.num_swb; g++) { - int sfb = w*16+g; - int sum = sce0->ics.prediction_used[sfb] + sce1->ics.prediction_used[sfb]; - float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f; - struct AACISError ph_err1, ph_err2, *erf; - if (sfb < PRED_SFB_START || sfb > pmax || sum != 2) { - RESTORE_PRED(sce0, sfb); - RESTORE_PRED(sce1, sfb); - start += sce0->ics.swb_sizes[g]; - continue; - } - for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { - for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { - float coef0 = sce0->pcoeffs[start+(w+w2)*128+i]; - float coef1 = sce1->pcoeffs[start+(w+w2)*128+i]; - ener0 += coef0*coef0; - ener1 += coef1*coef1; - ener01 += (coef0 + coef1)*(coef0 + coef1); - } - } - ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 1, -1); - ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, - ener0, ener1, ener01, 1, +1); - erf = ph_err1.error < ph_err2.error ? &ph_err1 : &ph_err2; - if (erf->pass) { - sce0->ics.prediction_used[sfb] = 1; - sce1->ics.prediction_used[sfb] = 1; - count++; - } else { - RESTORE_PRED(sce0, sfb); - RESTORE_PRED(sce1, sfb); - } - start += sce0->ics.swb_sizes[g]; - } - } - - sce1->ics.predictor_present = sce0->ics.predictor_present = !!count; -} - -static void update_pred_resets(SingleChannelElement *sce) -{ - int i, max_group_id_c, max_frame = 0; - float avg_frame = 0.0f; - IndividualChannelStream *ics = &sce->ics; - - /* Update the counters and immediately update any frame behind schedule */ - if ((ics->predictor_reset_group = update_counters(&sce->ics, 1))) - return; - - for (i = 1; i < 31; i++) { - /* Count-based */ - if (ics->predictor_reset_count[i] > max_frame) { - max_group_id_c = i; - max_frame = ics->predictor_reset_count[i]; - } - avg_frame = (ics->predictor_reset_count[i] + avg_frame)/2; - } - - if (max_frame > PRED_RESET_MIN) { - ics->predictor_reset_group = max_group_id_c; - } else { - ics->predictor_reset_group = 0; - } -} - -void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb, i, count = 0, cost_coeffs = 0, cost_pred = 0; - const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - float *O34 = &s->scoefs[128*0], *P34 = &s->scoefs[128*1]; - float *SENT = &s->scoefs[128*2], *S34 = &s->scoefs[128*3]; - float *QERR = &s->scoefs[128*4]; - - if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - sce->ics.predictor_present = 0; - return; - } - - if (!sce->ics.predictor_initialized) { - reset_all_predictors(sce->predictor_state); - sce->ics.predictor_initialized = 1; - memcpy(sce->prcoeffs, sce->coeffs, 1024*sizeof(float)); - for (i = 1; i < 31; i++) - sce->ics.predictor_reset_count[i] = i; - } - - update_pred_resets(sce); - memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type)); - - for (sfb = PRED_SFB_START; sfb < pmax; sfb++) { - int cost1, cost2, cb_p; - float dist1, dist2, dist_spec_err = 0.0f; - const int cb_n = sce->zeroes[sfb] ? 0 : sce->band_type[sfb]; - const int cb_min = sce->zeroes[sfb] ? 0 : 1; - const int cb_max = sce->zeroes[sfb] ? 0 : RESERVED_BT; - const int start_coef = sce->ics.swb_offset[sfb]; - const int num_coeffs = sce->ics.swb_offset[sfb + 1] - start_coef; - const FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[sfb]; - - if (start_coef + num_coeffs > MAX_PREDICTORS || - (s->cur_channel && sce->band_type[sfb] >= INTENSITY_BT2) || - sce->band_type[sfb] == NOISE_BT) - continue; - - /* Normal coefficients */ - s->aacdsp.abs_pow34(O34, &sce->coeffs[start_coef], num_coeffs); - dist1 = ff_quantize_and_encode_band_cost(s, NULL, &sce->coeffs[start_coef], NULL, - O34, num_coeffs, sce->sf_idx[sfb], - cb_n, s->lambda / band->threshold, INFINITY, &cost1, NULL); - cost_coeffs += cost1; - - /* Encoded coefficients - needed for #bits, band type and quant. error */ - for (i = 0; i < num_coeffs; i++) - SENT[i] = sce->coeffs[start_coef + i] - sce->prcoeffs[start_coef + i]; - s->aacdsp.abs_pow34(S34, SENT, num_coeffs); - if (cb_n < RESERVED_BT) - cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, S34), sce->sf_idx[sfb]), cb_min, cb_max); - else - cb_p = cb_n; - ff_quantize_and_encode_band_cost(s, NULL, SENT, QERR, S34, num_coeffs, - sce->sf_idx[sfb], cb_p, s->lambda / band->threshold, INFINITY, - &cost2, NULL); - - /* Reconstructed coefficients - needed for distortion measurements */ - for (i = 0; i < num_coeffs; i++) - sce->prcoeffs[start_coef + i] += QERR[i] != 0.0f ? (sce->prcoeffs[start_coef + i] - QERR[i]) : 0.0f; - s->aacdsp.abs_pow34(P34, &sce->prcoeffs[start_coef], num_coeffs); - if (cb_n < RESERVED_BT) - cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, P34), sce->sf_idx[sfb]), cb_min, cb_max); - else - cb_p = cb_n; - dist2 = ff_quantize_and_encode_band_cost(s, NULL, &sce->prcoeffs[start_coef], NULL, - P34, num_coeffs, sce->sf_idx[sfb], - cb_p, s->lambda / band->threshold, INFINITY, NULL, NULL); - for (i = 0; i < num_coeffs; i++) - dist_spec_err += (O34[i] - P34[i])*(O34[i] - P34[i]); - dist_spec_err *= s->lambda / band->threshold; - dist2 += dist_spec_err; - - if (dist2 <= dist1 && cb_p <= cb_n) { - cost_pred += cost2; - sce->ics.prediction_used[sfb] = 1; - sce->band_alt[sfb] = cb_n; - sce->band_type[sfb] = cb_p; - count++; - } else { - cost_pred += cost1; - sce->band_alt[sfb] = cb_p; - } - } - - if (count && cost_coeffs < cost_pred) { - count = 0; - for (sfb = PRED_SFB_START; sfb < pmax; sfb++) - RESTORE_PRED(sce, sfb); - memset(&sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); - } - - sce->ics.predictor_present = !!count; -} - -/** - * Encoder predictors data. - */ -void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce) -{ - int sfb; - IndividualChannelStream *ics = &sce->ics; - const int pmax = FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); - - if (s->profile != AV_PROFILE_AAC_MAIN || - !ics->predictor_present) - return; - - put_bits(&s->pb, 1, !!ics->predictor_reset_group); - if (ics->predictor_reset_group) - put_bits(&s->pb, 5, ics->predictor_reset_group); - for (sfb = 0; sfb < pmax; sfb++) - put_bits(&s->pb, 1, ics->prediction_used[sfb]); -} diff --git a/libavcodec/aacenc_pred.h b/libavcodec/aacenc_pred.h deleted file mode 100644 index aa305f45a5..0000000000 --- a/libavcodec/aacenc_pred.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * AAC encoder main-type prediction - * Copyright (C) 2015 Rostislav Pehlivanov - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * AAC encoder main-type prediction - * @author Rostislav Pehlivanov ( atomnuker gmail com ) - */ - -#ifndef AVCODEC_AACENC_PRED_H -#define AVCODEC_AACENC_PRED_H - -#include "aacenc.h" - -/* Every predictor group needs to get reset at least once in this many frames */ -#define PRED_RESET_FRAME_MIN 240 - -/* Any frame with less than this amount of frames since last reset is ok */ -#define PRED_RESET_MIN 64 - -/* Raise to filter any low frequency artifacts due to prediction */ -#define PRED_SFB_START 10 - -void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce); -void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe); -void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce); -void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce); - -#endif /* AVCODEC_AACENC_PRED_H */ diff --git a/libavcodec/aacenc_tns.c b/libavcodec/aacenc_tns.c index fa3cd2af39..1e71c658c4 100644 --- a/libavcodec/aacenc_tns.c +++ b/libavcodec/aacenc_tns.c @@ -117,7 +117,7 @@ void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce) continue; // tns_decode_coef - compute_lpc_coefs(tns->coef[w][filt], order, lpc, 0, 0, 0); + compute_lpc_coefs(tns->coef[w][filt], 0, order, lpc, 0, 0, 0, NULL); start = ics->swb_offset[FFMIN(bottom, mmm)]; end = ics->swb_offset[FFMIN( top, mmm)]; @@ -168,11 +168,12 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4; const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm); const int sfb_end = av_clip(sce->ics.num_swb, 0, mmm); - const int order = is8 ? 7 : s->profile == AV_PROFILE_AAC_LOW ? 12 : TNS_MAX_ORDER; + const int order = is8 ? 7 : 12; const int slant = sce->ics.window_sequence[0] == LONG_STOP_SEQUENCE ? 1 : sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2; const int sfb_len = sfb_end - sfb_start; const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start]; + const int n_filt = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3; if (coef_len <= 0 || sfb_len <= 0) { sce->tns.present = 0; @@ -180,16 +181,30 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) } for (w = 0; w < sce->ics.num_windows; w++) { - float en[2] = {0.0f, 0.0f}; + float en[4] = {0.0f, 0.0f, 0.0f, 0.0f}; int oc_start = 0; int coef_start = sce->ics.swb_offset[sfb_start]; - for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g]; - if (g > sfb_start + (sfb_len/2)) - en[1] += band->energy; - else - en[0] += band->energy; + if (n_filt == 2) { + for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g]; + if (g > sfb_start + (sfb_len/2)) + en[1] += band->energy; /* End */ + else + en[0] += band->energy; /* Start */ + } + en[2] = en[0]; + } else { + for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g]; + if (g > sfb_start + (sfb_len/2) + (sfb_len/4)) + en[2] += band->energy; /* End */ + else if (g > sfb_start + (sfb_len/2) - (sfb_len/4)) + en[1] += band->energy; /* Middle */ + else + en[0] += band->energy; /* Start */ + } + en[3] = en[0]; } /* LPC */ @@ -199,9 +214,9 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH) continue; - tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3; + tns->n_filt[w] = n_filt; for (g = 0; g < tns->n_filt[w]; g++) { - tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g]; + tns->direction[w][g] = slant != 2 ? slant : en[g] < en[g + 1]; tns->order[w][g] = order/tns->n_filt[w]; tns->length[w][g] = sfb_len/tns->n_filt[w]; quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g], diff --git a/libavcodec/aacencdsp.h b/libavcodec/aacencdsp.h index 67836d8cf7..d0d86c3d70 100644 --- a/libavcodec/aacencdsp.h +++ b/libavcodec/aacencdsp.h @@ -34,6 +34,7 @@ typedef struct AACEncDSPContext { void ff_aacenc_dsp_init_riscv(AACEncDSPContext *s); void ff_aacenc_dsp_init_x86(AACEncDSPContext *s); +void ff_aacenc_dsp_init_aarch64(AACEncDSPContext *s); static inline void abs_pow34_v(float *out, const float *in, const int size) { @@ -66,6 +67,8 @@ static inline void ff_aacenc_dsp_init(AACEncDSPContext *s) ff_aacenc_dsp_init_riscv(s); #elif ARCH_X86 ff_aacenc_dsp_init_x86(s); +#elif ARCH_AARCH64 + ff_aacenc_dsp_init_aarch64(s); #endif } diff --git a/libavcodec/aacenctab.c b/libavcodec/aacenctab.c index 874365a593..fd40e076e2 100644 --- a/libavcodec/aacenctab.c +++ b/libavcodec/aacenctab.c @@ -25,9 +25,7 @@ static const uint8_t swb_size_128_96[] = { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 }; -static const uint8_t swb_size_128_64[] = { - 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 -}; +#define swb_size_128_64 swb_size_128_96 static const uint8_t swb_size_128_48[] = { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 @@ -103,6 +101,3 @@ const uint8_t *const ff_aac_swb_size_1024[] = { swb_size_1024_16, swb_size_1024_16, swb_size_1024_8, swb_size_1024_8 }; - -const int ff_aac_swb_size_128_len = FF_ARRAY_ELEMS(ff_aac_swb_size_128); -const int ff_aac_swb_size_1024_len = FF_ARRAY_ELEMS(ff_aac_swb_size_1024); diff --git a/libavcodec/aacenctab.h b/libavcodec/aacenctab.h index f2d6f597bc..fee9c245d8 100644 --- a/libavcodec/aacenctab.h +++ b/libavcodec/aacenctab.h @@ -41,9 +41,7 @@ #define AAC_MAX_CHANNELS 16 extern const uint8_t *const ff_aac_swb_size_1024[]; -extern const int ff_aac_swb_size_1024_len; extern const uint8_t *const ff_aac_swb_size_128[]; -extern const int ff_aac_swb_size_128_len; /* Supported layouts without using a PCE */ static const AVChannelLayout aac_normal_chan_layouts[7] = { @@ -125,9 +123,7 @@ static const unsigned char aac_maxval_cb[] = { }; static const int aacenc_profiles[] = { - AV_PROFILE_AAC_MAIN, AV_PROFILE_AAC_LOW, - AV_PROFILE_AAC_LTP, AV_PROFILE_MPEG2_AAC_LOW, }; diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c index 019be09fa3..ed03cb68ac 100644 --- a/libavcodec/aacpsy.c +++ b/libavcodec/aacpsy.c @@ -168,7 +168,7 @@ typedef struct AacPsyContext{ * LAME psy model preset struct */ typedef struct PsyLamePreset { - int quality; ///< Quality to map the rest of the vaules to. + int quality; ///< Quality to map the rest of the values to. /* This is overloaded to be both kbps per channel in ABR mode, and * requested quality in constant quality mode. */ @@ -593,7 +593,6 @@ static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr, return thr; } -#ifndef calc_thr_3gpp static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsyChannel *pch, const uint8_t *band_sizes, const float *coefs, const int cutoff) { @@ -622,9 +621,7 @@ static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsy } } } -#endif /* calc_thr_3gpp */ -#ifndef psy_hp_filter static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_fir_coeffs) { int i, j; @@ -641,7 +638,6 @@ static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_ hpfsmpl[i] = (sum1 + sum2) * 32768.0f; } } -#endif /* psy_hp_filter */ /** * Calculate band thresholds as suggested in 3GPP TS26.403 diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c index 436b549fe7..3c39da509d 100644 --- a/libavcodec/aacsbr_template.c +++ b/libavcodec/aacsbr_template.c @@ -59,7 +59,7 @@ static void sbr_turnoff(SpectralBandReplication *sbr) { sbr->start = 0; sbr->usac = 0; sbr->ready_for_dequant = 0; - // Init defults used in pure upsampling mode + // Init defaults used in pure upsampling mode sbr->kx[1] = 32; //Typo in spec, kx' inits to 32 sbr->m[1] = 0; // Reset values for first SBR header @@ -599,6 +599,7 @@ static int sbr_make_f_derived(AACDecContext *ac, SpectralBandReplication *sbr) if (sbr->n_q > 5) { av_log(ac->avctx, AV_LOG_ERROR, "Too many noise floor scale factors: %d\n", sbr->n_q); + sbr->n_q = 1; return -1; } @@ -1625,6 +1626,9 @@ static void sbr_env_estimate(AAC_FLOAT (*e_curr)[48], INTFLOAT X_high[64][40][2] int ilb = ch_data->t_env[e] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; int iub = ch_data->t_env[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; + if (ilb >= 40) + return; + for (m = 0; m < sbr->m[1]; m++) { AAC_FLOAT sum = sbr->dsp.sum_square(X_high[m+kx1] + ilb, iub - ilb); #if USE_FIXED @@ -1643,6 +1647,9 @@ static void sbr_env_estimate(AAC_FLOAT (*e_curr)[48], INTFLOAT X_high[64][40][2] int iub = ch_data->t_env[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; const uint16_t *table = ch_data->bs_freq_res[e + 1] ? sbr->f_tablehigh : sbr->f_tablelow; + if (ilb >= 40) + return; + for (p = 0; p < sbr->n[ch_data->bs_freq_res[e + 1]]; p++) { #if USE_FIXED SoftFloat sum = FLOAT_0; diff --git a/libavcodec/aacsbrdata.h b/libavcodec/aacsbrdata.h index 9c25098240..996e557059 100644 --- a/libavcodec/aacsbrdata.h +++ b/libavcodec/aacsbrdata.h @@ -41,7 +41,7 @@ static const int8_t sbr_offset[6][16] = { {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}, // 64000 Hz < fs_sbr }; -///< window coefficients for analysis/synthesis QMF banks +/// window coefficients for analysis/synthesis QMF banks static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320] = { Q31( 0.0000000000f), Q31(-0.0005617692f), Q31(-0.0004875227f), Q31(-0.0005040714f), diff --git a/libavcodec/aactab.c b/libavcodec/aactab.c index 8d4587d241..128bacfdf1 100644 --- a/libavcodec/aactab.c +++ b/libavcodec/aactab.c @@ -170,10 +170,6 @@ const uint8_t ff_aac_num_swb_128[] = { 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 }; -const uint8_t ff_aac_num_swb_120[] = { - 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 -}; - const uint8_t ff_aac_num_swb_96[] = { 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14 }; @@ -1838,13 +1834,7 @@ static const uint16_t swb_offset_768_48[] = 544, 576, 608, 640, 672, 704, 736, 768 }; -static const uint16_t swb_offset_768_32[] = -{ - 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, - 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, - 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, - 544, 576, 608, 640, 672, 704, 736, 768 -}; +#define swb_offset_768_32 swb_offset_768_48 static const uint16_t swb_offset_768_24[] = { @@ -3884,31 +3874,6 @@ const DECLARE_ALIGNED(32, int, ff_aac_eld_window_480_fixed)[1800] = { 0xffedebe1, 0xffee287d, 0xffee654e, 0xffeea23f, }; -/* As specified by ISO/IEC 23003 */ -#define USAC_EMPH_COEFF 0.68 - -DECLARE_ALIGNED(16, const float, ff_aac_deemph_weights)[16] = { - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - 0, - USAC_EMPH_COEFF, - USAC_EMPH_COEFF*USAC_EMPH_COEFF, - - 0, - 0, - 0, - USAC_EMPH_COEFF, -}; - const int ff_aac_usac_samplerate[32] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, -1, -1, 57600, @@ -3936,12 +3901,3 @@ const float ff_aac_usac_mdst_filt_cur[4 /* Window */][4 /* Shape */][7] = { 0.207421, 0.001416, 0.635010, 0.000000, -0.635010, -0.001416, -0.207421 }, { 0.207421, -0.001416, 0.635010, 0.000000, -0.635010, 0.001416, -0.207421 } } }; - -/* Window type (everything/longstop+stopstart), sine or kbd */ -const float ff_aac_usac_mdst_filt_prev[2 /* Window */][2 /* sine/kbd */][7] = -{ - { { 0.000000, 0.106103, 0.250000, 0.318310, 0.250000, 0.106103, 0.000000 }, - { 0.059509, 0.123714, 0.186579, 0.213077, 0.186579, 0.123714, 0.059509 } }, - { { 0.038498, 0.039212, 0.039645, 0.039790, 0.039645, 0.039212, 0.038498 }, - { 0.026142, 0.026413, 0.026577, 0.026631, 0.026577, 0.026413, 0.026142 } } -}; diff --git a/libavcodec/aactab.h b/libavcodec/aactab.h index 84879aa8f8..e7dbbf1ecd 100644 --- a/libavcodec/aactab.h +++ b/libavcodec/aactab.h @@ -64,8 +64,6 @@ DECLARE_ALIGNED(32, extern const float, ff_aac_eld_window_480)[1800]; DECLARE_ALIGNED(32, extern const int, ff_aac_eld_window_480_fixed)[1800]; // @} -extern const float ff_aac_deemph_weights[16]; - /* Initializes data shared between float decoder and encoder. */ void ff_aac_float_common_init(void); @@ -78,7 +76,7 @@ extern const uint8_t ff_aac_num_swb_768 []; extern const uint8_t ff_aac_num_swb_512 []; extern const uint8_t ff_aac_num_swb_480 []; extern const uint8_t ff_aac_num_swb_128 []; -extern const uint8_t ff_aac_num_swb_120 []; +#define ff_aac_num_swb_120 ff_aac_num_swb_128 extern const uint8_t ff_aac_num_swb_96 []; // @} @@ -125,7 +123,5 @@ extern const int ff_aac_usac_samplerate[32]; /* Window type (only long+eight, start/stop/stopstart), sine+sine, kbd+kbd, sine+kbd, kbd+sine */ extern const float ff_aac_usac_mdst_filt_cur[4 /* Window */][4 /* Shape */][7]; -/* Window type (everything/longstop+stopstart), sine or kbd */ -extern const float ff_aac_usac_mdst_filt_prev[2 /* Window */][2 /* sine/kbd */][7]; #endif /* AVCODEC_AACTAB_H */ diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile index 9affb92789..2bf48dfa28 100644 --- a/libavcodec/aarch64/Makefile +++ b/libavcodec/aarch64/Makefile @@ -10,7 +10,7 @@ OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_init_aarch64.o OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o -OBJS-$(CONFIG_MPEGVIDEOENC) += aarch64/mpegvideoencdsp_init.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += aarch64/mpegvideoencdsp_init.o OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_init_aarch64.o OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o @@ -19,6 +19,7 @@ OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_init_aarch64.o # decoders/encoders OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_init_aarch64.o \ aarch64/sbrdsp_init_aarch64.o +OBJS-$(CONFIG_AAC_ENCODER) += aarch64/aacencdsp_init.o OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_init.o OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_init.o OBJS-$(CONFIG_RV40_DECODER) += aarch64/rv40dsp_init_aarch64.o @@ -38,6 +39,7 @@ ARMV8-OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp.o # subsystems NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/sbrdsp_neon.o +NEON-OBJS-$(CONFIG_AAC_ENCODER) += aarch64/aacencdsp_neon.o NEON-OBJS-$(CONFIG_AC3DSP) += aarch64/ac3dsp_neon.o NEON-OBJS-$(CONFIG_FDCTDSP) += aarch64/fdctdsp_neon.o NEON-OBJS-$(CONFIG_FMTCONVERT) += aarch64/fmtconvert_neon.o @@ -52,7 +54,7 @@ NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ aarch64/simple_idct_neon.o NEON-OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_neon.o NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o -NEON-OBJS-$(CONFIG_MPEGVIDEOENC) += aarch64/mpegvideoencdsp_neon.o +NEON-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += aarch64/mpegvideoencdsp_neon.o NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o diff --git a/libpostproc/version.c b/libavcodec/aarch64/aacencdsp_init.c similarity index 57% rename from libpostproc/version.c rename to libavcodec/aarch64/aacencdsp_init.c index 304abe08e6..23498e7891 100644 --- a/libpostproc/version.c +++ b/libavcodec/aarch64/aacencdsp_init.c @@ -1,5 +1,5 @@ /* - * Version functions. + * Copyright (c) 2025 Krzysztof Aleksander Pyrkosz * * This file is part of FFmpeg. * @@ -18,28 +18,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include "config.h" -#include "postprocess.h" -#include "version.h" -#include "libavutil/ffversion.h" -const char postproc_ffversion[] = "FFmpeg version " FFMPEG_VERSION; +#include "libavutil/arm/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/aacencdsp.h" -unsigned postproc_version(void) +void ff_abs_pow34_neon(float *out, const float *in, const int size); +void ff_aac_quant_bands_neon(int *, const float *, const float *, int, int, + int, const float, const float); + +av_cold void ff_aacenc_dsp_init_aarch64(AACEncDSPContext *s) { - static_assert(LIBPOSTPROC_VERSION_MICRO >= 100, "micro version starts at 100"); - return LIBPOSTPROC_VERSION_INT; -} + int cpu_flags = av_get_cpu_flags(); + if (!have_neon(cpu_flags)) return; -const char *postproc_configuration(void) -{ - return FFMPEG_CONFIGURATION; -} - -const char *postproc_license(void) -{ -#define LICENSE_PREFIX "libpostproc license: " - return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1]; + s->abs_pow34 = ff_abs_pow34_neon; + s->quant_bands = ff_aac_quant_bands_neon; } diff --git a/libavcodec/aarch64/aacencdsp_neon.S b/libavcodec/aarch64/aacencdsp_neon.S new file mode 100644 index 0000000000..14f7f667c3 --- /dev/null +++ b/libavcodec/aarch64/aacencdsp_neon.S @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Krzysztof Aleksander Pyrkosz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/aarch64/asm.S" + +function ff_abs_pow34_neon, export=1 +1: + ld1 {v0.4s}, [x1], #16 + subs w2, w2, #4 + fabs v0.4s, v0.4s + fsqrt v2.4s, v0.4s + fmul v0.4s, v2.4s, v0.4s + fsqrt v0.4s, v0.4s + st1 {v0.4s}, [x0], #16 + b.ne 1b + ret +endfunc + +function ff_aac_quant_bands_neon, export=1 + scvtf s2, w5 + dup v1.4s, v1.s[0] + dup v2.4s, v2.s[0] + cbz w4, 0f + movi v5.4s, 0x80, lsl #24 +.irp signed,1,0 +\signed: + ld1 {v3.4s}, [x2], #16 + subs w3, w3, #4 + fmul v3.4s, v3.4s, v0.s[0] +.if \signed + ld1 {v4.4s}, [x1], #16 +.endif + fadd v3.4s, v3.4s, v1.4s +.if \signed + and v4.16b, v4.16b, v5.16b +.endif + fmin v3.4s, v3.4s, v2.4s +.if \signed + eor v3.16b, v4.16b, v3.16b +.endif + fcvtzs v3.4s, v3.4s + st1 {v3.4s}, [x0], #16 + b.ne \signed\()b + ret +.endr +endfunc diff --git a/libavcodec/aarch64/ac3dsp_neon.S b/libavcodec/aarch64/ac3dsp_neon.S index 7e97cc39f7..c28e2082a9 100644 --- a/libavcodec/aarch64/ac3dsp_neon.S +++ b/libavcodec/aarch64/ac3dsp_neon.S @@ -69,21 +69,20 @@ function ff_ac3_sum_square_butterfly_int32_neon, export=1 movi v0.2d, #0 movi v1.2d, #0 movi v2.2d, #0 - movi v3.2d, #0 1: ld1 {v4.2s}, [x1], #8 ld1 {v5.2s}, [x2], #8 - add v6.2s, v4.2s, v5.2s - sub v7.2s, v4.2s, v5.2s - smlal v0.2d, v4.2s, v4.2s - smlal v1.2d, v5.2s, v5.2s - smlal v2.2d, v6.2s, v6.2s - smlal v3.2d, v7.2s, v7.2s subs w3, w3, #2 + smlal v0.2d, v4.2s, v4.2s // sum of a^2 + smlal v1.2d, v5.2s, v5.2s // sum of b^2 + sqdmlal v2.2d, v4.2s, v5.2s // sum of 2ab b.gt 1b addp d0, v0.2d addp d1, v1.2d addp d2, v2.2d - addp d3, v3.2d + sub d3, d0, d2 // a^2 + b^2 - 2ab + add d2, d0, d2 + add d3, d3, d1 // a^2 + b^2 + 2ab + add d2, d2, d1 st1 {v0.1d-v3.1d}, [x0] ret endfunc diff --git a/libavcodec/aarch64/h264pred_neon.S b/libavcodec/aarch64/h264pred_neon.S index ea37689f34..d0999938ef 100644 --- a/libavcodec/aarch64/h264pred_neon.S +++ b/libavcodec/aarch64/h264pred_neon.S @@ -502,28 +502,27 @@ function ff_pred16x16_plane_neon_10, export=1 add v7.4h, v7.4h, v0.4h shl v2.4h, v7.4h, #4 ssubl v2.4s, v2.4h, v3.4h - shl v3.4h, v4.4h, #4 ext v0.16b, v0.16b, v0.16b, #14 - ssubl v6.4s, v5.4h, v3.4h + sxtl v6.4s, v5.4h // c mov v0.h[0], wzr mul v0.8h, v0.8h, v4.h[0] dup v16.4s, v2.s[0] dup v17.4s, v2.s[0] - dup v2.8h, v4.h[0] - dup v3.4s, v6.s[0] - shl v2.8h, v2.8h, #3 + dup v2.8h, v4.h[0] // b + dup v3.4s, v6.s[0] // c + sshll v2.4s, v2.4h, #3 // b * 8 saddw v16.4s, v16.4s, v0.4h saddw2 v17.4s, v17.4s, v0.8h - saddw v3.4s, v3.4s, v2.4h + sub v3.4s, v3.4s, v2.4s mov w3, #16 mvni v4.8h, #0xFC, lsl #8 // 1023 for clipping 1: sqshrun v0.4h, v16.4s, #5 sqshrun2 v0.8h, v17.4s, #5 - saddw v16.4s, v16.4s, v2.4h - saddw v17.4s, v17.4s, v2.4h + add v16.4s, v16.4s, v2.4s + add v17.4s, v17.4s, v2.4s sqshrun v1.4h, v16.4s, #5 sqshrun2 v1.8h, v17.4s, #5 add v16.4s, v16.4s, v3.4s @@ -595,12 +594,11 @@ function ff_pred8x8_plane_neon_10, export=1 ssubl v2.4s, v2.4h, v3.4h ext v0.16b, v0.16b, v0.16b, #14 mov v0.h[0], wzr - mul v0.8h, v0.8h, v5.h[0] dup v1.4s, v2.s[0] dup v2.4s, v2.s[0] dup v3.8h, v5.h[1] - saddw v1.4s, v1.4s, v0.4h - saddw2 v2.4s, v2.4s, v0.8h + smlal v1.4s, v0.4h, v5.h[0] + smlal2 v2.4s, v0.8h, v5.h[0] mov w3, #8 mvni v4.8h, #0xFC, lsl #8 // 1023 for clipping 1: diff --git a/libavcodec/aarch64/h26x/dsp.h b/libavcodec/aarch64/h26x/dsp.h index 0fefb4d70f..6c91004301 100644 --- a/libavcodec/aarch64/h26x/dsp.h +++ b/libavcodec/aarch64/h26x/dsp.h @@ -28,6 +28,10 @@ void ff_h26x_sao_band_filter_8x8_8_neon(uint8_t *_dst, const uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, const int16_t *sao_offset_val, int sao_left_class, int width, int height); +void ff_h26x_sao_band_filter_16x16_8_neon(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, + const int16_t *sao_offset_val, int sao_left_class, + int width, int height); void ff_hevc_sao_edge_filter_16x16_8_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, const int16_t *sao_offset_val, int eo, int width, int height); void ff_hevc_sao_edge_filter_8x8_8_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, @@ -88,6 +92,11 @@ NEON8_FNPROTO(pel_bi_pixels, (uint8_t *dst, ptrdiff_t dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width),); +NEON8_FNPROTO(pel_bi_w_pixels, (uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, + int height, int denom, int wx0, int wx1, + int ox0, int ox1, intptr_t mx, intptr_t my, int width),); + NEON8_FNPROTO(epel_bi_h, (uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width),); diff --git a/libavcodec/aarch64/h26x/epel_neon.S b/libavcodec/aarch64/h26x/epel_neon.S index e44a448b1f..4cf6339171 100644 --- a/libavcodec/aarch64/h26x/epel_neon.S +++ b/libavcodec/aarch64/h26x/epel_neon.S @@ -473,6 +473,379 @@ function ff_hevc_put_hevc_pel_bi_pixels64_8_neon, export=1 ret endfunc +.macro load_bi_w_pixels_param + ldrsw x8, [sp] // wx1 +#if defined(__APPLE__) + ldpsw x9, x10, [sp, #4] // ox0, ox1 + ldrsw x11, [sp, #32] // width +#else + ldrsw x9, [sp, #8] // ox0 + ldrsw x10, [sp, #16] // ox1 + ldrsw x11, [sp, 40] // width +#endif +.endm + +function ff_hevc_put_hevc_pel_bi_w_pixels4_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8b}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + sshl v3.4s, v3.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtun v3.8b, v3.8h + st1 {v3.s}[0], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels6_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x1, x1, #4 +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8h}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + mov v7.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + smlal2 v7.4s, v4.8h, v1.8h + smlal2 v7.4s, v5.8h, v0.8h + sshl v3.4s, v3.4s, v6.4s + sshl v7.4s, v7.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtn2 v3.8h, v7.4s + sqxtun v3.8b, v3.8h + str s3, [x0], #4 + st1 {v3.h}[2], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels8_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v4.8b}, [x2], x3 // load src + ld1 {v5.8h}, [x4], x8 // load src2 + subs w5, w5, #1 + mov v3.16b, v2.16b + mov v7.16b, v2.16b + ushll v4.8h, v4.8b, #6 + smlal v3.4s, v4.4h, v1.4h + smlal v3.4s, v5.4h, v0.4h + smlal2 v7.4s, v4.8h, v1.8h + smlal2 v7.4s, v5.8h, v0.8h + sshl v3.4s, v3.4s, v6.4s + sshl v7.4s, v7.4s, v6.4s + sqxtn v3.4h, v3.4s + sqxtn2 v3.8h, v7.4s + sqxtun v3.8b, v3.8h + st1 {v3.8b}, [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels12_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x1, x1, #8 +1: + ld1 {v24.16b}, [x2], x3 // load src + ld1 {v20.16b, v21.16b}, [x4], x8 // load src2 + subs w5, w5, #1 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + str d3, [x0], #8 + st1 {v3.s}[2], [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels16_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) +1: + ld1 {v24.16b}, [x2], x3 // load src + ld1 {v20.16b, v21.16b}, [x4], x8 // load src2 + subs w5, w5, #1 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + st1 {v3.16b}, [x0], x1 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels24_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + mov x7, #24 + sub x3, x3, x11 + sub x8, x8, x11, lsl #1 + sub x1, x1, x11 +1: + mov w6, w11 +2: + ld1 {v24.16b, v25.16b}, [x2], x7 + ld1 {v20.8h, v21.8h, v22.8h}, [x4], #48 + + subs w6, w6, #24 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + mov v26.16b, v2.16b + mov v27.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + ushll v5.8h, v25.8b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + smlal v26.4s, v5.4h, v1.4h + smlal v26.4s, v22.4h, v0.4h + smlal2 v27.4s, v5.8h, v1.8h + smlal2 v27.4s, v22.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + sshl v26.4s, v26.4s, v6.4s + sshl v27.4s, v27.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtn v26.4h, v26.4s + sqxtn2 v26.8h, v27.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + sqxtun v4.8b, v26.8h + str q3, [x0], #16 + str d4, [x0], #8 + b.ne 2b + + subs w5, w5, #1 + add x0, x0, x1 + add x2, x2, x3 + add x4, x4, x8 + b.ne 1b + ret +endfunc + +function ff_hevc_put_hevc_pel_bi_w_pixels32_8_neon, export=1 + load_bi_w_pixels_param + add w6, w6, #6 // log2Wd + dup v0.8h, w7 // wx0 + dup v1.8h, w8 // wx1 + add w9, w9, w10 + add w9, w9, #1 // ox0 + ox1 + 1 + lsl w9, w9, w6 + add w7, w6, #1 // (log2Wd + 1) + mov x8, #(2 * HEVC_MAX_PB_SIZE) + neg w7, w7 + dup v2.4s, w9 // (ox0 + ox1 + 1) << logwWd + dup v6.4s, w7 // -(log2Wd + 1) + sub x3, x3, x11 + sub x8, x8, x11, lsl #1 + sub x1, x1, x11 +1: + mov w6, w11 +2: + ld1 {v24.16b, v25.16b}, [x2], #32 // load src + ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [x4], #64 // load src2 + + subs w6, w6, #32 + + mov v16.16b, v2.16b + mov v17.16b, v2.16b + mov v18.16b, v2.16b + mov v19.16b, v2.16b + mov v26.16b, v2.16b + mov v27.16b, v2.16b + mov v28.16b, v2.16b + mov v29.16b, v2.16b + + ushll v4.8h, v24.8b, #6 + ushll2 v24.8h, v24.16b, #6 + ushll v5.8h, v25.8b, #6 + ushll2 v25.8h, v25.16b, #6 + + smlal v16.4s, v4.4h, v1.4h + smlal v16.4s, v20.4h, v0.4h + smlal2 v17.4s, v4.8h, v1.8h + smlal2 v17.4s, v20.8h, v0.8h + smlal v18.4s, v24.4h, v1.4h + smlal v18.4s, v21.4h, v0.4h + smlal2 v19.4s, v24.8h, v1.8h + smlal2 v19.4s, v21.8h, v0.8h + smlal v26.4s, v5.4h, v1.4h + smlal v26.4s, v22.4h, v0.4h + smlal2 v27.4s, v5.8h, v1.8h + smlal2 v27.4s, v22.8h, v0.8h + smlal v28.4s, v25.4h, v1.4h + smlal v28.4s, v23.4h, v0.4h + smlal2 v29.4s, v25.8h, v1.8h + smlal2 v29.4s, v23.8h, v0.8h + + sshl v16.4s, v16.4s, v6.4s + sshl v17.4s, v17.4s, v6.4s + sshl v18.4s, v18.4s, v6.4s + sshl v19.4s, v19.4s, v6.4s + sshl v26.4s, v26.4s, v6.4s + sshl v27.4s, v27.4s, v6.4s + sshl v28.4s, v28.4s, v6.4s + sshl v29.4s, v29.4s, v6.4s + + sqxtn v16.4h, v16.4s + sqxtn2 v16.8h, v17.4s + sqxtn v18.4h, v18.4s + sqxtn2 v18.8h, v19.4s + sqxtn v26.4h, v26.4s + sqxtn2 v26.8h, v27.4s + sqxtn v28.4h, v28.4s + sqxtn2 v28.8h, v29.4s + sqxtun v3.8b, v16.8h + sqxtun2 v3.16b, v18.8h + sqxtun v4.8b, v26.8h + sqxtun2 v4.16b, v28.8h + st1 {v3.16b, v4.16b}, [x0], #32 + b.ne 2b + + subs w5, w5, #1 + add x0, x0, x1 + add x2, x2, x3 + add x4, x4, x8 + b.ne 1b + ret +endfunc function ff_hevc_put_hevc_epel_bi_h4_8_neon, export=1 load_epel_filterb x6, x7 diff --git a/libavcodec/aarch64/h26x/qpel_neon.S b/libavcodec/aarch64/h26x/qpel_neon.S index 5c3f0263b6..f5aa266ab5 100644 --- a/libavcodec/aarch64/h26x/qpel_neon.S +++ b/libavcodec/aarch64/h26x/qpel_neon.S @@ -4141,9 +4141,9 @@ DISABLE_I8MM #endif function vvc_put_qpel_hv4_8_end_neon - vvc_load_qpel_filterh x5 - mov x7, #(VVC_MAX_PB_SIZE * 2) - b 1f + vvc_load_qpel_filterh x5 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f endfunc function hevc_put_hevc_qpel_hv4_8_end_neon diff --git a/libavcodec/aarch64/h26x/sao_neon.S b/libavcodec/aarch64/h26x/sao_neon.S index c43820135e..354614ecab 100644 --- a/libavcodec/aarch64/h26x/sao_neon.S +++ b/libavcodec/aarch64/h26x/sao_neon.S @@ -35,48 +35,67 @@ // int16_t *sao_offset_val, int sao_left_class, // int width, int height) function ff_h26x_sao_band_filter_8x8_8_neon, export=1 - stp xzr, xzr, [sp, #-64]! + stp xzr, xzr, [sp, #-32]! stp xzr, xzr, [sp, #16] - stp xzr, xzr, [sp, #32] - stp xzr, xzr, [sp, #48] mov w8, #4 -0: ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] - subs w8, w8, #1 - add w10, w8, w5 // k + sao_left_class +0: + ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] + subs w8, w8, #1 + add w10, w8, w5 // k + sao_left_class and w10, w10, #0x1F - strh w9, [sp, x10, lsl #1] + strb w9, [sp, x10] bne 0b - add w6, w6, #7 - bic w6, w6, #7 - ld1 {v16.16b-v19.16b}, [sp], #64 - sub x2, x2, x6 - sub x3, x3, x6 - movi v20.8h, #1 -1: mov w8, w6 // beginning of line -2: // Simple layout for accessing 16bit values - // with 8bit LUT. - // - // 00 01 02 03 04 05 06 07 - // +-----------------------------------> - // |xDE#xAD|xCA#xFE|xBE#xEF|xFE#xED|.... - // +-----------------------------------> - // i-0 i-1 i-2 i-3 - ld1 {v2.8b}, [x1], #8 // dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]); - subs w8, w8, #8 - uxtl v0.8h, v2.8b // load src[x] - ushr v2.8h, v0.8h, #3 // >> BIT_DEPTH - 3 - shl v1.8h, v2.8h, #1 // low (x2, accessing short) - add v3.8h, v1.8h, v20.8h // +1 access upper short - sli v1.8h, v3.8h, #8 // shift insert index to upper byte - tbx v2.16b, {v16.16b-v19.16b}, v1.16b // table - add v1.8h, v0.8h, v2.8h // src[x] + table - sqxtun v4.8b, v1.8h // clip + narrow - st1 {v4.8b}, [x0], #8 // store - // done 8 pixels + ldp q16, q17, [sp], #32 +1: + ld1 {v2.8b}, [x1], x3 + subs w7, w7, #1 + uxtl v0.8h, v2.8b + ushr v3.8b, v2.8b, #3 // >> BIT_DEPTH - 3 + tbl v3.8b, {v16.16b-v17.16b}, v3.8b + sxtl v2.8h, v3.8b + add v0.8h, v0.8h, v2.8h // src[x] + table + sqxtun v0.8b, v0.8h // clip + narrow + st1 {v0.8b}, [x0], x2 + bne 1b + ret +endfunc + +function ff_h26x_sao_band_filter_16x16_8_neon, export=1 + stp xzr, xzr, [sp, #-32]! + stp xzr, xzr, [sp, #16] + mov w8, #4 +0: + ldrsh x9, [x4, x8, lsl #1] // sao_offset_val[k+1] + subs w8, w8, #1 + add w10, w8, w5 // k + sao_left_class + and w10, w10, #0x1F + strb w9, [sp, x10] + bne 0b + add w6, w6, #15 + bic w6, w6, #15 + ldp q16, q17, [sp], #32 + sub x2, x2, x6 + sub x3, x3, x6 +1: + mov w8, w6 // beginning of line +2: + ldr q2, [x1], #16 + subs w8, w8, #16 + uxtl v0.8h, v2.8b + uxtl2 v1.8h, v2.16b + ushr v3.16b, v2.16b, #3 // >> BIT_DEPTH - 3 + tbl v3.16b, {v16.16b-v17.16b}, v3.16b + sxtl v2.8h, v3.8b + sxtl2 v3.8h, v3.16b + add v0.8h, v0.8h, v2.8h // src[x] + table + add v1.8h, v1.8h, v3.8h + sqxtun v0.8b, v0.8h // clip + narrow + sqxtun2 v0.16b, v1.8h + str q0, [x0], #16 bne 2b - subs w7, w7, #1 // finished line, prep. new - add x0, x0, x2 // dst += stride_dst - add x1, x1, x3 // src += stride_src + subs w7, w7, #1 + add x0, x0, x2 // dst += stride_dst + add x1, x1, x3 // src += stride_src bne 1b ret endfunc diff --git a/libavcodec/aarch64/hevcdsp_idct_neon.S b/libavcodec/aarch64/hevcdsp_idct_neon.S index 3cac6e6db9..954ce2407a 100644 --- a/libavcodec/aarch64/hevcdsp_idct_neon.S +++ b/libavcodec/aarch64/hevcdsp_idct_neon.S @@ -888,51 +888,65 @@ function ff_hevc_transform_luma_4x4_neon_8, export=1 ret endfunc +.macro idct_8x8_dc_store offset +.irp i, 0x0, 0x20, 0x40, 0x60 + stp q0, q0, [x0, #(\offset + \i)] +.endr +.endm + +.macro idct_16x16_dc_store +.irp index, 0x0, 0x80, 0x100, 0x180 + idct_8x8_dc_store offset=\index +.endr +.endm + // void ff_hevc_idct_NxN_dc_DEPTH_neon(int16_t *coeffs) -.macro idct_dc size, bitdepth -function ff_hevc_idct_\size\()x\size\()_dc_\bitdepth\()_neon, export=1 - ld1r {v4.8h}, [x0] - srshr v4.8h, v4.8h, #1 - srshr v0.8h, v4.8h, #(14 - \bitdepth) - srshr v1.8h, v4.8h, #(14 - \bitdepth) -.if \size > 4 - srshr v2.8h, v4.8h, #(14 - \bitdepth) - srshr v3.8h, v4.8h, #(14 - \bitdepth) -.if \size > 16 /* dc 32x32 */ - mov x2, #4 +.macro idct_dc size +function ff_hevc_idct_\size\()x\size\()_dc_10_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 10)) + asr w1, w1, #(14 - 10) + b 2f +endfunc + +function ff_hevc_idct_\size\()x\size\()_dc_12_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 12)) + asr w1, w1, #(14 - 12) + b 2f +endfunc + +function ff_hevc_idct_\size\()x\size\()_dc_8_neon, export=1 + ldrsh w1, [x0] + add w1, w1, #1 + asr w1, w1, #1 + add w1, w1, #(1 << (13 - 8)) + asr w1, w1, #(14 - 8) +2: + dup v0.8h, w1 +.if \size < 8 + stp q0, q0, [x0] +.elseif \size < 16 + idct_8x8_dc_store 0x0 +.elseif \size < 32 + idct_16x16_dc_store +.else + add x2, x0, #(32 * 32 * 2) 1: - subs x2, x2, #1 -.endif - add x12, x0, #64 - mov x13, #128 -.if \size > 8 /* dc 16x16 */ - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 -.endif /* dc 8x8 */ - st1 {v0.8h-v3.8h}, [x0], x13 - st1 {v0.8h-v3.8h}, [x12], x13 -.if \size > 16 /* dc 32x32 */ - bne 1b -.endif -.else /* dc 4x4 */ - st1 {v0.8h-v1.8h}, [x0] + idct_16x16_dc_store + add x0, x0, #(16 * 16 * 2) + cmp x0, x2 + b.lt 1b .endif ret endfunc .endm -idct_dc 4, 8 -idct_dc 4, 10 - -idct_dc 8, 8 -idct_dc 8, 10 - -idct_dc 16, 8 -idct_dc 16, 10 - -idct_dc 32, 8 -idct_dc 32, 10 +idct_dc 4 +idct_dc 8 +idct_dc 16 +idct_dc 32 diff --git a/libavcodec/aarch64/hevcdsp_init_aarch64.c b/libavcodec/aarch64/hevcdsp_init_aarch64.c index 386d7c59c8..8dec58bc7f 100644 --- a/libavcodec/aarch64/hevcdsp_init_aarch64.c +++ b/libavcodec/aarch64/hevcdsp_init_aarch64.c @@ -91,6 +91,10 @@ 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_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_12_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_12_neon(int16_t *coeffs); void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); #define NEON8_FNASSIGN(member, v, h, fn, ext) \ @@ -130,6 +134,17 @@ void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); member[7][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; \ member[9][v][h] = ff_hevc_put_hevc_##fn##64_8_neon##ext; +#define NEON8_FNASSIGN_PARTIAL_6(member, v, h, fn, ext) \ + member[1][v][h] = ff_hevc_put_hevc_##fn##4_8_neon##ext; \ + member[2][v][h] = ff_hevc_put_hevc_##fn##6_8_neon##ext; \ + member[3][v][h] = ff_hevc_put_hevc_##fn##8_8_neon##ext; \ + member[4][v][h] = ff_hevc_put_hevc_##fn##12_8_neon##ext; \ + member[5][v][h] = ff_hevc_put_hevc_##fn##16_8_neon##ext; \ + member[6][v][h] = ff_hevc_put_hevc_##fn##24_8_neon##ext; \ + member[7][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; \ + member[8][v][h] = ff_hevc_put_hevc_##fn##24_8_neon##ext; \ + member[9][v][h] = ff_hevc_put_hevc_##fn##32_8_neon##ext; + av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) { int cpu_flags = av_get_cpu_flags(); @@ -153,11 +168,11 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_neon; c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_neon; c->transform_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; - c->sao_band_filter[0] = + c->sao_band_filter[0] = ff_h26x_sao_band_filter_8x8_8_neon; c->sao_band_filter[1] = c->sao_band_filter[2] = c->sao_band_filter[3] = - c->sao_band_filter[4] = ff_h26x_sao_band_filter_8x8_8_neon; + c->sao_band_filter[4] = ff_h26x_sao_band_filter_16x16_8_neon; c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_8_neon; c->sao_edge_filter[1] = c->sao_edge_filter[2] = @@ -200,6 +215,8 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) NEON8_FNASSIGN(c->put_hevc_epel_bi, 1, 0, epel_bi_v,); NEON8_FNASSIGN(c->put_hevc_qpel_bi, 0, 0, pel_bi_pixels,); NEON8_FNASSIGN(c->put_hevc_qpel_bi, 1, 0, qpel_bi_v,); + NEON8_FNASSIGN_PARTIAL_6(c->put_hevc_qpel_bi_w, 0, 0, pel_bi_w_pixels,); + NEON8_FNASSIGN_PARTIAL_6(c->put_hevc_epel_bi_w, 0, 0, pel_bi_w_pixels,); NEON8_FNASSIGN(c->put_hevc_epel_uni, 0, 0, pel_uni_pixels,); NEON8_FNASSIGN(c->put_hevc_epel_uni, 1, 0, epel_uni_v,); NEON8_FNASSIGN(c->put_hevc_qpel_uni, 0, 0, pel_uni_pixels,); @@ -267,5 +284,9 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) c->add_residual[1] = ff_hevc_add_residual_8x8_12_neon; c->add_residual[2] = ff_hevc_add_residual_16x16_12_neon; c->add_residual[3] = ff_hevc_add_residual_32x32_12_neon; + c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_neon; } } diff --git a/libavcodec/aarch64/me_cmp_init_aarch64.c b/libavcodec/aarch64/me_cmp_init_aarch64.c index fa2724403d..dac6676886 100644 --- a/libavcodec/aarch64/me_cmp_init_aarch64.c +++ b/libavcodec/aarch64/me_cmp_init_aarch64.c @@ -21,66 +21,66 @@ #include "config.h" #include "libavutil/attributes.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" -int ff_pix_abs16_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_xy2_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_xy2_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_neon(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs8_neon(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int sse16_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse16_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int sse8_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse8_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int sse4_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse4_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int vsad16_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsad16_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsad_intra16_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsad_intra16_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h) ; -int vsad_intra8_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsad_intra8_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h) ; -int vsse16_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse16_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse_intra16_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsse_intra16_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); int nsse16_neon(int multiplier, const uint8_t *s, const uint8_t *s2, ptrdiff_t stride, int h); -int nsse16_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse16_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int pix_median_abs16_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int pix_median_abs16_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int pix_median_abs8_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int pix_median_abs8_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_xy2_neon(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_neon(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); int nsse8_neon(int multiplier, const uint8_t *s, const uint8_t *s2, ptrdiff_t stride, int h); -int nsse8_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse8_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse8_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse8_neon(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int vsse_intra8_neon(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, +int vsse_intra8_neon(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); #if HAVE_DOTPROD -int sse16_neon_dotprod(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int sse16_neon_dotprod(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int vsse_intra16_neon_dotprod(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int vsse_intra16_neon_dotprod(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); #endif @@ -129,20 +129,20 @@ av_cold void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx) #endif } -int nsse16_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse16_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return nsse16_neon(c->avctx->nsse_weight, s1, s2, stride, h); + return nsse16_neon(c->c.avctx->nsse_weight, s1, s2, stride, h); else return nsse16_neon(8, s1, s2, stride, h); } -int nsse8_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +int nsse8_neon_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return nsse8_neon(c->avctx->nsse_weight, s1, s2, stride, h); + return nsse8_neon(c->c.avctx->nsse_weight, s1, s2, stride, h); else return nsse8_neon(8, s1, s2, stride, h); } diff --git a/libavcodec/aarch64/me_cmp_neon.S b/libavcodec/aarch64/me_cmp_neon.S index 20e3b33a83..efa28a77ac 100644 --- a/libavcodec/aarch64/me_cmp_neon.S +++ b/libavcodec/aarch64/me_cmp_neon.S @@ -534,7 +534,7 @@ function ff_pix_abs16_y2_neon, export=1 ld1 {v2.16b}, [x2], x3 // Load pix3 for first iteration ld1 {v0.16b}, [x1], x3 // Load pix1 for first iteration urhadd v30.16b, v1.16b, v2.16b // Rounding halving add, first iteration - ld1 {v5.16b}, [x2], x3 // Load pix3 for second iteartion + ld1 {v5.16b}, [x2], x3 // Load pix3 for second iteration uabal v29.8h, v0.8b, v30.8b // Absolute difference of lower half, first iteration uabal2 v28.8h, v0.16b, v30.16b // Absolute difference of upper half, first iteration ld1 {v3.16b}, [x1], x3 // Load pix1 for second iteration @@ -606,7 +606,7 @@ function sse16_neon, export=1 uabd v27.16b, v2.16b, v3.16b // Absolute difference, second iteration uadalp v17.4s, v29.8h // Pairwise add, first iteration ld1 {v4.16b}, [x1], x3 // Load pix1 for third iteration - umull v26.8h, v27.8b, v27.8b // Mulitply lower half, second iteration + umull v26.8h, v27.8b, v27.8b // Multiply lower half, second iteration umull2 v25.8h, v27.16b, v27.16b // Multiply upper half, second iteration ld1 {v5.16b}, [x2], x3 // Load pix2 for third iteration uadalp v17.4s, v26.8h // Pairwise add and accumulate, second iteration @@ -616,7 +616,7 @@ function sse16_neon, export=1 umull v23.8h, v24.8b, v24.8b // Multiply lower half, third iteration umull2 v22.8h, v24.16b, v24.16b // Multiply upper half, third iteration uadalp v17.4s, v23.8h // Pairwise add and accumulate, third iteration - ld1 {v7.16b}, [x2], x3 // Load pix2 for fouth iteration + ld1 {v7.16b}, [x2], x3 // Load pix2 for fourth iteration uadalp v17.4s, v22.8h // Pairwise add and accumulate, third iteration uabd v21.16b, v6.16b, v7.16b // Absolute difference, fourth iteration uadalp v17.4s, v28.8h // Pairwise add and accumulate, first iteration @@ -748,7 +748,7 @@ function sse4_neon, export=1 uabdl v28.8h, v4.8b, v5.8b // Absolute difference, third iteration umlal v16.4s, v29.4h, v29.4h // Multiply and accumulate, second iteration sub w4, w4, #4 - uabdl v27.8h, v6.8b, v7.8b // Absolue difference, fourth iteration + uabdl v27.8h, v6.8b, v7.8b // Absolute difference, fourth iteration umlal v16.4s, v28.4h, v28.4h // Multiply and accumulate, third iteration cmp w4, #4 umlal v16.4s, v27.4h, v27.4h // Multiply and accumulate, fourth iteration @@ -1593,7 +1593,7 @@ function sse16_neon_dotprod, export=1 uabd v24.16b, v4.16b, v5.16b // Absolute difference, third iteration ld1 {v6.16b}, [x1], x3 // Load pix1 for fourth iteration udot v17.4s, v24.16b, v24.16b - ld1 {v7.16b}, [x2], x3 // Load pix2 for fouth iteration + ld1 {v7.16b}, [x2], x3 // Load pix2 for fourth iteration uabd v21.16b, v6.16b, v7.16b // Absolute difference, fourth iteration sub w4, w4, #4 // h -= 4 udot v17.4s, v21.16b, v21.16b diff --git a/libavcodec/aarch64/opusdsp_neon.S b/libavcodec/aarch64/opusdsp_neon.S index 253825aa61..990fc44c70 100644 --- a/libavcodec/aarch64/opusdsp_neon.S +++ b/libavcodec/aarch64/opusdsp_neon.S @@ -55,35 +55,28 @@ endfunc function ff_opus_postfilter_neon, export=1 ld1 {v0.4s}, [x2] + sub x5, x0, w1, sxtw #2 + sub x1, x5, #8 dup v1.4s, v0.s[1] dup v2.4s, v0.s[2] dup v0.4s, v0.s[0] - add w1, w1, #2 - sub x1, x0, x1, lsl #2 - - ld1 {v3.4s}, [x1] + ld1 {v3.4s}, [x1], #16 + sub x4, x5, #4 + add x6, x5, #4 fmul v3.4s, v3.4s, v2.4s -1: add x1, x1, #4 - ld1 {v4.4s}, [x1] - add x1, x1, #4 - ld1 {v5.4s}, [x1] - add x1, x1, #4 - ld1 {v6.4s}, [x1] - add x1, x1, #4 - ld1 {v7.4s}, [x1] - +1: ld1 {v7.4s}, [x1], #16 + ld1 {v4.4s}, [x4], #16 fmla v3.4s, v7.4s, v2.4s + ld1 {v6.4s}, [x6], #16 + ld1 {v5.4s}, [x5], #16 fadd v6.4s, v6.4s, v4.4s + fmla v3.4s, v5.4s, v0.4s ld1 {v4.4s}, [x0] - fmla v4.4s, v5.4s, v0.4s - - fmul v6.4s, v6.4s, v1.4s - fadd v6.4s, v6.4s, v3.4s - - fadd v4.4s, v4.4s, v6.4s + fmla v3.4s, v6.4s, v1.4s + fadd v4.4s, v4.4s, v3.4s fmul v3.4s, v7.4s, v2.4s st1 {v4.4s}, [x0], #16 diff --git a/libavcodec/aarch64/pixblockdsp_init_aarch64.c b/libavcodec/aarch64/pixblockdsp_init_aarch64.c index e4bac722f8..404f3680a6 100644 --- a/libavcodec/aarch64/pixblockdsp_init_aarch64.c +++ b/libavcodec/aarch64/pixblockdsp_init_aarch64.c @@ -21,7 +21,6 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" void ff_get_pixels_neon(int16_t *block, const uint8_t *pixels, @@ -30,7 +29,6 @@ void ff_diff_pixels_neon(int16_t *block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/aarch64/vp9mc_neon.S b/libavcodec/aarch64/vp9mc_neon.S index abf2bae9db..38f44ca56d 100644 --- a/libavcodec/aarch64/vp9mc_neon.S +++ b/libavcodec/aarch64/vp9mc_neon.S @@ -230,6 +230,9 @@ function \type\()_8tap_\size\()h_\idx1\idx2 // reduced dst stride .if \size >= 16 sub x1, x1, x5 +.elseif \size == 4 + add x12, x2, #8 + add x13, x7, #8 .endif // size >= 16 loads two qwords and increments x2, // for size 4/8 it's enough with one qword and no @@ -248,9 +251,14 @@ function \type\()_8tap_\size\()h_\idx1\idx2 .if \size >= 16 ld1 {v4.8b, v5.8b, v6.8b}, [x2], #24 ld1 {v16.8b, v17.8b, v18.8b}, [x7], #24 -.else +.elseif \size == 8 ld1 {v4.8b, v5.8b}, [x2] ld1 {v16.8b, v17.8b}, [x7] +.else // \size == 4 + ld1 {v4.8b}, [x2] + ld1 {v16.8b}, [x7] + ld1 {v5.s}[0], [x12], x3 + ld1 {v17.s}[0], [x13], x3 .endif uxtl v4.8h, v4.8b uxtl v5.8h, v5.8b diff --git a/libavcodec/aarch64/vvc/alf.S b/libavcodec/aarch64/vvc/alf.S index c624093640..8801b3afb6 100644 --- a/libavcodec/aarch64/vvc/alf.S +++ b/libavcodec/aarch64/vvc/alf.S @@ -148,7 +148,7 @@ sqxtun v20.8b, v20.8h str d20, [dst] .else - smin v20.8h, v20.8h, v25.8h + umin v20.8h, v20.8h, v25.8h str q20, [dst] .endif ret @@ -249,7 +249,7 @@ sqxtun v20.8b, v20.8h str s20, [dst] .else - smin v20.4h, v20.4h, v25.4h + umin v20.4h, v20.4h, v25.4h str d20, [dst] .endif ret diff --git a/libavcodec/aarch64/vvc/dsp_init.c b/libavcodec/aarch64/vvc/dsp_init.c index ad767d17e2..9a171234f6 100644 --- a/libavcodec/aarch64/vvc/dsp_init.c +++ b/libavcodec/aarch64/vvc/dsp_init.c @@ -27,16 +27,34 @@ #include "libavcodec/vvc/dec.h" #include "libavcodec/vvc/ctu.h" +#define BDOF_BLOCK_SIZE 16 +#define BDOF_MIN_BLOCK_SIZE 4 + +void ff_vvc_prof_grad_filter_8x_neon(int16_t *gradient_h, + int16_t *gradient_v, + ptrdiff_t gradient_stride, + const int16_t *_src, + ptrdiff_t src_stride, + int width, int height); + +void ff_vvc_derive_bdof_vx_vy_neon(const int16_t *_src0, const int16_t *_src1, + int pad_mask, + const int16_t **gradient_h, + const int16_t **gradient_v, + int16_t *vx, int16_t *vy); #define BIT_DEPTH 8 #include "alf_template.c" +#include "of_template.c" #undef BIT_DEPTH #define BIT_DEPTH 10 #include "alf_template.c" +#include "of_template.c" #undef BIT_DEPTH #define BIT_DEPTH 12 #include "alf_template.c" +#include "of_template.c" #undef BIT_DEPTH int ff_vvc_sad_neon(const int16_t *src0, const int16_t *src1, int dx, int dy, @@ -52,6 +70,50 @@ void ff_vvc_avg_12_neon(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int width, int height); +void ff_vvc_w_avg_8_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +void ff_vvc_w_avg_10_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +void ff_vvc_w_avg_12_neon(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *src0, const int16_t *src1, + int width, int height, + uintptr_t w0_w1, uintptr_t offset_shift); +/* When passing arguments to functions, Apple platforms diverge from the ARM64 + * standard ABI for functions that require passing arguments on the stack. To + * simplify portability in the assembly function interface, use a different + * function signature that doesn't require passing arguments on the stack. + */ +#define W_AVG_FUN(bit_depth) \ +static void vvc_w_avg_ ## bit_depth(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height, \ + int denom, int w0, int w1, int o0, int o1) \ +{ \ + int shift = denom + FFMAX(3, 15 - bit_depth); \ + int offset = ((o0 + o1) * (1 << (bit_depth - 8)) + 1) * (1 << (shift - 1)); \ + uintptr_t w0_w1 = ((uintptr_t)w0 << 32) | (uint32_t)w1; \ + uintptr_t offset_shift = ((uintptr_t)offset << 32) | (uint32_t)shift; \ + ff_vvc_w_avg_ ## bit_depth ## _neon(dst, dst_stride, src0, src1, width, height, w0_w1, offset_shift); \ +} + +W_AVG_FUN(8) +W_AVG_FUN(10) +W_AVG_FUN(12) + +#define DMVR_FUN(fn, bd) \ + void ff_vvc_dmvr_ ## fn ## bd ## _neon(int16_t *dst, \ + const uint8_t *_src, ptrdiff_t _src_stride, int height, \ + intptr_t mx, intptr_t my, int width); + +DMVR_FUN(, 8) +DMVR_FUN(, 12) +DMVR_FUN(hv_, 8) +DMVR_FUN(hv_, 10) +DMVR_FUN(hv_, 12) + void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) { int cpu_flags = av_get_cpu_flags(); @@ -87,6 +149,13 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) c->inter.put[0][5][1][1] = ff_vvc_put_qpel_hv64_8_neon; c->inter.put[0][6][1][1] = ff_vvc_put_qpel_hv128_8_neon; + c->inter.put[1][1][0][0] = ff_vvc_put_pel_pixels4_8_neon; + c->inter.put[1][2][0][0] = ff_vvc_put_pel_pixels8_8_neon; + c->inter.put[1][3][0][0] = ff_vvc_put_pel_pixels16_8_neon; + c->inter.put[1][4][0][0] = ff_vvc_put_pel_pixels32_8_neon; + c->inter.put[1][5][0][0] = ff_vvc_put_pel_pixels64_8_neon; + c->inter.put[1][6][0][0] = ff_vvc_put_pel_pixels128_8_neon; + c->inter.put[1][1][0][1] = ff_vvc_put_epel_h4_8_neon; c->inter.put[1][2][0][1] = ff_vvc_put_epel_h8_8_neon; c->inter.put[1][3][0][1] = ff_vvc_put_epel_h16_8_neon; @@ -123,9 +192,14 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) c->inter.put_uni_w[0][6][0][0] = ff_vvc_put_pel_uni_w_pixels128_8_neon; c->inter.avg = ff_vvc_avg_8_neon; + c->inter.w_avg = vvc_w_avg_8; + c->inter.dmvr[0][0] = ff_vvc_dmvr_8_neon; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_8_neon; + c->inter.apply_bdof = apply_bdof_8; - for (int i = 0; i < FF_ARRAY_ELEMS(c->sao.band_filter); i++) - c->sao.band_filter[i] = ff_h26x_sao_band_filter_8x8_8_neon; + c->sao.band_filter[0] = ff_h26x_sao_band_filter_8x8_8_neon; + for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.band_filter); i++) + c->sao.band_filter[i] = ff_h26x_sao_band_filter_16x16_8_neon; c->sao.edge_filter[0] = ff_vvc_sao_edge_filter_8x8_8_neon; for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.edge_filter); i++) c->sao.edge_filter[i] = ff_vvc_sao_edge_filter_16x16_8_neon; @@ -163,11 +237,18 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const int bd) } } else if (bd == 10) { c->inter.avg = ff_vvc_avg_10_neon; + c->inter.w_avg = vvc_w_avg_10; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_10_neon; + c->inter.apply_bdof = apply_bdof_10; c->alf.filter[LUMA] = alf_filter_luma_10_neon; c->alf.filter[CHROMA] = alf_filter_chroma_10_neon; } else if (bd == 12) { c->inter.avg = ff_vvc_avg_12_neon; + c->inter.w_avg = vvc_w_avg_12; + c->inter.dmvr[0][0] = ff_vvc_dmvr_12_neon; + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_12_neon; + c->inter.apply_bdof = apply_bdof_12; c->alf.filter[LUMA] = alf_filter_luma_12_neon; c->alf.filter[CHROMA] = alf_filter_chroma_12_neon; diff --git a/libavcodec/aarch64/vvc/inter.S b/libavcodec/aarch64/vvc/inter.S index 2f69274b86..c299e6f68b 100644 --- a/libavcodec/aarch64/vvc/inter.S +++ b/libavcodec/aarch64/vvc/inter.S @@ -21,10 +21,12 @@ #include "libavutil/aarch64/asm.S" #define VVC_MAX_PB_SIZE 128 +#define BDOF_BLOCK_SIZE 16 +#define BDOF_MIN_BLOCK_SIZE 4 -.macro vvc_avg, bit_depth +.macro vvc_w_avg bit_depth -.macro vvc_avg_\bit_depth\()_2_4, tap +.macro vvc_w_avg_\bit_depth\()_2_4 tap .if \tap == 2 ldr s0, [src0] ldr s2, [src1] @@ -32,9 +34,12 @@ ldr d0, [src0] ldr d2, [src1] .endif - saddl v4.4s, v0.4h, v2.4h - add v4.4s, v4.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + sqshl v4.4s, v4.4s, v22.4s + sqxtun v4.4h, v4.4s + .if \bit_depth == 8 sqxtun v4.8b, v4.8h .if \tap == 2 @@ -44,8 +49,7 @@ .endif .else // bit_depth > 8 - smin v4.4h, v4.4h, v17.4h - smax v4.4h, v4.4h, v18.4h + umin v4.4h, v4.4h, v17.4h .if \tap == 2 str s4, [dst] .else @@ -57,7 +61,7 @@ add dst, dst, dst_stride .endm -function ff_vvc_avg_\bit_depth\()_neon, export=1 +function ff_vvc_w_avg_\bit_depth\()_neon, export=1 dst .req x0 dst_stride .req x1 src0 .req x2 @@ -67,49 +71,56 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 mov x10, #(VVC_MAX_PB_SIZE * 2) cmp width, #8 -.if \bit_depth == 8 - movi v16.4s, #64 -.else -.if \bit_depth == 10 - mov w6, #1023 - movi v16.4s, #16 -.else - mov w6, #4095 - movi v16.4s, #4 -.endif - movi v18.8h, #0 + lsr x11, x6, #32 // weight0 + mov w12, w6 // weight1 + lsr x13, x7, #32 // offset + mov w14, w7 // shift + + dup v19.8h, w11 + neg w14, w14 // so we can use sqshl + dup v20.8h, w12 + dup v16.4s, w13 + dup v22.4s, w14 + +.if \bit_depth >= 10 + // clip pixel + mov w6, #((1 << \bit_depth) - 1) dup v17.8h, w6 .endif + b.eq 8f b.hi 16f cmp width, #4 b.eq 4f 2: // width == 2 subs height, height, #1 - vvc_avg_\bit_depth\()_2_4 2 + vvc_w_avg_\bit_depth\()_2_4 2 b.ne 2b b 32f 4: // width == 4 subs height, height, #1 - vvc_avg_\bit_depth\()_2_4 4 + vvc_w_avg_\bit_depth\()_2_4 4 b.ne 4b b 32f 8: // width == 8 ld1 {v0.8h}, [src0], x10 ld1 {v2.8h}, [src1], x10 - saddl v4.4s, v0.4h, v2.4h - saddl2 v5.4s, v0.8h, v2.8h - add v4.4s, v4.4s, v16.4s - add v5.4s, v5.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) - sqshrn2 v4.8h, v5.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + mov v5.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + smlal2 v5.4s, v0.8h, v19.8h + smlal2 v5.4s, v2.8h, v20.8h + sqshl v4.4s, v4.4s, v22.4s + sqshl v5.4s, v5.4s, v22.4s + sqxtun v4.4h, v4.4s + sqxtun2 v4.8h, v5.4s subs height, height, #1 .if \bit_depth == 8 sqxtun v4.8b, v4.8h st1 {v4.8b}, [dst], dst_stride .else - smin v4.8h, v4.8h, v17.8h - smax v4.8h, v4.8h, v18.8h + umin v4.8h, v4.8h, v17.8h st1 {v4.8h}, [dst], dst_stride .endif b.ne 8b @@ -122,28 +133,34 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 17: ldp q0, q1, [x7], #32 ldp q2, q3, [x8], #32 - saddl v4.4s, v0.4h, v2.4h - saddl2 v5.4s, v0.8h, v2.8h - saddl v6.4s, v1.4h, v3.4h - saddl2 v7.4s, v1.8h, v3.8h - add v4.4s, v4.4s, v16.4s - add v5.4s, v5.4s, v16.4s - add v6.4s, v6.4s, v16.4s - add v7.4s, v7.4s, v16.4s - sqshrn v4.4h, v4.4s, #(15 - \bit_depth) - sqshrn2 v4.8h, v5.4s, #(15 - \bit_depth) - sqshrn v6.4h, v6.4s, #(15 - \bit_depth) - sqshrn2 v6.8h, v7.4s, #(15 - \bit_depth) + mov v4.16b, v16.16b + mov v5.16b, v16.16b + mov v6.16b, v16.16b + mov v7.16b, v16.16b + smlal v4.4s, v0.4h, v19.4h + smlal v4.4s, v2.4h, v20.4h + smlal2 v5.4s, v0.8h, v19.8h + smlal2 v5.4s, v2.8h, v20.8h + smlal v6.4s, v1.4h, v19.4h + smlal v6.4s, v3.4h, v20.4h + smlal2 v7.4s, v1.8h, v19.8h + smlal2 v7.4s, v3.8h, v20.8h + sqshl v4.4s, v4.4s, v22.4s + sqshl v5.4s, v5.4s, v22.4s + sqshl v6.4s, v6.4s, v22.4s + sqshl v7.4s, v7.4s, v22.4s + sqxtun v4.4h, v4.4s + sqxtun v6.4h, v6.4s + sqxtun2 v4.8h, v5.4s + sqxtun2 v6.8h, v7.4s subs w6, w6, #16 .if \bit_depth == 8 sqxtun v4.8b, v4.8h sqxtun2 v4.16b, v6.8h str q4, [x9], #16 .else - smin v4.8h, v4.8h, v17.8h - smin v6.8h, v6.8h, v17.8h - smax v4.8h, v4.8h, v18.8h - smax v6.8h, v6.8h, v18.8h + umin v4.8h, v4.8h, v17.8h + umin v6.8h, v6.8h, v17.8h stp q4, q6, [x9], #32 .endif b.ne 17b @@ -155,9 +172,894 @@ function ff_vvc_avg_\bit_depth\()_neon, export=1 b.ne 16b 32: ret + +.unreq dst +.unreq dst_stride +.unreq src0 +.unreq src1 +.unreq width +.unreq height +endfunc +.endm + +vvc_w_avg 8 +vvc_w_avg 10 +vvc_w_avg 12 + +.macro vvc_avg bit_depth +function ff_vvc_avg_\bit_depth\()_neon, export=1 + mov x10, #(VVC_MAX_PB_SIZE * 2) + movi v16.8h, #0 + movi v17.16b, #255 + ushr v17.8h, v17.8h, #(16 - \bit_depth) + + cmp w4, #8 + b.gt 16f + b.eq 8f + cmp w4, #4 + b.eq 4f + +2: // width == 2 + ldr s0, [x2] + subs w5, w5, #1 + ldr s1, [x3] +.if \bit_depth == 8 + shadd v0.4h, v0.4h, v1.4h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str h0, [x0] +.else + shadd v0.4h, v0.4h, v1.4h + srshr v0.4h, v0.4h, #(15 - 1 - \bit_depth) + smax v0.4h, v0.4h, v16.4h + smin v0.4h, v0.4h, v17.4h + str s0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 2b + ret + +4: // width == 4 + ldr d0, [x2] + subs w5, w5, #1 + ldr d1, [x3] +.if \bit_depth == 8 + shadd v0.4h, v0.4h, v1.4h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str s0, [x0] +.else + shadd v0.4h, v0.4h, v1.4h + srshr v0.4h, v0.4h, #(15 - 1 - \bit_depth) + smax v0.4h, v0.4h, v16.4h + smin v0.4h, v0.4h, v17.4h + str d0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 4b + ret + +8: // width == 8 + ldr q0, [x2] + subs w5, w5, #1 + ldr q1, [x3] +.if \bit_depth == 8 + shadd v0.8h, v0.8h, v1.8h + sqrshrun v0.8b, v0.8h, #(15 - 1 - \bit_depth) + str d0, [x0] +.else + shadd v0.8h, v0.8h, v1.8h + srshr v0.8h, v0.8h, #(15 - 1 - \bit_depth) + smax v0.8h, v0.8h, v16.8h + smin v0.8h, v0.8h, v17.8h + str q0, [x0] +.endif + add x2, x2, #(VVC_MAX_PB_SIZE * 2) + add x3, x3, #(VVC_MAX_PB_SIZE * 2) + add x0, x0, x1 + b.ne 8b + ret + +16: // width >= 16 +.if \bit_depth == 8 + sub x1, x1, w4, sxtw +.else + sub x1, x1, w4, sxtw #1 +.endif + sub x10, x10, w4, sxtw #1 +3: + mov w6, w4 // width +1: + ldp q0, q1, [x2], #32 + subs w6, w6, #16 + ldp q2, q3, [x3], #32 +.if \bit_depth == 8 + shadd v4.8h, v0.8h, v2.8h + shadd v5.8h, v1.8h, v3.8h + sqrshrun v0.8b, v4.8h, #6 + sqrshrun2 v0.16b, v5.8h, #6 + st1 {v0.16b}, [x0], #16 +.else + shadd v4.8h, v0.8h, v2.8h + shadd v5.8h, v1.8h, v3.8h + srshr v0.8h, v4.8h, #(15 - 1 - \bit_depth) + srshr v1.8h, v5.8h, #(15 - 1 - \bit_depth) + smax v0.8h, v0.8h, v16.8h + smax v1.8h, v1.8h, v16.8h + smin v0.8h, v0.8h, v17.8h + smin v1.8h, v1.8h, v17.8h + stp q0, q1, [x0], #32 +.endif + b.ne 1b + + subs w5, w5, #1 + add x2, x2, x10 + add x3, x3, x10 + add x0, x0, x1 + b.ne 3b + ret endfunc .endm vvc_avg 8 vvc_avg 10 vvc_avg 12 + +/* x0: int16_t *dst + * x1: const uint8_t *_src + * x2: ptrdiff_t _src_stride + * w3: int height + * x4: intptr_t mx + * x5: intptr_t my + * w6: int width + */ +function ff_vvc_dmvr_8_neon, export=1 + dst .req x0 + src .req x1 + src_stride .req x2 + height .req w3 + mx .req x4 + my .req x5 + width .req w6 + + sxtw x6, w6 + mov x7, #(VVC_MAX_PB_SIZE * 2 + 8) + cmp width, #16 + sub src_stride, src_stride, x6 + cset w15, gt // width > 16 + movi v16.8h, #2 // DMVR_SHIFT + sub x7, x7, x6, lsl #1 +1: + cbz w15, 2f + ldr q0, [src], #16 + ushll v1.8h, v0.8b, #2 + ushll2 v2.8h, v0.16b, #2 + stp q1, q2, [dst], #32 + b 3f +2: + ldr d0, [src], #8 + ushll v1.8h, v0.8b, #2 + str q1, [dst], #16 +3: + subs height, height, #1 + ldr s3, [src], #4 + ushll v4.8h, v3.8b, #2 + st1 {v4.4h}, [dst], x7 + + add src, src, src_stride + b.ne 1b + + ret +endfunc + +function ff_vvc_dmvr_12_neon, export=1 + sxtw x6, w6 + mov x7, #(VVC_MAX_PB_SIZE * 2 + 8) + cmp width, #16 + sub src_stride, src_stride, x6, lsl #1 + cset w15, gt // width > 16 + sub x7, x7, x6, lsl #1 +1: + cbz w15, 2f + ldp q0, q1, [src], #32 + urshr v0.8h, v0.8h, #2 + urshr v1.8h, v1.8h, #2 + + stp q0, q1, [dst], #32 + b 3f +2: + ldr q0, [src], #16 + urshr v0.8h, v0.8h, #2 + str q0, [dst], #16 +3: + subs height, height, #1 + ldr d0, [src], #8 + urshr v0.4h, v0.4h, #2 + st1 {v0.4h}, [dst], x7 + + add src, src, src_stride + b.ne 1b + + ret +endfunc + +function ff_vvc_dmvr_hv_8_neon, export=1 + tmp0 .req x7 + tmp1 .req x8 + + sub sp, sp, #(VVC_MAX_PB_SIZE * 4) + + movrel x9, X(ff_vvc_inter_luma_dmvr_filters) + add x12, x9, mx, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + mov tmp0, sp + add tmp1, tmp0, #(VVC_MAX_PB_SIZE * 2) + // We know the value are positive + dup v0.8h, w10 // filter_x[0] + dup v1.8h, w11 // filter_x[1] + + add x12, x9, my, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + sxtw x6, w6 + dup v2.8h, w10 // filter_y[0] + dup v3.8h, w11 // filter_y[1] + + // Valid value for width can only be 8 + 4, 16 + 4 + cmp width, #16 + mov w10, #0 // start filter_y or not + add height, height, #1 + sub dst, dst, #(VVC_MAX_PB_SIZE * 2) + sub src_stride, src_stride, x6 + cset w15, gt // width > 16 +1: + mov x12, tmp0 + mov x13, tmp1 + mov x14, dst + cbz w15, 2f + + // width > 16 + ldur q5, [src, #1] + ldr q4, [src], #16 + uxtl v7.8h, v5.8b + uxtl2 v17.8h, v5.16b + uxtl v6.8h, v4.8b + uxtl2 v16.8h, v4.16b + mul v6.8h, v6.8h, v0.8h + mul v16.8h, v16.8h, v0.8h + mla v6.8h, v7.8h, v1.8h + mla v16.8h, v17.8h, v1.8h + urshr v6.8h, v6.8h, #(8 - 6) + urshr v7.8h, v16.8h, #(8 - 6) + stp q6, q7, [x13], #32 + + cbz w10, 3f + + ldp q16, q17, [x12], #32 + mul v16.8h, v16.8h, v2.8h + mul v17.8h, v17.8h, v2.8h + mla v16.8h, v6.8h, v3.8h + mla v17.8h, v7.8h, v3.8h + urshr v16.8h, v16.8h, #4 + urshr v17.8h, v17.8h, #4 + stp q16, q17, [x14], #32 + b 3f +2: + // width > 8 + ldur d5, [src, #1] + ldr d4, [src], #8 + uxtl v7.8h, v5.8b + uxtl v6.8h, v4.8b + mul v6.8h, v6.8h, v0.8h + mla v6.8h, v7.8h, v1.8h + urshr v6.8h, v6.8h, #(8 - 6) + str q6, [x13], #16 + + cbz w10, 3f + + ldr q16, [x12], #16 + mul v16.8h, v16.8h, v2.8h + mla v16.8h, v6.8h, v3.8h + urshr v16.8h, v16.8h, #4 + str q16, [x14], #16 +3: + ldur s5, [src, #1] + ldr s4, [src], #4 + uxtl v7.8h, v5.8b + uxtl v6.8h, v4.8b + mul v6.4h, v6.4h, v0.4h + mla v6.4h, v7.4h, v1.4h + urshr v6.4h, v6.4h, #(8 - 6) + str d6, [x13], #8 + + cbz w10, 4f + + ldr d16, [x12], #8 + mul v16.4h, v16.4h, v2.4h + mla v16.4h, v6.4h, v3.4h + urshr v16.4h, v16.4h, #4 + str d16, [x14], #8 +4: + subs height, height, #1 + mov w10, #1 + add src, src, src_stride + add dst, dst, #(VVC_MAX_PB_SIZE * 2) + eor tmp0, tmp0, tmp1 + eor tmp1, tmp0, tmp1 + eor tmp0, tmp0, tmp1 + b.ne 1b + + add sp, sp, #(VVC_MAX_PB_SIZE * 4) + ret +endfunc + +function ff_vvc_dmvr_hv_12_neon, export=1 + movi v29.4s, #(12 - 6) + movi v30.4s, #(1 << (12 - 7)) // offset1 + b 0f +endfunc + +function ff_vvc_dmvr_hv_10_neon, export=1 + movi v29.4s, #(10 - 6) + movi v30.4s, #(1 << (10 - 7)) // offset1 +0: + movi v31.4s, #8 // offset2 + neg v29.4s, v29.4s + + sub sp, sp, #(VVC_MAX_PB_SIZE * 4) + + movrel x9, X(ff_vvc_inter_luma_dmvr_filters) + add x12, x9, mx, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + mov tmp0, sp + add tmp1, tmp0, #(VVC_MAX_PB_SIZE * 2) + // We know the value are positive + dup v0.8h, w10 // filter_x[0] + dup v1.8h, w11 // filter_x[1] + + add x12, x9, my, lsl #1 + ldrb w10, [x12] + ldrb w11, [x12, #1] + sxtw x6, w6 + dup v2.8h, w10 // filter_y[0] + dup v3.8h, w11 // filter_y[1] + + // Valid value for width can only be 8 + 4, 16 + 4 + cmp width, #16 + mov w10, #0 // start filter_y or not + add height, height, #1 + sub dst, dst, #(VVC_MAX_PB_SIZE * 2) + sub src_stride, src_stride, x6, lsl #1 + cset w15, gt // width > 16 +1: + mov x12, tmp0 + mov x13, tmp1 + mov x14, dst + cbz w15, 2f + + // width > 16 + add x16, src, #2 + ldp q6, q16, [src], #32 + ldp q7, q17, [x16] + umull v4.4s, v6.4h, v0.4h + umull2 v5.4s, v6.8h, v0.8h + umull v18.4s, v16.4h, v0.4h + umull2 v19.4s, v16.8h, v0.8h + umlal v4.4s, v7.4h, v1.4h + umlal2 v5.4s, v7.8h, v1.8h + umlal v18.4s, v17.4h, v1.4h + umlal2 v19.4s, v17.8h, v1.8h + + add v4.4s, v4.4s, v30.4s + add v5.4s, v5.4s, v30.4s + add v18.4s, v18.4s, v30.4s + add v19.4s, v19.4s, v30.4s + ushl v4.4s, v4.4s, v29.4s + ushl v5.4s, v5.4s, v29.4s + ushl v18.4s, v18.4s, v29.4s + ushl v19.4s, v19.4s, v29.4s + uqxtn v6.4h, v4.4s + uqxtn2 v6.8h, v5.4s + uqxtn v7.4h, v18.4s + uqxtn2 v7.8h, v19.4s + stp q6, q7, [x13], #32 + + cbz w10, 3f + + ldp q4, q5, [x12], #32 + umull v17.4s, v4.4h, v2.4h + umull2 v18.4s, v4.8h, v2.8h + umull v19.4s, v5.4h, v2.4h + umull2 v20.4s, v5.8h, v2.8h + umlal v17.4s, v6.4h, v3.4h + umlal2 v18.4s, v6.8h, v3.8h + umlal v19.4s, v7.4h, v3.4h + umlal2 v20.4s, v7.8h, v3.8h + add v17.4s, v17.4s, v31.4s + add v18.4s, v18.4s, v31.4s + add v19.4s, v19.4s, v31.4s + add v20.4s, v20.4s, v31.4s + ushr v17.4s, v17.4s, #4 + ushr v18.4s, v18.4s, #4 + ushr v19.4s, v19.4s, #4 + ushr v20.4s, v20.4s, #4 + uqxtn v6.4h, v17.4s + uqxtn2 v6.8h, v18.4s + uqxtn v7.4h, v19.4s + uqxtn2 v7.8h, v20.4s + stp q6, q7, [x14], #32 + b 3f +2: + // width > 8 + ldur q7, [src, #2] + ldr q6, [src], #16 + umull v4.4s, v6.4h, v0.4h + umull2 v5.4s, v6.8h, v0.8h + umlal v4.4s, v7.4h, v1.4h + umlal2 v5.4s, v7.8h, v1.8h + + add v4.4s, v4.4s, v30.4s + add v5.4s, v5.4s, v30.4s + ushl v4.4s, v4.4s, v29.4s + ushl v5.4s, v5.4s, v29.4s + uqxtn v6.4h, v4.4s + uqxtn2 v6.8h, v5.4s + str q6, [x13], #16 + + cbz w10, 3f + + ldr q16, [x12], #16 + umull v17.4s, v16.4h, v2.4h + umull2 v18.4s, v16.8h, v2.8h + umlal v17.4s, v6.4h, v3.4h + umlal2 v18.4s, v6.8h, v3.8h + add v17.4s, v17.4s, v31.4s + add v18.4s, v18.4s, v31.4s + ushr v17.4s, v17.4s, #4 + ushr v18.4s, v18.4s, #4 + uqxtn v16.4h, v17.4s + uqxtn2 v16.8h, v18.4s + str q16, [x14], #16 +3: + ldur d7, [src, #2] + ldr d6, [src], #8 + umull v4.4s, v7.4h, v1.4h + umlal v4.4s, v6.4h, v0.4h + add v4.4s, v4.4s, v30.4s + ushl v4.4s, v4.4s, v29.4s + uqxtn v6.4h, v4.4s + str d6, [x13], #8 + + cbz w10, 4f + + ldr d16, [x12], #8 + umull v17.4s, v16.4h, v2.4h + umlal v17.4s, v6.4h, v3.4h + add v17.4s, v17.4s, v31.4s + ushr v17.4s, v17.4s, #4 + uqxtn v16.4h, v17.4s + str d16, [x14], #8 +4: + subs height, height, #1 + mov w10, #1 + add src, src, src_stride + add dst, dst, #(VVC_MAX_PB_SIZE * 2) + eor tmp0, tmp0, tmp1 + eor tmp1, tmp0, tmp1 + eor tmp0, tmp0, tmp1 + b.ne 1b + + add sp, sp, #(VVC_MAX_PB_SIZE * 4) + ret + +.unreq dst +.unreq src +.unreq src_stride +.unreq height +.unreq mx +.unreq my +.unreq width +.unreq tmp0 +.unreq tmp1 +endfunc + +function ff_vvc_prof_grad_filter_8x_neon, export=1 + gh .req x0 + gv .req x1 + gstride .req x2 + src .req x3 + src_stride .req x4 + width .req w5 + height .req w6 + + lsl src_stride, src_stride, #1 + neg x7, src_stride +1: + mov x10, src + mov w11, width + mov x12, gh + mov x13, gv +2: + ldur q0, [x10, #2] + ldur q1, [x10, #-2] + subs w11, w11, #8 + ldr q2, [x10, src_stride] + ldr q3, [x10, x7] + sshr v0.8h, v0.8h, #6 + sshr v1.8h, v1.8h, #6 + sshr v2.8h, v2.8h, #6 + sshr v3.8h, v3.8h, #6 + sub v0.8h, v0.8h, v1.8h + sub v2.8h, v2.8h, v3.8h + st1 {v0.8h}, [x12], #16 + st1 {v2.8h}, [x13], #16 + add x10, x10, #16 + b.ne 2b + + subs height, height, #1 + add gh, gh, gstride, lsl #1 + add gv, gv, gstride, lsl #1 + add src, src, src_stride + b.ne 1b + ret + +.unreq gh +.unreq gv +.unreq gstride +.unreq src +.unreq src_stride +.unreq width +.unreq height +endfunc + +.macro vvc_apply_bdof_block bit_depth + dst .req x0 + dst_stride .req x1 + src0 .req x2 + src1 .req x3 + gh .req x4 + gv .req x5 + vx .req x6 + vy .req x7 + + ld1r {v0.8h}, [vx], #2 + ld1r {v1.8h}, [vy], #2 + ld1r {v2.8h}, [vx] + ld1r {v3.8h}, [vy] + ins v0.d[1], v2.d[1] + ins v1.d[1], v3.d[1] + + movi v7.4s, #(1 << (14 - \bit_depth)) + ldp x8, x9, [gh] + ldp x10, x11, [gv] + mov x12, #(BDOF_BLOCK_SIZE * 2) + mov w13, #(BDOF_MIN_BLOCK_SIZE) + mov x14, #(VVC_MAX_PB_SIZE * 2) +.if \bit_depth >= 10 + // clip pixel + mov w15, #((1 << \bit_depth) - 1) + movi v18.8h, #0 + lsl dst_stride, dst_stride, #1 + dup v19.8h, w15 +.endif +1: + ld1 {v2.8h}, [x8], x12 + ld1 {v3.8h}, [x9], x12 + ld1 {v4.8h}, [x10], x12 + ld1 {v5.8h}, [x11], x12 + sub v2.8h, v2.8h, v3.8h + sub v4.8h, v4.8h, v5.8h + smull v3.4s, v0.4h, v2.4h + smull2 v16.4s, v0.8h, v2.8h + smlal v3.4s, v1.4h, v4.4h + smlal2 v16.4s, v1.8h, v4.8h + + ld1 {v5.8h}, [src0], x14 + ld1 {v6.8h}, [src1], x14 + saddl v2.4s, v5.4h, v6.4h + add v2.4s, v2.4s, v7.4s + add v2.4s, v2.4s, v3.4s + saddl2 v4.4s, v5.8h, v6.8h + add v4.4s, v4.4s, v7.4s + add v4.4s, v4.4s, v16.4s + + sqshrn v5.4h, v2.4s, #(15 - \bit_depth) + sqshrn2 v5.8h, v4.4s, #(15 - \bit_depth) + subs w13, w13, #1 +.if \bit_depth == 8 + sqxtun v5.8b, v5.8h + str d5, [dst] + add dst, dst, dst_stride +.else + smin v5.8h, v5.8h, v19.8h + smax v5.8h, v5.8h, v18.8h + st1 {v5.8h}, [dst], dst_stride +.endif + b.ne 1b + ret + +.unreq dst +.unreq dst_stride +.unreq src0 +.unreq src1 +.unreq gh +.unreq gv +.unreq vx +.unreq vy +.endm + +function ff_vvc_apply_bdof_block_8_neon, export=1 + vvc_apply_bdof_block 8 +endfunc + +function ff_vvc_apply_bdof_block_10_neon, export=1 + vvc_apply_bdof_block 10 +endfunc + +function ff_vvc_apply_bdof_block_12_neon, export=1 + vvc_apply_bdof_block 12 +endfunc + +function ff_vvc_derive_bdof_vx_vy_neon, export=1 + src0 .req x0 + src1 .req x1 + pad_mask .req w2 + gh .req x3 + gv .req x4 + vx .req x5 + vy .req x6 + + gh0 .req x7 + gh1 .req x8 + gv0 .req x9 + gv1 .req x10 + y .req x12 + + sgx2 .req w7 + sgy2 .req w8 + sgxgy .req w9 + sgxdi .req w10 + sgydi .req w11 + + sgx2_v .req v22 + sgy2_v .req v23 + sgxgy_v .req v24 + sgxdi_v .req v25 + sgydi_v .req v26 + + sgx2_v2 .req v27 + sgy2_v2 .req v28 + sgxgy_v2 .req v29 + sgxdi_v2 .req v30 + sgydi_v2 .req v31 + + ldp gh0, gh1, [gh] + ldp gv0, gv1, [gv] + movi sgx2_v.4s, #0 + movi sgy2_v.4s, #0 + movi sgxgy_v.4s, #0 + movi sgxdi_v.4s, #0 + movi sgydi_v.4s, #0 + movi sgx2_v2.4s, #0 + movi sgy2_v2.4s, #0 + movi sgxgy_v2.4s, #0 + movi sgxdi_v2.4s, #0 + movi sgydi_v2.4s, #0 + mov x13, #-1 // dy + movi v6.4s, #0 + mov y, #-1 + tbz pad_mask, #1, 1f // check pad top + mov x13, #0 // dy: pad top +1: + mov x16, #-2 // dx + add x14, src0, x13, lsl #8 // local src0 + add x15, src1, x13, lsl #8 // local src1 + add x17, x16, x13, lsl #5 + ldr q0, [x14, x16] + ldr q1, [x15, x16] + ldr q2, [gh0, x17] + ldr q3, [gh1, x17] + ldr q4, [gv0, x17] + ldr q5, [gv1, x17] + add x16, x16, #8 + add x17, x17, #8 + ins v0.s[3], v6.s[3] + ins v1.s[3], v6.s[3] + ins v2.s[3], v6.s[3] + ins v3.s[3], v6.s[3] + ins v4.s[3], v6.s[3] + ins v5.s[3], v6.s[3] + + ldr q16, [x14, x16] + ldr q17, [x15, x16] + ldr q18, [gh0, x17] + ldr q19, [gh1, x17] + ldr q20, [gv0, x17] + ldr q21, [gv1, x17] + ins v16.s[3], v6.s[3] + ins v17.s[3], v6.s[3] + ins v18.s[3], v6.s[3] + ins v19.s[3], v6.s[3] + ins v20.s[3], v6.s[3] + ins v21.s[3], v6.s[3] + + tbz pad_mask, #0, 20f + // pad left + ins v0.h[0], v0.h[1] + ins v1.h[0], v1.h[1] + ins v2.h[0], v2.h[1] + ins v3.h[0], v3.h[1] + ins v4.h[0], v4.h[1] + ins v5.h[0], v5.h[1] +20: + tbz pad_mask, #2, 21f + // pad right + ins v16.h[5], v16.h[4] + ins v17.h[5], v17.h[4] + ins v18.h[5], v18.h[4] + ins v19.h[5], v19.h[4] + ins v20.h[5], v20.h[4] + ins v21.h[5], v21.h[4] +21: + sshr v0.8h, v0.8h, #4 + sshr v1.8h, v1.8h, #4 + add v2.8h, v2.8h, v3.8h + add v4.8h, v4.8h, v5.8h + sub v0.8h, v0.8h, v1.8h // diff + sshr v2.8h, v2.8h, #1 // temph + sshr v4.8h, v4.8h, #1 // tempv + + sshr v16.8h, v16.8h, #4 + sshr v17.8h, v17.8h, #4 + add v18.8h, v18.8h, v19.8h + add v20.8h, v20.8h, v21.8h + sub v16.8h, v16.8h, v17.8h // diff + sshr v18.8h, v18.8h, #1 // temph + sshr v20.8h, v20.8h, #1 // tempv + + abs v3.8h, v2.8h + abs v5.8h, v4.8h + uxtl v19.4s, v3.4h + uxtl v21.4s, v5.4h + uxtl2 v3.4s, v3.8h + uxtl2 v5.4s, v5.8h + add v3.4s, v3.4s, v19.4s + add v5.4s, v5.4s, v21.4s + add sgx2_v.4s, sgx2_v.4s, v3.4s + add sgy2_v.4s, sgy2_v.4s, v5.4s + + abs v3.8h, v18.8h + abs v5.8h, v20.8h + uxtl v19.4s, v3.4h + uxtl v21.4s, v5.4h + uxtl2 v3.4s, v3.8h + uxtl2 v5.4s, v5.8h + add v3.4s, v3.4s, v19.4s + add v5.4s, v5.4s, v21.4s + add sgx2_v2.4s, sgx2_v2.4s, v3.4s + add sgy2_v2.4s, sgy2_v2.4s, v5.4s + + cmgt v17.8h, v4.8h, #0 + cmlt v7.8h, v4.8h, #0 + cmgt v19.8h, v20.8h, #0 + cmlt v21.8h, v20.8h, #0 + sub v17.8h, v7.8h, v17.8h // VVC_SIGN(tempv) + sub v19.8h, v21.8h, v19.8h // VVC_SIGN(tempv) + + smlal sgxgy_v.4s, v17.4h, v2.4h + smlal2 sgxgy_v.4s, v17.8h, v2.8h + smlsl sgydi_v.4s, v17.4h, v0.4h + smlsl2 sgydi_v.4s, v17.8h, v0.8h + + cmgt v3.8h, v2.8h, #0 + cmlt v5.8h, v2.8h, #0 + cmgt v17.8h, v18.8h, #0 + cmlt v21.8h, v18.8h, #0 + sub v3.8h, v5.8h, v3.8h // VVC_SIGN(temph) + sub v17.8h, v21.8h, v17.8h // VVC_SIGN(temph) + + smlal sgxgy_v2.4s, v19.4h, v18.4h + smlal2 sgxgy_v2.4s, v19.8h, v18.8h + smlsl sgydi_v2.4s, v19.4h, v16.4h + smlsl2 sgydi_v2.4s, v19.8h, v16.8h + + smlsl sgxdi_v.4s, v3.4h, v0.4h + smlsl2 sgxdi_v.4s, v3.8h, v0.8h + smlsl sgxdi_v2.4s, v17.4h, v16.4h + smlsl2 sgxdi_v2.4s, v17.8h, v16.8h +3: + add y, y, #1 + cmp y, #(BDOF_MIN_BLOCK_SIZE) + mov x13, y + b.gt 4f + b.lt 1b + tbz pad_mask, #3, 1b + sub x13, x13, #1 // pad bottom + b 1b +4: + addv s22, sgx2_v.4s + addv s23, sgy2_v.4s + addv s24, sgxgy_v.4s + addv s25, sgxdi_v.4s + addv s26, sgydi_v.4s + + mov w3, #31 + mov w16, #-15 + mov w17, #15 +40: + mov w14, #0 + + mov sgx2, v22.s[0] + mov sgy2, v23.s[0] + mov sgxgy, v24.s[0] + mov sgxdi, v25.s[0] + mov sgydi, v26.s[0] + + cbz sgx2, 5f + clz w12, sgx2 + lsl sgxdi, sgxdi, #2 + sub w13, w3, w12 // log2(sgx2) + asr sgxdi, sgxdi, w13 + cmp sgxdi, w16 + csel w14, w16, sgxdi, lt // clip to -15 + b.le 5f + cmp sgxdi, w17 + csel w14, w17, sgxdi, gt // clip to 15 +5: + strh w14, [vx], #2 + + mov w15, #0 + cbz sgy2, 6f + lsl sgydi, sgydi, #2 + smull x14, w14, sgxgy + asr w14, w14, #1 + sub sgydi, sgydi, w14 + clz w12, sgy2 + sub w13, w3, w12 // log2(sgy2) + asr sgydi, sgydi, w13 + cmp sgydi, w16 + csel w15, w16, sgydi, lt // clip to -15 + b.le 6f + cmp sgydi, w17 + csel w15, w17, sgydi, gt // clip to 15 +6: + strh w15, [vy], #2 + cbz x0, 7f + addv s22, sgx2_v2.4s + addv s23, sgy2_v2.4s + addv s24, sgxgy_v2.4s + addv s25, sgxdi_v2.4s + addv s26, sgydi_v2.4s + mov x0, #0 + b 40b +7: + ret + +.unreq src0 +.unreq src1 +.unreq pad_mask +.unreq gh +.unreq gv +.unreq vx +.unreq vy +.unreq sgx2 +.unreq sgy2 +.unreq sgxgy +.unreq sgxdi +.unreq sgydi +.unreq sgx2_v +.unreq sgy2_v +.unreq sgxgy_v +.unreq sgxdi_v +.unreq sgydi_v +.unreq sgx2_v2 +.unreq sgy2_v2 +.unreq sgxgy_v2 +.unreq sgxdi_v2 +.unreq sgydi_v2 +.unreq y +endfunc diff --git a/libavcodec/aarch64/vvc/of_template.c b/libavcodec/aarch64/vvc/of_template.c new file mode 100644 index 0000000000..ac6182b09d --- /dev/null +++ b/libavcodec/aarch64/vvc/of_template.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/bit_depth_template.c" + +void FUNC2(ff_vvc_apply_bdof_block, BIT_DEPTH, _neon)(pixel* dst, + ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, + const int16_t **gh, const int16_t **gv, int16_t *vx, int16_t *vy); + +static void FUNC(apply_bdof)(uint8_t *_dst, ptrdiff_t _dst_stride, + const int16_t *_src0, const int16_t *_src1, + int block_w, int block_h) { + // +2 for pad left and right + int16_t gradient_buf_h[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2]; + int16_t gradient_buf_v[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE + 2]; + int16_t *gradient_h[2] = {&gradient_buf_h[0][1], &gradient_buf_h[1][1]}; + int16_t *gradient_v[2] = {&gradient_buf_v[0][1], &gradient_buf_v[1][1]}; + ptrdiff_t dst_stride = _dst_stride / sizeof(pixel); + pixel *dst = (pixel *) _dst; + + ff_vvc_prof_grad_filter_8x_neon(gradient_h[0], gradient_v[0], + BDOF_BLOCK_SIZE, + _src0, MAX_PB_SIZE, block_w, block_h); + ff_vvc_prof_grad_filter_8x_neon(gradient_h[1], gradient_v[1], + BDOF_BLOCK_SIZE, + _src1, MAX_PB_SIZE, block_w, block_h); + + for (int y = 0; y < block_h; y += BDOF_MIN_BLOCK_SIZE) { + for (int x = 0; x < block_w; x += BDOF_MIN_BLOCK_SIZE * 2) { + const int16_t *src0 = _src0 + y * MAX_PB_SIZE + x; + const int16_t *src1 = _src1 + y * MAX_PB_SIZE + x; + pixel *d = dst + x; + int idx = BDOF_BLOCK_SIZE * y + x; + const int16_t *gh[] = {gradient_h[0] + idx, gradient_h[1] + idx}; + const int16_t *gv[] = {gradient_v[0] + idx, gradient_v[1] + idx}; + int16_t vx[2], vy[2]; + int pad_mask = !x | ((!y) << 1) | + ((x + 2 * BDOF_MIN_BLOCK_SIZE == block_w) << 2) | + ((y + BDOF_MIN_BLOCK_SIZE == block_h) << 3); + ff_vvc_derive_bdof_vx_vy_neon(src0, src1, pad_mask, gh, gv, vx, vy); + FUNC2(ff_vvc_apply_bdof_block, BIT_DEPTH, _neon)(d, dst_stride, + src0, src1, gh, gv, + vx, vy); + } + dst += BDOF_MIN_BLOCK_SIZE * dst_stride; + } +} diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h index 2386c15ad0..ccd437f700 100644 --- a/libavcodec/ac3.h +++ b/libavcodec/ac3.h @@ -81,17 +81,6 @@ typedef float SHORTFLOAT; #define AC3_LEVEL(x) ROUND15((x) * FIXR15(M_SQRT1_2)) -/* pre-defined gain values */ -#define LEVEL_PLUS_3DB M_SQRT2 -#define LEVEL_PLUS_1POINT5DB 1.1892071150027209 -#define LEVEL_MINUS_1POINT5DB 0.8408964152537145 -#define LEVEL_MINUS_3DB M_SQRT1_2 -#define LEVEL_MINUS_4POINT5DB 0.5946035575013605 -#define LEVEL_MINUS_6DB 0.5000000000000000 -#define LEVEL_MINUS_9DB 0.3535533905932738 -#define LEVEL_ZERO 0.0000000000000000 -#define LEVEL_ONE 1.0000000000000000 - typedef struct AC3BitAllocParameters { int sr_code; int sr_shift; diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 69989690dd..a8bc3afc74 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -73,6 +73,217 @@ int ff_ac3_find_syncword(const uint8_t *buf, int buf_size) return i; } +/** + * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream. + * GetBitContext within AC3DecodeContext must point to + * the start of the synchronized AC-3 bitstream. + */ +static int ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) +{ + /* read the rest of the bsi. read twice for dual mono mode. */ + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + hdr->dialog_normalization[i] = -get_bits(gbc, 5); + hdr->compression_exists[i] = get_bits1(gbc); + if (hdr->compression_exists[i]) + hdr->heavy_dynamic_range[i] = get_bits(gbc, 8); + if (get_bits1(gbc)) + skip_bits(gbc, 8); //skip language code + if (get_bits1(gbc)) + skip_bits(gbc, 7); //skip audio production information + } + + skip_bits(gbc, 2); //skip copyright bit and original bitstream bit + + /* skip the timecodes or parse the Alternate Bit Stream Syntax */ + if (hdr->bitstream_id != 6) { + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode1 + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode2 + } else { + if (get_bits1(gbc)) { + hdr->preferred_downmix = get_bits(gbc, 2); + hdr->center_mix_level_ltrt = get_bits(gbc, 3); + hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); + hdr->center_mix_level = get_bits(gbc, 3); + hdr->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); + } + if (get_bits1(gbc)) { + hdr->dolby_surround_ex_mode = get_bits(gbc, 2); + hdr->dolby_headphone_mode = get_bits(gbc, 2); + skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1) + } + } + + /* skip additional bitstream info */ + if (get_bits1(gbc)) { + int i = get_bits(gbc, 6); + do { + skip_bits(gbc, 8); + } while (i--); + } + + return 0; +} + +static int eac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) +{ + if (hdr->frame_type == EAC3_FRAME_TYPE_RESERVED) + return AC3_PARSE_ERROR_FRAME_TYPE; + if (hdr->substreamid) + return AC3_PARSE_ERROR_FRAME_TYPE; + + skip_bits(gbc, 5); // skip bitstream id + + /* volume control params */ + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + hdr->dialog_normalization[i] = -get_bits(gbc, 5); + hdr->compression_exists[i] = get_bits1(gbc); + if (hdr->compression_exists[i]) + hdr->heavy_dynamic_range[i] = get_bits(gbc, 8); + } + + /* dependent stream channel map */ + if (hdr->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + hdr->channel_map_present = get_bits1(gbc); + if (hdr->channel_map_present) { + int64_t channel_layout = 0; + int channel_map = get_bits(gbc, 16); + + for (int i = 0; i < 16; i++) + if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1))) + channel_layout |= ff_eac3_custom_channel_map_locations[i][1]; + + if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) { + return AC3_PARSE_ERROR_CHANNEL_MAP; + } + hdr->channel_map = channel_map; + } + } + + /* mixing metadata */ + if (get_bits1(gbc)) { + /* center and surround mix levels */ + if (hdr->channel_mode > AC3_CHMODE_STEREO) { + hdr->preferred_downmix = get_bits(gbc, 2); + if (hdr->channel_mode & 1) { + /* if three front channels exist */ + hdr->center_mix_level_ltrt = get_bits(gbc, 3); + hdr->center_mix_level = get_bits(gbc, 3); + } + if (hdr->channel_mode & 4) { + /* if a surround channel exists */ + hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); + hdr->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); + } + } + + /* lfe mix level */ + if (hdr->lfe_on && (hdr->lfe_mix_level_exists = get_bits1(gbc))) { + hdr->lfe_mix_level = get_bits(gbc, 5); + } + + /* info for mixing with other streams and substreams */ + if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + // TODO: apply program scale factor + if (get_bits1(gbc)) { + skip_bits(gbc, 6); // skip program scale factor + } + } + if (get_bits1(gbc)) { + skip_bits(gbc, 6); // skip external program scale factor + } + /* skip mixing parameter data */ + switch(get_bits(gbc, 2)) { + case 1: skip_bits(gbc, 5); break; + case 2: skip_bits(gbc, 12); break; + case 3: { + int mix_data_size = (get_bits(gbc, 5) + 2) << 3; + skip_bits_long(gbc, mix_data_size); + break; + } + } + /* skip pan information for mono or dual mono source */ + if (hdr->channel_mode < AC3_CHMODE_STEREO) { + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + if (get_bits1(gbc)) { + /* note: this is not in the ATSC A/52B specification + reference: ETSI TS 102 366 V1.1.1 + section: E.1.3.1.25 */ + skip_bits(gbc, 8); // skip pan mean direction index + skip_bits(gbc, 6); // skip reserved paninfo bits + } + } + } + /* skip mixing configuration information */ + if (get_bits1(gbc)) { + for (int i = 0; i < hdr->num_blocks; i++) { + if (hdr->num_blocks == 1 || get_bits1(gbc)) { + skip_bits(gbc, 5); + } + } + } + } + } + + /* informational metadata */ + if (get_bits1(gbc)) { + hdr->bitstream_mode = get_bits(gbc, 3); + skip_bits(gbc, 2); // skip copyright bit and original bitstream bit + if (hdr->channel_mode == AC3_CHMODE_STEREO) { + hdr->dolby_surround_mode = get_bits(gbc, 2); + hdr->dolby_headphone_mode = get_bits(gbc, 2); + } + if (hdr->channel_mode >= AC3_CHMODE_2F2R) { + hdr->dolby_surround_ex_mode = get_bits(gbc, 2); + } + for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + if (get_bits1(gbc)) { + skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type + } + } + if (hdr->sr_code != EAC3_SR_CODE_REDUCED) { + skip_bits1(gbc); // skip source sample rate code + } + } + + /* converter synchronization flag + If frames are less than six blocks, this bit should be turned on + once every 6 blocks to indicate the start of a frame set. + reference: RFC 4598, Section 2.1.3 Frame Sets */ + if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && hdr->num_blocks != 6) { + skip_bits1(gbc); // skip converter synchronization flag + } + + /* original frame size code if this stream was converted from AC-3 */ + if (hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT && + (hdr->num_blocks == 6 || get_bits1(gbc))) { + skip_bits(gbc, 6); // skip frame size code + } + + /* additional bitstream info */ + if (get_bits1(gbc)) { + int addbsil = get_bits(gbc, 6); + for (int i = 0; i < addbsil + 1; i++) { + if (i == 0) { + /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a + which can be used to detect Atmos presence */ + skip_bits(gbc, 7); + hdr->eac3_extension_type_a = get_bits1(gbc); + if (hdr->eac3_extension_type_a) { + hdr->complexity_index_type_a = get_bits(gbc, 8); + i++; + } + } else { + skip_bits(gbc, 8); // skip additional bit stream info + } + } + } + + return 0; +} + int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) { int frame_size_code; @@ -133,6 +344,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->frame_size = ff_ac3_frame_size_tab[frame_size_code][hdr->sr_code] * 2; hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT; hdr->substreamid = 0; + + int ret = ac3_parse_header(gbc, hdr); + if (ret < 0) + return ret; } else { /* Enhanced AC-3 */ hdr->crc1 = 0; @@ -165,6 +380,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->bit_rate = 8LL * hdr->frame_size * hdr->sample_rate / (hdr->num_blocks * 256); hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on; + + int ret = eac3_parse_header(gbc, hdr); + if (ret < 0) + return ret; } hdr->channel_layout = ff_ac3_channel_layout_tab[hdr->channel_mode]; if (hdr->lfe_on) @@ -202,9 +421,13 @@ int av_ac3_parse_header(const uint8_t *buf, size_t size, { GetBitContext gb; AC3HeaderInfo hdr; + uint8_t tmp[32 + AV_INPUT_BUFFER_PADDING_SIZE]; int err; - err = init_get_bits8(&gb, buf, size); + size = FFMIN(32, size); + memcpy(tmp, buf, size); + memset(tmp + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + err = init_get_bits8(&gb, tmp, size); if (err < 0) return AVERROR_INVALIDDATA; err = ff_ac3_parse_header(&gb, &hdr); diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h index 46814bfb1f..ab5df34003 100644 --- a/libavcodec/ac3_parser_internal.h +++ b/libavcodec/ac3_parser_internal.h @@ -46,6 +46,7 @@ typedef struct AC3HeaderInfo { int substreamid; ///< substream identification int center_mix_level; ///< Center mix level index int surround_mix_level; ///< Surround mix level index + uint8_t channel_map_present; uint16_t channel_map; int num_blocks; ///< number of audio blocks int dolby_surround_mode; @@ -62,6 +63,23 @@ typedef struct AC3HeaderInfo { uint64_t channel_layout; int8_t ac3_bit_rate_code; /** @} */ + + /** @name enhanced eac3 extension coded elements + * @{ + */ + int8_t dialog_normalization[2]; + uint8_t compression_exists[2]; + uint8_t heavy_dynamic_range[2]; + uint8_t center_mix_level_ltrt; ///< Center mix level index + uint8_t surround_mix_level_ltrt; ///< Surround mix level index + uint8_t dolby_headphone_mode; + uint8_t dolby_surround_ex_mode; + uint8_t lfe_mix_level_exists; + uint8_t lfe_mix_level; + uint8_t preferred_downmix; + uint8_t eac3_extension_type_a; + uint8_t complexity_index_type_a; + /** @} */ } AC3HeaderInfo; typedef enum { @@ -71,6 +89,7 @@ typedef enum { AC3_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, AC3_PARSE_ERROR_FRAME_TYPE = -0x5030c0a, AC3_PARSE_ERROR_CRC = -0x6030c0a, + AC3_PARSE_ERROR_CHANNEL_MAP = -0x7030c0a, } AC3ParseError; /** diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index 0a4d3375ee..2f0e7f5344 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -46,142 +46,32 @@ #include "decode.h" #include "kbdwin.h" -/** - * table for ungrouping 3 values in 7 bits. - * used for exponents and bap=2 mantissas - */ -static uint8_t ungroup_3_in_7_bits_tab[128][3]; - -/** tables for ungrouping mantissas */ -static int b1_mantissas[32][3]; -static int b2_mantissas[128][3]; -static int b3_mantissas[8]; -static int b4_mantissas[128][2]; -static int b5_mantissas[16]; - -/** - * Quantization table: levels for symmetric. bits for asymmetric. - * reference: Table 7.18 Mapping of bap to Quantizer - */ -static const uint8_t quantization_tab[16] = { - 0, 3, 5, 7, 11, 15, - 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 -}; - #if (!USE_FIXED) /** dynamic range table. converts codes to scale factors. */ static float dynamic_range_tab[256]; float ff_ac3_heavy_dynamic_range_tab[256]; -#endif - -/** Adjustments in dB gain */ -static const float gain_levels[9] = { - LEVEL_PLUS_3DB, - LEVEL_PLUS_1POINT5DB, - LEVEL_ONE, - LEVEL_MINUS_1POINT5DB, - LEVEL_MINUS_3DB, - LEVEL_MINUS_4POINT5DB, - LEVEL_MINUS_6DB, - LEVEL_ZERO, - LEVEL_MINUS_9DB -}; - -/** Adjustments in dB gain (LFE, +10 to -21 dB) */ -static const float gain_levels_lfe[32] = { - 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893, - 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946, - 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227, - 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253, - 0.125892, 0.112201, 0.100000, 0.089125 -}; - -/** - * Table for default stereo downmixing coefficients - * reference: Section 7.8.2 Downmixing Into Two Channels - */ -static const uint8_t ac3_default_coeffs[8][5][2] = { - { { 2, 7 }, { 7, 2 }, }, - { { 4, 4 }, }, - { { 2, 7 }, { 7, 2 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, }, - { { 2, 7 }, { 7, 2 }, { 6, 6 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 8, 8 }, }, - { { 2, 7 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, - { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, -}; - -/** - * Symmetrical Dequantization - * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization - * Tables 7.19 to 7.23 - */ -static inline int -symmetric_dequant(int code, int levels) -{ - return ((code - (levels >> 1)) * (1 << 24)) / levels; -} /* * Initialize tables at runtime. */ -static av_cold void ac3_tables_init(void) +static av_cold void ac3_float_tables_init(void) { - int i; - - /* generate table for ungrouping 3 values in 7 bits - reference: Section 7.1.3 Exponent Decoding */ - for (i = 0; i < 128; i++) { - ungroup_3_in_7_bits_tab[i][0] = i / 25; - ungroup_3_in_7_bits_tab[i][1] = (i % 25) / 5; - ungroup_3_in_7_bits_tab[i][2] = (i % 25) % 5; - } - - /* generate grouped mantissa tables - reference: Section 7.3.5 Ungrouping of Mantissas */ - for (i = 0; i < 32; i++) { - /* bap=1 mantissas */ - b1_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][0], 3); - b1_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][1], 3); - b1_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][2], 3); - } - for (i = 0; i < 128; i++) { - /* bap=2 mantissas */ - b2_mantissas[i][0] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][0], 5); - b2_mantissas[i][1] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][1], 5); - b2_mantissas[i][2] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][2], 5); - - /* bap=4 mantissas */ - b4_mantissas[i][0] = symmetric_dequant(i / 11, 11); - b4_mantissas[i][1] = symmetric_dequant(i % 11, 11); - } - /* generate ungrouped mantissa tables - reference: Tables 7.21 and 7.23 */ - for (i = 0; i < 7; i++) { - /* bap=3 mantissas */ - b3_mantissas[i] = symmetric_dequant(i, 7); - } - for (i = 0; i < 15; i++) { - /* bap=5 mantissas */ - b5_mantissas[i] = symmetric_dequant(i, 15); - } - -#if (!USE_FIXED) /* generate dynamic range table reference: Section 7.7.1 Dynamic Range Control */ - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { int v = (i >> 5) - ((i >> 7) << 3) - 5; dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0x1F) | 0x20); } /* generate compr dynamic range table reference: Section 7.7.2 Heavy Compression */ - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { int v = (i >> 4) - ((i >> 7) << 4) - 4; ff_ac3_heavy_dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0xF) | 0x10); } -#endif + ff_ac3_init_static(); } +#endif static void ac3_downmix(AVCodecContext *avctx) { @@ -199,7 +89,6 @@ static void ac3_downmix(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; } - s->downmixed = 1; } /** @@ -207,7 +96,6 @@ static void ac3_downmix(AVCodecContext *avctx) */ static av_cold int ac3_decode_init(AVCodecContext *avctx) { - static AVOnce init_static_once = AV_ONCE_INIT; AC3DecodeContext *s = avctx->priv_data; const float scale = 1.0f; int i, ret; @@ -241,81 +129,31 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx) avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; ac3_downmix(avctx); + s->downmixed = 1; for (i = 0; i < AC3_MAX_CHANNELS; i++) { s->xcfptr[i] = s->transform_coeffs[i]; s->dlyptr[i] = s->delay[i]; } - ff_thread_once(&init_static_once, ac3_tables_init); +#if USE_FIXED + ff_ac3_init_static(); +#else + static AVOnce init_static_once = AV_ONCE_INIT; + ff_thread_once(&init_static_once, ac3_float_tables_init); +#endif return 0; } -/** - * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream. - * GetBitContext within AC3DecodeContext must point to - * the start of the synchronized AC-3 bitstream. - */ -static int ac3_parse_header(AC3DecodeContext *s) +static av_cold void ac3_decode_flush(AVCodecContext *avctx) { - GetBitContext *gbc = &s->gbc; - int i; + AC3DecodeContext *s = avctx->priv_data; - /* read the rest of the bsi. read twice for dual mono mode. */ - i = !s->channel_mode; - do { - s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5); - if (s->dialog_normalization[(!s->channel_mode)-i] == 0) { - s->dialog_normalization[(!s->channel_mode)-i] = -31; - } - if (s->target_level != 0) { - s->level_gain[(!s->channel_mode)-i] = powf(2.0f, - (float)(s->target_level - - s->dialog_normalization[(!s->channel_mode)-i])/6.0f); - } - if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) { - s->heavy_dynamic_range[(!s->channel_mode)-i] = - AC3_HEAVY_RANGE(get_bits(gbc, 8)); - } - if (get_bits1(gbc)) - skip_bits(gbc, 8); //skip language code - if (get_bits1(gbc)) - skip_bits(gbc, 7); //skip audio production information - } while (i--); + memset(&s->frame_type, 0, sizeof(*s) - offsetof(AC3DecodeContext, frame_type)); - skip_bits(gbc, 2); //skip copyright bit and original bitstream bit - - /* skip the timecodes or parse the Alternate Bit Stream Syntax */ - if (s->bitstream_id != 6) { - if (get_bits1(gbc)) - skip_bits(gbc, 14); //skip timecode1 - if (get_bits1(gbc)) - skip_bits(gbc, 14); //skip timecode2 - } else { - if (get_bits1(gbc)) { - s->preferred_downmix = get_bits(gbc, 2); - s->center_mix_level_ltrt = get_bits(gbc, 3); - s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); - s->center_mix_level = get_bits(gbc, 3); - s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); - } - if (get_bits1(gbc)) { - s->dolby_surround_ex_mode = get_bits(gbc, 2); - s->dolby_headphone_mode = get_bits(gbc, 2); - skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1) - } - } - - /* skip additional bitstream info */ - if (get_bits1(gbc)) { - i = get_bits(gbc, 6); - do { - skip_bits(gbc, 8); - } while (i--); - } - - return 0; + AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256); + av_lfg_init(&s->dith_state, 0); } /** @@ -345,9 +183,11 @@ static int parse_frame_header(AC3DecodeContext *s) 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; + if (hdr.bitstream_id <= 10) { + s->center_mix_level = hdr.center_mix_level; + s->surround_mix_level = hdr.surround_mix_level; + } s->center_mix_level_ltrt = 4; // -3.0dB - s->surround_mix_level = hdr.surround_mix_level; s->surround_mix_level_ltrt = 4; // -3.0dB s->lfe_mix_level_exists = 0; s->num_blocks = hdr.num_blocks; @@ -375,10 +215,25 @@ static int parse_frame_header(AC3DecodeContext *s) s->dba_syntax = 1; s->skip_syntax = 1; memset(s->channel_uses_aht, 0, sizeof(s->channel_uses_aht)); - return ac3_parse_header(s); + /* volume control params */ + for (int i = 0; i < (s->channel_mode ? 1 : 2); i++) { + s->dialog_normalization[i] = hdr.dialog_normalization[i]; + if (s->dialog_normalization[i] == 0) { + s->dialog_normalization[i] = -31; + } + if (s->target_level != 0) { + s->level_gain[i] = powf(2.0f, + (float)(s->target_level - s->dialog_normalization[i])/6.0f); + } + s->compression_exists[i] = hdr.compression_exists[i]; + if (s->compression_exists[i]) { + s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr.heavy_dynamic_range[i]); + } + } + return 0; } else if (CONFIG_EAC3_DECODER) { s->eac3 = 1; - return ff_eac3_parse_header(s); + return ff_eac3_parse_header(s, &hdr); } else { av_log(s->avctx, AV_LOG_ERROR, "E-AC-3 support not compiled in\n"); return AVERROR(ENOSYS); @@ -392,8 +247,8 @@ static int parse_frame_header(AC3DecodeContext *s) static int set_downmix_coeffs(AC3DecodeContext *s) { int i; - float cmix = gain_levels[s-> center_mix_level]; - float smix = gain_levels[s->surround_mix_level]; + float cmix = ff_ac3_gain_levels[s-> center_mix_level]; + float smix = ff_ac3_gain_levels[s->surround_mix_level]; float norm0, norm1; float downmix_coeffs[2][AC3_MAX_CHANNELS]; @@ -406,8 +261,8 @@ static int set_downmix_coeffs(AC3DecodeContext *s) } for (i = 0; i < s->fbw_channels; i++) { - downmix_coeffs[0][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]]; - downmix_coeffs[1][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]]; + downmix_coeffs[0][i] = ff_ac3_gain_levels[ff_ac3_default_coeffs[s->channel_mode][i][0]]; + downmix_coeffs[1][i] = ff_ac3_gain_levels[ff_ac3_default_coeffs[s->channel_mode][i][1]]; } if (s->channel_mode > 1 && s->channel_mode & 1) { downmix_coeffs[0][1] = downmix_coeffs[1][1] = cmix; @@ -467,9 +322,9 @@ static int decode_exponents(AC3DecodeContext *s, av_log(s->avctx, AV_LOG_ERROR, "expacc %d is out-of-range\n", expacc); return AVERROR_INVALIDDATA; } - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][0]; - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][1]; - dexp[i++] = ungroup_3_in_7_bits_tab[expacc][2]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][0]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][1]; + dexp[i++] = ff_ac3_ungroup_3_in_7_bits_tab[expacc][2]; } /* convert to absolute exps and expand groups */ @@ -564,9 +419,9 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b1_mant[m->b1]; } else { int bits = get_bits(gbc, 5); - mantissa = b1_mantissas[bits][0]; - m->b1_mant[1] = b1_mantissas[bits][1]; - m->b1_mant[0] = b1_mantissas[bits][2]; + mantissa = ff_ac3_bap1_mantissas[bits][0]; + m->b1_mant[1] = ff_ac3_bap1_mantissas[bits][1]; + m->b1_mant[0] = ff_ac3_bap1_mantissas[bits][2]; m->b1 = 2; } break; @@ -576,14 +431,14 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b2_mant[m->b2]; } else { int bits = get_bits(gbc, 7); - mantissa = b2_mantissas[bits][0]; - m->b2_mant[1] = b2_mantissas[bits][1]; - m->b2_mant[0] = b2_mantissas[bits][2]; + mantissa = ff_ac3_bap2_mantissas[bits][0]; + m->b2_mant[1] = ff_ac3_bap2_mantissas[bits][1]; + m->b2_mant[0] = ff_ac3_bap2_mantissas[bits][2]; m->b2 = 2; } break; case 3: - mantissa = b3_mantissas[get_bits(gbc, 3)]; + mantissa = ff_ac3_bap3_mantissas[get_bits(gbc, 3)]; break; case 4: if (m->b4) { @@ -591,13 +446,13 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma mantissa = m->b4_mant; } else { int bits = get_bits(gbc, 7); - mantissa = b4_mantissas[bits][0]; - m->b4_mant = b4_mantissas[bits][1]; + mantissa = ff_ac3_bap4_mantissas[bits][0]; + m->b4_mant = ff_ac3_bap4_mantissas[bits][1]; m->b4 = 1; } break; case 5: - mantissa = b5_mantissas[get_bits(gbc, 4)]; + mantissa = ff_ac3_bap5_mantissas[get_bits(gbc, 4)]; break; default: /* 6 to 15 */ /* Shift mantissa and sign-extend it. */ @@ -605,7 +460,7 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma av_log(s->avctx, AV_LOG_ERROR, "bap %d is invalid in plain AC-3\n", bap); bap = 15; } - mantissa = (unsigned)get_sbits(gbc, quantization_tab[bap]) << (24 - quantization_tab[bap]); + mantissa = (unsigned)get_sbits(gbc, ff_ac3_quantization_tab[bap]) << (24 - ff_ac3_quantization_tab[bap]); break; } coeffs[freq] = mantissa >> exps[freq]; @@ -842,16 +697,18 @@ static void decode_band_structure(GetBitContext *gbc, int blk, int eac3, static inline int spx_strategy(AC3DecodeContext *s, int blk) { GetBitContext *bc = &s->gbc; - int fbw_channels = s->fbw_channels; int dst_start_freq, dst_end_freq, src_start_freq, - start_subband, end_subband, ch; + start_subband, end_subband; /* determine which channels use spx */ if (s->channel_mode == AC3_CHMODE_MONO) { s->channel_uses_spx[1] = 1; } else { - for (ch = 1; ch <= fbw_channels; ch++) - s->channel_uses_spx[ch] = get_bits1(bc); + unsigned channel_uses_spx = get_bits(bc, s->fbw_channels); + for (int ch = s->fbw_channels; ch >= 1; --ch) { + s->channel_uses_spx[ch] = channel_uses_spx & 1; + channel_uses_spx >>= 1; + } } /* get the frequency bins of the spx copy region and the spx start @@ -1498,7 +1355,6 @@ static int ac3_decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t extended_channel_map[EAC3_MAX_CHANNELS]; const SHORTFLOAT *output[AC3_MAX_CHANNELS]; enum AVMatrixEncoding matrix_encoding; - AVDownmixInfo *downmix_info; uint64_t mask; s->superframe_size = 0; @@ -1562,6 +1418,9 @@ dependent_frame: av_log(avctx, AV_LOG_ERROR, "invalid frame type\n"); } break; + case AC3_PARSE_ERROR_CHANNEL_MAP: + av_log(avctx, AV_LOG_ERROR, "invalid channel map\n"); + return AVERROR_INVALIDDATA; case AC3_PARSE_ERROR_CRC: break; default: // Normal AVERROR do not try to recover. @@ -1607,10 +1466,24 @@ dependent_frame: s->output_mode = AC3_CHMODE_STEREO; } - s->loro_center_mix_level = gain_levels[s-> center_mix_level]; - s->loro_surround_mix_level = gain_levels[s->surround_mix_level]; - s->ltrt_center_mix_level = LEVEL_MINUS_3DB; - s->ltrt_surround_mix_level = LEVEL_MINUS_3DB; + s->loro_center_mix_level = ff_ac3_gain_levels[s-> center_mix_level]; + s->loro_surround_mix_level = ff_ac3_gain_levels[s->surround_mix_level]; + s->ltrt_center_mix_level = ff_ac3_gain_levels[s-> center_mix_level_ltrt]; + s->ltrt_surround_mix_level = ff_ac3_gain_levels[s->surround_mix_level_ltrt]; + switch (s->preferred_downmix) { + case AC3_DMIXMOD_LTRT: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_LTRT; + break; + case AC3_DMIXMOD_LORO: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_LORO; + break; + case AC3_DMIXMOD_DPLII: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_DPLII; + break; + default: + s->preferred_stereo_downmix = AV_DOWNMIX_TYPE_UNKNOWN; + break; + } /* set downmixing coefficients if needed */ if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) && s->fbw_channels == s->out_channels)) { @@ -1811,11 +1684,16 @@ skip: break; } } - if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0) + if (matrix_encoding != AV_MATRIX_ENCODING_NONE && + (ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0) return ret; /* AVDownmixInfo */ - if ((downmix_info = av_downmix_info_update_side_data(frame))) { + if ( (s->channel_mode > AC3_CHMODE_STEREO) && + ((s->output_mode & ~AC3_OUTPUT_LFEON) > AC3_CHMODE_STEREO)) { + AVDownmixInfo *downmix_info = av_downmix_info_update_side_data(frame); + if (!downmix_info) + return AVERROR(ENOMEM); switch (s->preferred_downmix) { case AC3_DMIXMOD_LTRT: downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LTRT; @@ -1830,16 +1708,15 @@ skip: downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_UNKNOWN; break; } - downmix_info->center_mix_level = gain_levels[s-> center_mix_level]; - downmix_info->center_mix_level_ltrt = gain_levels[s-> center_mix_level_ltrt]; - downmix_info->surround_mix_level = gain_levels[s-> surround_mix_level]; - downmix_info->surround_mix_level_ltrt = gain_levels[s->surround_mix_level_ltrt]; + downmix_info->center_mix_level = ff_ac3_gain_levels[s-> center_mix_level]; + downmix_info->center_mix_level_ltrt = ff_ac3_gain_levels[s-> center_mix_level_ltrt]; + downmix_info->surround_mix_level = ff_ac3_gain_levels[s-> surround_mix_level]; + downmix_info->surround_mix_level_ltrt = ff_ac3_gain_levels[s->surround_mix_level_ltrt]; if (s->lfe_mix_level_exists) - downmix_info->lfe_mix_level = gain_levels_lfe[s->lfe_mix_level]; + downmix_info->lfe_mix_level = ff_eac3_gain_levels_lfe[s->lfe_mix_level]; else downmix_info->lfe_mix_level = 0.0; // -inf dB - } else - return AVERROR(ENOMEM); + } *got_frame_ptr = 1; diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h index 98de7b5abf..a099264475 100644 --- a/libavcodec/ac3dec.h +++ b/libavcodec/ac3dec.h @@ -75,6 +75,29 @@ typedef struct AC3DecodeContext { AVCodecContext *avctx; ///< parent context GetBitContext gbc; ///< bitstream reader +///@name Optimization + BswapDSPContext bdsp; +#if USE_FIXED + AVFixedDSPContext *fdsp; +#else + AVFloatDSPContext *fdsp; +#endif + AC3DSPContext ac3dsp; + FmtConvertContext fmt_conv; ///< optimized conversion functions +///@} + + AVTXContext *tx_128, *tx_256; + av_tx_fn tx_fn_128, tx_fn_256; + + INTFLOAT *xcfptr[AC3_MAX_CHANNELS]; + INTFLOAT *dlyptr[AC3_MAX_CHANNELS]; + + AVChannelLayout downmix_layout; + SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients + +// Start of flushable fields. +// frame_type must be the flushable field, or the offset changed in ac3_decode_flush(). + ///@name Bit stream information ///@{ int frame_type; ///< frame type (strmtyp) @@ -164,7 +187,6 @@ typedef struct AC3DecodeContext { int fbw_channels; ///< number of full-bandwidth channels int channels; ///< number of total channels int lfe_ch; ///< index of LFE channel - SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients int downmixed; ///< indicates if coeffs are currently downmixed int output_mode; ///< output channel configuration int prev_output_mode; ///< output channel configuration for previous frame @@ -222,24 +244,9 @@ typedef struct AC3DecodeContext { ///@name IMDCT int block_switch[AC3_MAX_CHANNELS]; ///< block switch flags (blksw) - AVTXContext *tx_128, *tx_256; - av_tx_fn tx_fn_128, tx_fn_256; -///@} - -///@name Optimization - BswapDSPContext bdsp; -#if USE_FIXED - AVFixedDSPContext *fdsp; -#else - AVFloatDSPContext *fdsp; -#endif - AC3DSPContext ac3dsp; - FmtConvertContext fmt_conv; ///< optimized conversion functions ///@} SHORTFLOAT *outptr[AC3_MAX_CHANNELS]; - INTFLOAT *xcfptr[AC3_MAX_CHANNELS]; - INTFLOAT *dlyptr[AC3_MAX_CHANNELS]; ///@name Aligned arrays DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients @@ -251,15 +258,15 @@ typedef struct AC3DecodeContext { 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 ///@} - - AVChannelLayout downmix_layout; } AC3DecodeContext; +struct AC3HeaderInfo; + /** * Parse the E-AC-3 frame header. * This parses both the bit stream info and audio frame header. */ -static int ff_eac3_parse_header(AC3DecodeContext *s); +static int ff_eac3_parse_header(AC3DecodeContext *s, const struct AC3HeaderInfo *hdr); /** * Decode mantissas in a single channel for the entire frame. diff --git a/libavcodec/ac3dec_data.c b/libavcodec/ac3dec_data.c index a3794ab223..0f5402c335 100644 --- a/libavcodec/ac3dec_data.c +++ b/libavcodec/ac3dec_data.c @@ -21,10 +21,11 @@ /** * @file - * Tables taken directly from the AC-3 spec. + * Tables taken directly from the AC-3 spec or derived from it. */ #include "ac3dec_data.h" +#include "libavutil/thread.h" /** * Table used to ungroup 3 values stored in 5 bits. @@ -42,6 +43,124 @@ const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3] = { { 3, 0, 1 }, { 3, 0, 2 }, { 3, 1, 0 }, { 3, 1, 1 } }; +/** + * table for ungrouping 3 values in 7 bits. + * used for exponents and bap=2 mantissas + */ +uint8_t ff_ac3_ungroup_3_in_7_bits_tab[128][3]; + +/** + * Symmetrical Dequantization + * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization + * Tables 7.19 to 7.23 + */ +#define SYMMETRIC_DEQUANT(code, levels) (((code - (levels >> 1)) * (1 << 24)) / levels) +/** + * Ungrouped mantissa tables; the extra entry is padding to avoid range checks + */ +/** + * Table 7.21 + */ +const int ff_ac3_bap3_mantissas[7 + 1] = { + SYMMETRIC_DEQUANT(0, 7), + SYMMETRIC_DEQUANT(1, 7), + SYMMETRIC_DEQUANT(2, 7), + SYMMETRIC_DEQUANT(3, 7), + SYMMETRIC_DEQUANT(4, 7), + SYMMETRIC_DEQUANT(5, 7), + SYMMETRIC_DEQUANT(6, 7), +}; +/** + * Table 7.23 + */ +const int ff_ac3_bap5_mantissas[15 + 1] = { + SYMMETRIC_DEQUANT(0, 15), + SYMMETRIC_DEQUANT(1, 15), + SYMMETRIC_DEQUANT(2, 15), + SYMMETRIC_DEQUANT(3, 15), + SYMMETRIC_DEQUANT(4, 15), + SYMMETRIC_DEQUANT(5, 15), + SYMMETRIC_DEQUANT(6, 15), + SYMMETRIC_DEQUANT(7, 15), + SYMMETRIC_DEQUANT(8, 15), + SYMMETRIC_DEQUANT(9, 15), + SYMMETRIC_DEQUANT(10, 15), + SYMMETRIC_DEQUANT(11, 15), + SYMMETRIC_DEQUANT(12, 15), + SYMMETRIC_DEQUANT(13, 15), + SYMMETRIC_DEQUANT(14, 15), +}; + +int ff_ac3_bap1_mantissas[32][3]; +int ff_ac3_bap2_mantissas[128][3]; +int ff_ac3_bap4_mantissas[128][2]; + +static inline int +symmetric_dequant(int code, int levels) +{ + return SYMMETRIC_DEQUANT(code, levels); +} + +static av_cold void ac3_init_static(void) +{ + /* generate table for ungrouping 3 values in 7 bits + reference: Section 7.1.3 Exponent Decoding */ + for (int i = 0; i < 128; ++i) { + ff_ac3_ungroup_3_in_7_bits_tab[i][0] = i / 25; + ff_ac3_ungroup_3_in_7_bits_tab[i][1] = (i % 25) / 5; + ff_ac3_ungroup_3_in_7_bits_tab[i][2] = (i % 25) % 5; + } + + /* generate grouped mantissa tables + reference: Section 7.3.5 Ungrouping of Mantissas */ + for (int i = 0; i < 32; ++i) { + /* bap=1 mantissas */ + ff_ac3_bap1_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][0], 3); + ff_ac3_bap1_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][1], 3); + ff_ac3_bap1_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][2], 3); + } + for (int i = 0; i < 128; ++i) { + /* bap=2 mantissas */ + ff_ac3_bap2_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][0], 5); + ff_ac3_bap2_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][1], 5); + ff_ac3_bap2_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_7_bits_tab[i][2], 5); + + /* bap=4 mantissas */ + ff_ac3_bap4_mantissas[i][0] = symmetric_dequant(i / 11, 11); + ff_ac3_bap4_mantissas[i][1] = symmetric_dequant(i % 11, 11); + } +} + +av_cold void ff_ac3_init_static(void) +{ + static AVOnce ac3_init_static_once = AV_ONCE_INIT; + ff_thread_once(&ac3_init_static_once, ac3_init_static); +} + +/** + * Quantization table: levels for symmetric. bits for asymmetric. + * reference: Table 7.18 Mapping of bap to Quantizer + */ +const uint8_t ff_ac3_quantization_tab[16] = { + 0, 3, 5, 7, 11, 15, + 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 +}; + +/** + * Table for default stereo downmixing coefficients + * reference: Section 7.8.2 Downmixing Into Two Channels + */ +const uint8_t ff_ac3_default_coeffs[8][5][2] = { + { { 2, 7 }, { 7, 2 }, }, + { { 4, 4 }, }, + { { 2, 7 }, { 7, 2 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 8, 8 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, +}; + const uint8_t ff_eac3_hebap_tab[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, @@ -57,3 +176,12 @@ const uint8_t ff_eac3_hebap_tab[64] = { */ const uint8_t ff_eac3_default_spx_band_struct[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; + +/** Adjustments in dB gain (LFE, +10 to -21 dB) */ +const float ff_eac3_gain_levels_lfe[32] = { + 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893, + 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946, + 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227, + 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253, + 0.125892, 0.112201, 0.100000, 0.089125 +}; diff --git a/libavcodec/ac3dec_data.h b/libavcodec/ac3dec_data.h index 975b52ef2c..613871627b 100644 --- a/libavcodec/ac3dec_data.h +++ b/libavcodec/ac3dec_data.h @@ -24,9 +24,31 @@ #include +#include "libavutil/attributes_internal.h" + +FF_VISIBILITY_PUSH_HIDDEN + extern const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3]; +extern uint8_t ff_ac3_ungroup_3_in_7_bits_tab[128][3]; + +extern const int ff_ac3_bap3_mantissas[ 7 + 1]; +extern const int ff_ac3_bap5_mantissas[15 + 1]; + +/** tables for ungrouping mantissas */ +extern int ff_ac3_bap1_mantissas[32][3]; +extern int ff_ac3_bap2_mantissas[128][3]; +extern int ff_ac3_bap4_mantissas[128][2]; + +extern const uint8_t ff_ac3_quantization_tab[16]; + +extern const uint8_t ff_ac3_default_coeffs[8][5][2]; extern const uint8_t ff_eac3_hebap_tab[64]; extern const uint8_t ff_eac3_default_spx_band_struct[17]; +extern const float ff_eac3_gain_levels_lfe[32]; + +void ff_ac3_init_static(void); + +FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_AC3DEC_DATA_H */ diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c index c9e5cda69c..285553c22e 100644 --- a/libavcodec/ac3dec_fixed.c +++ b/libavcodec/ac3dec_fixed.c @@ -47,6 +47,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config_components.h" #define USE_FIXED 1 #include "ac3dec.h" #include "codec_internal.h" @@ -152,7 +153,9 @@ static void ac3_downmix_c_fixed16(int16_t **samples, int16_t **matrix, } } +#if CONFIG_EAC3_DECODER #include "eac3dec.c" +#endif #include "ac3dec.c" static const AVOption options[] = { @@ -178,11 +181,11 @@ const FFCodec ff_ac3_fixed_decoder = { .p.priv_class = &ac3_decoder_class, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c index 550a9017de..95a0c424c6 100644 --- a/libavcodec/ac3dec_float.c +++ b/libavcodec/ac3dec_float.c @@ -34,20 +34,23 @@ #include "ac3dec.h" #include "codec_internal.h" #include "profiles.h" +#if CONFIG_EAC3_DECODER #include "eac3dec.c" +#endif #include "ac3dec.c" +#define EXPORT (AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY) static const AVOption options[] = { { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR }, -{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, 0, .unit = "dmix_mode"}, -{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, -{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, +{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 3, EXPORT, .unit = "dmix_mode"}, +{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, +{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, EXPORT }, { "downmix", "Request a specific channel layout from the decoder", OFFSET(downmix_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL}, .flags = PAR }, @@ -67,13 +70,13 @@ const FFCodec ff_ac3_decoder = { .p.id = AV_CODEC_ID_AC3, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, CODEC_LONG_NAME("ATSC A/52A (AC-3)"), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ac3_eac3_decoder_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -85,13 +88,13 @@ const FFCodec ff_eac3_decoder = { .p.id = AV_CODEC_ID_EAC3, .priv_data_size = sizeof (AC3DecodeContext), .init = ac3_decode_init, + .flush = ac3_decode_flush, .close = ac3_decode_end, FF_CODEC_DECODE_CB(ac3_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, CODEC_LONG_NAME("ATSC A/52B (AC-3, E-AC-3)"), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ac3_eac3_decoder_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_eac3_profiles), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/ac3defs.h b/libavcodec/ac3defs.h index ff92f0ac4a..8d6a58d21f 100644 --- a/libavcodec/ac3defs.h +++ b/libavcodec/ac3defs.h @@ -34,6 +34,19 @@ #define AC3_CRITICAL_BANDS 50 #define AC3_MAX_CPL_BANDS 18 +#define EAC3_SR_CODE_REDUCED 3 + +/* pre-defined gain values */ +#define LEVEL_PLUS_3DB M_SQRT2 +#define LEVEL_PLUS_1POINT5DB 1.1892071150027209 +#define LEVEL_MINUS_1POINT5DB 0.8408964152537145 +#define LEVEL_MINUS_3DB M_SQRT1_2 +#define LEVEL_MINUS_4POINT5DB 0.5946035575013605 +#define LEVEL_MINUS_6DB 0.5000000000000000 +#define LEVEL_MINUS_9DB 0.3535533905932738 +#define LEVEL_ZERO 0.0000000000000000 +#define LEVEL_ONE 1.0000000000000000 + /* exponent encoding strategy */ #define EXP_REUSE 0 #define EXP_NEW 1 diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 3649289865..a316d4e4d7 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -71,10 +71,7 @@ static const float surmixlev_options[SURMIXLEV_NUM_OPTIONS] = { }; #define EXTMIXLEV_NUM_OPTIONS 8 -static const float extmixlev_options[EXTMIXLEV_NUM_OPTIONS] = { - LEVEL_PLUS_3DB, LEVEL_PLUS_1POINT5DB, LEVEL_ONE, LEVEL_MINUS_1POINT5DB, - LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB, LEVEL_ZERO -}; +#define extmixlev_options ff_ac3_gain_levels /* The first two options apply only to the AC-3 encoders; * the rest is also valid for EAC-3. When modifying it, @@ -1638,6 +1635,8 @@ static void ac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) { AC3EncOptions *opt = &s->options; + put_bits_assume_flushed(pb); + put_bits(pb, 16, 0x0b77); /* frame header */ put_bits(pb, 16, 0); /* crc1: will be filled later */ put_bits(pb, 2, s->bit_alloc.sr_code); diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index 869e1f27a2..42530b0ea1 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -119,11 +119,10 @@ const FFCodec ff_ac3_fixed_encoder = { .init = ac3_fixed_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), .p.priv_class = &ff_ac3enc_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, }; diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 94e8ebc42d..0ae7ddd7eb 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -121,11 +121,10 @@ const FFCodec ff_ac3_encoder = { .init = ff_ac3_float_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &ff_ac3enc_class, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/ac3tab.c b/libavcodec/ac3tab.c index 48c89a8ba0..b38e7237b3 100644 --- a/libavcodec/ac3tab.c +++ b/libavcodec/ac3tab.c @@ -25,6 +25,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mathematics.h" #include "ac3tab.h" @@ -147,6 +148,19 @@ const uint16_t ff_ac3_fast_gain_tab[8]= { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, }; +/** Adjustments in dB gain */ +const float ff_ac3_gain_levels[9] = { + LEVEL_PLUS_3DB, + LEVEL_PLUS_1POINT5DB, + LEVEL_ONE, + LEVEL_MINUS_1POINT5DB, + LEVEL_MINUS_3DB, + LEVEL_MINUS_4POINT5DB, + LEVEL_MINUS_6DB, + LEVEL_ZERO, + LEVEL_MINUS_9DB +}; + const uint64_t ff_eac3_custom_channel_map_locations[16][2] = { { 1, AV_CH_FRONT_LEFT }, { 1, AV_CH_FRONT_CENTER }, diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h index dcef643acb..3f83ce7b8c 100644 --- a/libavcodec/ac3tab.h +++ b/libavcodec/ac3tab.h @@ -26,6 +26,9 @@ #include "ac3defs.h" +#include "libavutil/attributes_internal.h" + +FF_VISIBILITY_PUSH_HIDDEN extern const uint16_t ff_ac3_frame_size_tab[38][3]; extern const uint8_t ff_ac3_channels_tab[8]; extern const uint16_t ff_ac3_channel_layout_tab[8]; @@ -43,7 +46,9 @@ extern const int16_t ff_ac3_floor_tab[8]; extern const uint16_t ff_ac3_fast_gain_tab[8]; extern const uint8_t ff_ac3_band_start_tab[AC3_CRITICAL_BANDS+1]; extern const uint8_t ff_ac3_bin_to_band_tab[253]; +extern const float ff_ac3_gain_levels[9]; extern const uint64_t ff_eac3_custom_channel_map_locations[16][2]; +FF_VISIBILITY_POP_HIDDEN #define COMMON_CHANNEL_MAP \ { { 0, 1, }, { 0, 1, 2, } },\ diff --git a/libavcodec/acelp_pitch_delay.c b/libavcodec/acelp_pitch_delay.c index 6cf880e4ac..65f659cb2e 100644 --- a/libavcodec/acelp_pitch_delay.c +++ b/libavcodec/acelp_pitch_delay.c @@ -90,7 +90,7 @@ float ff_amr_set_fixed_gain(float fixed_gain_factor, float fixed_mean_energy, // Note 10^(0.05 * -10log(average x2)) = 1/sqrt((average x2)). float val = fixed_gain_factor * ff_exp10(0.05 * - (avpriv_scalarproduct_float_c(pred_table, prediction_error, 4) + + (ff_scalarproduct_float_c(pred_table, prediction_error, 4) + energy_mean)) / sqrtf(fixed_mean_energy ? fixed_mean_energy : 1.0); diff --git a/libavcodec/acelp_vectors.c b/libavcodec/acelp_vectors.c index 04cbffd79f..f47da40008 100644 --- a/libavcodec/acelp_vectors.c +++ b/libavcodec/acelp_vectors.c @@ -193,7 +193,7 @@ void ff_adaptive_gain_control(float *out, const float *in, float speech_energ, int size, float alpha, float *gain_mem) { int i; - float postfilter_energ = avpriv_scalarproduct_float_c(in, in, size); + float postfilter_energ = ff_scalarproduct_float_c(in, in, size); float gain_scale_factor = 1.0; float mem = *gain_mem; @@ -214,7 +214,7 @@ void ff_scale_vector_to_given_sum_of_squares(float *out, const float *in, float sum_of_squares, const int n) { int i; - float scalefactor = avpriv_scalarproduct_float_c(in, in, n); + float scalefactor = ff_scalarproduct_float_c(in, in, n); if (scalefactor) scalefactor = sqrt(sum_of_squares / scalefactor); for (i = 0; i < n; i++) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index c6b6e22e95..83ef7c780a 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -17,6 +17,7 @@ * Ubisoft ADPCM decoder by Zane van Iperen (zane@zanevaniperen.com) * High Voltage Software ALP decoder by Zane van Iperen (zane@zanevaniperen.com) * Cunning Developments decoder by Zane van Iperen (zane@zanevaniperen.com) + * Sanyo LD-ADPCM decoder by Peter Ross (pross@xvid.org) * * This file is part of FFmpeg. * @@ -260,6 +261,9 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_IMA_AMV: max_channels = 1; break; + case AV_CODEC_ID_ADPCM_SANYO: + max_channels = 2; + break; case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_EA_R1: case AV_CODEC_ID_ADPCM_EA_R2: @@ -307,6 +311,14 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) avctx->block_align != 17 * avctx->ch_layout.nb_channels) return AVERROR_INVALIDDATA; break; + case AV_CODEC_ID_ADPCM_SANYO: + if (avctx->bits_per_coded_sample < 3 || avctx->bits_per_coded_sample > 5) + return AVERROR_INVALIDDATA; + break; + case AV_CODEC_ID_ADPCM_IMA_XBOX: + if (avctx->bits_per_coded_sample != 4) + return AVERROR_INVALIDDATA; + break; case AV_CODEC_ID_ADPCM_ZORK: if (avctx->bits_per_coded_sample != 8) return AVERROR_INVALIDDATA; @@ -321,6 +333,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_QT: case AV_CODEC_ID_ADPCM_IMA_WAV: + case AV_CODEC_ID_ADPCM_IMA_XBOX: case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_XA: case AV_CODEC_ID_ADPCM_XMD: @@ -333,6 +346,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_PSX: + case AV_CODEC_ID_ADPCM_SANYO: case AV_CODEC_ID_ADPCM_MTAF: case AV_CODEC_ID_ADPCM_ARGO: case AV_CODEC_ID_ADPCM_IMA_MOFLEX: @@ -832,6 +846,172 @@ int16_t ff_adpcm_argo_expand_nibble(ADPCMChannelStatus *cs, int nibble, int shif return sample; } +static int adpcm_sanyo_expand3(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 4; + if (sign) + delta = 4 - (bits & 3); + else + delta = bits; + + switch (delta) { + case 0: + add = 0; + c->step = (3 * c->step) >> 2; + break; + case 1: + add = c->step; + c->step = (4 * c->step - (c->step >> 1)) >> 2; + break; + case 2: + add = 2 * c->step; + c->step = ((c->step >> 1) + add) >> 1; + break; + case 3: + add = 4 * c->step - (c->step >> 1); + c->step = 2 * c->step; + break; + case 4: + add = (11 * c->step) >> 1; + c->step = 3 * c->step; + break; + default: + av_unreachable("There are cases for all control paths when bits is 3-bit"); + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 7281); + return c->predictor; +} + +static int adpcm_sanyo_expand4(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 8; + if (sign) + delta = 8 - (bits & 7); + else + delta = bits; + + switch (delta) { + case 0: + add = 0; + c->step = (3 * c->step) >> 2; + break; + case 1: + add = c->step; + c->step = (3 * c->step) >> 2; + break; + case 2: + add = 2 * c->step; + break; + case 3: + add = 3 * c->step; + break; + case 4: + add = 4 * c->step; + break; + case 5: + add = (11 * c->step) >> 1; + c->step += c->step >> 2; + break; + case 6: + add = (15 * c->step) >> 1; + c->step = 2 * c->step; + break; + case 7: + if (sign) + add = (19 * c->step) >> 1; + else + add = (21 * c->step) >> 1; + c->step = (c->step >> 1) + 2 * c->step; + break; + case 8: + add = (25 * c->step) >> 1; + c->step = 5 * c->step; + break; + default: + av_unreachable("There are cases for all control paths when bits is 4-bit"); + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 2621); + return c->predictor; +} + +static int adpcm_sanyo_expand5(ADPCMChannelStatus *c, int bits) +{ + int sign, delta, add; + + sign = bits & 0x10; + if (sign) + delta = 16 - (bits & 0xF); + else + delta = bits; + + add = delta * c->step; + switch (delta) { + case 0: + c->step += (c->step >> 2) - (c->step >> 1); + break; + case 1: + case 2: + case 3: + c->step += (c->step >> 3) - (c->step >> 2); + break; + case 4: + case 5: + c->step += (c->step >> 4) - (c->step >> 3); + break; + case 6: + break; + case 7: + c->step += c->step >> 3; + break; + case 8: + c->step += c->step >> 2; + break; + case 9: + c->step += c->step >> 1; + break; + case 10: + c->step = 2 * c->step - (c->step >> 3); + break; + case 11: + c->step = 2 * c->step + (c->step >> 3); + break; + case 12: + c->step = 2 * c->step + (c->step >> 1) - (c->step >> 3); + break; + case 13: + c->step = 3 * c->step - (c->step >> 2); + break; + case 14: + c->step *= 3; + break; + case 15: + case 16: + c->step = (7 * c->step) >> 1; + break; + } + + if (sign) + add = -add; + + c->predictor = av_clip_int16(c->predictor + add); + c->step = av_clip(c->step, 1, 1024); + return c->predictor; +} + /** * Get the number of samples (per channel) that will be decoded from the packet. * In one case, this is actually the maximum number of samples possible to @@ -979,6 +1159,15 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, return AVERROR_INVALIDDATA; nb_samples = 1 + (buf_size - 4 * ch) / (bsize * ch) * bsamples; ) /* End of CASE */ + CASE(ADPCM_IMA_XBOX, + int bsize = ff_adpcm_ima_block_sizes[avctx->bits_per_coded_sample - 2]; + int bsamples = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2]; + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + if (buf_size < 4 * ch) + return AVERROR_INVALIDDATA; + nb_samples = (buf_size - 4 * ch) / (bsize * ch) * bsamples + 1; + ) /* End of CASE */ case AV_CODEC_ID_ADPCM_MS: if (avctx->block_align > 0) buf_size = FFMIN(buf_size, avctx->block_align); @@ -1058,6 +1247,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_ZORK: nb_samples = buf_size / ch; break; + case AV_CODEC_ID_ADPCM_SANYO: + if (!avctx->extradata || avctx->extradata_size != 2) + return AVERROR_INVALIDDATA; + nb_samples = AV_RL16(avctx->extradata); + break; } /* validate coded sample count */ @@ -1197,6 +1391,32 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_IMA_XBOX, + for (int i = 0; i < channels; i++) { + ADPCMChannelStatus *cs = &c->status[i]; + cs->predictor = samples_p[i][0] = sign_extend(bytestream2_get_le16u(&gb), 16); + + cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + if (cs->step_index > 88u) { + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", + i, cs->step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int n = 0; n < (nb_samples-1) / 8; n++) { + for (int i = 0; i < channels; i++) { + ADPCMChannelStatus *cs = &c->status[i]; + samples = &samples_p[i][1 + n * 8]; + for (int m = 0; m < 8; m += 2) { + int v = bytestream2_get_byteu(&gb); + samples[m ] = adpcm_ima_expand_nibble(cs, v & 0x0F, 3); + samples[m + 1] = adpcm_ima_expand_nibble(cs, v >> 4 , 3); + } + } + } + frame->nb_samples--; + ) /* End of CASE */ CASE(ADPCM_4XM, for (int i = 0; i < channels; i++) c->status[i].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); @@ -2225,6 +2445,29 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_SANYO, + int (*expand)(ADPCMChannelStatus *c, int bits); + GetBitContext g; + + switch(avctx->bits_per_coded_sample) { + case 3: expand = adpcm_sanyo_expand3; break; + case 4: expand = adpcm_sanyo_expand4; break; + case 5: expand = adpcm_sanyo_expand5; break; + } + + for (int ch = 0; ch < channels; ch++) { + c->status[ch].predictor = sign_extend(bytestream2_get_le16(&gb), 16); + c->status[ch].step = sign_extend(bytestream2_get_le16(&gb), 16); + } + + init_get_bits8(&g, gb.buffer, bytestream2_get_bytes_left(&gb)); + for (int i = 0; i < nb_samples; i++) + for (int ch = 0; ch < channels; ch++) + samples_p[ch][i] = expand(&c->status[ch], get_bits_le(&g, avctx->bits_per_coded_sample)); + + align_get_bits(&g); + bytestream2_skip(&gb, get_bits_count(&g) / 8); + ) /* End of CASE */ CASE(ADPCM_ARGO, /* * The format of each block: @@ -2279,7 +2522,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } ) /* End of CASE */ default: - av_assert0(0); // unsupported codec_id should not happen + av_unreachable("There are cases for all codec ids using adpcm_decode_frame"); } if (avpkt->size && bytestream2_tell(&gb) == 0) { @@ -2355,7 +2598,7 @@ const FFCodec ff_ ## name_ ## _decoder = { \ .p.type = AVMEDIA_TYPE_AUDIO, \ .p.id = id_, \ .p.capabilities = AV_CODEC_CAP_DR1, \ - .p.sample_fmts = sample_fmts_, \ + CODEC_SAMPLEFMTS_ARRAY(sample_fmts_), \ .priv_data_size = sizeof(ADPCMDecodeContext), \ .init = adpcm_decode_init, \ FF_CODEC_DECODE_CB(adpcm_decode_frame), \ @@ -2404,9 +2647,11 @@ ADPCM_DECODER(ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA ADPCM_DECODER(ADPCM_IMA_ALP, sample_fmts_s16, adpcm_ima_alp, "ADPCM IMA High Voltage Software ALP") ADPCM_DECODER(ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV") ADPCM_DECODER(ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood") +ADPCM_DECODER(ADPCM_IMA_XBOX, sample_fmts_s16p, adpcm_ima_xbox, "ADPCM IMA Xbox") ADPCM_DECODER(ADPCM_MS, sample_fmts_both, adpcm_ms, "ADPCM Microsoft") ADPCM_DECODER(ADPCM_MTAF, sample_fmts_s16p, adpcm_mtaf, "ADPCM MTAF") ADPCM_DECODER(ADPCM_PSX, sample_fmts_s16p, adpcm_psx, "ADPCM Playstation") +ADPCM_DECODER(ADPCM_SANYO, sample_fmts_s16p, adpcm_sanyo, "ADPCM Sanyo") ADPCM_DECODER(ADPCM_SBPRO_2, sample_fmts_s16, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit") ADPCM_DECODER(ADPCM_SBPRO_3, sample_fmts_s16, adpcm_sbpro_3, "ADPCM Sound Blaster Pro 2.6-bit") ADPCM_DECODER(ADPCM_SBPRO_4, sample_fmts_s16, adpcm_sbpro_4, "ADPCM Sound Blaster Pro 4-bit") diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c index 4d7534e47f..96a053351d 100644 --- a/libavcodec/adpcmenc.c +++ b/libavcodec/adpcmenc.c @@ -1002,11 +1002,11 @@ const FFCodec ff_ ## name_ ## _encoder = { \ CODEC_LONG_NAME(long_name_), \ .p.type = AVMEDIA_TYPE_AUDIO, \ .p.id = id_, \ - .p.sample_fmts = sample_fmts_, \ - .p.ch_layouts = ch_layouts, \ .p.capabilities = capabilities_ | AV_CODEC_CAP_DR1 | \ AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, \ .p.priv_class = &adpcm_encoder_class, \ + CODEC_CH_LAYOUTS_ARRAY(ch_layouts), \ + CODEC_SAMPLEFMTS_ARRAY(sample_fmts_), \ .priv_data_size = sizeof(ADPCMEncodeContext), \ .init = adpcm_encode_init, \ FF_CODEC_ENCODE_CB(adpcm_encode_frame), \ diff --git a/libavcodec/adxdec.c b/libavcodec/adxdec.c index 4300dede5e..21be6fea97 100644 --- a/libavcodec/adxdec.c +++ b/libavcodec/adxdec.c @@ -264,6 +264,5 @@ const FFCodec ff_adpcm_adx_decoder = { .flush = adx_decode_flush, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c index 796efdab63..5a8d4b8625 100644 --- a/libavcodec/adxenc.c +++ b/libavcodec/adxenc.c @@ -197,7 +197,6 @@ const FFCodec ff_adpcm_adx_encoder = { .priv_data_size = sizeof(ADXContext), .init = adx_encode_init, FF_CODEC_ENCODE_CB(adx_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_EOF_FLUSH, }; diff --git a/libavcodec/alacenc.c b/libavcodec/alacenc.c index caac624217..474200fee5 100644 --- a/libavcodec/alacenc.c +++ b/libavcodec/alacenc.c @@ -646,8 +646,6 @@ const FFCodec ff_alac_encoder = { .init = alac_encode_init, FF_CODEC_ENCODE_CB(alac_encode_frame), .close = alac_encode_close, - .p.ch_layouts = ff_alac_ch_layouts, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS_ARRAY(ff_alac_ch_layouts), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/aliaspixenc.c b/libavcodec/aliaspixenc.c index 90d2a63319..ed9202088c 100644 --- a/libavcodec/aliaspixenc.c +++ b/libavcodec/aliaspixenc.c @@ -108,7 +108,5 @@ const FFCodec ff_alias_pix_encoder = { .p.id = AV_CODEC_ID_ALIAS_PIX, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index aa0fc47647..f5ec2e01e8 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -29,6 +29,7 @@ #include "config.h" #include "libavutil/thread.h" +#include "avcodec.h" #include "codec.h" #include "codec_id.h" #include "codec_internal.h" @@ -46,6 +47,7 @@ extern const FFCodec ff_anm_decoder; extern const FFCodec ff_ansi_decoder; extern const FFCodec ff_apng_encoder; extern const FFCodec ff_apng_decoder; +extern const FFCodec ff_apv_decoder; extern const FFCodec ff_arbc_decoder; extern const FFCodec ff_argo_decoder; extern const FFCodec ff_asv1_encoder; @@ -116,6 +118,7 @@ extern const FFCodec ff_escape130_decoder; extern const FFCodec ff_exr_encoder; extern const FFCodec ff_exr_decoder; extern const FFCodec ff_ffv1_encoder; +extern const FFCodec ff_ffv1_vulkan_encoder; extern const FFCodec ff_ffv1_decoder; extern const FFCodec ff_ffvhuff_encoder; extern const FFCodec ff_ffvhuff_decoder; @@ -266,6 +269,7 @@ extern const FFCodec ff_prores_encoder; extern const FFCodec ff_prores_decoder; extern const FFCodec ff_prores_aw_encoder; extern const FFCodec ff_prores_ks_encoder; +extern const FFCodec ff_prores_raw_decoder; extern const FFCodec ff_prosumer_decoder; extern const FFCodec ff_psd_decoder; extern const FFCodec ff_ptx_decoder; @@ -296,6 +300,7 @@ extern const FFCodec ff_rv20_encoder; extern const FFCodec ff_rv20_decoder; extern const FFCodec ff_rv30_decoder; extern const FFCodec ff_rv40_decoder; +extern const FFCodec ff_rv60_decoder; extern const FFCodec ff_s302m_encoder; extern const FFCodec ff_s302m_decoder; extern const FFCodec ff_sanm_decoder; @@ -345,12 +350,14 @@ extern const FFCodec ff_utvideo_decoder; extern const FFCodec ff_v210_encoder; extern const FFCodec ff_v210_decoder; extern const FFCodec ff_v210x_decoder; +#if FF_API_V408_CODECID extern const FFCodec ff_v308_encoder; extern const FFCodec ff_v308_decoder; extern const FFCodec ff_v408_encoder; extern const FFCodec ff_v408_decoder; extern const FFCodec ff_v410_encoder; extern const FFCodec ff_v410_decoder; +#endif extern const FFCodec ff_vb_decoder; extern const FFCodec ff_vbn_encoder; extern const FFCodec ff_vbn_decoder; @@ -471,6 +478,7 @@ extern const FFCodec ff_flac_decoder; extern const FFCodec ff_ftr_decoder; extern const FFCodec ff_g723_1_encoder; extern const FFCodec ff_g723_1_decoder; +extern const FFCodec ff_g728_decoder; extern const FFCodec ff_g729_decoder; extern const FFCodec ff_gsm_decoder; extern const FFCodec ff_gsm_ms_decoder; @@ -682,10 +690,12 @@ extern const FFCodec ff_adpcm_ima_wav_encoder; extern const FFCodec ff_adpcm_ima_wav_decoder; extern const FFCodec ff_adpcm_ima_ws_encoder; extern const FFCodec ff_adpcm_ima_ws_decoder; +extern const FFCodec ff_adpcm_ima_xbox_decoder; extern const FFCodec ff_adpcm_ms_encoder; extern const FFCodec ff_adpcm_ms_decoder; extern const FFCodec ff_adpcm_mtaf_decoder; extern const FFCodec ff_adpcm_psx_decoder; +extern const FFCodec ff_adpcm_sanyo_decoder; extern const FFCodec ff_adpcm_sbpro_2_decoder; extern const FFCodec ff_adpcm_sbpro_3_decoder; extern const FFCodec ff_adpcm_sbpro_4_decoder; @@ -773,11 +783,14 @@ extern const FFCodec ff_libgsm_ms_encoder; extern const FFCodec ff_libgsm_ms_decoder; extern const FFCodec ff_libilbc_encoder; extern const FFCodec ff_libilbc_decoder; +extern const FFCodec ff_libjxl_anim_decoder; +extern const FFCodec ff_libjxl_anim_encoder; extern const FFCodec ff_libjxl_decoder; extern const FFCodec ff_libjxl_encoder; extern const FFCodec ff_liblc3_encoder; extern const FFCodec ff_liblc3_decoder; extern const FFCodec ff_libmp3lame_encoder; +extern const FFCodec ff_liboapv_encoder; extern const FFCodec ff_libopencore_amrnb_encoder; extern const FFCodec ff_libopencore_amrnb_decoder; extern const FFCodec ff_libopencore_amrwb_decoder; @@ -838,13 +851,19 @@ extern const FFCodec ff_av1_nvenc_encoder; extern const FFCodec ff_av1_qsv_decoder; extern const FFCodec ff_av1_qsv_encoder; extern const FFCodec ff_av1_amf_encoder; +extern const FFCodec ff_av1_amf_decoder; +extern const FFCodec ff_av1_mf_encoder; extern const FFCodec ff_av1_vaapi_encoder; +extern const FFCodec ff_av1_vulkan_encoder; extern const FFCodec ff_libopenh264_encoder; extern const FFCodec ff_libopenh264_decoder; extern const FFCodec ff_h264_amf_encoder; +extern const FFCodec ff_h264_amf_decoder; extern const FFCodec ff_h264_cuvid_decoder; extern const FFCodec ff_h264_mf_encoder; extern const FFCodec ff_h264_nvenc_encoder; +extern const FFCodec ff_h264_oh_decoder; +extern const FFCodec ff_h264_oh_encoder; extern const FFCodec ff_h264_omx_encoder; extern const FFCodec ff_h264_qsv_encoder; extern const FFCodec ff_h264_v4l2m2m_encoder; @@ -852,12 +871,15 @@ extern const FFCodec ff_h264_vaapi_encoder; extern const FFCodec ff_h264_videotoolbox_encoder; extern const FFCodec ff_h264_vulkan_encoder; extern const FFCodec ff_hevc_amf_encoder; +extern const FFCodec ff_hevc_amf_decoder; extern const FFCodec ff_hevc_cuvid_decoder; extern const FFCodec ff_hevc_d3d12va_encoder; extern const FFCodec ff_hevc_mediacodec_decoder; extern const FFCodec ff_hevc_mediacodec_encoder; extern const FFCodec ff_hevc_mf_encoder; extern const FFCodec ff_hevc_nvenc_encoder; +extern const FFCodec ff_hevc_oh_decoder; +extern const FFCodec ff_hevc_oh_encoder; extern const FFCodec ff_hevc_qsv_encoder; extern const FFCodec ff_hevc_v4l2m2m_encoder; extern const FFCodec ff_hevc_vaapi_encoder; @@ -887,6 +909,7 @@ extern const FFCodec ff_vp8_mediacodec_encoder; extern const FFCodec ff_vp8_qsv_decoder; extern const FFCodec ff_vp8_v4l2m2m_encoder; extern const FFCodec ff_vp8_vaapi_encoder; +extern const FFCodec ff_vp9_amf_decoder; extern const FFCodec ff_vp9_cuvid_decoder; extern const FFCodec ff_vp9_mediacodec_decoder; extern const FFCodec ff_vp9_mediacodec_encoder; @@ -925,14 +948,11 @@ static void av_codec_init_static(void) FF_DISABLE_DEPRECATION_WARNINGS switch (codec->p.type) { case AVMEDIA_TYPE_VIDEO: - codec->get_supported_config(NULL, &codec->p, - AV_CODEC_CONFIG_PIX_FORMAT, 0, - (const void **) &codec->p.pix_fmts, - &dummy); - codec->get_supported_config(NULL, &codec->p, - AV_CODEC_CONFIG_FRAME_RATE, 0, - (const void **) &codec->p.supported_framerates, - &dummy); + if (!codec->p.pix_fmts) + codec->get_supported_config(NULL, &codec->p, + AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void **) &codec->p.pix_fmts, + &dummy); break; case AVMEDIA_TYPE_AUDIO: codec->get_supported_config(NULL, &codec->p, @@ -1001,12 +1021,12 @@ static const AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) const AVCodec *avcodec_find_encoder(enum AVCodecID id) { - return find_codec(id, av_codec_is_encoder); + return find_codec(id, ff_codec_is_encoder); } const AVCodec *avcodec_find_decoder(enum AVCodecID id) { - return find_codec(id, av_codec_is_decoder); + return find_codec(id, ff_codec_is_decoder); } static const AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *)) @@ -1029,10 +1049,10 @@ static const AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCode const AVCodec *avcodec_find_encoder_by_name(const char *name) { - return find_codec_by_name(name, av_codec_is_encoder); + return find_codec_by_name(name, ff_codec_is_encoder); } const AVCodec *avcodec_find_decoder_by_name(const char *name) { - return find_codec_by_name(name, av_codec_is_decoder); + return find_codec_by_name(name, ff_codec_is_decoder); } diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index 28f2079985..fc55aa2687 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -38,6 +38,7 @@ #include "internal.h" #include "mlz.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavutil/crc.h" #include "libavutil/softfloat_ieee754.h" @@ -194,6 +195,7 @@ typedef struct ALSChannelData { typedef struct ALSDecContext { + AVClass *av_class; AVCodecContext *avctx; ALSSpecificConfig sconf; GetBitContext gb; @@ -222,7 +224,7 @@ typedef struct ALSDecContext { int32_t *quant_cof_buffer; ///< contains all quantized parcor coefficients int32_t **lpc_cof; ///< coefficients of the direct form prediction filter for a channel int32_t *lpc_cof_buffer; ///< contains all coefficients of the direct form prediction filter - int32_t *lpc_cof_reversed_buffer; ///< temporary buffer to set up a reversed versio of lpc_cof_buffer + int32_t *lpc_cof_reversed_buffer; ///< temporary buffer to set up a reversed version of lpc_cof_buffer ALSChannelData **chan_data; ///< channel data for multi-channel correlation ALSChannelData *chan_data_buffer; ///< contains channel data for all channels int *reverted_channels; ///< stores a flag for each reverted channel @@ -239,6 +241,7 @@ typedef struct ALSDecContext { unsigned char *larray; ///< buffer to store the output of masked lz decompression int *nbits; ///< contains the number of bits to read for masked lz decompression for all samples int highest_decoded_channel; + int user_max_order; ///< user specified maximum prediction order } ALSDecContext; @@ -352,6 +355,11 @@ static av_cold int read_specific_config(ALSDecContext *ctx) skip_bits(&gb, 5); // skip 5 reserved bits skip_bits1(&gb); // skip aux_data_enabled + if (sconf->max_order > ctx->user_max_order) { + av_log(avctx, AV_LOG_ERROR, "order %d exceeds specified max %d\n", sconf->max_order, ctx->user_max_order); + return AVERROR_INVALIDDATA; + } + // check for ALSSpecificConfig struct if (als_id != MKBETAG('A','L','S','\0')) @@ -1550,7 +1558,7 @@ static int read_diff_float_data(ALSDecContext *ctx, unsigned int ra_frame) { if (highest_byte) { for (i = 0; i < frame_length; ++i) { if (ctx->raw_samples[c][i] != 0) { - //The following logic is taken from Tabel 14.45 and 14.46 from the ISO spec + //The following logic is taken from Table 14.45 and 14.46 from the ISO spec if (av_cmp_sf_ieee754(acf[c], FLOAT_1)) { nbits[i] = 23 - av_log2(abs(ctx->raw_samples[c][i])); } else { @@ -2119,8 +2127,8 @@ static av_cold int decode_init(AVCodecContext *avctx) ctx->nbits = av_malloc_array(ctx->cur_frame_length, sizeof(*ctx->nbits)); ctx->mlz = av_mallocz(sizeof(*ctx->mlz)); - if (!ctx->mlz || !ctx->acf || !ctx->shift_value || !ctx->last_shift_value - || !ctx->last_acf_mantissa || !ctx->raw_mantissa) { + if (!ctx->larray || !ctx->nbits || !ctx->mlz || !ctx->acf || !ctx->shift_value + || !ctx->last_shift_value || !ctx->last_acf_mantissa || !ctx->raw_mantissa) { av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n"); return AVERROR(ENOMEM); } @@ -2132,6 +2140,10 @@ static av_cold int decode_init(AVCodecContext *avctx) for (c = 0; c < channels; ++c) { ctx->raw_mantissa[c] = av_calloc(ctx->cur_frame_length, sizeof(**ctx->raw_mantissa)); + if (!ctx->raw_mantissa[c]) { + av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n"); + return AVERROR(ENOMEM); + } } } @@ -2179,6 +2191,17 @@ static av_cold void flush(AVCodecContext *avctx) ctx->frame_id = 0; } +static const AVOption options[] = { + { "max_order", "Sets the maximum order (ALS simple profile allows max 15)", offsetof(ALSDecContext, user_max_order), AV_OPT_TYPE_INT, { .i64 = 1023 }, 0, 1023, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + { NULL } +}; + +static const AVClass als_class = { + .class_name = "als", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; const FFCodec ff_als_decoder = { .p.name = "als", @@ -2189,11 +2212,8 @@ const FFCodec ff_als_decoder = { .init = decode_init, .close = decode_end, FF_CODEC_DECODE_CB(decode_frame), + .p.priv_class = &als_class, .flush = flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/amfdec.c b/libavcodec/amfdec.c new file mode 100644 index 0000000000..7b038c6181 --- /dev/null +++ b/libavcodec/amfdec.c @@ -0,0 +1,728 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" +#include "amfdec.h" +#include "codec_internal.h" +#include "hwconfig.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/time.h" +#include "decode.h" +#include "decode_bsf.h" +#include "libavutil/mastering_display_metadata.h" + +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif +#if CONFIG_DXVA2 +#define COBJMACROS +#include "libavutil/hwcontext_dxva2.h" +#endif + +#ifdef _WIN32 +#include "compat/w32dlfcn.h" +#else +#include +#endif +//will be in public headers soon +#define AMF_VIDEO_DECODER_OUTPUT_FORMAT L"OutputDecodeFormat" + +const enum AVPixelFormat amf_dec_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_P010, + AV_PIX_FMT_P012, + AV_PIX_FMT_AMF_SURFACE, + AV_PIX_FMT_NONE +}; + +static const AVCodecHWConfigInternal *const amf_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_AMF_SURFACE, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_AMF, + }, + .hwaccel = NULL, + }, + NULL +}; + +static void amf_free_amfsurface(void *opaque, uint8_t *data) +{ + AMFSurface *surface = (AMFSurface*)(data); + surface->pVtbl->Release(surface); +} + +static int amf_legacy_driver_no_bitness_detect(AVAMFDeviceContext *amf_device_ctx) +{ + if( AMF_GET_MAJOR_VERSION(amf_device_ctx->version) <= 1 && + AMF_GET_MINOR_VERSION(amf_device_ctx->version) <= 4 && + AMF_GET_SUBMINOR_VERSION(amf_device_ctx->version) < 36) + return 1; + return 0; +} + +static int amf_init_decoder(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext*)hw_device_ctx->hwctx; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + AMFBuffer *buffer; + amf_int64 color_profile; + int pool_size = 36; + // way-around for older drivers that don't support dynamic bitness detection - + // define HEVC and VP9 10-bit based on container info + int no_bitness_detect = amf_legacy_driver_no_bitness_detect(amf_device_ctx); + + ctx->drain = 0; + ctx->resolution_changed = 0; + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + codec_id = AMFVideoDecoderUVD_H264_AVC; + break; + case AV_CODEC_ID_HEVC: { + codec_id = AMFVideoDecoderHW_H265_HEVC; + if(no_bitness_detect){ + if(avctx->pix_fmt == AV_PIX_FMT_YUV420P10) + codec_id = AMFVideoDecoderHW_H265_MAIN10; + } + } break; + case AV_CODEC_ID_VP9: { + codec_id = AMFVideoDecoderHW_VP9; + if(no_bitness_detect){ + if(avctx->pix_fmt == AV_PIX_FMT_YUV420P10) + codec_id = AMFVideoDecoderHW_VP9_10BIT; + } + } break; + case AV_CODEC_ID_AV1: + codec_id = AMFVideoDecoderHW_AV1; + break; + default: + break; + } + AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); + + res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_ctx->context, codec_id, &ctx->decoder); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); + + // Color Metadata + /// Color Range (Support for older Drivers) + if (avctx->color_range == AVCOL_RANGE_JPEG) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->decoder, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 1); + } else if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->decoder, AMF_VIDEO_DECODER_FULL_RANGE_COLOR, 0); + } + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN; + switch (avctx->colorspace) { + case AVCOL_SPC_SMPTE170M: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601; + } + break; + case AVCOL_SPC_BT709: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709; + } + break; + case AVCOL_SPC_BT2020_NCL: + case AVCOL_SPC_BT2020_CL: + if (avctx->color_range == AVCOL_RANGE_JPEG) { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020; + } else { + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020; + } + break; + } + if (color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_PROFILE, color_profile); + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC, (amf_int64)avctx->color_trc); + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_COLOR_PRIMARIES, (amf_int64)avctx->color_primaries); + + if (ctx->timestamp_mode != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_TIMESTAMP_MODE, ctx->timestamp_mode); + if (ctx->decoder_mode != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_REORDER_MODE, ctx->decoder_mode); + if (ctx->dpb_size != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_DPB_SIZE, ctx->dpb_size); + if (ctx->lowlatency != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_LOW_LATENCY, ctx->lowlatency); + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF decoder.\n"); + return AVERROR(EINVAL); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_LOW_LATENCY, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode for decoder.\n"); + } + } + } + if (ctx->skip_transfer_sav != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SKIP_TRANSFER_SMART_ACCESS_VIDEO, ctx->skip_transfer_sav); + + if (ctx->copy_output != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SURFACE_COPY, ctx->copy_output); + + if (avctx->extradata_size) { + const uint8_t *extradata; + int extradata_size; + ff_decode_get_extradata(avctx, &extradata, &extradata_size); + res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, extradata_size, &buffer); + if (res == AMF_OK) { + memcpy(buffer->pVtbl->GetNative(buffer), extradata, extradata_size); + AMF_ASSIGN_PROPERTY_INTERFACE(res,ctx->decoder, AMF_VIDEO_DECODER_EXTRADATA, buffer); + buffer->pVtbl->Release(buffer); + buffer = NULL; + } + } + if (ctx->surface_pool_size == -1) { + ctx->surface_pool_size = pool_size; + if (avctx->extra_hw_frames > 0) + ctx->surface_pool_size += avctx->extra_hw_frames; + if (avctx->active_thread_type & FF_THREAD_FRAME) + ctx->surface_pool_size += avctx->thread_count; + } + + //at the moment, there is such a restriction in AMF. + //when it is possible, I will remove this code + if (ctx->surface_pool_size > 100) + ctx->surface_pool_size = 100; + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->decoder, AMF_VIDEO_DECODER_SURFACE_POOL_SIZE, ctx->surface_pool_size); + res = ctx->decoder->pVtbl->Init(ctx->decoder, AMF_SURFACE_UNKNOWN, avctx->width, avctx->height); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Decoder initialization failed with error %d\n", res); + return AVERROR(EINVAL); + } + return 0; +} + +static int amf_decode_close(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + + if (ctx->decoder) { + ctx->decoder->pVtbl->Terminate(ctx->decoder); + ctx->decoder->pVtbl->Release(ctx->decoder); + ctx->decoder = NULL; + } + + av_buffer_unref(&ctx->device_ctx_ref); + av_packet_free(&ctx->in_pkt); + + return 0; +} + +static int amf_init_frames_context(AVCodecContext *avctx, int sw_format, int new_width, int new_height) +{ + int ret; + AVHWDeviceContext *hwdev_ctx; + AVHWFramesContext *hwframes_ctx; + AMFDecoderContext *ctx; + if (!avctx->hw_frames_ctx || !avctx->hw_device_ctx) + return 0; + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + hwframes_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx = avctx->priv_data; + + if (hwdev_ctx->type != AV_HWDEVICE_TYPE_AMF) + return 0; + + hwframes_ctx->width = new_width; + hwframes_ctx->height = new_height; + hwframes_ctx->format = AV_PIX_FMT_AMF_SURFACE; + hwframes_ctx->sw_format = sw_format; + hwframes_ctx->initial_pool_size = ctx->surface_pool_size + 8; + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing a AMF frame pool\n"); + av_buffer_unref(&avctx->hw_frames_ctx); + return ret; + } + return 0; +} + +static int amf_decode_init(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + int ret; + ctx->in_pkt = av_packet_alloc(); + if (!ctx->in_pkt) + return AVERROR(ENOMEM); + + if (avctx->hw_device_ctx && !avctx->hw_frames_ctx) { + AVHWDeviceContext *hwdev_ctx; + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) + { + ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx); + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); + + AMF_GOTO_FAIL_IF_FALSE(avctx, !!avctx->hw_frames_ctx, AVERROR(ENOMEM), "av_hwframe_ctx_alloc failed\n"); + } else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); + } + } else { + ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); + } + if ((ret = amf_init_decoder(avctx)) == 0) { + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext*)hw_device_ctx->hwctx; + enum AVPixelFormat surf_pix_fmt = AV_PIX_FMT_NONE; + + if(amf_legacy_driver_no_bitness_detect(amf_device_ctx)){ + // if bitness detection is not supported in legacy driver use format from container + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + surf_pix_fmt = AV_PIX_FMT_NV12; break; + case AV_PIX_FMT_YUV420P10: + surf_pix_fmt = AV_PIX_FMT_P010; break; + } + }else{ + AMFVariantStruct format_var = {0}; + + ret = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_OUTPUT_FORMAT, &format_var); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == AMF_OK, AVERROR(EINVAL), "Failed to get output format (AMF) : %d\n", ret); + + surf_pix_fmt = av_amf_to_av_format(format_var.int64Value); + } + if(avctx->hw_frames_ctx) + { + // this values should be set for avcodec_open2 + // will be updated after header decoded if not true. + if(surf_pix_fmt == AV_PIX_FMT_NONE) + surf_pix_fmt = AV_PIX_FMT_NV12; // for older drivers + if (!avctx->coded_width) + avctx->coded_width = 1280; + if (!avctx->coded_height) + avctx->coded_height = 720; + ret = amf_init_frames_context(avctx, surf_pix_fmt, avctx->coded_width, avctx->coded_height); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to init frames context (AMF) : %s\n", av_err2str(ret)); + } + else + avctx->pix_fmt = surf_pix_fmt; + + return 0; + } +fail: + amf_decode_close(avctx); + return ret; +} + +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 int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface* surface, AVFrame *frame) +{ + AMFVariantStruct var = {0}; + AMFPlane *plane; + int i; + int ret; + int format_amf; + + if (avctx->hw_device_ctx && ((AVHWDeviceContext*)avctx->hw_device_ctx->data)->type == AV_HWDEVICE_TYPE_AMF) { + // prepare frame similar to ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); + + ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) + return ret; + + avctx->sw_pix_fmt = avctx->pix_fmt; + + ret = ff_attach_decode_data(frame); + if (ret < 0) + return ret; + frame->width = avctx->width; + frame->height = avctx->height; + + //// + frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_free_amfsurface, (void*)avctx, + AV_BUFFER_FLAG_READONLY); + AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); + + frame->data[0] = (uint8_t *)surface; + frame->format = AV_PIX_FMT_AMF_SURFACE; + format_amf = surface->pVtbl->GetFormat(surface); + avctx->sw_pix_fmt = av_amf_to_av_format(format_amf); + frame->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); + } else { + ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST); + AMF_RETURN_IF_FALSE(avctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", ret); + + for (i = 0; i < surface->pVtbl->GetPlanesCount(surface); i++) { + plane = surface->pVtbl->GetPlaneAt(surface, i); + frame->data[i] = plane->pVtbl->GetNative(plane); + frame->linesize[i] = plane->pVtbl->GetHPitch(plane); + } + + frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_free_amfsurface, (void*)avctx, + AV_BUFFER_FLAG_READONLY); + AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); + + format_amf = surface->pVtbl->GetFormat(surface); + frame->format = av_amf_to_av_format(format_amf); + } + + frame->width = avctx->width; + frame->height = avctx->height; + + frame->pts = surface->pVtbl->GetPts(surface); + + surface->pVtbl->GetProperty(surface, L"FFMPEG:dts", &var); + frame->pkt_dts = var.int64Value; + + frame->duration = surface->pVtbl->GetDuration(surface); + if (frame->duration < 0) + frame->duration = 0; + + frame->color_range = avctx->color_range; + frame->colorspace = avctx->colorspace; + frame->color_trc = avctx->color_trc; + frame->color_primaries = avctx->color_primaries; + + if (frame->color_trc == AVCOL_TRC_SMPTE2084) { + AMFBuffer * hdrmeta_buffer = NULL; + ret = amf_get_property_buffer((AMFData *)surface, AMF_VIDEO_DECODER_HDR_METADATA, &hdrmeta_buffer); + if (hdrmeta_buffer != NULL) { + AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); + if (ret != AMF_OK) + return ret; + if (hdrmeta != NULL) { + AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame); + const int chroma_den = 50000; + const int luma_den = 10000; + + if (!mastering) + return AVERROR(ENOMEM); + + mastering->display_primaries[0][0] = av_make_q(hdrmeta->redPrimary[0], chroma_den); + mastering->display_primaries[0][1] = av_make_q(hdrmeta->redPrimary[1], chroma_den); + + mastering->display_primaries[1][0] = av_make_q(hdrmeta->greenPrimary[0], chroma_den); + mastering->display_primaries[1][1] = av_make_q(hdrmeta->greenPrimary[1], chroma_den); + + mastering->display_primaries[2][0] = av_make_q(hdrmeta->bluePrimary[0], chroma_den); + mastering->display_primaries[2][1] = av_make_q(hdrmeta->bluePrimary[1], chroma_den); + + mastering->white_point[0] = av_make_q(hdrmeta->whitePoint[0], chroma_den); + mastering->white_point[1] = av_make_q(hdrmeta->whitePoint[1], chroma_den); + + mastering->max_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den); + mastering->min_luminance = av_make_q(hdrmeta->maxMasteringLuminance, luma_den); + + mastering->has_luminance = 1; + mastering->has_primaries = 1; + if (hdrmeta->maxContentLightLevel) { + AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame); + + if (!light) + return AVERROR(ENOMEM); + + light->MaxCLL = hdrmeta->maxContentLightLevel; + light->MaxFALL = hdrmeta->maxFrameAverageLightLevel; + } + } + } + } + return 0; +} + +static AMF_RESULT amf_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AMF_RESULT ret = AMF_OK; + AMFSurface *surface = NULL; + AMFData *data_out = NULL; + + ret = ctx->decoder->pVtbl->QueryOutput(ctx->decoder, &data_out); + if (ret != AMF_OK && ret != AMF_REPEAT) { + return ret; + } + if (data_out == NULL) { + return AMF_REPEAT; + } + + if (data_out) { + AMFGuid guid = IID_AMFSurface(); + data_out->pVtbl->QueryInterface(data_out, &guid, (void**)&surface); // query for buffer interface + data_out->pVtbl->Release(data_out); + data_out = NULL; + } + + ret = amf_amfsurface_to_avframe(avctx, surface, frame); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret >= 0, AMF_FAIL, "Failed to convert AMFSurface to AVFrame = %d\n", ret); + return AMF_OK; +fail: + + if (surface) { + surface->pVtbl->Release(surface); + surface = NULL; + } + return ret; +} + +static AMF_RESULT amf_update_buffer_properties(AVCodecContext *avctx, AMFBuffer* buffer, const AVPacket* pkt) +{ + AMF_RESULT res; + + AMF_RETURN_IF_FALSE(avctx, buffer != NULL, AMF_INVALID_ARG, "update_buffer_properties() - buffer not passed in"); + AMF_RETURN_IF_FALSE(avctx, pkt != NULL, AMF_INVALID_ARG, "update_buffer_properties() - packet not passed in"); + buffer->pVtbl->SetPts(buffer, pkt->pts); + buffer->pVtbl->SetDuration(buffer, pkt->duration); + AMF_ASSIGN_PROPERTY_INT64(res, buffer, L"FFMPEG:dts", pkt->dts); + if (res != AMF_OK) + av_log(avctx, AV_LOG_VERBOSE, "Failed to assign dts value."); + return AMF_OK; +} + +static AMF_RESULT amf_buffer_from_packet(AVCodecContext *avctx, const AVPacket* pkt, AMFBuffer** buffer) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + AMFContext *ctxt = amf_device_ctx->context; + void *mem; + AMF_RESULT err; + AMFBuffer *buf = NULL; + + AMF_RETURN_IF_FALSE(ctxt, pkt != NULL, AMF_INVALID_ARG, "amf_buffer_from_packet() - packet not passed in"); + AMF_RETURN_IF_FALSE(ctxt, buffer != NULL, AMF_INVALID_ARG, "amf_buffer_from_packet() - buffer pointer not passed in"); + + err = ctxt->pVtbl->AllocBuffer(ctxt, AMF_MEMORY_HOST, pkt->size + AV_INPUT_BUFFER_PADDING_SIZE, buffer); + AMF_RETURN_IF_FALSE(ctxt, err == AMF_OK, err, "amf_buffer_from_packet() - failed"); + buf = *buffer; + err = buf->pVtbl->SetSize(buf, pkt->size); + AMF_RETURN_IF_FALSE(ctxt, err == AMF_OK, err, "amf_buffer_from_packet() - SetSize failed"); + // get the memory location and check the buffer was indeed allocated + mem = buf->pVtbl->GetNative(buf); + AMF_RETURN_IF_FALSE(ctxt, mem != NULL, AMF_INVALID_POINTER, "amf_buffer_from_packet() - GetNative failed"); + + // copy the packet memory and clear data padding + memcpy(mem, pkt->data, pkt->size); + memset((amf_int8*)(mem)+pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return amf_update_buffer_properties(avctx, buf, pkt); +} + +static int amf_decode_frame(AVCodecContext *avctx, struct AVFrame *frame) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AMFBuffer *buf; + AMF_RESULT res; + int got_frame = 0; + AVPacket *avpkt = ctx->in_pkt; + + if (!ctx->decoder) + return AVERROR(EINVAL); + + // get packet if needed + if(!ctx->drain){ + if(ctx->resolution_changed) + ctx->resolution_changed = 0; + else{ + int ret; + av_packet_unref(avpkt); + ret = ff_decode_get_packet(avctx, avpkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + if (ret == AVERROR_EOF) { + //nothing to consume, start external drain + ctx->decoder->pVtbl->Drain(ctx->decoder); + ctx->drain = 1; + } + } + } + + if(!ctx->drain){ + // submit frame + res = amf_buffer_from_packet(avctx, avpkt, &buf); + AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, 0, "Cannot convert AVPacket to AMFbuffer"); + do{ + res = ctx->decoder->pVtbl->SubmitInput(ctx->decoder, (AMFData*) buf); + if(res == AMF_DECODER_NO_FREE_SURFACES) + { + av_usleep(100); + } + } while (res == AMF_DECODER_NO_FREE_SURFACES); + + buf->pVtbl->Release(buf); + + if(res == AMF_DECODER_NO_FREE_SURFACES) { + // input is not consumed, need to QueryOutput and submit again + av_log(avctx, AV_LOG_VERBOSE, "SubmitInput() returned NO_FREE_SURFACES and came out of loop - should never happen\n"); + res = AMF_OK; + } else if (res == AMF_RESOLUTION_CHANGED) { + //input is not consumed, start internal drain + ctx->decoder->pVtbl->Drain(ctx->decoder); + ctx->drain = 1; + // process resolution_changed when internal drain is complete + ctx->resolution_changed = 1; + res = AMF_OK; + } else if (res != AMF_OK && res != AMF_NEED_MORE_INPUT && res != AMF_REPEAT) { + av_log(avctx, AV_LOG_ERROR, "SubmitInput() returned error %d\n", res); + return AVERROR(EINVAL); + } + } + + res = amf_receive_frame(avctx, frame); + if (res == AMF_OK) + got_frame = 1; + else if (res == AMF_REPEAT) + // decoder has no output yet + res = AMF_OK; + else if (res == AMF_EOF) { + // drain is complete + ctx->drain = 0; + if(ctx->resolution_changed){ + // re-initialze decoder + AMFVariantStruct size_var = {0}; + AMFVariantStruct format_var = {0}; + res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_CURRENT_SIZE, &size_var); + if (res != AMF_OK) { + return AVERROR(EINVAL); + } + + avctx->width = size_var.sizeValue.width; + avctx->height = size_var.sizeValue.height; + avctx->coded_width = size_var.sizeValue.width; + avctx->coded_height = size_var.sizeValue.height; + res = ctx->decoder->pVtbl->ReInit(ctx->decoder, avctx->width, avctx->height); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "ReInit() returned %d\n", res); + return AVERROR(EINVAL); + } + res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, AMF_VIDEO_DECODER_OUTPUT_FORMAT, &format_var); + if (res == AMF_OK) { + res = amf_init_frames_context(avctx, av_amf_to_av_format(format_var.int64Value), avctx->coded_width, avctx->coded_height); + } + + if (res < 0) + return AVERROR(EINVAL); + }else + return AVERROR_EOF; + } else { + av_log(avctx, AV_LOG_ERROR, "Unknown result from QueryOutput %d\n", res); + } + return got_frame ? 0 : AVERROR(EAGAIN); +} + +static void amf_decode_flush(AVCodecContext *avctx) +{ + AMFDecoderContext *ctx = avctx->priv_data; + ctx->decoder->pVtbl->Flush(ctx->decoder); +} + +#define OFFSET(x) offsetof(AMFDecoderContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { + // Decoder mode + { "decoder_mode", "Decoder mode", OFFSET(decoder_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_DECODER_MODE_LOW_LATENCY, VD, "decoder_mode" }, + { "regular", "DPB delay is based on number of reference frames + 1", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_REGULAR }, 0, 0, VD, "decoder_mode" }, + { "compliant", "DPB delay is based on profile - up to 16", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_COMPLIANT }, 0, 0, VD, "decoder_mode" }, + { "low_latency", "DPB delay is 0", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_DECODER_MODE_LOW_LATENCY }, 0, 0, VD, "decoder_mode" }, + + // Timestamp mode + { "timestamp_mode", "Timestamp mode", OFFSET(timestamp_mode), AV_OPT_TYPE_INT, { .i64 = AMF_TS_SORT }, -1, AMF_TS_DECODE, VD, "timestamp_mode" }, + { "presentation", "Preserve timestamps from input to output", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_PRESENTATION }, 0, 0, VD, "timestamp_mode" }, + { "sort", "Resort PTS list", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_SORT }, 0, 0, VD, "timestamp_mode" }, + { "decode", "Decode order", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_TS_DECODE }, 0, 0, VD, "timestamp_mode" }, + + // Reference frame management + { "surface_pool_size", "Number of surfaces in the decode pool", OFFSET(surface_pool_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VD, NULL }, + { "dpb_size", "Minimum number of surfaces for reordering", OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, VD, NULL }, + + { "lowlatency", "Low latency", OFFSET(lowlatency), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "smart_access_video", "Smart Access Video", OFFSET(smart_access_video), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "skip_transfer_sav", "Skip transfer on another GPU when SAV enabled", OFFSET(skip_transfer_sav), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + { "copy_output", "Copy Output", OFFSET(copy_output), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD, NULL }, + + { NULL } +}; + +static const AVClass amf_decode_class = { + .class_name = "amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +#define DEFINE_AMF_DECODER(x, X, bsf_name) \ +const FFCodec ff_##x##_amf_decoder = { \ + .p.name = #x "_amf", \ + CODEC_LONG_NAME(#X " AMD AMF video decoder"), \ + .priv_data_size = sizeof(AMFDecoderContext), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = AV_CODEC_ID_##X, \ + .init = amf_decode_init, \ + FF_CODEC_RECEIVE_FRAME_CB(amf_decode_frame), \ + .flush = amf_decode_flush, \ + .close = amf_decode_close, \ + .bsfs = bsf_name, \ + .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .p.priv_class = &amf_decode_class, \ + CODEC_PIXFMTS_ARRAY(amf_dec_pix_fmts), \ + .hw_configs = amf_hw_configs, \ + .p.wrapper_name = "amf", \ + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ +}; \ + +DEFINE_AMF_DECODER(h264, H264, "h264_mp4toannexb") +DEFINE_AMF_DECODER(hevc, HEVC, NULL) +DEFINE_AMF_DECODER(vp9, VP9, NULL) +DEFINE_AMF_DECODER(av1, AV1, NULL) diff --git a/libavcodec/amfdec.h b/libavcodec/amfdec.h new file mode 100644 index 0000000000..205d7a84a5 --- /dev/null +++ b/libavcodec/amfdec.h @@ -0,0 +1,63 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_AMFDEC_H +#define AVCODEC_AMFDEC_H + +#include +#include +#include +#include +#include +#include +#include + +#include "avcodec.h" +#include "libavformat/avformat.h" +#include "libavutil/fifo.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" +#include "libavutil/hwcontext_amf.h" +/** +* AMF decoder context +*/ +typedef struct AMFDecoderContext { + AVClass *avclass; + AVBufferRef *device_ctx_ref; + + //decoder + AMFComponent *decoder; ///< AMF decoder object + AMF_SURFACE_FORMAT format; ///< AMF surface format + + // common decoder options + int decoder_mode; + int timestamp_mode; + int surface_pool_size; + int dpb_size; + int lowlatency; + int smart_access_video; + int skip_transfer_sav; + int drain; + int resolution_changed; + int copy_output; + AVPacket* in_pkt; + enum AMF_SURFACE_FORMAT output_format; + +} AMFDecoderContext; + +#endif // AVCODEC_AMFDEC_H diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index a47aea6108..b16b642e4c 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -22,6 +22,8 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" #if CONFIG_D3D11VA #include "libavutil/hwcontext_d3d11va.h" #endif @@ -38,6 +40,9 @@ #include "internal.h" #include "libavutil/mastering_display_metadata.h" +#define AMF_AV_FRAME_REF L"av_frame_ref" +#define PTS_PROP L"PtsProp" + static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta) { AVFrameSideData *sd_display; @@ -100,7 +105,6 @@ static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AM #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" -#define PTS_PROP L"PtsProp" const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_NV12, @@ -112,288 +116,42 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_DXVA2_VLD, #endif AV_PIX_FMT_P010, + AV_PIX_FMT_AMF_SURFACE, + AV_PIX_FMT_BGR0, + AV_PIX_FMT_RGB0, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_ARGB, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_X2BGR10, + AV_PIX_FMT_RGBAF16, 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_P010, AMF_SURFACE_P010 }, - { 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 auto-realloc if too small - ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), - AV_FIFO_FLAG_AUTO_GROW); - 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; - AMFContext1 *context1 = NULL; - 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 { - AMFGuid guid = IID_AMFContext1(); - res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res); - - res = context1->pVtbl->InitVulkan(context1, NULL); - context1->pVtbl->Release(context1); - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res); - return AVERROR(ENOSYS); - } - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n"); - } - } - } - return 0; -} +static int64_t next_encoder_index = 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; + AMFEncoderContext *ctx = avctx->priv_data; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + enum AVPixelFormat pix_fmt; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + int alloc_size; + wchar_t name[512]; + + + alloc_size = swprintf(name, amf_countof(name), L"%s%lld",PTS_PROP, next_encoder_index) + 1; + ctx->pts_property_name = av_memdup(name, alloc_size * sizeof(wchar_t)); + if(!ctx->pts_property_name) + return AVERROR(ENOMEM); + + alloc_size = swprintf(name, amf_countof(name), L"%s%lld",AMF_AV_FRAME_REF, next_encoder_index) + 1; + ctx->av_frame_property_name = av_memdup(name, alloc_size * sizeof(wchar_t)); + if(!ctx->av_frame_property_name) + return AVERROR(ENOMEM); + + next_encoder_index++; switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -410,33 +168,32 @@ static int amf_init_encoder(AVCodecContext *avctx) } 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; + if (avctx->hw_frames_ctx) + pix_fmt = ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format; else pix_fmt = avctx->pix_fmt; if (pix_fmt == AV_PIX_FMT_P010) { - AMF_RETURN_IF_FALSE(ctx, ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); + AMF_RETURN_IF_FALSE(ctx, amf_device_ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); } - ctx->format = amf_av_to_amf_format(pix_fmt); + ctx->format = av_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); + res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_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); + ctx->submitted_frame = 0; + ctx->encoded_frame = 0; + ctx->eof = 0; + 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; - } + AMFEncoderContext *ctx = avctx->priv_data; if (ctx->encoder) { ctx->encoder->pVtbl->Terminate(ctx->encoder); @@ -444,29 +201,22 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) 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_buffer_unref(&ctx->device_ctx_ref); av_fifo_freep2(&ctx->timestamp_list); + if (ctx->output_list) { + // release remaining AMF output buffers + while(av_fifo_can_read(ctx->output_list)) { + AMFBuffer* buffer = NULL; + av_fifo_read(ctx->output_list, &buffer, 1); + if(buffer != NULL) + buffer->pVtbl->Release(buffer); + } + av_fifo_freep2(&ctx->output_list); + } + av_freep(&ctx->pts_property_name); + av_freep(&ctx->av_frame_property_name); + return 0; } @@ -474,12 +224,12 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { AMFPlane *plane; - uint8_t *dst_data[4]; - int dst_linesize[4]; + uint8_t *dst_data[4] = {0}; + int dst_linesize[4] = {0}; int planes; int i; - planes = surface->pVtbl->GetPlanesCount(surface); + planes = (int)surface->pVtbl->GetPlanesCount(surface); av_assert0(planes < FF_ARRAY_ELEMS(dst_data)); for (i = 0; i < planes; i++) { @@ -496,7 +246,7 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) { - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; int ret; AMFVariantStruct var = {0}; int64_t timestamp = AV_NOPTS_VALUE; @@ -529,11 +279,10 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff break; } - buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); + buffer->pVtbl->GetProperty(buffer, ctx->pts_property_name, &var); pkt->pts = var.int64Value; // original pts - AMF_RETURN_IF_FALSE(ctx, av_fifo_read(ctx->timestamp_list, ×tamp, 1) >= 0, AVERROR_UNKNOWN, "timestamp_list is empty\n"); @@ -558,14 +307,54 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff int ff_amf_encode_init(AVCodecContext *avctx) { int ret; + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hwdev_ctx = NULL; - if ((ret = amf_load_library(avctx)) == 0) { - if ((ret = amf_init_context(avctx)) == 0) { - if ((ret = amf_init_encoder(avctx)) == 0) { - return 0; + // hardcoded to current HW queue size - will auto-realloc if too small + ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), + AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->timestamp_list) { + return AVERROR(ENOMEM); + } + ctx->output_list = av_fifo_alloc2(2, sizeof(AMFBuffer*), AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->output_list) + return AVERROR(ENOMEM); + + ctx->dts_delay = 0; + + ctx->hwsurfaces_in_queue = 0; + + if (avctx->hw_device_ctx) { + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) + { + ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx); + } + else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); + } + } else if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->device_ref ) { + if (frames_ctx->format == AV_PIX_FMT_AMF_SURFACE) { + ctx->device_ctx_ref = av_buffer_ref(frames_ctx->device_ref); + } + else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, frames_ctx->device_ref, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); } } } + else { + ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); + AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); + } + + if ((ret = amf_init_encoder(avctx)) == 0) { + return 0; + } + ff_amf_encode_close(avctx); return ret; } @@ -592,241 +381,179 @@ static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *nam return res; } -static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +static AMF_RESULT amf_lock_context(AVCodecContext *avctx) { + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; 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; - } + + switch(amf_device_ctx->memory_type) { + case AMF_MEMORY_DX11: + res = amf_device_ctx->context->pVtbl->LockDX11(amf_device_ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX11() failed with error %d\n", res); + break; + case AMF_MEMORY_DX12: + { + AMFContext2 *context2 = NULL; + AMFGuid guid = IID_AMFContext2(); + res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface for AMFContext2 failed with error %d\n", res); + res = context2->pVtbl->LockDX12(context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX12() failed with error %d\n", res); + context2->pVtbl->Release(context2); } - AMFVariantClear(&var); + break; + case AMF_MEMORY_DX9: + res = amf_device_ctx->context->pVtbl->LockDX9(amf_device_ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX9() failed with error %d\n", res); + + case AMF_MEMORY_VULKAN: + { + AMFContext2 *context2 = NULL; + AMFGuid guid = IID_AMFContext2(); + res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface for AMFContext2 failed with error %d\n", res); + res = context2->pVtbl->LockVulkan(context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockVulkan() failed with error %d\n", res); + context2->pVtbl->Release(context2); + } + break; + } + return AMF_OK; +} +static AMF_RESULT amf_unlock_context(AVCodecContext *avctx) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + AMF_RESULT res; + + switch(amf_device_ctx->memory_type) { + case AMF_MEMORY_DX11: + res = amf_device_ctx->context->pVtbl->UnlockDX11(amf_device_ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX11() failed with error %d\n", res); + break; + case AMF_MEMORY_DX12: + { + AMFContext2 *context2 = NULL; + AMFGuid guid = IID_AMFContext2(); + res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface for AMFContext2 failed with error %d\n", res); + res = context2->pVtbl->UnlockDX12(context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX12() failed with error %d\n", res); + context2->pVtbl->Release(context2); + } + break; + case AMF_MEMORY_DX9: + res = amf_device_ctx->context->pVtbl->UnlockDX9(amf_device_ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockDX9() failed with error %d\n", res); + + case AMF_MEMORY_VULKAN: + { + AMFContext2 *context2 = NULL; + AMFGuid guid = IID_AMFContext2(); + res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface for AMFContext2 failed with error %d\n", res); + res = context2->pVtbl->UnlockVulkan(context2); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "LockVulkan() failed with error %d\n", res); + context2->pVtbl->Release(context2); + } + break; + } + return AMF_OK; +} + +static AMF_RESULT amf_store_attached_frame_ref(AMFEncoderContext *ctx, const AVFrame *frame, AMFSurface *surface) +{ + AMF_RESULT res = AMF_FAIL; + int64_t data; + AVFrame *frame_ref = av_frame_clone(frame); + if (frame_ref) { + memcpy(&data, &frame_ref, sizeof(frame_ref)); // store pointer in 8 bytes + AMF_ASSIGN_PROPERTY_INT64(res, surface, ctx->av_frame_property_name, data); } return res; } -static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) +static AMF_RESULT amf_release_attached_frame_ref(AMFEncoderContext *ctx, AMFBuffer *buffer) { - 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; - } + AMFVariantStruct var = {0}; + AMF_RESULT res = buffer->pVtbl->GetProperty(buffer, ctx->av_frame_property_name, &var); + if(res == AMF_OK && var.int64Value){ + AVFrame *frame_ref; + memcpy(&frame_ref, &var.int64Value, sizeof(frame_ref)); + av_frame_free(&frame_ref); } - return frame_ref_storage_buffer; + return res; } -static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) +static int amf_submit_frame(AVCodecContext *avctx, AVFrame *frame, AMFSurface **surface_resubmit) { - 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); -} + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx; + AMFSurface *surface; + AMF_RESULT res; + int ret; + int hw_surface = 0; + int max_b_frames = ctx->max_b_frames < 0 ? 0 : ctx->max_b_frames; -int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) -{ - AmfContext *ctx = avctx->priv_data; - AMFSurface *surface; - AMF_RESULT res; - int ret; - AMF_RESULT res_query; - AMFData *data = NULL; - AVFrame *frame = ctx->delayed_frame; - int block_and_wait; - int query_output_data_flag = 0; - AMF_RESULT res_resubmit; - - if (!ctx->encoder) - return AVERROR(EINVAL); - - if (!frame->buf[0]) { - ret = ff_encode_get_frame(avctx, frame); - if (ret < 0 && ret != AVERROR_EOF) - return ret; - } - - if (!frame->buf[0]) { // 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 if (!ctx->delayed_surface) { // submit frame - int hw_surface = 0; - - // prepare surface from frame - switch (frame->format) { +// 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); - + 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 && avctx->hw_frames_ctx && + frame->hw_frames_ctx->data == avctx->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); - + res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_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; + } + 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); - + case AV_PIX_FMT_DXVA2_VLD: + { + IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_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; + } + 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; + case AV_PIX_FMT_AMF_SURFACE: + { + surface = (AMFSurface*)frame->data[0]; + surface->pVtbl->Acquire(surface); + hw_surface = 1; } - - 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); - } - - // HDR10 metadata - if (frame->color_trc == AVCOL_TRC_SMPTE2084) { - AMFBuffer * hdrmeta_buffer = NULL; - res = ctx->context->pVtbl->AllocBuffer(ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); - if (res == AMF_OK) { - AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); - if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) { - switch (avctx->codec->id) { - case AV_CODEC_ID_H264: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_HEVC: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_AV1: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break; - } - res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer); - AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); - } - hdrmeta_buffer->pVtbl->Release(hdrmeta_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; - //case AV_CODEC_ID_AV1 not supported - 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; - } else { - int64_t pts = frame->pts; - surface->pVtbl->Release(surface); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); - - av_frame_unref(frame); - ret = av_fifo_write(ctx->timestamp_list, &pts, 1); - if (ret < 0) - return ret; + break; + default: + { + res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_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; } - - - do { - block_and_wait = 0; - // poll data - if (!avpkt->data && !avpkt->buf) { - res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); - if (data) { - // copy data to packet - AMFBuffer *buffer; - AMFGuid guid = IID_AMFBuffer(); - query_output_data_flag = 1; - 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); - } - } - res_resubmit = AMF_OK; - if (ctx->delayed_surface != NULL) { // try to resubmit frame - if (ctx->delayed_surface->pVtbl->HasProperty(ctx->delayed_surface, L"av_frame_hdrmeta")) { - AMFBuffer * hdrmeta_buffer = NULL; - res = amf_get_property_buffer((AMFData *)ctx->delayed_surface, L"av_frame_hdrmeta", &hdrmeta_buffer); - AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); + if (hw_surface) { + amf_store_attached_frame_ref(ctx, frame, surface); + ctx->hwsurfaces_in_queue++; + // input HW surfaces can be vertically aligned by 16; tell AMF the real size + surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); + } + // HDR10 metadata + if (frame->color_trc == AVCOL_TRC_SMPTE2084) { + AMFBuffer * hdrmeta_buffer = NULL; + res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); + if (res == AMF_OK) { + AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); + if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) { switch (avctx->codec->id) { case AV_CODEC_ID_H264: AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; @@ -835,34 +562,200 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) case AV_CODEC_ID_AV1: AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break; } - hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); + res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); } - res_resubmit = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); - if (res_resubmit != 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_resubmit == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res_resubmit); + hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); + } + } + surface->pVtbl->SetPts(surface, frame->pts); - ret = av_fifo_write(ctx->timestamp_list, &pts, 1); - if (ret < 0) - return ret; - } - } 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); + AMF_ASSIGN_PROPERTY_INT64(res, surface, ctx->pts_property_name, frame->pts); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); + switch (frame->pict_type) { + case AV_PICTURE_TYPE_I: + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); } else { - av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); + } + break; + case AV_PICTURE_TYPE_P: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); + break; + case AV_PICTURE_TYPE_B: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); + break; + } + break; + case AV_CODEC_ID_HEVC: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); + switch (frame->pict_type) { + case AV_PICTURE_TYPE_I: + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I); + } + break; + case AV_PICTURE_TYPE_P: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P); + break; + } + break; + case AV_CODEC_ID_AV1: + if (frame->pict_type == AV_PICTURE_TYPE_I) { + if (ctx->forced_idr) { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1); + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY); } } + 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 + *surface_resubmit = surface; + } else { + surface->pVtbl->Release(surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + ctx->submitted_frame++; + ret = av_fifo_write(ctx->timestamp_list, &frame->pts, 1); + if (ret < 0) + return ret; + if(ctx->submitted_frame <= ctx->encoded_frame + max_b_frames + 1) + return AVERROR(EAGAIN); // if frame just submiited - don't poll or wait + } + return 0; +} - if (query_output_data_flag == 0) { - if (res_resubmit == AMF_INPUT_FULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { - block_and_wait = 1; +static int amf_submit_frame_locked(AVCodecContext *avctx, AVFrame *frame, AMFSurface **surface_resubmit) +{ + int ret; + int locked = amf_lock_context(avctx); + if(locked != AMF_OK) + av_log(avctx, AV_LOG_WARNING, "amf_lock_context() failed with %d - should not happen\n", locked); + + ret = amf_submit_frame(avctx, frame, surface_resubmit); + + if(locked == AMF_OK) + amf_unlock_context(avctx); + return ret; +} +static AMF_RESULT amf_query_output(AVCodecContext *avctx, AMFBuffer **buffer) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AMFData *data = NULL; + AMF_RESULT ret = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); + *buffer = NULL; + if (data) { + AMFGuid guid = IID_AMFBuffer(); + data->pVtbl->QueryInterface(data, &guid, (void**)buffer); // query for buffer interface + data->pVtbl->Release(data); + if (amf_release_attached_frame_ref(ctx, *buffer) == AMF_OK) + ctx->hwsurfaces_in_queue--; + ctx->encoded_frame++; + } + return ret; +} + +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AMFSurface *surface = NULL; + AMF_RESULT res; + int ret; + AMF_RESULT res_query; + AMFBuffer* buffer = NULL; + AVFrame *frame = av_frame_alloc(); + int block_and_wait; + int64_t pts = 0; + int max_b_frames = ctx->max_b_frames < 0 ? 0 : ctx->max_b_frames; + + if (!ctx->encoder){ + av_frame_free(&frame); + return AVERROR(EINVAL); + } + // check if some outputs are available + av_fifo_read(ctx->output_list, &buffer, 1); + if (buffer != NULL) { // return already retrieved output + ret = amf_copy_buffer(avctx, avpkt, buffer); + buffer->pVtbl->Release(buffer); + return ret; + } + + ret = ff_encode_get_frame(avctx, frame); + if(ret < 0){ + if(ret != AVERROR_EOF){ + av_frame_free(&frame); + if(ret == AVERROR(EAGAIN)){ + if(ctx->submitted_frame <= ctx->encoded_frame + max_b_frames + 1) // too soon to poll + return ret; + } + } + } + if(ret != AVERROR(EAGAIN)){ + if (!frame->buf[0]) { // submit drain + if (!ctx->eof) { // submit drain one time only + 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 receive loop + } 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 { // submit frame + ret = amf_submit_frame_locked(avctx, frame, &surface); + if(ret < 0){ + av_frame_free(&frame); + return ret; + } + pts = frame->pts; + } + } + av_frame_free(&frame); + + do { + block_and_wait = 0; + // poll data + res_query = amf_query_output(avctx, &buffer); + if (buffer) { + ret = amf_copy_buffer(avctx, avpkt, buffer); + buffer->pVtbl->Release(buffer); + + AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); + + 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_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max) || surface) { + block_and_wait = 1; + // Only sleep if the driver doesn't support waiting in QueryOutput() + // or if we already have output data so we will skip calling it. + if (!ctx->query_timeout_supported || avpkt->data || avpkt->buf) { av_usleep(1000); } } @@ -870,9 +763,43 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) if (res_query == AMF_EOF) { ret = AVERROR_EOF; - } else if (data == NULL) { + } else if (buffer == NULL) { ret = AVERROR(EAGAIN); } else { + if(surface) { + // resubmit surface + do { + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); + if (res != AMF_INPUT_FULL) + break; + + if (!ctx->query_timeout_supported) + av_usleep(1000); + + // Need to free up space in the encoder queue. + // The number of retrieved outputs is limited currently to 21 + amf_query_output(avctx, &buffer); + if (buffer != NULL) { + ret = av_fifo_write(ctx->output_list, &buffer, 1); + if (ret < 0) + return ret; + } + } while(res == AMF_INPUT_FULL); + + surface->pVtbl->Release(surface); + if (res == AMF_INPUT_FULL) { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n"); + } else { + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + + ret = av_fifo_write(ctx->timestamp_list, &pts, 1); + + ctx->submitted_frame++; + + if (ret < 0) + return ret; + } + } ret = 0; } return ret; @@ -922,5 +849,7 @@ const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(DXVA2_VLD, DXVA2), HW_CONFIG_ENCODER_DEVICE(NONE, DXVA2), #endif + HW_CONFIG_ENCODER_FRAMES(AMF_SURFACE, AMF), + HW_CONFIG_ENCODER_DEVICE(NONE, AMF), NULL, }; diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index d985d01bb1..8f5eb5a9ef 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -33,54 +33,37 @@ #define MAX_LOOKAHEAD_DEPTH 41 -/** -* 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 { +typedef struct AMFEncoderContext { 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 + AVBufferRef *device_ctx_ref; - 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) + wchar_t *pts_property_name; + wchar_t *av_frame_property_name; int hwsurfaces_in_queue; int hwsurfaces_in_queue_max; + int query_timeout_supported; // helpers to handle async calls int delayed_drain; - AMFSurface *delayed_surface; - AVFrame *delayed_frame; // shift dts back by max_b_frames in timing AVFifo *timestamp_list; int64_t dts_delay; + int64_t submitted_frame; + int64_t encoded_frame; + AVFifo *output_list; - // common encoder option options - - int log_to_dbg; + // common encoder options // Static options, have to be set before Init() call int usage; @@ -91,6 +74,8 @@ typedef struct AmfContext { int quality; int b_frame_delta_qp; int ref_b_frame_delta_qp; + int bit_depth; + int smart_access_video; // Dynamic options, can be set after Init() call @@ -114,6 +99,7 @@ typedef struct AmfContext { int max_b_frames; int qvbr_quality_level; int hw_high_motion_quality_boost; + int forced_idr; // HEVC - specific options @@ -123,6 +109,8 @@ typedef struct AmfContext { int max_qp_i; int min_qp_p; int max_qp_p; + int min_qp_b; + int max_qp_b; int tier; // AV1 - specific options @@ -150,7 +138,7 @@ typedef struct AmfContext { int pa_adaptive_mini_gop; -} AmfContext; +} AMFEncoderContext; extern const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[]; diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index 2a7a782063..7202e0fcd5 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -26,17 +26,21 @@ #define AMF_VIDEO_ENCODER_AV1_CAP_WIDTH_ALIGNMENT_FACTOR_LOCAL L"Av1WidthAlignmentFactor" // amf_int64; default = 1 #define AMF_VIDEO_ENCODER_AV1_CAP_HEIGHT_ALIGNMENT_FACTOR_LOCAL L"Av1HeightAlignmentFactor" // amf_int64; default = 1 -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, 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 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, - { "ultralowlatency", "ultra low latency trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, + { "ultralowlatency", "ultra low latency transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "lowlatency", "Low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, - { "high_quality", "high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - { "lowlatency_high_quality","low latency yet high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + { "high_quality", "high quality transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + { "lowlatency_high_quality","low latency yet high quality transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, + + { "bitdepth", "Set color bit deph", OFFSET(bit_depth), AV_OPT_TYPE_INT, {.i64 = AMF_COLOR_BIT_DEPTH_UNDEFINED }, AMF_COLOR_BIT_DEPTH_UNDEFINED, AMF_COLOR_BIT_DEPTH_10, VE, .unit = "bitdepth" }, + { "8", "8 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_8 }, 0, 0, VE, .unit = "bitdepth" }, + { "10", "10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_10 }, 0, 0, VE, .unit = "bitdepth" }, { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST,{.i64 = AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, @@ -84,7 +88,7 @@ static const AVOption options[] = { { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, - { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, @@ -97,32 +101,42 @@ static const AVOption options[] = { { "gop", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "frame", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, 16, VE }, + { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, + // B-Frames + { "max_b_frames", "Maximum number of consecutive B Pictures", OFFSET(max_consecutive_b_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, + { "bf", "B Picture Pattern", OFFSET(max_b_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, + { "high_motion_quality_boost_enable", "Enable High motion quality boost mode", OFFSET(hw_high_motion_quality_boost), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - // min_qp_i -> min_qp_intra, min_qp_p -> min_qp_inter + // min_qp_i -> min_qp_intra, min_qp_p -> min_qp_p min_qp_b -> min_qp_b { "min_qp_i", "min quantization parameter for I-frame", OFFSET(min_qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "max_qp_i", "max quantization parameter for I-frame", OFFSET(max_qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "min_qp_p", "min quantization parameter for P-frame", OFFSET(min_qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "min_qp_b", "min quantization parameter for B-frame", OFFSET(min_qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "max_qp_b", "max quantization parameter for B-frame", OFFSET(max_qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "qp_p", "quantization parameter for P-frame", OFFSET(qp_p), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "qp_i", "quantization parameter for I-frame", OFFSET(qp_i), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, + { "qp_b", "quantization parameter for B-frame", OFFSET(qp_b), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 255, VE }, { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, { "aq_mode", "adaptive quantization mode", OFFSET(aq_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ, VE , .unit = "adaptive_quantisation_mode" }, { "none", "no adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, { "caq", "context adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "align", "alignment mode", OFFSET(align), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS }, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS, VE, .unit = "align" }, { "64x16", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY }, 0, 0, VE, .unit = "align" }, { "1080p", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_1080P_CODED_1082 }, 0, 0, VE, .unit = "align" }, { "none", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS }, 0, 0, VE, .unit = "align" }, - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{.i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, @@ -134,16 +148,16 @@ static const AVOption options[] = { { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -169,6 +183,9 @@ static const AVOption options[] = { { "pa_high_motion_quality_boost_mode", "Sets the PA high motion quality boost mode", OFFSET(pa_high_motion_quality_boost_mode), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO, VE , .unit = "high_motion_quality_boost_mode" }, { "none", "no high motion quality boost", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_NONE }, 0, 0, VE, .unit = "high_motion_quality_boost_mode" }, { "auto", "auto high motion quality boost", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_HIGH_MOTION_QUALITY_BOOST_MODE_AUTO }, 0, 0, VE, .unit = "high_motion_quality_boost_mode" }, + + { "pa_adaptive_mini_gop", "Enable Adaptive B-frame", OFFSET(pa_adaptive_mini_gop), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { NULL } }; @@ -177,15 +194,15 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext* ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; - AMFBuffer* buffer; + AMFBuffer *buffer; AMFGuid guid; AMFRate framerate; AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); - amf_int64 color_depth; + amf_int64 bit_depth; amf_int64 color_profile; enum AVPixelFormat pix_fmt; @@ -199,13 +216,7 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) < 0) @@ -237,30 +248,37 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PROFILE, profile); } - /// Color profile + // Color bit depth + pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format + : avctx->pix_fmt; + bit_depth = ctx->bit_depth; + if(bit_depth == AMF_COLOR_BIT_DEPTH_UNDEFINED){ + bit_depth = pix_fmt == AV_PIX_FMT_P010 ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, bit_depth); + + // Color profile color_profile = ff_amf_get_color_profile(avctx); AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); - /// Color Depth - pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format - : avctx->pix_fmt; - color_depth = AMF_COLOR_BIT_DEPTH_8; - if (pix_fmt == AV_PIX_FMT_P010) { - color_depth = AMF_COLOR_BIT_DEPTH_10; + // Color Range + // TODO + + // Color Transfer Characteristics (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_primaries are for VUI only + // AMF VCN color conversion supports only specific output primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, avctx->color_trc); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, color_depth); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); - if (color_depth == AMF_COLOR_BIT_DEPTH_8) { - /// Color Transfer Characteristics (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); - /// Color Primaries (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); - } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); + // Color Primaries (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010 ) + { + // AMF VCN color conversion supports only specific primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, avctx->color_primaries); } - profile_level = avctx->level; if (profile_level == AV_LEVEL_UNKNOWN) { profile_level = ctx->level; @@ -280,7 +298,9 @@ FF_ENABLE_DEPRECATION_WARNINGS } // Picture control properties - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_GOP_SIZE, avctx->gop_size); + if (avctx->gop_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_GOP_SIZE, avctx->gop_size); + } // Setup header insertion mode only if this option was defined explicitly if (ctx->header_insertion_mode != -1) { @@ -292,7 +312,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_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->min_qp_b != -1 || ctx->max_qp_b != -1 || + ctx->qp_i != -1 || ctx->qp_p != -1 || ctx->qp_b != -1) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); } @@ -305,6 +326,21 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); } } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } // Pre-Pass, Pre-Analysis, Two-Pass if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP) { @@ -367,7 +403,7 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE, avctx->rc_max_rate); } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_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"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (avctx->bit_rate > 0) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; @@ -456,6 +492,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->pa_taq_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_TAQ_MODE, ctx->pa_taq_mode); } + if (ctx->pa_adaptive_mini_gop != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ADAPTIVE_MINIGOP, ((ctx->pa_adaptive_mini_gop == 0) ? false : true)); + } if (ctx->pa_ltr != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_PA_LTR_ENABLE, ((ctx->pa_ltr == 0) ? false : true)); } @@ -467,6 +506,67 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // B-Frames + AMFVariantStruct is_adaptive_b_frames = { 0 }; + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_ADAPTIVE_MINIGOP, &is_adaptive_b_frames); + if (ctx->max_consecutive_b_frames != -1 || ctx->max_b_frames != -1 || is_adaptive_b_frames.boolValue == true) { + + //Get the capability of encoder + AMFCaps *encoder_caps = NULL; + ctx->encoder->pVtbl->GetCaps(ctx->encoder, &encoder_caps); + if (encoder_caps != NULL) + { + res = encoder_caps->pVtbl->GetProperty(encoder_caps, AMF_VIDEO_ENCODER_AV1_CAP_BFRAMES, &var); + if (res == AMF_OK) { + + //encoder supports AV1 B-frame + if(var.boolValue == true){ + //adaptive b-frames is higher priority than max_b_frames + if (is_adaptive_b_frames.boolValue == true) + { + //force AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES to 3 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES, 3); + + if(ctx->pa_lookahead_buffer_depth < 1) + { + //force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 if not set or smaller than 1 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 1); + } + } + else { + if (ctx->max_b_frames != -1) { + //in case user sets B-frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_B_PIC_PATTERN, ctx->max_b_frames); + if (res != AMF_OK) { + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_B_PIC_PATTERN, &var); + av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", ctx->max_b_frames, (int)var.int64Value); + ctx->max_b_frames = (int)var.int64Value; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_CONSECUTIVE_BPICTURES, ctx->max_b_frames); + } + } + + } + //encoder doesn't support AV1 B-frame + else { + av_log(ctx, AV_LOG_WARNING, "The current GPU in use does not support AV1 B-frame encoding, there will be no B-frame in bitstream.\n"); + } + } else { + //Can't get the capability of encoder + av_log(ctx, AV_LOG_WARNING, "Unable to get AV1 B-frame capability.\n"); + av_log(ctx, AV_LOG_WARNING, "There will be no B-frame in bitstream.\n"); + } + + encoder_caps->pVtbl->Release(encoder_caps); + encoder_caps = NULL; + } + } + + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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); @@ -493,6 +593,13 @@ FF_ENABLE_DEPRECATION_WARNINGS int qval = avctx->qmin > 255 ? 255 : avctx->qmin; AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER, qval); } + if (ctx->min_qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER_B, ctx->min_qp_b); + } + else if (avctx->qmin != -1) { + int qval = avctx->qmin > 255 ? 255 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER_B, qval); + } if (ctx->max_qp_p != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER, ctx->max_qp_p); } @@ -500,6 +607,13 @@ FF_ENABLE_DEPRECATION_WARNINGS int qval = avctx->qmax > 255 ? 255 : avctx->qmax; AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER, qval); } + if (ctx->max_qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER_B, ctx->max_qp_b); + } + else if (avctx->qmax != -1) { + int qval = avctx->qmax > 255 ? 255 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER_B, qval); + } if (ctx->qp_p != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER, ctx->qp_p); @@ -507,6 +621,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->qp_i != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA, ctx->qp_i); } + if (ctx->qp_b != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER_B, ctx->qp_b); + } if (ctx->skip_frame != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME, ((ctx->skip_frame == 0) ? false : true)); @@ -540,7 +657,7 @@ FF_ENABLE_DEPRECATION_WARNINGS buffer->pVtbl->Release(buffer); var.pInterface->pVtbl->Release(var.pInterface); - //processing crop informaiton according to alignment + //processing crop information according to alignment if (ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_CAP_WIDTH_ALIGNMENT_FACTOR_LOCAL, &var) != AMF_OK) // assume older driver and Navi3x width_alignment_factor = 64; @@ -622,13 +739,13 @@ const FFCodec ff_av1_amf_encoder = { .init = amf_encode_init_av1, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &av1_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c index 8edd39c633..131ba871f5 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -24,7 +24,7 @@ #include "codec_internal.h" #include -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -82,7 +82,7 @@ static const AVOption options[] = { { "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_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "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, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "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, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, @@ -110,6 +110,9 @@ static const AVOption options[] = { /// Header Insertion Spacing { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, + /// Maximum queued frames + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, 16, 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 }, @@ -133,10 +136,10 @@ static const AVOption options[] = { { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) , AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, - - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, @@ -148,16 +151,16 @@ static const AVOption options[] = { { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -192,7 +195,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -207,13 +210,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) != 0) @@ -391,13 +388,29 @@ FF_ENABLE_DEPRECATION_WARNINGS 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"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (ctx->latency != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_LOWLATENCY_MODE, ((ctx->latency == 0) ? false : true)); } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_LOWLATENCY_MODE, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } + if (ctx->preanalysis != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, !!((ctx->preanalysis == 0) ? false : true)); } @@ -455,26 +468,61 @@ FF_ENABLE_DEPRECATION_WARNINGS } // B-Frames - if (ctx->max_consecutive_b_frames != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, ctx->max_consecutive_b_frames); - if (ctx->max_b_frames != -1) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, ctx->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", - ctx->max_b_frames, (int)var.int64Value); - ctx->max_b_frames = (int)var.int64Value; - } - if (ctx->max_consecutive_b_frames < ctx->max_b_frames) { - av_log(ctx, AVERROR_BUG, "Maxium B frames needs to be greater than the specified B frame count.\n"); + AMFVariantStruct is_adaptive_b_frames = { 0 }; + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_ADAPTIVE_MINIGOP, &is_adaptive_b_frames); + if (ctx->max_consecutive_b_frames != -1 || ctx->max_b_frames != -1 || is_adaptive_b_frames.boolValue == true) { + + //Get the capability of encoder + AMFCaps *encoder_caps = NULL; + ctx->encoder->pVtbl->GetCaps(ctx->encoder, &encoder_caps); + if (encoder_caps != NULL) + { + res = encoder_caps->pVtbl->GetProperty(encoder_caps, AMF_VIDEO_ENCODER_CAP_BFRAMES, &var); + if (res == AMF_OK) { + + //encoder supports H.264 B-frame + if(var.boolValue == true){ + //adaptive b-frames is higher priority than max_b_frames + if (is_adaptive_b_frames.boolValue == true) + { + //force AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES to 3 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, 3); + + if(ctx->pa_lookahead_buffer_depth < 1) + { + //force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 if not set or smaller than 1 + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 1); + } + } + else { + if (ctx->max_b_frames != -1) { + //in case user sets B-frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, ctx->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", ctx->max_b_frames, (int)var.int64Value); + ctx->max_b_frames = (int)var.int64Value; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_CONSECUTIVE_BPICTURES, ctx->max_b_frames); + } + } + + } + //encoder doesn't support H.264 B-frame + else { + av_log(ctx, AV_LOG_WARNING, "The current GPU in use does not support H.264 B-frame encoding, there will be no B-frame in bitstream.\n"); + } + } else { + //Can't get the capability of encoder + av_log(ctx, AV_LOG_WARNING, "Unable to get H.264 B-frame capability.\n"); + av_log(ctx, AV_LOG_WARNING, "There will be no B-frame in bitstream.\n"); } + + encoder_caps->pVtbl->Release(encoder_caps); + encoder_caps = NULL; } } - else { - if (ctx->max_b_frames != -1) { - av_log(ctx, AVERROR_BUG, "Maxium number of B frames needs to be specified.\n"); - } - } + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); if ((int)var.int64Value) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, ctx->b_frame_delta_qp); @@ -482,6 +530,21 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, ctx->ref_b_frame_delta_qp); } + 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 { + if (ctx->enable_vbaq != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + } + + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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); @@ -499,19 +562,12 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, ((ctx->skip_frame == 0) ? false : true)); } - 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 { - if (ctx->enable_vbaq != -1) { - 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); // Keyframe Interval - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + if (avctx->gop_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + } // Header Insertion Spacing if (ctx->header_spacing >= 0) @@ -594,14 +650,14 @@ const FFCodec ff_h264_amf_encoder = { .init = amf_encode_init_h264, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &h264_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c index 4898824f3a..73c555db38 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -23,11 +23,11 @@ #include "codec_internal.h" #include -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, 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 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, + { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, { "ultralowlatency", "Ultra low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, { "lowlatency", "Low latency usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, @@ -35,15 +35,19 @@ static const AVOption options[] = { { "high_quality", "High quality usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, { "lowlatency_high_quality", "Low latency yet high quality usecase", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, .unit = "profile" }, + { "bitdepth", "Set color bit deph", OFFSET(bit_depth), AV_OPT_TYPE_INT, {.i64 = AMF_COLOR_BIT_DEPTH_UNDEFINED }, AMF_COLOR_BIT_DEPTH_UNDEFINED, AMF_COLOR_BIT_DEPTH_10, VE, .unit = "bitdepth" }, + { "8", "8 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_8 }, 0, 0, VE, .unit = "bitdepth" }, + { "10", "10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_COLOR_BIT_DEPTH_10 }, 0, 0, VE, .unit = "bitdepth" }, + + { "profile", "Set the profile", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "main10", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, .unit = "profile" }, - { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, .unit = "tier" }, + { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, .unit = "tier" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, 0, 0, VE, .unit = "tier" }, { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_HIGH }, 0, 0, VE, .unit = "tier" }, - { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, .unit = "level" }, + { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, .unit = "level" }, { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, .unit = "level" }, { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_1 }, 0, 0, VE, .unit = "level" }, { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2 }, 0, 0, VE, .unit = "level" }, @@ -59,37 +63,39 @@ static const AVOption options[] = { { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_1 }, 0, 0, VE, .unit = "level" }, { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_2 }, 0, 0, VE, .unit = "level" }, - { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, - { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, { "balanced", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED }, 0, 0, VE, .unit = "quality" }, { "speed", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, 0, 0, VE, .unit = "quality" }, - { "latency", "enables low latency mode", OFFSET(latency), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, + { "latency", "enables low latency mode", OFFSET(latency), AV_OPT_TYPE_BOOL,{.i64 = -1 }, -1, 1, VE }, - { "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_HIGH_QUALITY_CBR, VE, .unit = "rc" }, + { "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_HIGH_QUALITY_CBR, VE, .unit = "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, .unit = "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, .unit = "rc" }, + { "vbr_peak", "Peak Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, .unit = "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, .unit = "rc" }, { "qvbr", "Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqvbr", "High Quality Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR }, 0, 0, VE, .unit = "rc" }, { "hqcbr", "High Quality Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR }, 0, 0, VE, .unit = "rc" }, - { "qvbr_quality_level", "Sets the QVBR quality level", OFFSET(qvbr_quality_level), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, + { "qvbr_quality_level", "Sets the QVBR quality level", OFFSET(qvbr_quality_level), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, - { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, .unit = "hdrmode" }, + { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, .unit = "hdrmode" }, { "none", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, 0, 0, VE, .unit = "hdrmode" }, { "gop", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, { "idr", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED }, 0, 0, VE, .unit = "hdrmode" }, + { "async_depth", "Set maximum encoding parallelism. Higher values increase output latency.", OFFSET(hwsurfaces_in_queue_max), AV_OPT_TYPE_INT, {.i64 = 16 }, 1, 16, VE }, + { "high_motion_quality_boost_enable", "Enable High motion quality boost mode", OFFSET(hw_high_motion_quality_boost), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, { "gops_per_idr", "GOPs per IDR 0-no IDR will be inserted", OFFSET(gops_per_idr), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, VE }, { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE}, - { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, INT_MAX, VE}, + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 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 }, @@ -100,31 +106,31 @@ static const AVOption options[] = { { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, - - { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { "smart_access_video", "Enable Smart Access Video to enhance performance by utilizing both APU and dGPU memory access", OFFSET(smart_access_video), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, //Pre Analysis options - { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_activity_type", "Set the type of activity analysis", OFFSET(pa_activity_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_ACTIVITY_YUV, VE, .unit = "activity_type" }, + { "pa_activity_type", "Set the type of activity analysis", OFFSET(pa_activity_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_ACTIVITY_YUV, VE, .unit = "activity_type" }, { "y", "activity y", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_ACTIVITY_Y }, 0, 0, VE, .unit = "activity_type" }, { "yuv", "activity yuv", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_ACTIVITY_YUV }, 0, 0, VE, .unit = "activity_type" }, - { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "pa_scene_change_detection_enable", "Enable scene change detection", OFFSET(pa_scene_change_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, - { "low", "low scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "medium", "medium scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "high", "high scene change dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "pa_scene_change_detection_sensitivity", "Set the sensitivity of scene change detection", OFFSET(pa_scene_change_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH, VE, .unit = "scene_change_sensitivity" }, + { "low", "low scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "medium", "medium scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "scene_change_sensitivity" }, + { "high", "high scene change detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_SCENE_CHANGE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "scene_change_sensitivity" }, - { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, + { "pa_static_scene_detection_enable", "Enable static scene detection", OFFSET(pa_static_scene_detection), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, - { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, - { "low", "low static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "medium", "medium static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, - { "high", "high static scene dectection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "pa_static_scene_detection_sensitivity", "Set the sensitivity of static scene detection", OFFSET(pa_static_scene_detection_sensitivity), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH, VE , .unit = "static_scene_sensitivity" }, + { "low", "low static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_LOW }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "medium", "medium static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_MEDIUM }, 0, 0, VE, .unit = "static_scene_sensitivity" }, + { "high", "high static scene detection sensitivity", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_PA_STATIC_SCENE_DETECTION_SENSITIVITY_HIGH }, 0, 0, VE, .unit = "static_scene_sensitivity" }, { "pa_initial_qp_after_scene_change", "The QP value that is used immediately after a scene change", OFFSET(pa_initial_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, { "pa_max_qp_before_force_skip", "The QP threshold to allow a skip frame", OFFSET(pa_max_qp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 51, VE }, @@ -157,7 +163,7 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = {0}; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -166,20 +172,14 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) AMFRate framerate; AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; - amf_int64 color_depth; + amf_int64 bit_depth; amf_int64 color_profile; enum AVPixelFormat pix_fmt; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); } else { -FF_DISABLE_DEPRECATION_WARNINGS - framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ); -FF_ENABLE_DEPRECATION_WARNINGS + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num); } if ((ret = ff_amf_encode_init(avctx)) < 0) @@ -241,35 +241,48 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); } - color_profile = ff_amf_get_color_profile(avctx); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile); - /// Color Range (Support for older Drivers) - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE, !!(avctx->color_range == AVCOL_RANGE_JPEG)); - /// Color Depth - color_depth = AMF_COLOR_BIT_DEPTH_8; + // Color bit depth pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format : avctx->pix_fmt; - if (pix_fmt == AV_PIX_FMT_P010) { - color_depth = AMF_COLOR_BIT_DEPTH_10; + + bit_depth = ctx->bit_depth; + if(bit_depth == AMF_COLOR_BIT_DEPTH_UNDEFINED){ + bit_depth = pix_fmt == AV_PIX_FMT_P010 ? AMF_COLOR_BIT_DEPTH_10 : AMF_COLOR_BIT_DEPTH_8; } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, color_depth); - if (color_depth == AMF_COLOR_BIT_DEPTH_8) { - /// Color Transfer Characteristics (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); - /// Color Primaries (AMF matches ISO/IEC) - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); - } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, bit_depth); + + // Color profile + color_profile = ff_amf_get_color_profile(avctx); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile); + + // Color Range (Support for older Drivers) + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE, !!(avctx->color_range == AVCOL_RANGE_JPEG)); + + // Color Transfer Characteristics (AMF matches ISO/IEC) + if(avctx->color_trc != AVCOL_TRC_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_trc is for VUI only - any value + // AMF VCN color conversion supports only specific output transfer characteristic SMPTE2084 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, avctx->color_trc); + } + + // Color Primaries (AMF matches ISO/IEC) + if(avctx->color_primaries != AVCOL_PRI_UNSPECIFIED && (pix_fmt == AV_PIX_FMT_NV12 || pix_fmt == AV_PIX_FMT_P010)){ + // if input is YUV, color_primaries are for VUI only + // AMF VCN color conversion supports only specific output primaries BT2020 for 10-bit and BT709 for 8-bit + // vpp_amf supports more + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, avctx->color_primaries); } // 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->gop_size != -1) { + 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_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, !deblocking_filter); if (ctx->header_insertion_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); @@ -292,6 +305,22 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + if (ctx->smart_access_video != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_SMART_ACCESS_VIDEO, ctx->smart_access_video != 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "The Smart Access Video is not supported by AMF.\n"); + if (ctx->smart_access_video != 0) + return AVERROR(ENOSYS); + } else { + av_log(avctx, AV_LOG_INFO, "The Smart Access Video (%d) is set.\n", ctx->smart_access_video); + // Set low latency mode if Smart Access Video is enabled + if (ctx->smart_access_video != 0) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE, true); + av_log(avctx, AV_LOG_INFO, "The Smart Access Video set low latency mode.\n"); + } + } + } + // Pre-Pass, Pre-Analysis, Two-Pass if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, 0); @@ -369,7 +398,7 @@ FF_ENABLE_DEPRECATION_WARNINGS 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"); + av_log(ctx, AV_LOG_DEBUG, "rate control mode is vbr_peak but max_rate is not set, default max_rate will be applied.\n"); } if (ctx->latency != -1) { @@ -429,6 +458,11 @@ FF_ENABLE_DEPRECATION_WARNINGS } } + // Wait inside QueryOutput() if supported by the driver + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, 1); + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, &var); + ctx->query_timeout_supported = res == AMF_OK && var.int64Value; + // 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); @@ -511,6 +545,7 @@ static const FFCodecDefault defaults[] = { { "slices", "1" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "flags", "+loop"}, { NULL }, }; static const AVClass hevc_amf_class = { @@ -528,15 +563,15 @@ const FFCodec ff_hevc_amf_encoder = { .init = amf_encode_init_hevc, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &hevc_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_amf_pix_fmts, - .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ + CODEC_PIXFMTS_ARRAY(ff_amf_pix_fmts), + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, }; diff --git a/libavcodec/amrnbdec.c b/libavcodec/amrnbdec.c index bfdcbba778..822dc1297b 100644 --- a/libavcodec/amrnbdec.c +++ b/libavcodec/amrnbdec.c @@ -1104,6 +1104,5 @@ const FFCodec ff_amrnb_decoder = { .init = amrnb_decode_init, FF_CODEC_DECODE_CB(amrnb_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index bb0864587a..91fb870a64 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -556,7 +556,8 @@ static void decode_fixed_vector(float *fixed_vector, const uint16_t *pulse_hi, ((int) pulse_hi[i] << 11), 4, 1); break; default: - av_assert2(0); + av_unreachable("Everything >= MODE_SID is impossible: MODE_SID is patchwelcome," + "> MODE_SID is invalid"); } memset(fixed_vector, 0, sizeof(float) * AMRWB_SFR_SIZE); @@ -1307,6 +1308,5 @@ const FFCodec ff_amrwb_decoder = { .init = amrwb_decode_init, FF_CODEC_DECODE_CB(amrwb_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/ansi.c b/libavcodec/ansi.c index d8d32bafbd..bde9edbe60 100644 --- a/libavcodec/ansi.c +++ b/libavcodec/ansi.c @@ -82,7 +82,7 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_PAL8; /* defaults */ - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); s->font_height = 16; s->fg = DEFAULT_FG_COLOR; s->bg = DEFAULT_BG_COLOR; @@ -217,19 +217,19 @@ static int execute_code(AVCodecContext * avctx, int c) s->args[0] = DEFAULT_SCREEN_MODE; switch(s->args[0]) { case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 40<<3; height = 25<<3; break; case 2: case 3: //640x400 (25 rows) - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); s->font_height = 16; width = 80<<3; height = 25<<4; break; case 6: case 14: //640x200 (25 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 25<<3; @@ -237,13 +237,13 @@ static int execute_code(AVCodecContext * avctx, int c) case 7: //set line wrapping break; case 15: case 16: //640x350 (43 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 43<<3; break; case 17: case 18: //640x480 (60 rows) - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); s->font_height = 8; width = 80<<3; height = 60<<4; @@ -262,11 +262,6 @@ static int execute_code(AVCodecContext * avctx, int c) AV_GET_BUFFER_FLAG_REF)) < 0) return ret; s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif set_palette((uint32_t *)s->frame->data[1]); erase_screen(avctx); } else if (c == 'l') { @@ -375,11 +370,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif set_palette((uint32_t *)s->frame->data[1]); if (!s->first_frame) { erase_screen(avctx); diff --git a/libavcodec/aom_film_grain.c b/libavcodec/aom_film_grain.c index e302567ba5..0f24a2bcf8 100644 --- a/libavcodec/aom_film_grain.c +++ b/libavcodec/aom_film_grain.c @@ -26,7 +26,9 @@ */ #include "libavutil/avassert.h" +#include "libavutil/buffer.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "aom_film_grain.h" #include "get_bits.h" @@ -124,7 +126,7 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, { GetBitContext gbc, *gb = &gbc; AVFilmGrainAOMParams *aom; - AVFilmGrainParams *fgp, *ref = NULL; + AVFilmGrainParams *fgp = NULL, *ref = NULL; int ret, num_sets, n, i, uv, num_y_coeffs, update_grain, luma_only; ret = init_get_bits8(gb, payload, payload_size); @@ -135,28 +137,38 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, if (!s->enable) return 0; + for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) + av_buffer_unref(&s->sets[i]); + skip_bits(gb, 4); // reserved num_sets = get_bits(gb, 3) + 1; for (n = 0; n < num_sets; n++) { int payload_4byte, payload_size, set_idx, apply_units_log2, vsc_flag; int predict_scaling, predict_y_scaling, predict_uv_scaling[2]; int payload_bits, start_position; + size_t fgp_size; start_position = get_bits_count(gb); payload_4byte = get_bits1(gb); payload_size = get_bits(gb, payload_4byte ? 2 : 8); set_idx = get_bits(gb, 3); - fgp = &s->sets[set_idx]; + fgp = av_film_grain_params_alloc(&fgp_size); + if (!fgp) + goto error; aom = &fgp->codec.aom; fgp->type = get_bits1(gb) ? AV_FILM_GRAIN_PARAMS_AV1 : AV_FILM_GRAIN_PARAMS_NONE; - if (!fgp->type) + if (!fgp->type) { + av_freep(&fgp); continue; + } fgp->seed = get_bits(gb, 16); update_grain = get_bits1(gb); - if (!update_grain) + if (!update_grain) { + av_freep(&fgp); continue; + } apply_units_log2 = get_bits(gb, 4); fgp->width = get_bits(gb, 12) << apply_units_log2; @@ -330,32 +342,46 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, if (payload_bits > payload_size * 8) goto error; skip_bits(gb, payload_size * 8 - payload_bits); + + av_buffer_unref(&s->sets[set_idx]); + s->sets[set_idx] = av_buffer_create((uint8_t *)fgp, fgp_size, NULL, NULL, 0); + if (!s->sets[set_idx]) + goto error; } return 0; error: - memset(s, 0, sizeof(*s)); + av_free(fgp); + ff_aom_uninit_film_grain_params(s); return AVERROR_INVALIDDATA; } int ff_aom_attach_film_grain_sets(const AVFilmGrainAFGS1Params *s, AVFrame *frame) { - AVFilmGrainParams *fgp; if (!s->enable) return 0; for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) { - if (s->sets[i].type != AV_FILM_GRAIN_PARAMS_AV1) + if (!s->sets[i]) continue; - fgp = av_film_grain_params_create_side_data(frame); - if (!fgp) + + if (!av_frame_side_data_add(&frame->side_data, &frame->nb_side_data, + AV_FRAME_DATA_FILM_GRAIN_PARAMS, + (AVBufferRef**)&s->sets[i], + AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) return AVERROR(ENOMEM); - memcpy(fgp, &s->sets[i], sizeof(*fgp)); } return 0; } +void ff_aom_uninit_film_grain_params(AVFilmGrainAFGS1Params *s) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) + av_buffer_unref(&s->sets[i]); + s->enable = 0; +} + // Taken from the AV1 spec. Range is [-2048, 2047], mean is 0 and stddev is 512 static const int16_t gaussian_sequence[2048] = { 56, 568, -180, 172, 124, -84, 172, -64, -900, 24, 820, diff --git a/libavcodec/aom_film_grain.h b/libavcodec/aom_film_grain.h index 1f8c78f657..97c33deb47 100644 --- a/libavcodec/aom_film_grain.h +++ b/libavcodec/aom_film_grain.h @@ -28,11 +28,12 @@ #ifndef AVCODEC_AOM_FILM_GRAIN_H #define AVCODEC_AOM_FILM_GRAIN_H +#include "libavutil/buffer.h" #include "libavutil/film_grain_params.h" typedef struct AVFilmGrainAFGS1Params { int enable; - AVFilmGrainParams sets[8]; + AVBufferRef *sets[8]; } AVFilmGrainAFGS1Params; // Synthesizes film grain on top of `in` and stores the result to `out`. `out` @@ -48,4 +49,7 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, // Attach all valid film grain param sets to `frame`. int ff_aom_attach_film_grain_sets(const AVFilmGrainAFGS1Params *s, AVFrame *frame); +// Free all allocations in `s` and zero the entire struct. +void ff_aom_uninit_film_grain_params(AVFilmGrainAFGS1Params *s); + #endif /* AVCODEC_AOM_FILM_GRAIN_H */ diff --git a/libavcodec/apac.c b/libavcodec/apac.c index eb05d38636..a092b1e372 100644 --- a/libavcodec/apac.c +++ b/libavcodec/apac.c @@ -269,12 +269,7 @@ const FFCodec ff_apac_decoder = { FF_CODEC_DECODE_CB(apac_decode), .close = apac_close, .p.capabilities = AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c index d75a85f466..6634650355 100644 --- a/libavcodec/apedec.c +++ b/libavcodec/apedec.c @@ -1759,17 +1759,10 @@ const FFCodec ff_ape_decoder = { .init = ape_decode_init, .close = ape_decode_close, FF_CODEC_DECODE_CB(ape_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DELAY | + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = ape_flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), .p.priv_class = &ape_decoder_class, }; diff --git a/libavcodec/aptx.h b/libavcodec/aptx.h index da0697e652..8e5bf31ab2 100644 --- a/libavcodec/aptx.h +++ b/libavcodec/aptx.h @@ -108,7 +108,7 @@ typedef const struct { extern ConstTables ff_aptx_quant_tables[2][NB_SUBBANDS]; -/* Rounded right shift with optionnal clipping */ +/* Rounded right shift with optional clipping */ #define RSHIFT_SIZE(size) \ av_always_inline \ static int##size##_t rshift##size(int##size##_t value, int shift) \ diff --git a/libavcodec/aptxdec.c b/libavcodec/aptxdec.c index 4b083b6558..35f50052a6 100644 --- a/libavcodec/aptxdec.c +++ b/libavcodec/aptxdec.c @@ -183,9 +183,8 @@ const FFCodec ff_aptx_decoder = { .init = ff_aptx_init, FF_CODEC_DECODE_CB(aptx_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), }; #endif @@ -199,8 +198,7 @@ const FFCodec ff_aptx_hd_decoder = { .init = ff_aptx_init, FF_CODEC_DECODE_CB(aptx_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), }; #endif diff --git a/libavcodec/aptxenc.c b/libavcodec/aptxenc.c index 5e041b9a1b..ab02459733 100644 --- a/libavcodec/aptxenc.c +++ b/libavcodec/aptxenc.c @@ -276,10 +276,9 @@ const FFCodec ff_aptx_encoder = { .init = aptx_encode_init, FF_CODEC_ENCODE_CB(aptx_encode_frame), .close = aptx_close, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(8000, 16000, 24000, 32000, 44100, 48000), }; #endif @@ -294,9 +293,8 @@ const FFCodec ff_aptx_hd_encoder = { .init = aptx_encode_init, FF_CODEC_ENCODE_CB(aptx_encode_frame), .close = aptx_close, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(8000, 16000, 24000, 32000, 44100, 48000), }; #endif diff --git a/libavcodec/apv.h b/libavcodec/apv.h new file mode 100644 index 0000000000..14ca27bf31 --- /dev/null +++ b/libavcodec/apv.h @@ -0,0 +1,89 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_APV_H +#define AVCODEC_APV_H + +// Signature value in APV bitstreams (section 5.3.1). +#define APV_SIGNATURE MKBETAG('a', 'P', 'v', '1') + +// PBU types (section 5.3.3). +enum { + APV_PBU_PRIMARY_FRAME = 1, + APV_PBU_NON_PRIMARY_FRAME = 2, + APV_PBU_PREVIEW_FRAME = 25, + APV_PBU_DEPTH_FRAME = 26, + APV_PBU_ALPHA_FRAME = 27, + APV_PBU_ACCESS_UNIT_INFORMATION = 65, + APV_PBU_METADATA = 66, + APV_PBU_FILLER = 67, +}; + +// Format parameters (section 4.2). +enum { + APV_MAX_NUM_COMP = 4, + APV_MB_WIDTH = 16, + APV_MB_HEIGHT = 16, + APV_TR_SIZE = 8, +}; + +// Chroma formats (section 4.2). +enum { + APV_CHROMA_FORMAT_400 = 0, + APV_CHROMA_FORMAT_422 = 2, + APV_CHROMA_FORMAT_444 = 3, + APV_CHROMA_FORMAT_4444 = 4, +}; + +// Coefficient limits (section 5.3.15). +enum { + APV_BLK_COEFFS = (APV_TR_SIZE * APV_TR_SIZE), + APV_MIN_TRANS_COEFF = -32768, + APV_MAX_TRANS_COEFF = 32767, +}; + +// Profiles (section 10.1.3). +enum { + APV_PROFILE_422_10 = 33, + APV_PROFILE_422_12 = 44, + APV_PROFILE_444_10 = 55, + APV_PROFILE_444_12 = 66, + APV_PROFILE_4444_10 = 77, + APV_PROFILE_4444_12 = 88, + APV_PROFILE_400_10 = 99, +}; + +// General level limits for tiles (section 10.1.4.1). +enum { + APV_MIN_TILE_WIDTH_IN_MBS = 16, + APV_MIN_TILE_HEIGHT_IN_MBS = 8, + APV_MAX_TILE_COLS = 20, + APV_MAX_TILE_ROWS = 20, + APV_MAX_TILE_COUNT = APV_MAX_TILE_COLS * APV_MAX_TILE_ROWS, +}; + +// Metadata types (section 10.3.1). +enum { + APV_METADATA_ITU_T_T35 = 4, + APV_METADATA_MDCV = 5, + APV_METADATA_CLL = 6, + APV_METADATA_FILLER = 10, + APV_METADATA_USER_DEFINED = 170, +}; + +#endif /* AVCODEC_APV_H */ diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c new file mode 100644 index 0000000000..27aaf7aac7 --- /dev/null +++ b/libavcodec/apv_decode.c @@ -0,0 +1,571 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/mastering_display_metadata.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/thread.h" + +#include "apv.h" +#include "apv_decode.h" +#include "apv_dsp.h" +#include "avcodec.h" +#include "cbs.h" +#include "cbs_apv.h" +#include "codec_internal.h" +#include "decode.h" +#include "internal.h" +#include "thread.h" + + +typedef struct APVDerivedTileInfo { + uint8_t tile_cols; + uint8_t tile_rows; + uint16_t num_tiles; + // The spec uses an extra element on the end of these arrays + // not corresponding to any tile. + uint16_t col_starts[APV_MAX_TILE_COLS + 1]; + uint16_t row_starts[APV_MAX_TILE_ROWS + 1]; +} APVDerivedTileInfo; + +typedef struct APVDecodeContext { + CodedBitstreamContext *cbc; + APVDSPContext dsp; + + CodedBitstreamFragment au; + APVDerivedTileInfo tile_info; + + AVPacket *pkt; + AVFrame *output_frame; + atomic_int tile_errors; + + int nb_unit; + + uint8_t warned_additional_frames; + uint8_t warned_unknown_pbu_types; +} APVDecodeContext; + +static const enum AVPixelFormat apv_format_table[5][5] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 }, + { 0 }, // 4:2:0 is not valid. + { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV422P16 }, + { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16 }, + { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, 0 ,AV_PIX_FMT_YUVA444P16 }, +}; + +static APVVLCLUT decode_lut; + +static int apv_decode_check_format(AVCodecContext *avctx, + const APVRawFrameHeader *header) +{ + int err, bit_depth; + + avctx->profile = header->frame_info.profile_idc; + avctx->level = header->frame_info.level_idc; + + bit_depth = header->frame_info.bit_depth_minus8 + 8; + if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2) { + avpriv_request_sample(avctx, "Bit depth %d", bit_depth); + return AVERROR_PATCHWELCOME; + } + avctx->pix_fmt = + apv_format_table[header->frame_info.chroma_format_idc][bit_depth - 4 >> 2]; + + if (!avctx->pix_fmt) { + avpriv_request_sample(avctx, "YUVA444P14"); + return AVERROR_PATCHWELCOME; + } + + err = ff_set_dimensions(avctx, + FFALIGN(header->frame_info.frame_width, 16), + FFALIGN(header->frame_info.frame_height, 16)); + if (err < 0) { + // Unsupported frame size. + return err; + } + avctx->width = header->frame_info.frame_width; + avctx->height = header->frame_info.frame_height; + + avctx->sample_aspect_ratio = (AVRational){ 1, 1 }; + + avctx->color_primaries = header->color_primaries; + avctx->color_trc = header->transfer_characteristics; + avctx->colorspace = header->matrix_coefficients; + avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + + avctx->refs = 0; + avctx->has_b_frames = 0; + + return 0; +} + +static const CodedBitstreamUnitType apv_decompose_unit_types[] = { + APV_PBU_PRIMARY_FRAME, + APV_PBU_METADATA, +}; + +static AVOnce apv_entropy_once = AV_ONCE_INIT; + +static av_cold void apv_entropy_build_decode_lut(void) +{ + ff_apv_entropy_build_decode_lut(&decode_lut); +} + +static av_cold int apv_decode_init(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + ff_thread_once(&apv_entropy_once, apv_entropy_build_decode_lut); + + err = ff_cbs_init(&apv->cbc, AV_CODEC_ID_APV, avctx); + if (err < 0) + return err; + + apv->cbc->decompose_unit_types = + apv_decompose_unit_types; + apv->cbc->nb_decompose_unit_types = + FF_ARRAY_ELEMS(apv_decompose_unit_types); + + // Extradata could be set here, but is ignored by the decoder. + + apv->pkt = avctx->internal->in_pkt; + ff_apv_dsp_init(&apv->dsp); + + atomic_init(&apv->tile_errors, 0); + + return 0; +} + +static void apv_decode_flush(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + + apv->nb_unit = 0; + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + ff_cbs_flush(apv->cbc); +} + +static av_cold int apv_decode_close(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + + ff_cbs_fragment_free(&apv->au); + ff_cbs_close(&apv->cbc); + + return 0; +} + +static int apv_decode_block(AVCodecContext *avctx, + void *output, + ptrdiff_t pitch, + GetBitContext *gbc, + APVEntropyState *entropy_state, + int bit_depth, + int qp_shift, + const uint16_t *qmatrix) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + LOCAL_ALIGNED_32(int16_t, coeff, [64]); + memset(coeff, 0, 64 * sizeof(int16_t)); + + err = ff_apv_entropy_decode_block(coeff, gbc, entropy_state); + if (err < 0) + return err; + + apv->dsp.decode_transquant(output, pitch, + coeff, qmatrix, + bit_depth, qp_shift); + + return 0; +} + +static int apv_decode_tile_component(AVCodecContext *avctx, void *data, + int job, int thread) +{ + APVRawFrame *input = data; + APVDecodeContext *apv = avctx->priv_data; + const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; + const APVDerivedTileInfo *tile_info = &apv->tile_info; + + int tile_index = job / apv_cbc->num_comp; + int comp_index = job % apv_cbc->num_comp; + + const AVPixFmtDescriptor *pix_fmt_desc = + av_pix_fmt_desc_get(avctx->pix_fmt); + + int sub_w_shift = comp_index == 0 ? 0 : pix_fmt_desc->log2_chroma_w; + int sub_h_shift = comp_index == 0 ? 0 : pix_fmt_desc->log2_chroma_h; + + APVRawTile *tile = &input->tile[tile_index]; + + int tile_y = tile_index / tile_info->tile_cols; + int tile_x = tile_index % tile_info->tile_cols; + + int tile_start_x = tile_info->col_starts[tile_x]; + int tile_start_y = tile_info->row_starts[tile_y]; + + int tile_width = tile_info->col_starts[tile_x + 1] - tile_start_x; + int tile_height = tile_info->row_starts[tile_y + 1] - tile_start_y; + + int tile_mb_width = tile_width / APV_MB_WIDTH; + int tile_mb_height = tile_height / APV_MB_HEIGHT; + + int blk_mb_width = 2 >> sub_w_shift; + int blk_mb_height = 2 >> sub_h_shift; + + int bit_depth; + int qp_shift; + LOCAL_ALIGNED_32(uint16_t, qmatrix_scaled, [64]); + + GetBitContext gbc; + + APVEntropyState entropy_state = { + .log_ctx = avctx, + .decode_lut = &decode_lut, + .prev_dc = 0, + .prev_k_dc = 5, + .prev_k_level = 0, + }; + + int err; + + err = init_get_bits8(&gbc, tile->tile_data[comp_index], + tile->tile_header.tile_data_size[comp_index]); + if (err < 0) + goto fail; + + // Combine the bitstream quantisation matrix with the qp scaling + // in advance. (Including qp_shift as well would overflow 16 bits.) + // Fix the row ordering at the same time. + { + static const uint8_t apv_level_scale[6] = { 40, 45, 51, 57, 64, 71 }; + int qp = tile->tile_header.tile_qp[comp_index]; + int level_scale = apv_level_scale[qp % 6]; + + bit_depth = apv_cbc->bit_depth; + qp_shift = qp / 6; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) + qmatrix_scaled[y * 8 + x] = level_scale * + input->frame_header.quantization_matrix.q_matrix[comp_index][x][y]; + } + } + + for (int mb_y = 0; mb_y < tile_mb_height; mb_y++) { + for (int mb_x = 0; mb_x < tile_mb_width; mb_x++) { + for (int blk_y = 0; blk_y < blk_mb_height; blk_y++) { + for (int blk_x = 0; blk_x < blk_mb_width; blk_x++) { + int frame_y = (tile_start_y + + APV_MB_HEIGHT * mb_y + + APV_TR_SIZE * blk_y) >> sub_h_shift; + int frame_x = (tile_start_x + + APV_MB_WIDTH * mb_x + + APV_TR_SIZE * blk_x) >> sub_w_shift; + + ptrdiff_t frame_pitch = apv->output_frame->linesize[comp_index]; + uint8_t *block_start = apv->output_frame->data[comp_index] + + frame_y * frame_pitch + 2 * frame_x; + + err = apv_decode_block(avctx, + block_start, frame_pitch, + &gbc, &entropy_state, + bit_depth, + qp_shift, + qmatrix_scaled); + if (err < 0) { + // Error in block decode means entropy desync, + // so this is not recoverable. + goto fail; + } + } + } + } + } + + av_log(avctx, AV_LOG_DEBUG, + "Decoded tile %d component %d: %dx%d MBs starting at (%d,%d)\n", + tile_index, comp_index, tile_mb_width, tile_mb_height, + tile_start_x, tile_start_y); + + return 0; + +fail: + av_log(avctx, AV_LOG_VERBOSE, + "Decode error in tile %d component %d.\n", + tile_index, comp_index); + atomic_fetch_add_explicit(&apv->tile_errors, 1, memory_order_relaxed); + return err; +} + +static void apv_derive_tile_info(APVDerivedTileInfo *ti, + const APVRawFrameHeader *fh) +{ + int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4; + int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4; + int start_mb, i; + + start_mb = 0; + for (i = 0; start_mb < frame_width_in_mbs; i++) { + ti->col_starts[i] = start_mb * APV_MB_WIDTH; + start_mb += fh->tile_info.tile_width_in_mbs; + } + ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH; + ti->tile_cols = i; + + start_mb = 0; + for (i = 0; start_mb < frame_height_in_mbs; i++) { + ti->row_starts[i] = start_mb * APV_MB_HEIGHT; + start_mb += fh->tile_info.tile_height_in_mbs; + } + ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; + ti->tile_rows = i; + + ti->num_tiles = ti->tile_cols * ti->tile_rows; +} + +static int apv_decode(AVCodecContext *avctx, AVFrame *output, + APVRawFrame *input) +{ + APVDecodeContext *apv = avctx->priv_data; + const AVPixFmtDescriptor *desc = NULL; + APVDerivedTileInfo *tile_info = &apv->tile_info; + int err, job_count; + + err = apv_decode_check_format(avctx, &input->frame_header); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported format parameters.\n"); + return err; + } + + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + + desc = av_pix_fmt_desc_get(avctx->pix_fmt); + av_assert0(desc); + + err = ff_thread_get_buffer(avctx, output, 0); + if (err < 0) + return err; + + apv->output_frame = output; + atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); + + apv_derive_tile_info(tile_info, &input->frame_header); + + // Each component within a tile is independent of every other, + // so we can decode all in parallel. + job_count = tile_info->num_tiles * desc->nb_components; + + avctx->execute2(avctx, apv_decode_tile_component, + input, NULL, job_count); + + err = atomic_load_explicit(&apv->tile_errors, memory_order_relaxed); + if (err > 0) { + av_log(avctx, AV_LOG_ERROR, + "Decode errors in %d tile components.\n", err); + if (avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) { + // Output the frame anyway. + output->flags |= AV_FRAME_FLAG_CORRUPT; + } else { + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int apv_decode_metadata(AVCodecContext *avctx, AVFrame *frame, + const APVRawMetadata *md) +{ + int err; + + for (int i = 0; i < md->metadata_count; i++) { + const APVRawMetadataPayload *pl = &md->payloads[i]; + + switch (pl->payload_type) { + case APV_METADATA_MDCV: + { + const APVRawMetadataMDCV *mdcv = &pl->mdcv; + AVMasteringDisplayMetadata *mdm; + + err = ff_decode_mastering_display_new(avctx, frame, &mdm); + if (err < 0) + return err; + + if (mdm) { + for (int j = 0; j < 3; j++) { + mdm->display_primaries[j][0] = + av_make_q(mdcv->primary_chromaticity_x[j], 1 << 16); + mdm->display_primaries[j][1] = + av_make_q(mdcv->primary_chromaticity_y[j], 1 << 16); + } + + mdm->white_point[0] = + av_make_q(mdcv->white_point_chromaticity_x, 1 << 16); + mdm->white_point[1] = + av_make_q(mdcv->white_point_chromaticity_y, 1 << 16); + + mdm->max_luminance = + av_make_q(mdcv->max_mastering_luminance, 1 << 8); + mdm->min_luminance = + av_make_q(mdcv->min_mastering_luminance, 1 << 14); + + mdm->has_primaries = 1; + mdm->has_luminance = 1; + } + } + break; + case APV_METADATA_CLL: + { + const APVRawMetadataCLL *cll = &pl->cll; + AVContentLightMetadata *clm; + + err = ff_decode_content_light_new(avctx, frame, &clm); + if (err < 0) + return err; + + if (clm) { + clm->MaxCLL = cll->max_cll; + clm->MaxFALL = cll->max_fall; + } + } + break; + default: + // Ignore other types of metadata. + break; + } + } + + return 0; +} + +static int apv_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +{ + APVDecodeContext *apv = avctx->priv_data; + CodedBitstreamFragment *au = &apv->au; + int i, err; + + for (i = apv->nb_unit; i < au->nb_units; i++) { + CodedBitstreamUnit *pbu = &au->units[i]; + + switch (pbu->type) { + case APV_PBU_PRIMARY_FRAME: + err = apv_decode(avctx, frame, pbu->content); + i++; + goto end; + case APV_PBU_METADATA: + apv_decode_metadata(avctx, frame, pbu->content); + break; + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + if (!avctx->internal->is_copy && + !apv->warned_additional_frames) { + av_log(avctx, AV_LOG_WARNING, + "Stream contains additional non-primary frames " + "which will be ignored by the decoder.\n"); + apv->warned_additional_frames = 1; + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + case APV_PBU_FILLER: + // Not relevant to the decoder. + break; + default: + if (!avctx->internal->is_copy && + !apv->warned_unknown_pbu_types) { + av_log(avctx, AV_LOG_WARNING, + "Stream contains PBUs with unknown types " + "which will be ignored by the decoder.\n"); + apv->warned_unknown_pbu_types = 1; + } + break; + } + } + + err = AVERROR(EAGAIN); +end: + av_assert0(i <= apv->au.nb_units); + apv->nb_unit = i; + + if ((err < 0 && err != AVERROR(EAGAIN)) || apv->au.nb_units == i) { + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + apv->nb_unit = 0; + } + if (!err && !frame->buf[0]) + err = AVERROR(EAGAIN); + + return err; +} + +static int apv_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + do { + if (!apv->au.nb_units) { + err = ff_decode_get_packet(avctx, apv->pkt); + if (err < 0) + return err; + + err = ff_cbs_read_packet(apv->cbc, &apv->au, apv->pkt); + if (err < 0) { + ff_cbs_fragment_reset(&apv->au); + av_packet_unref(apv->pkt); + av_log(avctx, AV_LOG_ERROR, "Failed to read packet.\n"); + return err; + } + + apv->nb_unit = 0; + av_log(avctx, AV_LOG_DEBUG, "Total PBUs on this packet: %d.\n", + apv->au.nb_units); + } + + err = apv_receive_frame_internal(avctx, frame); + } while (err == AVERROR(EAGAIN)); + + return err; +} + +const FFCodec ff_apv_decoder = { + .p.name = "apv", + CODEC_LONG_NAME("Advanced Professional Video"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_APV, + .priv_data_size = sizeof(APVDecodeContext), + .init = apv_decode_init, + .flush = apv_decode_flush, + .close = apv_decode_close, + FF_CODEC_RECEIVE_FRAME_CB(apv_receive_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_SLICE_THREADS | + AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, +}; diff --git a/libavcodec/apv_decode.h b/libavcodec/apv_decode.h new file mode 100644 index 0000000000..5671d89552 --- /dev/null +++ b/libavcodec/apv_decode.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 AVCODEC_APV_DECODE_H +#define AVCODEC_APV_DECODE_H + +#include + +#include "apv.h" +#include "avcodec.h" +#include "get_bits.h" + + +// Number of bits in the entropy look-up tables. +// It may be desirable to tune this per-architecture, as a larger LUT +// trades greater memory use for fewer instructions. +// (N bits -> 24*2^N bytes of tables; 9 -> 12KB of tables.) +#define APV_VLC_LUT_BITS 9 +#define APV_VLC_LUT_SIZE (1 << APV_VLC_LUT_BITS) + +typedef struct APVSingleVLCLUTEntry { + uint16_t result; // Return value if not reading more. + uint8_t consume; // Number of bits to consume. + uint8_t more; // Whether to read additional bits. +} APVSingleVLCLUTEntry; + +typedef struct APVMultiVLCLUTEntry { + // Number of symbols this bit stream resolves to. + uint8_t count; + // k_run after decoding all symbols. + uint8_t k_run : 2; + // k_level after decoding the first level symbol. + uint8_t k_level_0 : 3; + // k_level after decoding all symbols. + uint8_t k_level_1 : 3; + // Run output values. + uint8_t run[2]; + // Level output values. + int16_t level[2]; + // Bit index of the end of each code. + uint8_t offset[4]; +} APVMultiVLCLUTEntry; + +typedef struct APVVLCLUT { + // Single-symbol LUT for VLCs. + // Applies to all coefficients, but used only for DC coefficients + // in the decoder. + APVSingleVLCLUTEntry single_lut[6][APV_VLC_LUT_SIZE]; + // Multi-symbol LUT for run/level combinations, decoding up to four + // symbols per step. Comes in two versions, which to use depends on + // whether the next symbol is a run or a level. + APVMultiVLCLUTEntry run_first_lut[3][5][APV_VLC_LUT_SIZE]; + APVMultiVLCLUTEntry level_first_lut[3][5][APV_VLC_LUT_SIZE]; +} APVVLCLUT; + +typedef struct APVEntropyState { + void *log_ctx; + + const APVVLCLUT *decode_lut; + + // Previous DC level value. + int16_t prev_dc; + // k parameter implied by the previous DC level value. + uint8_t prev_k_dc; + // k parameter implied by the previous first AC level value. + uint8_t prev_k_level; +} APVEntropyState; + + +/** + * Build the decoder VLC look-up tables. + */ +void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut); + +/** + * Entropy decode a single 8x8 block to coefficients. + * + * Outputs nonzero coefficients only to the block row-major order + * (dezigzag is applied within the function). The output block + * must have been filled with zeroes before calling this function. + */ +int ff_apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state); + +#endif /* AVCODEC_APV_DECODE_H */ diff --git a/libavcodec/apv_dsp.c b/libavcodec/apv_dsp.c new file mode 100644 index 0000000000..8fbabcf63d --- /dev/null +++ b/libavcodec/apv_dsp.c @@ -0,0 +1,140 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#include "apv.h" +#include "apv_dsp.h" + + +static const int8_t apv_trans_matrix[8][8] = { + { 64, 64, 64, 64, 64, 64, 64, 64 }, + { 89, 75, 50, 18, -18, -50, -75, -89 }, + { 84, 35, -35, -84, -84, -35, 35, 84 }, + { 75, -18, -89, -50, 50, 89, 18, -75 }, + { 64, -64, -64, 64, 64, -64, -64, 64 }, + { 50, -89, 18, 75, -75, -18, 89, -50 }, + { 35, -84, 84, -35, -35, 84, -84, 35 }, + { 18, -50, 75, -89, 89, -75, 50, -18 }, +}; + +static void apv_decode_transquant_c(void *output, + ptrdiff_t pitch, + const int16_t *input_flat, + const int16_t *qmatrix_flat, + int bit_depth, + int qp_shift) +{ + const int16_t (*input)[8] = (const int16_t(*)[8])input_flat; + const int16_t (*qmatrix)[8] = (const int16_t(*)[8])qmatrix_flat; + + int16_t scaled_coeff[8][8]; + int32_t recon_sample[8][8]; + + // Dequant. + { + // Note that level_scale was already combined into qmatrix + // before we got here. + int bd_shift = bit_depth + 3 - 5; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int coeff = ((int)(input[y][x] * qmatrix[y][x] * (1U << qp_shift) + + (1 << (bd_shift - 1)))) >> bd_shift; + + scaled_coeff[y][x] = + av_clip(coeff, APV_MIN_TRANS_COEFF, + APV_MAX_TRANS_COEFF); + } + } + } + + // Transform. + { + int32_t tmp[8][8]; + + // Vertical transform of columns. + for (int x = 0; x < 8; x++) { + for (int i = 0; i < 8; i++) { + int sum = 0; + for (int j = 0; j < 8; j++) + sum += apv_trans_matrix[j][i] * scaled_coeff[j][x]; + tmp[i][x] = sum; + } + } + + // Renormalise. + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) + tmp[y][x] = (tmp[y][x] + 64) >> 7; + } + + // Horizontal transform of rows. + for (int y = 0; y < 8; y++) { + for (int i = 0; i < 8; i++) { + int sum = 0; + for (int j = 0; j < 8; j++) + sum += apv_trans_matrix[j][i] * tmp[y][j]; + recon_sample[y][i] = sum; + } + } + } + + // Output. + if (bit_depth == 8) { + uint8_t *ptr = output; + int bd_shift = 20 - bit_depth; + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int sample = ((recon_sample[y][x] + + (1 << (bd_shift - 1))) >> bd_shift) + + (1 << (bit_depth - 1)); + ptr[x] = av_clip_uintp2(sample, bit_depth); + } + ptr += pitch; + } + } else { + uint16_t *ptr = output; + int bd_shift = 20 - bit_depth; + pitch /= 2; // Pitch was in bytes, 2 bytes per sample. + + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + int sample = ((recon_sample[y][x] + + (1 << (bd_shift - 1))) >> bd_shift) + + (1 << (bit_depth - 1)); + ptr[x] = av_clip_uintp2(sample, bit_depth); + } + ptr += pitch; + } + } +} + +av_cold void ff_apv_dsp_init(APVDSPContext *dsp) +{ + dsp->decode_transquant = apv_decode_transquant_c; + +#if ARCH_X86_64 + ff_apv_dsp_init_x86_64(dsp); +#endif +} diff --git a/libavutil/dict_internal.h b/libavcodec/apv_dsp.h similarity index 59% rename from libavutil/dict_internal.h rename to libavcodec/apv_dsp.h index 6d5b0dc2b0..c63d6a88ee 100644 --- a/libavutil/dict_internal.h +++ b/libavcodec/apv_dsp.h @@ -16,22 +16,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_DICT_INTERNAL_H -#define AVUTIL_DICT_INTERNAL_H +#ifndef AVCODEC_APV_DSP_H +#define AVCODEC_APV_DSP_H +#include #include -#include "dict.h" -/** - * Set a dictionary value to an ISO-8601 compliant timestamp string. - * - * @param dict pointer to a pointer to a dictionary struct. If *dict is NULL - * a dictionary struct is allocated and put in *dict. - * @param key metadata key - * @param timestamp unix timestamp in microseconds - * @return <0 on error - */ -int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp); +typedef struct APVDSPContext { + void (*decode_transquant)(void *output, + ptrdiff_t pitch, + const int16_t *input, + const int16_t *qmatrix, + int bit_depth, + int qp_shift); +} APVDSPContext; -#endif /* AVUTIL_DICT_INTERNAL_H */ +void ff_apv_dsp_init(APVDSPContext *dsp); + +void ff_apv_dsp_init_x86_64(APVDSPContext *dsp); + +#endif /* AVCODEC_APV_DSP_H */ diff --git a/libavcodec/apv_entropy.c b/libavcodec/apv_entropy.c new file mode 100644 index 0000000000..1cab88d547 --- /dev/null +++ b/libavcodec/apv_entropy.c @@ -0,0 +1,614 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "apv.h" +#include "apv_decode.h" + +#include "put_bits.h" + + +av_always_inline +static unsigned int apv_read_vlc(GetBitContext *restrict gbc, int k_param, + const APVVLCLUT *restrict lut) +{ + unsigned int next_bits; + const APVSingleVLCLUTEntry *ent; + + next_bits = show_bits(gbc, APV_VLC_LUT_BITS); + ent = &lut->single_lut[k_param][next_bits]; + + if (ent->more) { + unsigned int leading_zeroes; + + skip_bits(gbc, ent->consume); + + next_bits = show_bits(gbc, 16); + leading_zeroes = 15 - av_log2(next_bits); + + if (leading_zeroes == 0) { + // This can't happen mid-stream because the lookup would + // have resolved a leading one into a shorter code, but it + // can happen if we are hitting the end of the buffer. + // Return an invalid code to propagate as an error. + return APV_MAX_TRANS_COEFF + 1; + } + + skip_bits(gbc, leading_zeroes + 1); + + return (2 << k_param) + + ((1 << leading_zeroes) - 1) * (1 << k_param) + + get_bits(gbc, leading_zeroes + k_param); + } else { + skip_bits(gbc, ent->consume); + return ent->result; + } +} + +void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut) +{ + const int code_len = APV_VLC_LUT_BITS; + const int lut_size = APV_VLC_LUT_SIZE; + + // Build the single-symbol VLC table. + for (int k = 0; k <= 5; k++) { + for (unsigned int code = 0; code < lut_size; code++) { + APVSingleVLCLUTEntry *ent = &decode_lut->single_lut[k][code]; + unsigned int first_bit = code & (1 << code_len - 1); + unsigned int remaining_bits = code ^ first_bit; + + if (first_bit) { + ent->consume = 1 + k; + ent->result = remaining_bits >> (code_len - k - 1); + ent->more = 0; + } else { + unsigned int second_bit = code & (1 << code_len - 2); + remaining_bits ^= second_bit; + + if (second_bit) { + unsigned int bits_left = code_len - 2; + unsigned int first_set = bits_left - av_log2(remaining_bits); + unsigned int last_bits = first_set - 1 + k; + + if (first_set + last_bits <= bits_left) { + // Whole code fits here. + ent->consume = 2 + first_set + last_bits; + ent->result = ((2 << k) + + (((1 << first_set - 1) - 1) << k) + + ((code >> bits_left - first_set - last_bits) & (1 << last_bits) - 1)); + ent->more = 0; + } else { + // Need to read more, collapse to default. + ent->consume = 2; + ent->more = 1; + } + } else { + ent->consume = 2 + k; + ent->result = (1 << k) + (remaining_bits >> (code_len - k - 2)); + ent->more = 0; + } + } + } + } + + // Build the multi-symbol VLC table. + for (int start_run = 0; start_run <= 2; start_run++) { + for (int start_level = 0; start_level <= 4; start_level++) { + for (unsigned int code = 0; code < lut_size; code++) { + APVMultiVLCLUTEntry *ent; + int k_run, k_level; + GetBitContext gbc; + PutBitContext pbc; + uint8_t buffer[16]; + uint8_t run_first_buffer[16]; + uint8_t level_first_buffer[16]; + + memset(buffer, 0, sizeof(buffer)); + init_put_bits(&pbc, buffer, sizeof(buffer)); + put_bits(&pbc, APV_VLC_LUT_BITS, code); + flush_put_bits(&pbc); + + memcpy(run_first_buffer, buffer, sizeof(buffer)); + memcpy(level_first_buffer, buffer, sizeof(buffer)); + + k_run = start_run; + k_level = start_level; + + ent = &decode_lut->run_first_lut[k_run][k_level][code]; + memset(ent, 0, sizeof(*ent)); + init_get_bits8(&gbc, run_first_buffer, sizeof(run_first_buffer)); + + ent->count = 0; + for (int i = 0; i <= 1; i++) { + int value, sign, pos; + + value = apv_read_vlc(&gbc, k_run, decode_lut); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ent->run[i] = value; + ent->offset[ent->count] = pos; + ++ent->count; + k_run = FFMIN(value >> 2, 2); + + value = apv_read_vlc(&gbc, k_level, decode_lut); + sign = get_bits1(&gbc); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ++value; + ent->level[i] = sign ? -value : value; + ent->offset[ent->count] = pos; + ++ent->count; + k_level = FFMIN(value >> 2, 4); + if (i == 0) + ent->k_level_0 = k_level; + } + if (ent->count > 0 && ent->count < 4) + ent->offset[3] = ent->offset[ent->count - 1]; + ent->k_run = k_run; + ent->k_level_1 = k_level; + + k_run = start_run; + k_level = start_level; + + ent = &decode_lut->level_first_lut[k_run][k_level][code]; + memset(ent, 0, sizeof(*ent)); + init_get_bits8(&gbc, level_first_buffer, sizeof(level_first_buffer)); + + ent->count = 0; + for (int i = 0; i <= 1; i++) { + int value, sign, pos; + + value = apv_read_vlc(&gbc, k_level, decode_lut); + sign = get_bits1(&gbc); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ++value; + ent->level[i] = sign ? -value : value; + ent->offset[ent->count] = pos; + ++ent->count; + k_level = FFMIN(value >> 2, 4); + if (i == 0) + ent->k_level_0 = k_level; + + value = apv_read_vlc(&gbc, k_run, decode_lut); + pos = get_bits_count(&gbc); + if (pos > APV_VLC_LUT_BITS) + break; + ent->run[i] = value; + ent->offset[ent->count] = pos; + ++ent->count; + k_run = FFMIN(value >> 2, 2); + } + if (ent->count > 0 && ent->count < 4) + ent->offset[3] = ent->offset[ent->count - 1]; + ent->k_run = k_run; + ent->k_level_1 = k_level; + } + } + } +} + +int ff_apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state) +{ + const APVVLCLUT *lut = state->decode_lut; + int scan_pos; + int k_dc = state->prev_k_dc; + int k_run, k_level; + uint32_t next_bits, lut_bits; + const APVMultiVLCLUTEntry *ent; + + // DC coefficient is likely to be large and cannot be usefully + // combined with other read steps, so extract it separately. + { + int dc_coeff, abs_diff, sign; + + abs_diff = apv_read_vlc(gbc, k_dc, lut); + + if (abs_diff) { + sign = get_bits1(gbc); + if (sign) + dc_coeff = state->prev_dc - abs_diff; + else + dc_coeff = state->prev_dc + abs_diff; + } else { + dc_coeff = state->prev_dc; + } + + + if (dc_coeff < APV_MIN_TRANS_COEFF || + dc_coeff > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range DC coefficient value: %d.\n", + dc_coeff); + return AVERROR_INVALIDDATA; + } + + coeff[0] = dc_coeff; + + state->prev_dc = dc_coeff; + state->prev_k_dc = FFMIN(abs_diff >> 1, 5); + } + + // Repeatedly read 18 bits, look up the first half of them in either + // the run-first or the level-first table. If the next code is too + // long the 18 bits will allow resolving a run code (up to 63) + // without reading any more bits, and will allow the exact length + // of a level code to be determined. (Note that reusing the + // single-symbol LUT is never useful here as the multisymbol lookup + // has already determined that the code is too long.) + + // Run a single iteration of the run-first LUT to start, then a + // single iteration of the level-first LUT if that only read a + // single code. This avoids dealing with the first-AC logic inside + // the normal code lookup sequence. + + k_level = state->prev_k_level; + { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->run_first_lut[0][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits, low_bits; + unsigned int leading_zeroes, low_bit_count, low_bit_shift; + int run; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + if (leading_zeroes >= 6) { + // 6 zeroes implies run > 64, which is always invalid. + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range run value: %d leading zeroes.\n", + leading_zeroes); + return AVERROR_INVALIDDATA; + } + // Extract the low bits. + low_bit_count = leading_zeroes; + low_bit_shift = 16 - (1 + 2 * leading_zeroes); + low_bits = (bits >> low_bit_shift) & ((1 << low_bit_count) - 1); + // Construct run code. + run = 2 + ((1 << leading_zeroes) - 1) + low_bits; + // Skip over the bits just used. + skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count); + + scan_pos = run + 1; + if (scan_pos >= 64) + goto end_of_block; + k_run = FFMIN(run >> 2, 2); + goto first_level; + } else { + // One or more short codes starting with a run; if there is + // a level code then the length needs to be saved for the + // next block. + + scan_pos = ent->run[0] + 1; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + state->prev_k_level = ent->k_level_0; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count == 1) + goto first_level; + else if (ent->count & 1) + goto next_is_level; + else + goto next_is_run; + } + } + + first_level: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->level_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits; + unsigned int leading_zeroes; + int level, abs_level, sign; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + // Skip the prefix and length bits. + skip_bits(gbc, 2 + leading_zeroes + 1); + // Read the rest of the code and construct the level. + // Include the + 1 offset for nonzero value here. + abs_level = (2 << k_level) + + ((1 << leading_zeroes) - 1) * (1 << k_level) + + get_bits(gbc, leading_zeroes + k_level) + 1; + + sign = get_bits(gbc, 1); + if (sign) + level = -abs_level; + else + level = abs_level; + + // Check range (not checked in any other case, only a long + // code can be out of range). + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value at %d: %d.\n", + scan_pos, level); + return AVERROR_INVALIDDATA; + } + coeff[ff_zigzag_direct[scan_pos]] = level; + ++scan_pos; + k_level = FFMIN(abs_level >> 2, 4); + state->prev_k_level = k_level; + if (scan_pos >= 64) + goto end_of_block; + goto next_is_run; + + } else { + // One or more short codes. + + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + state->prev_k_level = ent->k_level_0; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_run; + else + goto next_is_level; + } + } + + next_is_run: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->run_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits, low_bits; + unsigned int leading_zeroes, low_bit_count, low_bit_shift; + int run; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + if (leading_zeroes >= 6) { + // 6 zeroes implies run > 64, which is always invalid. + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range run value: %d leading zeroes.\n", + leading_zeroes); + return AVERROR_INVALIDDATA; + } + // Extract the low bits. + low_bit_count = leading_zeroes + k_run; + low_bit_shift = 16 - (1 + 2 * leading_zeroes + k_run); + low_bits = (bits >> low_bit_shift) & ((1 << low_bit_count) - 1); + // Construct run code. + run = (2 << k_run) + + ((1 << leading_zeroes) - 1) * (1 << k_run) + + low_bits; + // Skip over the bits just used. + skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count); + + scan_pos += run; + if (scan_pos >= 64) + goto end_of_block; + k_run = FFMIN(run >> 2, 2); + goto next_is_level; + + } else { + // One or more short codes. + + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_level; + else + goto next_is_run; + } + } + + next_is_level: { + next_bits = show_bits(gbc, 18); + lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS); + + ent = &lut->level_first_lut[k_run][k_level][lut_bits]; + + if (ent->count == 0) { + // One long code. + uint32_t bits; + unsigned int leading_zeroes; + int level, abs_level, sign; + + // Remove the prefix bits. + bits = next_bits & 0xffff; + // Determine code length. + leading_zeroes = 15 - av_log2(bits); + // Skip the prefix and length bits. + skip_bits(gbc, 2 + leading_zeroes + 1); + // Read the rest of the code and construct the level. + // Include the + 1 offset for nonzero value here. + abs_level = (2 << k_level) + + ((1 << leading_zeroes) - 1) * (1 << k_level) + + get_bits(gbc, leading_zeroes + k_level) + 1; + + sign = get_bits(gbc, 1); + if (sign) + level = -abs_level; + else + level = abs_level; + + // Check range (not checked in any other case, only a long + // code can be out of range). + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value at %d: %d.\n", + scan_pos, level); + return AVERROR_INVALIDDATA; + } + coeff[ff_zigzag_direct[scan_pos]] = level; + ++scan_pos; + k_level = FFMIN(abs_level >> 2, 4); + if (scan_pos >= 64) + goto end_of_block; + goto next_is_run; + + } else { + // One or more short codes. + + coeff[ff_zigzag_direct[scan_pos]] = ent->level[0]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[0]); + goto end_of_block; + } + if (ent->count > 1) { + scan_pos += ent->run[0]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[1]); + goto end_of_block; + } + } + if (ent->count > 2) { + coeff[ff_zigzag_direct[scan_pos]] = ent->level[1]; + ++scan_pos; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[2]); + goto end_of_block; + } + } + if (ent->count > 3) { + scan_pos += ent->run[1]; + if (scan_pos >= 64) { + skip_bits(gbc, ent->offset[3]); + goto end_of_block; + } + } + skip_bits(gbc, ent->offset[3]); + k_run = ent->k_run; + k_level = ent->k_level_1; + if (ent->count & 1) + goto next_is_run; + else + goto next_is_level; + } + } + + end_of_block: { + if (scan_pos > 64) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Block decode reached invalid scan position %d.\n", + scan_pos); + return AVERROR_INVALIDDATA; + } + return 0; + } +} diff --git a/libavcodec/apv_parser.c b/libavcodec/apv_parser.c new file mode 100644 index 0000000000..fdd575339b --- /dev/null +++ b/libavcodec/apv_parser.c @@ -0,0 +1,149 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/buffer.h" + +#include "avcodec.h" +#include "apv.h" +#include "cbs.h" +#include "cbs_apv.h" + +typedef struct APVParseContext { + CodedBitstreamContext *cbc; + CodedBitstreamFragment au; +} APVParseContext; + +static const enum AVPixelFormat apv_format_table[5][5] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 }, + { 0 }, // 4:2:0 is not valid. + { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 }, + { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 }, + { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 }, +}; + +static void dummy_free(void *opaque, uint8_t *data) +{ + av_assert0(opaque == data); +} + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + APVParseContext *p = s->priv_data; + CodedBitstreamFragment *au = &p->au; + AVBufferRef *ref = NULL; + int ret; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + ref = av_buffer_create((uint8_t *)buf, buf_size, dummy_free, + (void *)buf, AV_BUFFER_FLAG_READONLY); + if (!ref) + return buf_size; + + p->cbc->log_ctx = avctx; + + ret = ff_cbs_read(p->cbc, au, ref, buf, buf_size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to parse access unit.\n"); + goto end; + } + + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_UNKNOWN; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + for (int i = 0; i < au->nb_units; i++) { + const CodedBitstreamUnit *pbu = &au->units[i]; + + switch (pbu->type) { + case APV_PBU_PRIMARY_FRAME: { + const APVRawFrame *frame = pbu->content; + const APVRawFrameHeader *header = &frame->frame_header; + const APVRawFrameInfo *info = &header->frame_info; + int bit_depth = info->bit_depth_minus8 + 8; + + if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2) + break; + + s->width = info->frame_width; + s->height = info->frame_height; + s->format = apv_format_table[info->chroma_format_idc][bit_depth - 4 >> 2]; + avctx->profile = info->profile_idc; + avctx->level = info->level_idc; + avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + avctx->color_primaries = header->color_primaries; + avctx->color_trc = header->transfer_characteristics; + avctx->colorspace = header->matrix_coefficients; + avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + goto end; + } + default: + break; + } + } + +end: + ff_cbs_fragment_reset(au); + av_assert1(av_buffer_get_ref_count(ref) == 1); + av_buffer_unref(&ref); + p->cbc->log_ctx = NULL; + + return buf_size; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + APV_PBU_PRIMARY_FRAME, +}; + +static av_cold int init(AVCodecParserContext *s) +{ + APVParseContext *p = s->priv_data; + int ret; + + ret = ff_cbs_init(&p->cbc, AV_CODEC_ID_APV, NULL); + if (ret < 0) + return ret; + + p->cbc->decompose_unit_types = decompose_unit_types; + p->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + + return 0; +} + +static av_cold void close(AVCodecParserContext *s) +{ + APVParseContext *p = s->priv_data; + + ff_cbs_fragment_free(&p->au); + ff_cbs_close(&p->cbc); +} + +const AVCodecParser ff_apv_parser = { + .codec_ids = { AV_CODEC_ID_APV }, + .priv_data_size = sizeof(APVParseContext), + .parser_init = init, + .parser_parse = parse, + .parser_close = close, +}; diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile index becf316eb6..811b364195 100644 --- a/libavcodec/arm/Makefile +++ b/libavcodec/arm/Makefile @@ -21,7 +21,7 @@ OBJS-$(CONFIG_LLAUDDSP) += arm/lossless_audiodsp_init_arm.o OBJS-$(CONFIG_ME_CMP) += arm/me_cmp_init_arm.o OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o -OBJS-$(CONFIG_MPEGVIDEOENC) += arm/mpegvideoencdsp_init_arm.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += arm/mpegvideoencdsp_init_arm.o OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o OBJS-$(CONFIG_PIXBLOCKDSP) += arm/pixblockdsp_init_arm.o OBJS-$(CONFIG_RV34DSP) += arm/rv34dsp_init_arm.o @@ -72,7 +72,7 @@ ARMV6-OBJS-$(CONFIG_IDCTDSP) += arm/idctdsp_init_armv6.o \ arm/simple_idct_armv6.o ARMV6-OBJS-$(CONFIG_ME_CMP) += arm/me_cmp_armv6.o ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_fixed_armv6.o -ARMV6-OBJS-$(CONFIG_MPEGVIDEOENC) += arm/mpegvideoencdsp_armv6.o +ARMV6-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += arm/mpegvideoencdsp_armv6.o ARMV6-OBJS-$(CONFIG_PIXBLOCKDSP) += arm/pixblockdsp_armv6.o ARMV6-OBJS-$(CONFIG_STARTCODE) += arm/startcode_armv6.o ARMV6-OBJS-$(CONFIG_VP8DSP) += arm/vp8_armv6.o \ diff --git a/libavcodec/arm/hevcdsp_idct_neon.S b/libavcodec/arm/hevcdsp_idct_neon.S index 66ed1c6785..feff373ff2 100644 --- a/libavcodec/arm/hevcdsp_idct_neon.S +++ b/libavcodec/arm/hevcdsp_idct_neon.S @@ -783,7 +783,7 @@ endfunc transpose8_4x4 d29, d3, d21, d23 store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 - @ reload multiplication coefficiens to q1 + @ reload multiplication coefficients to q1 vld1.s16 {q1}, [r9, :128] .endm diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S index 8fd9d1e0df..e5695027e4 100644 --- a/libavcodec/arm/hevcdsp_sao_neon.S +++ b/libavcodec/arm/hevcdsp_sao_neon.S @@ -100,7 +100,7 @@ function ff_hevc_sao_edge_filter_neon_8, export=1 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.8 {d0}, [r11] // edge_idx table load in d0 5x8bit vld1.16 {q1}, [r10] // sao_offset_val table load in q1, 5x16bit vmov.u8 d1, #2 vmov.u16 q2, #1 diff --git a/libavcodec/arm/int_neon.S b/libavcodec/arm/int_neon.S index 72c4c77c45..3c58b72842 100644 --- a/libavcodec/arm/int_neon.S +++ b/libavcodec/arm/int_neon.S @@ -48,4 +48,3 @@ function ff_scalarproduct_int16_neon, export=1 vmov.32 r0, d3[0] bx lr endfunc - diff --git a/libavcodec/arm/me_cmp_init_arm.c b/libavcodec/arm/me_cmp_init_arm.c index 8c556f1755..a47e2bc4fa 100644 --- a/libavcodec/arm/me_cmp_init_arm.c +++ b/libavcodec/arm/me_cmp_init_arm.c @@ -23,19 +23,18 @@ #include "libavutil/arm/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" -int ff_pix_abs16_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_x2_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs16_y2_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_pix_abs8_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_pix_abs8_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); -int ff_sse16_armv6(MpegEncContext *s, const uint8_t *blk1, const uint8_t *blk2, +int ff_sse16_armv6(MPVEncContext *s, const uint8_t *blk1, const uint8_t *blk2, ptrdiff_t stride, int h); av_cold void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx) diff --git a/libavcodec/arm/mpegvideo_arm.c b/libavcodec/arm/mpegvideo_arm.c index 28a3f2cdd9..5c96c9df2c 100644 --- a/libavcodec/arm/mpegvideo_arm.c +++ b/libavcodec/arm/mpegvideo_arm.c @@ -24,6 +24,7 @@ #include "libavutil/arm/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" #include "mpegvideo_arm.h" #include "asm-offsets.h" @@ -45,12 +46,12 @@ void ff_dct_unquantize_h263_inter_neon(MpegEncContext *s, int16_t *block, void ff_dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, int n, int qscale); -av_cold void ff_mpv_common_init_arm(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_arm(MPVUnquantDSPContext *s, int bitexact) { int cpu_flags = av_get_cpu_flags(); if (have_armv5te(cpu_flags)) - ff_mpv_common_init_armv5te(s); + ff_mpv_unquantize_init_armv5te(s); if (have_neon(cpu_flags)) { s->dct_unquantize_h263_intra = ff_dct_unquantize_h263_intra_neon; diff --git a/libavcodec/arm/mpegvideo_arm.h b/libavcodec/arm/mpegvideo_arm.h index 709ae6b247..93da7a5664 100644 --- a/libavcodec/arm/mpegvideo_arm.h +++ b/libavcodec/arm/mpegvideo_arm.h @@ -19,8 +19,8 @@ #ifndef AVCODEC_ARM_MPEGVIDEO_ARM_H #define AVCODEC_ARM_MPEGVIDEO_ARM_H -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" -void ff_mpv_common_init_armv5te(MpegEncContext *s); +void ff_mpv_unquantize_init_armv5te(MPVUnquantDSPContext *s); #endif /* AVCODEC_ARM_MPEGVIDEO_ARM_H */ diff --git a/libavcodec/arm/mpegvideo_armv5te.c b/libavcodec/arm/mpegvideo_armv5te.c index e20bb4c645..2737f68643 100644 --- a/libavcodec/arm/mpegvideo_armv5te.c +++ b/libavcodec/arm/mpegvideo_armv5te.c @@ -95,7 +95,7 @@ static void dct_unquantize_h263_inter_armv5te(MpegEncContext *s, ff_dct_unquantize_h263_armv5te(block, qmul, qadd, nCoeffs + 1); } -av_cold void ff_mpv_common_init_armv5te(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_armv5te(MPVUnquantDSPContext *s) { s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_armv5te; s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_armv5te; diff --git a/libavcodec/arm/pixblockdsp_init_arm.c b/libavcodec/arm/pixblockdsp_init_arm.c index 5481c0178c..121338ad0c 100644 --- a/libavcodec/arm/pixblockdsp_init_arm.c +++ b/libavcodec/arm/pixblockdsp_init_arm.c @@ -21,7 +21,6 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/arm/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" void ff_get_pixels_armv6(int16_t *block, const uint8_t *pixels, @@ -39,7 +38,6 @@ void ff_diff_pixels_unaligned_neon(int16_t *block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_arm(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/arm/vp9mc_neon.S b/libavcodec/arm/vp9mc_neon.S index bd8cda7c30..2ec729bb31 100644 --- a/libavcodec/arm/vp9mc_neon.S +++ b/libavcodec/arm/vp9mc_neon.S @@ -279,11 +279,13 @@ function \type\()_8tap_\size\()h_\idx1\idx2 sub r1, r1, r5 .endif @ size >= 16 loads two qwords and increments r2, - @ for size 4/8 it's enough with one qword and no - @ postincrement + @ size 4 loads 1 d word, increments r2 and loads 1 32-bit lane + @ for size 8 it's enough with one qword and no postincrement .if \size >= 16 sub r3, r3, r5 sub r3, r3, #8 +.elseif \size == 4 + sub r3, r3, #8 .endif @ Load the filter vector vld1.16 {q0}, [r12,:128] @@ -295,9 +297,14 @@ function \type\()_8tap_\size\()h_\idx1\idx2 .if \size >= 16 vld1.8 {d18, d19, d20}, [r2]! vld1.8 {d24, d25, d26}, [r7]! -.else +.elseif \size == 8 vld1.8 {q9}, [r2] vld1.8 {q12}, [r7] +.else @ size == 4 + vld1.8 {d18}, [r2]! + vld1.8 {d24}, [r7]! + vld1.32 {d19[0]}, [r2] + vld1.32 {d25[0]}, [r7] .endif vmovl.u8 q8, d18 vmovl.u8 q9, d19 diff --git a/libavcodec/ass_split.c b/libavcodec/ass_split.c index 73ef6196c5..9376265d7a 100644 --- a/libavcodec/ass_split.c +++ b/libavcodec/ass_split.c @@ -1,5 +1,5 @@ /* - * SSA/ASS spliting functions + * SSA/ASS splitting functions * Copyright (c) 2010 Aurelien Jacobs * * This file is part of FFmpeg. diff --git a/libavcodec/ass_split.h b/libavcodec/ass_split.h index a45fb9b8a1..41191c0f44 100644 --- a/libavcodec/ass_split.h +++ b/libavcodec/ass_split.h @@ -1,5 +1,5 @@ /* - * SSA/ASS spliting functions + * SSA/ASS splitting functions * Copyright (c) 2010 Aurelien Jacobs * * This file is part of FFmpeg. diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c index 4f81a4015d..883edd0468 100644 --- a/libavcodec/asvenc.c +++ b/libavcodec/asvenc.c @@ -26,6 +26,7 @@ #include "config_components.h" #include "libavutil/attributes.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" @@ -44,49 +45,64 @@ typedef struct ASVEncContext { PutBitContext pb; + void (*get_pixels)(int16_t *restrict block, + const uint8_t *pixels, + ptrdiff_t stride); + PixblockDSPContext pdsp; FDCTDSPContext fdsp; DECLARE_ALIGNED(32, int16_t, block)[6][64]; int q_intra_matrix[64]; } ASVEncContext; +enum { + ASV1_MAX_BLOCK_SIZE = 8 + 10 * FFMAX(2 /* skip */, 5 /* ccp */ + 4 * 11 /* level */) + 5, + ASV1_MAX_MB_SIZE = 6 * ASV1_MAX_BLOCK_SIZE, + ASV2_MAX_BLOCK_SIZE = 4 + 8 + 16 * (6 /* ccp */ + 4 * 13 /* level */), + ASV2_MAX_MB_SIZE = 6 * ASV2_MAX_BLOCK_SIZE, + MAX_MB_SIZE = (FFMAX(ASV1_MAX_MB_SIZE, ASV2_MAX_MB_SIZE) + 7) / 8 +}; + static inline void asv1_put_level(PutBitContext *pb, int level) { unsigned int index = level + 3; + unsigned n, code; if (index <= 6) { - put_bits(pb, ff_asv_level_tab[index][1], ff_asv_level_tab[index][0]); + n = ff_asv_level_tab[index][1]; + code = ff_asv_level_tab[index][0]; } else { - put_bits(pb, 3, 0); /* Escape code */ - put_sbits(pb, 8, level); + n = 3 + 8; + code = (0 /* Escape code */ << 8) | (level & 0xFF); } + put_bits(pb, n, code); } static inline void asv2_put_level(ASVEncContext *a, PutBitContext *pb, int level) { unsigned int index = level + 31; + unsigned n, code; if (index <= 62) { - put_bits_le(pb, ff_asv2_level_tab[index][1], ff_asv2_level_tab[index][0]); + n = ff_asv2_level_tab[index][1]; + code = ff_asv2_level_tab[index][0]; } else { - put_bits_le(pb, 5, 0); /* Escape code */ if (level < -128 || level > 127) { av_log(a->c.avctx, AV_LOG_WARNING, "Clipping level %d, increase qscale\n", level); level = av_clip_int8(level); } - put_bits_le(pb, 8, level & 0xFF); + n = 5 + 8; + code = (level & 0xFF) << 5 | /* Escape code */ 0; } + put_bits_le(pb, n, code); } static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) { - int i; - int nc_count = 0; - put_bits(&a->pb, 8, (block[0] + 32) >> 6); block[0] = 0; - for (i = 0; i < 10; i++) { + for (unsigned i = 0, nc_bits = 0, nc_val = 0; i < 10; i++) { const int index = ff_asv_scantab[4 * i]; int ccp = 0; @@ -104,10 +120,11 @@ static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) ccp |= 1; if (ccp) { - for (; nc_count; nc_count--) - put_bits(&a->pb, 2, 2); /* Skip */ - - put_bits(&a->pb, ff_asv_ccp_tab[ccp][1], ff_asv_ccp_tab[ccp][0]); + put_bits(&a->pb, nc_bits + ff_asv_ccp_tab[ccp][1], + nc_val << ff_asv_ccp_tab[ccp][1] /* Skip */ | + ff_asv_ccp_tab[ccp][0]); + nc_bits = 0; + nc_val = 0; if (ccp & 8) asv1_put_level(&a->pb, block[index + 0]); @@ -118,7 +135,8 @@ static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64]) if (ccp & 1) asv1_put_level(&a->pb, block[index + 9]); } else { - nc_count++; + nc_bits += 2; + nc_val = (nc_val << 2) | 2; } } put_bits(&a->pb, 5, 0xF); /* End of block */ @@ -137,8 +155,8 @@ static inline void asv2_encode_block(ASVEncContext *a, int16_t block[64]) count >>= 2; - put_bits_le(&a->pb, 4, count); - put_bits_le(&a->pb, 8, (block[0] + 32) >> 6); + put_bits_le(&a->pb, 4 + 8, count /* 4 bits */ | + (/* DC */(block[0] + 32) >> 6) << 4); block[0] = 0; for (i = 0; i <= count; i++) { @@ -177,8 +195,6 @@ static inline void asv2_encode_block(ASVEncContext *a, int16_t block[64]) } } -#define MAX_MB_SIZE (30 * 16 * 16 * 3 / 2 / 8) - static inline int encode_mb(ASVEncContext *a, int16_t block[6][64]) { int i; @@ -207,21 +223,73 @@ static inline void dct_get(ASVEncContext *a, const AVFrame *frame, const uint8_t *ptr_cb = frame->data[1] + (mb_y * 8 * frame->linesize[1]) + mb_x * 8; const uint8_t *ptr_cr = frame->data[2] + (mb_y * 8 * frame->linesize[2]) + mb_x * 8; - a->pdsp.get_pixels(block[0], ptr_y, linesize); - a->pdsp.get_pixels(block[1], ptr_y + 8, linesize); - a->pdsp.get_pixels(block[2], ptr_y + 8 * linesize, linesize); - a->pdsp.get_pixels(block[3], ptr_y + 8 * linesize + 8, linesize); + a->get_pixels(block[0], ptr_y, linesize); + a->get_pixels(block[1], ptr_y + 8, linesize); + a->get_pixels(block[2], ptr_y + 8 * linesize, linesize); + a->get_pixels(block[3], ptr_y + 8 * linesize + 8, linesize); for (i = 0; i < 4; i++) a->fdsp.fdct(block[i]); if (!(a->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { - a->pdsp.get_pixels(block[4], ptr_cb, frame->linesize[1]); - a->pdsp.get_pixels(block[5], ptr_cr, frame->linesize[2]); + a->get_pixels(block[4], ptr_cb, frame->linesize[1]); + a->get_pixels(block[5], ptr_cr, frame->linesize[2]); for (i = 4; i < 6; i++) a->fdsp.fdct(block[i]); } } +static void handle_partial_mb(ASVEncContext *a, const uint8_t *const data[3], + const int linesizes[3], + int valid_width, int valid_height) +{ + const int nb_blocks = a->c.avctx->flags & AV_CODEC_FLAG_GRAY ? 4 : 6; + static const struct Descriptor { + uint8_t x_offset, y_offset; + uint8_t component, subsampling; + } block_descriptor[] = { + { 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 0, 8, 0, 0 }, { 8, 8, 0, 0 }, + { 0, 0, 1, 1 }, { 0, 0, 2, 1 }, + }; + + for (int i = 0; i < nb_blocks; ++i) { + const struct Descriptor *const desc = block_descriptor + i; + int width_avail = AV_CEIL_RSHIFT(valid_width, desc->subsampling) - desc->x_offset; + int height_avail = AV_CEIL_RSHIFT(valid_height, desc->subsampling) - desc->y_offset; + + if (width_avail <= 0 || height_avail <= 0) { + // This block is outside of the visible part; don't replicate pixels, + // just zero the block, so that only the dc value will be coded. + memset(a->block[i], 0, sizeof(a->block[i])); + continue; + } + width_avail = FFMIN(width_avail, 8); + height_avail = FFMIN(height_avail, 8); + + ptrdiff_t linesize = linesizes[desc->component]; + const uint8_t *src = data[desc->component] + desc->y_offset * linesize + desc->x_offset; + int16_t *block = a->block[i]; + + for (int h = 0;; block += 8, src += linesize) { + int16_t last; + for (int w = 0; w < width_avail; ++w) + last = block[w] = src[w]; + for (int w = width_avail; w < 8; ++w) + block[w] = last; + if (++h == height_avail) + break; + } + const int16_t *const last_row = block; + for (int h = height_avail; h < 8; ++h) { + block += 8; + AV_COPY128(block, last_row); + } + + a->fdsp.fdct(a->block[i]); + } + + encode_mb(a, a->block); +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -229,51 +297,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const ASVCommonContext *const c = &a->c; int size, ret; - if (pict->width % 16 || pict->height % 16) { - AVFrame *clone = av_frame_alloc(); - int i; - - if (!clone) - return AVERROR(ENOMEM); - clone->format = pict->format; - clone->width = FFALIGN(pict->width, 16); - clone->height = FFALIGN(pict->height, 16); - ret = av_frame_get_buffer(clone, 0); - if (ret < 0) { - av_frame_free(&clone); - return ret; - } - - ret = av_frame_copy(clone, pict); - if (ret < 0) { - av_frame_free(&clone); - return ret; - } - - for (i = 0; i<3; i++) { - int x, y; - int w = AV_CEIL_RSHIFT(pict->width, !!i); - int h = AV_CEIL_RSHIFT(pict->height, !!i); - int w2 = AV_CEIL_RSHIFT(clone->width, !!i); - int h2 = AV_CEIL_RSHIFT(clone->height, !!i); - for (y=0; ydata[i][x + y*clone->linesize[i]] = - clone->data[i][w - 1 + y*clone->linesize[i]]; - for (y=h; ydata[i][x + y*clone->linesize[i]] = - clone->data[i][x + (h-1)*clone->linesize[i]]; - } - ret = encode_frame(avctx, pkt, clone, got_packet); - - av_frame_free(&clone); + ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3); + if (ret < 0) return ret; - } - if ((ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + - FF_INPUT_BUFFER_MIN_SIZE)) < 0) - return ret; + if (!PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED && + ((uintptr_t)pict->data[0] & 7 || pict->linesize[0] & 7 || + (uintptr_t)pict->data[1] & 7 || pict->linesize[1] & 7 || + (uintptr_t)pict->data[2] & 7 || pict->linesize[2] & 7)) + a->get_pixels = a->pdsp.get_pixels_unaligned; + else + a->get_pixels = a->pdsp.get_pixels; init_put_bits(&a->pb, pkt->data, pkt->size); @@ -284,19 +318,37 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } - if (c->mb_width2 != c->mb_width) { - int mb_x = c->mb_width2; + if (avctx->width & 15) { + const uint8_t *src[3] = { + pict->data[0] + c->mb_width2 * 16, + pict->data[1] + c->mb_width2 * 8, + pict->data[2] + c->mb_width2 * 8, + }; + int available_width = avctx->width & 15; + for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) { - dct_get(a, pict, mb_x, mb_y); - encode_mb(a, a->block); + handle_partial_mb(a, src, pict->linesize, available_width, 16); + src[0] += 16 * pict->linesize[0]; + src[1] += 8 * pict->linesize[1]; + src[2] += 8 * pict->linesize[2]; } } - if (c->mb_height2 != c->mb_height) { - int mb_y = c->mb_height2; - for (int mb_x = 0; mb_x < c->mb_width; mb_x++) { - dct_get(a, pict, mb_x, mb_y); - encode_mb(a, a->block); + if (avctx->height & 15) { + const uint8_t *src[3] = { + pict->data[0] + c->mb_height2 * 16 * pict->linesize[0], + pict->data[1] + c->mb_height2 * 8 * pict->linesize[1], + pict->data[2] + c->mb_height2 * 8 * pict->linesize[2], + }; + int available_height = avctx->height & 15; + + for (int remaining = avctx->width;; remaining -= 16) { + handle_partial_mb(a, src, pict->linesize, remaining, available_height); + if (remaining <= 16) + break; + src[0] += 16; + src[1] += 8; + src[2] += 8; } } @@ -327,7 +379,7 @@ static av_cold int encode_init(AVCodecContext *avctx) ff_asv_common_init(avctx); ff_fdctdsp_init(&a->fdsp, avctx); - ff_pixblockdsp_init(&a->pdsp, avctx); + ff_pixblockdsp_init(&a->pdsp, 8); if (avctx->global_quality <= 0) avctx->global_quality = 4 * FF_QUALITY_SCALE; @@ -339,8 +391,8 @@ static av_cold int encode_init(AVCodecContext *avctx) if (!avctx->extradata) return AVERROR(ENOMEM); avctx->extradata_size = 8; - AV_WLA(32, avctx->extradata, inv_qscale); - ((uint32_t *) avctx->extradata)[1] = av_le2ne32(AV_RL32("ASUS")); + AV_WL32A(avctx->extradata, inv_qscale); + AV_WL32A(avctx->extradata + 4, MKTAG('A', 'S', 'U', 'S')); for (i = 0; i < 64; i++) { if (a->fdsp.fdct == ff_fdct_ifast) { @@ -365,8 +417,7 @@ const FFCodec ff_asv1_encoder = { .priv_data_size = sizeof(ASVEncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; #endif @@ -381,8 +432,7 @@ const FFCodec ff_asv2_encoder = { .priv_data_size = sizeof(ASVEncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; #endif diff --git a/libavcodec/atrac1.c b/libavcodec/atrac1.c index cdcc7a669e..f0bef9b9e6 100644 --- a/libavcodec/atrac1.c +++ b/libavcodec/atrac1.c @@ -399,7 +399,6 @@ const FFCodec ff_atrac1_decoder = { .close = atrac1_decode_end, FF_CODEC_DECODE_CB(atrac1_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/atrac3.c b/libavcodec/atrac3.c index 39ddfd9e45..fe156fa482 100644 --- a/libavcodec/atrac3.c +++ b/libavcodec/atrac3.c @@ -526,7 +526,7 @@ static void reverse_matrixing(float *su1, float *su2, int *prev_code, } break; default: - av_assert1(0); + av_unreachable("curr_code/matrix_coeff_index_* values are stored in two bits"); } } } @@ -1027,13 +1027,8 @@ const FFCodec ff_atrac3_decoder = { .init = atrac3_decode_init, .close = atrac3_decode_close, FF_CODEC_DECODE_CB(atrac3_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -1046,12 +1041,7 @@ const FFCodec ff_atrac3al_decoder = { .init = atrac3_decode_init, .close = atrac3_decode_close, FF_CODEC_DECODE_CB(atrac3al_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/atrac3plusdsp.c b/libavcodec/atrac3plusdsp.c index 802f12aec5..6942cba506 100644 --- a/libavcodec/atrac3plusdsp.c +++ b/libavcodec/atrac3plusdsp.c @@ -114,7 +114,7 @@ av_cold void ff_atrac3p_init_dsp_static(void) * @param[in] fdsp ptr to floating-point DSP context * @param[in] invert_phase flag indicating 180° phase shift * @param[in] reg_offset region offset for trimming envelope data - * @param[out] out receives sythesized data + * @param[out] out receives synthesized data */ static void waves_synth(Atrac3pWaveSynthParams *synth_param, Atrac3pWavesData *waves_info, diff --git a/libavcodec/atrac9dec.c b/libavcodec/atrac9dec.c index e375f46fd0..9114d645d0 100644 --- a/libavcodec/atrac9dec.c +++ b/libavcodec/atrac9dec.c @@ -80,7 +80,7 @@ typedef struct ATRAC9BlockData { int cpe_base_channel; int is_signs[30]; - int reuseable; + int reusable; } ATRAC9BlockData; @@ -689,7 +689,7 @@ static int atrac9_decode_block(ATRAC9Context *s, GetBitContext *gb, if (!reuse_params) { int stereo_band, ext_band; const int min_band_count = s->samplerate_idx > 7 ? 1 : 3; - b->reuseable = 0; + b->reusable = 0; b->band_count = get_bits(gb, 4) + min_band_count; b->q_unit_cnt = at9_tab_band_q_unit_map[b->band_count]; @@ -721,9 +721,9 @@ static int atrac9_decode_block(ATRAC9Context *s, GetBitContext *gb, } b->band_ext_q_unit = at9_tab_band_q_unit_map[ext_band]; } - b->reuseable = 1; + b->reusable = 1; } - if (!b->reuseable) { + if (!b->reusable) { av_log(s->avctx, AV_LOG_ERROR, "invalid block reused!\n"); return AVERROR_INVALIDDATA; } @@ -1006,9 +1006,5 @@ const FFCodec ff_atrac9_decoder = { FF_CODEC_DECODE_CB(atrac9_decode_frame), .flush = atrac9_decode_flush, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, }; diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c index 0f7ce8e4eb..08203c5310 100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@ -542,6 +542,8 @@ static int ffat_decode(AVCodecContext *avctx, AVFrame *frame, frame->nb_samples = avctx->frame_size; + frame->flags |= AV_FRAME_FLAG_KEY; + out_buffers.mBuffers[0].mData = at->decoded_data; ret = AudioConverterFillComplexBuffer(at->converter, ffat_decode_callback, avctx, diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index ad2b863bb9..d999e5e8a2 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -576,6 +576,7 @@ static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt, avctx->frame_size, &avpkt->pts, &avpkt->duration); + avpkt->flags |= AV_PKT_FLAG_KEY; } else if (ret && ret != 1) { av_log(avctx, AV_LOG_ERROR, "Encode error: %i\n", ret); return AVERROR_EXTERNAL; @@ -649,13 +650,10 @@ static const AVOption options[] = { .p.priv_class = &ffat_##NAME##_enc_class, \ .p.capabilities = AV_CODEC_CAP_DELAY | \ AV_CODEC_CAP_ENCODER_FLUSH CAPS, \ - .p.ch_layouts = CH_LAYOUTS, \ - .p.sample_fmts = (const enum AVSampleFormat[]) { \ - AV_SAMPLE_FMT_S16, \ - AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NONE \ - }, \ .p.profiles = PROFILES, \ .p.wrapper_name = "at", \ + CODEC_CH_LAYOUTS_ARRAY(CH_LAYOUTS), \ + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), \ }; static const AVChannelLayout aac_at_ch_layouts[] = { diff --git a/libavcodec/av1_parser.c b/libavcodec/av1_parser.c index 2b79493bf8..1792e813f4 100644 --- a/libavcodec/av1_parser.c +++ b/libavcodec/av1_parser.c @@ -82,7 +82,7 @@ static int av1_parser_parse(AVCodecParserContext *ctx, ff_cbs_fragment_reset(td); } - ret = ff_cbs_read(s->cbc, td, data, size); + ret = ff_cbs_read(s->cbc, td, NULL, data, size); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to parse temporal unit.\n"); goto end; diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index 1d5b9ef4f4..be595484d1 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -39,9 +39,9 @@ #include "hwconfig.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -/**< same with Div_Lut defined in spec 7.11.3.7 */ +/** same with Div_Lut defined in spec 7.11.3.7 */ static const uint16_t div_lut[AV1_DIV_LUT_NUM] = { 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768, 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142, @@ -281,6 +281,8 @@ static void skip_mode_params(AV1DecContext *s) forward_idx = -1; backward_idx = -1; for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + if (!s->ref[header->ref_frame_idx[i]].raw_frame_header) + return; ref_hint = s->ref[header->ref_frame_idx[i]].raw_frame_header->order_hint; dist = get_relative_dist(seq, ref_hint, header->order_hint); if (dist < 0) { @@ -541,6 +543,7 @@ static int get_pixel_format(AVCodecContext *avctx) CONFIG_AV1_NVDEC_HWACCEL + \ CONFIG_AV1_VAAPI_HWACCEL + \ CONFIG_AV1_VDPAU_HWACCEL + \ + CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + \ CONFIG_AV1_VULKAN_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; @@ -568,6 +571,9 @@ static int get_pixel_format(AVCodecContext *avctx) #if CONFIG_AV1_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif #if CONFIG_AV1_VULKAN_HWACCEL *fmtp++ = AV_PIX_FMT_VULKAN; #endif @@ -592,6 +598,9 @@ static int get_pixel_format(AVCodecContext *avctx) #if CONFIG_AV1_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif #if CONFIG_AV1_VULKAN_HWACCEL *fmtp++ = AV_PIX_FMT_VULKAN; #endif @@ -678,8 +687,8 @@ static int get_pixel_format(AVCodecContext *avctx) static void av1_frame_unref(AV1Frame *f) { ff_progress_frame_unref(&f->pf); - ff_refstruct_unref(&f->hwaccel_picture_private); - ff_refstruct_unref(&f->header_ref); + av_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->header_ref); f->raw_frame_header = NULL; f->spatial_id = f->temporal_id = 0; memset(f->skip_mode_frame_idx, 0, @@ -692,13 +701,13 @@ static void av1_frame_replace(AV1Frame *dst, const AV1Frame *src) { av_assert1(dst != src); - ff_refstruct_replace(&dst->header_ref, src->header_ref); + av_refstruct_replace(&dst->header_ref, src->header_ref); dst->raw_frame_header = src->raw_frame_header; ff_progress_frame_replace(&dst->pf, &src->pf); - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); dst->spatial_id = src->spatial_id; @@ -738,10 +747,10 @@ static av_cold int av1_decode_free(AVCodecContext *avctx) av1_frame_unref(&s->ref[i]); av1_frame_unref(&s->cur_frame); av_buffer_unref(&s->seq_data_ref); - ff_refstruct_unref(&s->seq_ref); - ff_refstruct_unref(&s->header_ref); - ff_refstruct_unref(&s->cll_ref); - ff_refstruct_unref(&s->mdcv_ref); + av_refstruct_unref(&s->seq_ref); + av_refstruct_unref(&s->header_ref); + av_refstruct_unref(&s->cll_ref); + av_refstruct_unref(&s->mdcv_ref); av_freep(&s->tile_group_info); while (s->itut_t35_fifo && av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0) @@ -779,10 +788,14 @@ static int set_context_with_sequence(AVCodecContext *avctx, break; } +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (seq->film_grain_params_present) avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; else avctx->properties &= ~FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (avctx->width != width || avctx->height != height) { int ret = ff_set_dimensions(avctx, width, height); @@ -952,13 +965,13 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, { GetByteContext gb; AV1DecContext *s = avctx->priv_data; - int ret, provider_code; + int ret, provider_code, country_code; bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); provider_code = bytestream2_get_be16(&gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { + country_code = itut_t35->itu_t_t35_country_code ; + if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_ATSC) { uint32_t user_identifier = bytestream2_get_be32(&gb); switch (user_identifier) { case MKBETAG('G', 'A', '9', '4'): { // closed captions @@ -974,22 +987,23 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif break; } default: // ignore unsupported identifiers break; } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG) { AVDynamicHDRPlus *hdrplus; int provider_oriented_code = bytestream2_get_be16(&gb); int application_identifier = bytestream2_get_byte(&gb); - if (itut_t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 1 || application_identifier != 4) - break; + if (provider_oriented_code != 1 || application_identifier != 4) + return 0; // ignore hdrplus = av_dynamic_hdr_plus_create_side_data(frame); if (!hdrplus) @@ -999,28 +1013,23 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, bytestream2_get_bytes_left(&gb)); if (ret < 0) return ret; - break; - } - case ITU_T_T35_PROVIDER_CODE_DOLBY: { + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_DOLBY) { int provider_oriented_code = bytestream2_get_be32(&gb); - if (itut_t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 0x800) - break; + if (provider_oriented_code != 0x800) + return 0; // ignore ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, gb.buffer_end - gb.buffer, avctx->err_recognition); if (ret < 0) { av_log(avctx, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); - break; // ignore + return 0; // ignore } ret = ff_dovi_attach_side_data(&s->dovi, frame); if (ret < 0) return ret; - break; - } - default: // ignore unsupported provider codes - break; + } else { + // ignore unsupported provider codes } return 0; @@ -1179,12 +1188,6 @@ static int set_output_frame(AVCodecContext *avctx, AVFrame *frame) frame->pts = pkt->pts; frame->pkt_dts = pkt->dts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_size = pkt->size; - frame->pkt_pos = pkt->pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif av_packet_unref(pkt); @@ -1209,7 +1212,7 @@ static int get_current_frame(AVCodecContext *avctx) av1_frame_unref(&s->cur_frame); - s->cur_frame.header_ref = ff_refstruct_ref(s->header_ref); + s->cur_frame.header_ref = av_refstruct_ref(s->header_ref); s->cur_frame.raw_frame_header = s->raw_frame_header; @@ -1297,7 +1300,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->seq_data_ref->data = unit->data; s->seq_data_ref->size = unit->data_size; - ff_refstruct_replace(&s->seq_ref, unit->content_ref); + av_refstruct_replace(&s->seq_ref, unit->content_ref); s->raw_seq = &obu->obu.sequence_header; @@ -1312,6 +1315,15 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->pix_fmt = AV_PIX_FMT_NONE; + if (FF_HW_HAS_CB(avctx, decode_params)) { + ret = FF_HW_CALL(avctx, decode_params, AV1_OBU_SEQUENCE_HEADER, + s->seq_data_ref->data, s->seq_data_ref->size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "HW accel decode params fail.\n"); + return ret; + } + } + break; case AV1_OBU_REDUNDANT_FRAME_HEADER: if (s->raw_frame_header) @@ -1325,7 +1337,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) goto end; } - ff_refstruct_replace(&s->header_ref, unit->content_ref); + av_refstruct_replace(&s->header_ref, unit->content_ref); if (unit->type == AV1_OBU_FRAME) s->raw_frame_header = &obu->obu.frame.header; @@ -1363,7 +1375,8 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->cur_frame.temporal_id = header->temporal_id; if (avctx->hwaccel && s->cur_frame.f) { - ret = FF_HW_CALL(avctx, start_frame, unit->data, unit->data_size); + ret = FF_HW_CALL(avctx, start_frame, s->pkt->buf, + unit->data, unit->data_size); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "HW accel start frame fail.\n"); goto end; @@ -1405,11 +1418,11 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) case AV1_OBU_METADATA: switch (obu->obu.metadata.metadata_type) { case AV1_METADATA_TYPE_HDR_CLL: - ff_refstruct_replace(&s->cll_ref, unit->content_ref); + av_refstruct_replace(&s->cll_ref, unit->content_ref); s->cll = &obu->obu.metadata.metadata.hdr_cll; break; case AV1_METADATA_TYPE_HDR_MDCV: - ff_refstruct_replace(&s->mdcv_ref, unit->content_ref); + av_refstruct_replace(&s->mdcv_ref, unit->content_ref); s->mdcv = &obu->obu.metadata.metadata.hdr_mdcv; break; case AV1_METADATA_TYPE_ITUT_T35: { @@ -1439,6 +1452,10 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (raw_tile_group && (s->tile_num == raw_tile_group->tg_end + 1)) { int show_frame = s->raw_frame_header->show_frame; + // Set nb_unit to point at the next OBU, to indicate which + // OBUs have been processed for this current frame. (If this + // frame gets output, we set nb_unit to this value later too.) + s->nb_unit = i + 1; if (avctx->hwaccel && s->cur_frame.f) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); if (ret < 0) { @@ -1449,6 +1466,8 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) update_reference_list(avctx); + // Set start_unit to indicate the first OBU of the next frame. + s->start_unit = s->nb_unit; raw_tile_group = NULL; s->raw_frame_header = NULL; @@ -1478,7 +1497,7 @@ end: s->raw_frame_header = NULL; av_packet_unref(s->pkt); ff_cbs_fragment_reset(&s->current_obu); - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; } if (!ret && !frame->buf[0]) ret = AVERROR(EAGAIN); @@ -1505,7 +1524,7 @@ static int av1_receive_frame(AVCodecContext *avctx, AVFrame *frame) return ret; } - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; av_log(avctx, AV_LOG_DEBUG, "Total OBUs on this packet: %d.\n", s->current_obu.nb_units); } @@ -1526,7 +1545,7 @@ static void av1_decode_flush(AVCodecContext *avctx) av1_frame_unref(&s->cur_frame); s->operating_point_idc = 0; - s->nb_unit = 0; + s->nb_unit = s->start_unit = 0; s->raw_frame_header = NULL; s->raw_seq = NULL; s->cll = NULL; @@ -1594,6 +1613,9 @@ const FFCodec ff_av1_decoder = { #if CONFIG_AV1_VDPAU_HWACCEL HWACCEL_VDPAU(av1), #endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(av1), +#endif #if CONFIG_AV1_VULKAN_HWACCEL HWACCEL_VULKAN(av1), #endif diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h index 8b2a7b0896..10c807f73f 100644 --- a/libavcodec/av1dec.h +++ b/libavcodec/av1dec.h @@ -114,7 +114,8 @@ typedef struct AV1DecContext { AV1Frame ref[AV1_NUM_REF_FRAMES]; AV1Frame cur_frame; - int nb_unit; + int nb_unit; ///< The index of the next OBU to be processed. + int start_unit; ///< The index of the first OBU of the current frame. // AVOptions int operating_point; diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index d1daf47611..834b7ad242 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -45,7 +45,7 @@ #include "frame_thread_encoder.h" #include "hwconfig.h" #include "internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" /** @@ -65,6 +65,7 @@ const SideDataMap ff_sd_global_map[] = { { AV_PKT_DATA_CONTENT_LIGHT_LEVEL, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, { AV_PKT_DATA_ICC_PROFILE, AV_FRAME_DATA_ICC_PROFILE }, { AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT,AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT }, + { AV_PKT_DATA_3D_REFERENCE_DISPLAYS, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS }, { AV_PKT_DATA_NB }, }; @@ -145,6 +146,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code int ret = 0; AVCodecInternal *avci; const FFCodec *codec2; + const AVDictionaryEntry *e; if (avcodec_is_open(avctx)) return 0; @@ -175,15 +177,21 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE) return AVERROR(EINVAL); - if ((ret = av_opt_set_dict(avctx, options)) < 0) - return ret; + // set the whitelist from provided options dict, + // so we can check it immediately + e = options ? av_dict_get(*options, "codec_whitelist", NULL, 0) : NULL; + if (e) { + ret = av_opt_set(avctx, e->key, e->value, 0); + if (ret < 0) + return ret; + } if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) { av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist \'%s\'\n", codec->name, avctx->codec_whitelist); return AVERROR(EINVAL); } - avci = av_codec_is_decoder(codec) ? + avci = ff_codec_is_decoder(codec) ? ff_decode_internal_alloc() : ff_encode_internal_alloc(); if (!avci) { @@ -211,12 +219,14 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code av_opt_set_defaults(avctx->priv_data); } } - if (codec->priv_class && (ret = av_opt_set_dict(avctx->priv_data, options)) < 0) - goto free_and_end; } else { avctx->priv_data = NULL; } + ret = av_opt_set_dict2(avctx, options, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto free_and_end; + // only call ff_set_dimensions() for non H.264/VP6F/DXV codecs so as not to overwrite previously setup dimensions if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height && (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_VP6F || avctx->codec_id == AV_CODEC_ID_DXV))) { @@ -245,7 +255,11 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code } } - if (avctx->sample_rate < 0) { + /* AV_CODEC_CAP_CHANNEL_CONF is a decoder-only flag; so the code below + * in particular checks that sample_rate is set for all audio encoders. */ + if (avctx->sample_rate < 0 || + avctx->sample_rate == 0 && avctx->codec_type == AVMEDIA_TYPE_AUDIO && + !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)) { av_log(avctx, AV_LOG_ERROR, "Invalid sample rate: %d\n", avctx->sample_rate); ret = AVERROR(EINVAL); goto free_and_end; @@ -261,7 +275,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && !avctx->ch_layout.nb_channels && !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)) { av_log(avctx, AV_LOG_ERROR, "%s requires channel layout to be set\n", - av_codec_is_decoder(codec) ? "Decoder" : "Encoder"); + ff_codec_is_decoder(codec) ? "Decoder" : "Encoder"); ret = AVERROR(EINVAL); goto free_and_end; } @@ -281,13 +295,13 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if ((avctx->codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder"; + const char *codec_string = ff_codec_is_encoder(codec) ? "encoder" : "decoder"; const AVCodec *codec2; av_log(avctx, AV_LOG_ERROR, "The %s '%s' is experimental but experimental codecs are not enabled, " "add '-strict %d' if you want to use it.\n", codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL); - codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id); + codec2 = ff_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id); if (!(codec2->capabilities & AV_CODEC_CAP_EXPERIMENTAL)) av_log(avctx, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n", codec_string, codec2->name); @@ -301,7 +315,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code avctx->time_base.den = avctx->sample_rate; } - if (av_codec_is_encoder(avctx->codec)) + if (ff_codec_is_encoder(avctx->codec)) ret = ff_encode_preinit(avctx); else ret = ff_decode_preinit(avctx); @@ -336,7 +350,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code ret=0; - if (av_codec_is_decoder(avctx->codec)) { + if (ff_codec_is_decoder(avctx->codec)) { if (!avctx->bit_rate) avctx->bit_rate = get_bit_rate(avctx); @@ -420,9 +434,6 @@ av_cold void ff_codec_close(AVCodecContext *avctx) { int i; - if (!avctx) - return; - if (avcodec_is_open(avctx)) { AVCodecInternal *avci = avctx->internal; @@ -444,8 +455,8 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_frame_free(&avci->in_frame); av_frame_free(&avci->recon_frame); - ff_refstruct_unref(&avci->pool); - ff_refstruct_pool_uninit(&avci->progress_frame_pool); + av_refstruct_unref(&avci->pool); + av_refstruct_pool_uninit(&avci->progress_frame_pool); if (av_codec_is_decoder(avctx->codec)) ff_decode_internal_uninit(avctx); @@ -453,10 +464,6 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_bsf_free(&avci->bsf); -#if FF_API_DROPCHANGED - av_channel_layout_uninit(&avci->initial_ch_layout); -#endif - #if CONFIG_LCMS2 ff_icc_context_uninit(&avci->icc); #endif @@ -488,14 +495,6 @@ av_cold void ff_codec_close(AVCodecContext *avctx) avctx->active_thread_type = 0; } -#if FF_API_AVCODEC_CLOSE -int avcodec_close(AVCodecContext *avctx) -{ - ff_codec_close(avctx); - return 0; -} -#endif - static const char *unknown_if_null(const char *str) { return str ? str : "unknown"; @@ -638,12 +637,16 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) if (encode) { av_bprintf(&bprint, ", q=%d-%d", enc->qmin, enc->qmax); } else { +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (enc->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS) av_bprintf(&bprint, ", Closed Captions"); if (enc->properties & FF_CODEC_PROPERTY_FILM_GRAIN) av_bprintf(&bprint, ", Film Grain"); if (enc->properties & FF_CODEC_PROPERTY_LOSSLESS) av_bprintf(&bprint, ", lossless"); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } break; case AVMEDIA_TYPE_AUDIO: @@ -705,7 +708,10 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr { av_frame_unref(frame); - if (av_codec_is_decoder(avctx->codec)) + if (!avcodec_is_open(avctx) || !avctx->codec) + return AVERROR(EINVAL); + + if (ff_codec_is_decoder(avctx->codec)) return ff_decode_receive_frame(avctx, frame); return ff_encode_receive_frame(avctx, frame); } diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 77ca8dee1f..108df5a24e 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -187,17 +187,6 @@ struct AVCodecParameters; * @{ */ -#if FF_API_BUFFER_MIN_SIZE -/** - * @ingroup lavc_encoding - * minimum encoding buffer size - * Used to avoid some checks during header writing. - * @deprecated Unused: avcodec_receive_packet() does not work - * with preallocated packet buffers. - */ -#define AV_INPUT_BUFFER_MIN_SIZE 16384 -#endif - /** * @ingroup lavc_encoding */ @@ -234,18 +223,9 @@ typedef struct RcOverride{ * Use qpel MC. */ #define AV_CODEC_FLAG_QPEL (1 << 4) -#if FF_API_DROPCHANGED -/** - * Don't output frames whose parameters differ from first - * decoded frame in stream. - * - * @deprecated callers should implement this functionality in their own code - */ -#define AV_CODEC_FLAG_DROPCHANGED (1 << 5) -#endif /** * Request the encoder to output reconstructed frames, i.e.\ frames that would - * be produced by decoding the encoded bistream. These frames may be retrieved + * be produced by decoding the encoded bitstream. These frames may be retrieved * by calling avcodec_receive_frame() immediately after a successful call to * avcodec_receive_packet(). * @@ -515,16 +495,21 @@ typedef struct AVCodecContext { int flags2; /** - * some codecs need / can use extradata like Huffman tables. - * MJPEG: Huffman tables - * rv10: additional flags - * MPEG-4: global headers (they can be in the bitstream or here) - * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger - * than extradata_size to avoid problems if it is read with the bitstream reader. - * The bytewise contents of extradata must not depend on the architecture or CPU endianness. - * Must be allocated with the av_malloc() family of functions. - * - encoding: Set/allocated/freed by libavcodec. - * - decoding: Set/allocated/freed by user. + * Out-of-band global headers that may be used by some codecs. + * + * - decoding: Should be set by the caller when available (typically from a + * demuxer) before opening the decoder; some decoders require this to be + * set and will fail to initialize otherwise. + * + * The array must be allocated with the av_malloc() family of functions; + * allocated size must be at least AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than extradata_size. + * + * - encoding: May be set by the encoder in avcodec_open2() (possibly + * depending on whether the AV_CODEC_FLAG_GLOBAL_HEADER flag is set). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). */ uint8_t *extradata; int extradata_size; @@ -565,23 +550,6 @@ typedef struct AVCodecContext { */ AVRational framerate; -#if FF_API_TICKS_PER_FRAME - /** - * For some codecs, the time base is closer to the field rate than the frame rate. - * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration - * if no telecine is used ... - * - * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. - * - * @deprecated - * - decoding: Use AVCodecDescriptor.props & AV_CODEC_PROP_FIELDS - * - encoding: Set AVCodecContext.framerate instead - * - */ - attribute_deprecated - int ticks_per_frame; -#endif - /** * Codec delay. * @@ -1648,165 +1616,29 @@ typedef struct AVCodecContext { * See the AV_PROFILE_* defines in defs.h. */ int profile; -#if FF_API_FF_PROFILE_LEVEL - /** @deprecated The following defines are deprecated; use AV_PROFILE_* - * in defs.h instead. */ -#define FF_PROFILE_UNKNOWN -99 -#define FF_PROFILE_RESERVED -100 - -#define FF_PROFILE_AAC_MAIN 0 -#define FF_PROFILE_AAC_LOW 1 -#define FF_PROFILE_AAC_SSR 2 -#define FF_PROFILE_AAC_LTP 3 -#define FF_PROFILE_AAC_HE 4 -#define FF_PROFILE_AAC_HE_V2 28 -#define FF_PROFILE_AAC_LD 22 -#define FF_PROFILE_AAC_ELD 38 -#define FF_PROFILE_MPEG2_AAC_LOW 128 -#define FF_PROFILE_MPEG2_AAC_HE 131 - -#define FF_PROFILE_DNXHD 0 -#define FF_PROFILE_DNXHR_LB 1 -#define FF_PROFILE_DNXHR_SQ 2 -#define FF_PROFILE_DNXHR_HQ 3 -#define FF_PROFILE_DNXHR_HQX 4 -#define FF_PROFILE_DNXHR_444 5 - -#define FF_PROFILE_DTS 20 -#define FF_PROFILE_DTS_ES 30 -#define FF_PROFILE_DTS_96_24 40 -#define FF_PROFILE_DTS_HD_HRA 50 -#define FF_PROFILE_DTS_HD_MA 60 -#define FF_PROFILE_DTS_EXPRESS 70 -#define FF_PROFILE_DTS_HD_MA_X 61 -#define FF_PROFILE_DTS_HD_MA_X_IMAX 62 - - -#define FF_PROFILE_EAC3_DDP_ATMOS 30 - -#define FF_PROFILE_TRUEHD_ATMOS 30 - -#define FF_PROFILE_MPEG2_422 0 -#define FF_PROFILE_MPEG2_HIGH 1 -#define FF_PROFILE_MPEG2_SS 2 -#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 -#define FF_PROFILE_MPEG2_MAIN 4 -#define FF_PROFILE_MPEG2_SIMPLE 5 - -#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag -#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag - -#define FF_PROFILE_H264_BASELINE 66 -#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) -#define FF_PROFILE_H264_MAIN 77 -#define FF_PROFILE_H264_EXTENDED 88 -#define FF_PROFILE_H264_HIGH 100 -#define FF_PROFILE_H264_HIGH_10 110 -#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) -#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 -#define FF_PROFILE_H264_HIGH_422 122 -#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) -#define FF_PROFILE_H264_STEREO_HIGH 128 -#define FF_PROFILE_H264_HIGH_444 144 -#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 -#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) -#define FF_PROFILE_H264_CAVLC_444 44 - -#define FF_PROFILE_VC1_SIMPLE 0 -#define FF_PROFILE_VC1_MAIN 1 -#define FF_PROFILE_VC1_COMPLEX 2 -#define FF_PROFILE_VC1_ADVANCED 3 - -#define FF_PROFILE_MPEG4_SIMPLE 0 -#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 -#define FF_PROFILE_MPEG4_CORE 2 -#define FF_PROFILE_MPEG4_MAIN 3 -#define FF_PROFILE_MPEG4_N_BIT 4 -#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 -#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 -#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 -#define FF_PROFILE_MPEG4_HYBRID 8 -#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 -#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 -#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 -#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 -#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 -#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 -#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 - -#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 -#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 -#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 -#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 -#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 - -#define FF_PROFILE_VP9_0 0 -#define FF_PROFILE_VP9_1 1 -#define FF_PROFILE_VP9_2 2 -#define FF_PROFILE_VP9_3 3 - -#define FF_PROFILE_HEVC_MAIN 1 -#define FF_PROFILE_HEVC_MAIN_10 2 -#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 -#define FF_PROFILE_HEVC_REXT 4 -#define FF_PROFILE_HEVC_SCC 9 - -#define FF_PROFILE_VVC_MAIN_10 1 -#define FF_PROFILE_VVC_MAIN_10_444 33 - -#define FF_PROFILE_AV1_MAIN 0 -#define FF_PROFILE_AV1_HIGH 1 -#define FF_PROFILE_AV1_PROFESSIONAL 2 - -#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 -#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 -#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 -#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 -#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 - -#define FF_PROFILE_SBC_MSBC 1 - -#define FF_PROFILE_PRORES_PROXY 0 -#define FF_PROFILE_PRORES_LT 1 -#define FF_PROFILE_PRORES_STANDARD 2 -#define FF_PROFILE_PRORES_HQ 3 -#define FF_PROFILE_PRORES_4444 4 -#define FF_PROFILE_PRORES_XQ 5 - -#define FF_PROFILE_ARIB_PROFILE_A 0 -#define FF_PROFILE_ARIB_PROFILE_C 1 - -#define FF_PROFILE_KLVA_SYNC 0 -#define FF_PROFILE_KLVA_ASYNC 1 - -#define FF_PROFILE_EVC_BASELINE 0 -#define FF_PROFILE_EVC_MAIN 1 -#endif /** * Encoding level descriptor. * - encoding: Set by user, corresponds to a specific level defined by the * codec, usually corresponding to the profile level, if not specified it - * is set to FF_LEVEL_UNKNOWN. + * is set to AV_LEVEL_UNKNOWN. * - decoding: Set by libavcodec. * See AV_LEVEL_* in defs.h. */ int level; -#if FF_API_FF_PROFILE_LEVEL - /** @deprecated The following define is deprecated; use AV_LEVEL_UNKOWN - * in defs.h instead. */ -#define FF_LEVEL_UNKNOWN -99 -#endif +#if FF_API_CODEC_PROPS /** * Properties of the stream that gets decoded * - encoding: unused * - decoding: set by libavcodec */ + attribute_deprecated unsigned properties; #define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 #define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 #define FF_CODEC_PROPERTY_FILM_GRAIN 0x00000004 +#endif /** * Skip loop filtering for selected frames. @@ -1895,8 +1727,13 @@ typedef struct AVCodecContext { * For SUBTITLE_ASS subtitle type, it should contain the whole ASS * [Script Info] and [V4+ Styles] section, plus the [Events] line and * the Format line following. It shouldn't include any Dialogue line. - * - encoding: Set/allocated/freed by user (before avcodec_open2()) - * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) + * + * - encoding: May be set by the caller before avcodec_open2() to an array + * allocated with the av_malloc() family of functions. + * - decoding: May be set by libavcodec in avcodec_open2(). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). */ int subtitle_header_size; uint8_t *subtitle_header; @@ -2380,24 +2217,6 @@ int avcodec_parameters_to_context(AVCodecContext *codec, */ int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); -#if FF_API_AVCODEC_CLOSE -/** - * Close a given AVCodecContext and free all the data associated with it - * (but not the AVCodecContext itself). - * - * Calling this function on an AVCodecContext that hasn't been opened will free - * the codec-specific data allocated in avcodec_alloc_context3() with a non-NULL - * codec. Subsequent calls will do nothing. - * - * @deprecated Do not use this function. Use avcodec_free_context() to destroy a - * codec context (either open or closed). Opening and closing a codec context - * multiple times is not supported anymore -- use multiple codec contexts - * instead. - */ -attribute_deprecated -int avcodec_close(AVCodecContext *avctx); -#endif - /** * Free all allocated data in the given subtitle struct. * @@ -3081,7 +2900,7 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, * * @note for encoders, this function will only do something if the encoder * declares support for AV_CODEC_CAP_ENCODER_FLUSH. When called, the encoder - * will drain any remaining packets, and can then be re-used for a different + * will drain any remaining packets, and can then be reused for a different * stream (as opposed to sending a null frame which will leave the encoder * in a permanent EOF state after draining). This can be desirable if the * cost of tearing down and replacing the encoder instance is high. @@ -3116,8 +2935,8 @@ void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); /** - * @return a positive value if s is open (i.e. avcodec_open2() was called on it - * with no corresponding avcodec_close()), 0 otherwise. + * @return a positive value if s is open (i.e. avcodec_open2() was called on it), + * 0 otherwise. */ int avcodec_is_open(AVCodecContext *s); diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c index f995e73eab..5322b181bc 100644 --- a/libavcodec/avdct.c +++ b/libavcodec/avdct.c @@ -119,7 +119,7 @@ int avcodec_dct_init(AVDCT *dsp) #if CONFIG_PIXBLOCKDSP { PixblockDSPContext pdsp; - ff_pixblockdsp_init(&pdsp, avctx); + ff_pixblockdsp_init(&pdsp, dsp->bits_per_sample); COPY(pdsp, get_pixels); COPY(pdsp, get_pixels_unaligned); } diff --git a/libavcodec/avfft.c b/libavcodec/avfft.c deleted file mode 100644 index f6787937f6..0000000000 --- a/libavcodec/avfft.c +++ /dev/null @@ -1,268 +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 - -#include "libavutil/attributes.h" -#include "libavutil/macros.h" -#include "libavutil/mem.h" -#include "libavutil/tx.h" -#include "avfft.h" - -typedef struct AVTXWrapper { - AVTXContext *ctx; - av_tx_fn fn; - - AVTXContext *ctx2; - av_tx_fn fn2; - - ptrdiff_t stride; - int len; - int inv; - - float *tmp; - int out_of_place; -} AVTXWrapper; - -/* FFT */ - -FFTContext *av_fft_init(int nbits, int inverse) -{ - int ret; - float scale = 1.0f; - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_FFT, inverse, 1 << nbits, - &scale, AV_TX_INPLACE); - if (ret < 0) { - av_free(s); - return NULL; - } - - return (FFTContext *)s; -} - -void av_fft_permute(FFTContext *s, FFTComplex *z) -{ - /* Empty */ -} - -void av_fft_calc(FFTContext *s, FFTComplex *z) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, z, (void *)z, sizeof(AVComplexFloat)); -} - -av_cold void av_fft_end(FFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_tx_uninit(&w->ctx2); - av_free(w); - } -} - -FFTContext *av_mdct_init(int nbits, int inverse, double scale) -{ - int ret; - float scale_f = scale; - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_MDCT, inverse, 1 << (nbits - 1), &scale_f, 0); - if (ret < 0) { - av_free(s); - return NULL; - } - - if (inverse) { - ret = av_tx_init(&s->ctx2, &s->fn2, AV_TX_FLOAT_MDCT, inverse, 1 << (nbits - 1), - &scale_f, AV_TX_FULL_IMDCT); - if (ret < 0) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - } - - return (FFTContext *)s; -} - -void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn2(w->ctx2, output, (void *)input, sizeof(float)); -} - -void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, output, (void *)input, sizeof(float)); -} - -void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - w->fn(w->ctx, output, (void *)input, sizeof(float)); -} - -av_cold void av_mdct_end(FFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx2); - av_tx_uninit(&w->ctx); - av_free(w); - } -} - -RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans) -{ - int ret; - float scale = trans == IDFT_C2R ? 0.5f : 1.0f; - AVTXWrapper *s; - - /* The other 2 modes are unconventional, do not form an orthogonal - * transform, have never been useful, and so they're not implemented. */ - if (trans != IDFT_C2R && trans != DFT_R2C) - return NULL; - - s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - ret = av_tx_init(&s->ctx, &s->fn, AV_TX_FLOAT_RDFT, trans == IDFT_C2R, - 1 << nbits, &scale, 0x0); - if (ret < 0) { - av_free(s); - return NULL; - } - - s->stride = (trans == DFT_C2R) ? sizeof(AVComplexFloat) : sizeof(float); - s->len = 1 << nbits; - s->inv = trans == IDFT_C2R; - - s->tmp = av_malloc((s->len + 2)*sizeof(float)); - if (!s->tmp) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - - return (RDFTContext *)s; -} - -void av_rdft_calc(RDFTContext *s, FFTSample *data) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - float *src = w->inv ? w->tmp : (float *)data; - float *dst = w->inv ? (float *)data : w->tmp; - - if (w->inv) { - memcpy(src, data, w->len*sizeof(float)); - - src[w->len] = src[1]; - src[1] = 0.0f; - } - - w->fn(w->ctx, dst, (void *)src, w->stride); - - if (!w->inv) { - dst[1] = dst[w->len]; - memcpy(data, dst, w->len*sizeof(float)); - } -} - -av_cold void av_rdft_end(RDFTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_free(w->tmp); - av_free(w); - } -} - -DCTContext *av_dct_init(int nbits, enum DCTTransformType inverse) -{ - int ret; - const float scale_map[] = { - [DCT_II] = 0.5f, - [DCT_III] = 1.0f / (1 << nbits), - [DCT_I] = 0.5f, - [DST_I] = 2.0f, - }; - static const enum AVTXType type_map[] = { - [DCT_II] = AV_TX_FLOAT_DCT, - [DCT_III] = AV_TX_FLOAT_DCT, - [DCT_I] = AV_TX_FLOAT_DCT_I, - [DST_I] = AV_TX_FLOAT_DST_I, - }; - - AVTXWrapper *s = av_mallocz(sizeof(*s)); - if (!s) - return NULL; - - s->len = (1 << nbits); - s->out_of_place = (inverse == DCT_I) || (inverse == DST_I); - - ret = av_tx_init(&s->ctx, &s->fn, type_map[inverse], - (inverse == DCT_III), 1 << (nbits - (inverse == DCT_III)), - &scale_map[inverse], s->out_of_place ? 0 : AV_TX_INPLACE); - if (ret < 0) { - av_free(s); - return NULL; - } - - if (s->out_of_place) { - s->tmp = av_malloc((1 << (nbits + 1))*sizeof(float)); - if (!s->tmp) { - av_tx_uninit(&s->ctx); - av_free(s); - return NULL; - } - } - - return (DCTContext *)s; -} - -void av_dct_calc(DCTContext *s, FFTSample *data) -{ - AVTXWrapper *w = (AVTXWrapper *)s; - if (w->out_of_place) { - memcpy(w->tmp, data, w->len*sizeof(float)); - w->fn(w->ctx, (void *)data, w->tmp, sizeof(float)); - } else { - w->fn(w->ctx, data, (void *)data, sizeof(float)); - } -} - -av_cold void av_dct_end(DCTContext *s) -{ - if (s) { - AVTXWrapper *w = (AVTXWrapper *)s; - av_tx_uninit(&w->ctx); - av_free(w->tmp); - av_free(w); - } -} diff --git a/libavcodec/avfft.h b/libavcodec/avfft.h deleted file mode 100644 index e3a0da1eb9..0000000000 --- a/libavcodec/avfft.h +++ /dev/null @@ -1,149 +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_AVFFT_H -#define AVCODEC_AVFFT_H - -#include "libavutil/attributes.h" -#include "version_major.h" -#if FF_API_AVFFT - -/** - * @file - * @ingroup lavc_fft - * FFT functions - */ - -/** - * @defgroup lavc_fft FFT functions - * @ingroup lavc_misc - * - * @{ - */ - -typedef float FFTSample; - -typedef struct FFTComplex { - FFTSample re, im; -} FFTComplex; - -typedef struct FFTContext FFTContext; - -/** - * Set up a complex FFT. - * @param nbits log2 of the length of the input array - * @param inverse if 0 perform the forward transform, if 1 perform the inverse - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_FFT - */ -attribute_deprecated -FFTContext *av_fft_init(int nbits, int inverse); - -/** - * Do the permutation needed BEFORE calling ff_fft_calc(). - * @deprecated without replacement - */ -attribute_deprecated -void av_fft_permute(FFTContext *s, FFTComplex *z); - -/** - * Do a complex FFT with the parameters defined in av_fft_init(). The - * input data must be permuted before. No 1.0/sqrt(n) normalization is done. - * @deprecated use the av_tx_fn value returned by av_tx_init, which also does permutation - */ -attribute_deprecated -void av_fft_calc(FFTContext *s, FFTComplex *z); - -attribute_deprecated -void av_fft_end(FFTContext *s); - -/** - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_MDCT, - * with a flag of AV_TX_FULL_IMDCT for a replacement to av_imdct_calc. - */ -attribute_deprecated -FFTContext *av_mdct_init(int nbits, int inverse, double scale); -attribute_deprecated -void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); -attribute_deprecated -void av_mdct_end(FFTContext *s); - -/* Real Discrete Fourier Transform */ - -enum RDFTransformType { - DFT_R2C, - IDFT_C2R, - IDFT_R2C, - DFT_C2R, -}; - -typedef struct RDFTContext RDFTContext; - -/** - * Set up a real FFT. - * @param nbits log2 of the length of the input array - * @param trans the type of transform - * - * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_RDFT - */ -attribute_deprecated -RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); -attribute_deprecated -void av_rdft_calc(RDFTContext *s, FFTSample *data); -attribute_deprecated -void av_rdft_end(RDFTContext *s); - -/* Discrete Cosine Transform */ - -typedef struct DCTContext DCTContext; - -enum DCTTransformType { - DCT_II = 0, - DCT_III, - DCT_I, - DST_I, -}; - -/** - * Set up DCT. - * - * @param nbits size of the input array: - * (1 << nbits) for DCT-II, DCT-III and DST-I - * (1 << nbits) + 1 for DCT-I - * @param type the type of transform - * - * @note the first element of the input of DST-I is ignored - * - * @deprecated use av_tx_init from libavutil/tx.h with an appropriate type of AV_TX_FLOAT_DCT - */ -attribute_deprecated -DCTContext *av_dct_init(int nbits, enum DCTTransformType type); -attribute_deprecated -void av_dct_calc(DCTContext *s, FFTSample *data); -attribute_deprecated -void av_dct_end (DCTContext *s); - -/** - * @} - */ - -#endif /* FF_API_AVFFT */ -#endif /* AVCODEC_AVFFT_H */ diff --git a/libavcodec/avs3_parser.c b/libavcodec/avs3_parser.c index ea495b1c7c..71278c7e2d 100644 --- a/libavcodec/avs3_parser.c +++ b/libavcodec/avs3_parser.c @@ -97,7 +97,7 @@ static void parse_avs3_nal_units(AVCodecParserContext *s, const uint8_t *buf, if (sample_precision == 1) { avctx->pix_fmt = AV_PIX_FMT_YUV420P; } else if (sample_precision == 2) { - avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE; + avctx->pix_fmt = AV_PIX_FMT_YUV420P10; } else { avctx->pix_fmt = AV_PIX_FMT_NONE; } diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c index a2391b31ef..0dea87f104 100644 --- a/libavcodec/avuienc.c +++ b/libavcodec/avuienc.c @@ -99,7 +99,7 @@ const FFCodec ff_avui_encoder = { .p.id = AV_CODEC_ID_AVUI, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_EXPERIMENTAL | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_UYVY422, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_UYVY422), .color_ranges = AVCOL_RANGE_MPEG, .init = avui_encode_init, FF_CODEC_ENCODE_CB(avui_encode_frame), diff --git a/libavcodec/bethsoftvideo.c b/libavcodec/bethsoftvideo.c index 6de502822b..c06eaba32a 100644 --- a/libavcodec/bethsoftvideo.c +++ b/libavcodec/bethsoftvideo.c @@ -63,11 +63,6 @@ static int set_palette(BethsoftvidContext *ctx, GetByteContext *g) palette[a] = 0xFFU << 24 | bytestream2_get_be24u(g) * 4; palette[a] |= palette[a] >> 6 & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - ctx->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif return 0; } diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c index 58158f6eee..1d2d3a7204 100644 --- a/libavcodec/bfi.c +++ b/libavcodec/bfi.c @@ -83,19 +83,9 @@ static int bfi_decode_frame(AVCodecContext *avctx, AVFrame *frame, pal++; } memcpy(bfi->pal, frame->data[1], sizeof(bfi->pal)); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else { frame->pict_type = AV_PICTURE_TYPE_P; frame->flags &= ~AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], bfi->pal, sizeof(bfi->pal)); } diff --git a/libavcodec/bfin/README b/libavcodec/bfin/README deleted file mode 100644 index afb3461b72..0000000000 --- a/libavcodec/bfin/README +++ /dev/null @@ -1,6 +0,0 @@ -BFIN optimizations have been removed in -commit 880e2aa23645ed9871c66ee1cbd00f93c72d2d73 -The last revission with the optimizations is fa4e17c14035ebf43130fb369e1728cdd98d0b72 - -If you want to maintain these (or other) BFIN optimizations in ffmpeg, then please -contact ffmpeg-devel@ffmpeg.org diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c index b20d6ce176..356042c1f0 100644 --- a/libavcodec/bintext.c +++ b/libavcodec/bintext.c @@ -93,10 +93,10 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_WARNING, "font height %i not supported\n", s->font_height); s->font_height = 8; case 8: - s->font = avpriv_cga_font; + s->font = avpriv_cga_font_get(); break; case 16: - s->font = avpriv_vga16_font; + s->font = avpriv_vga16_font_get(); break; } } @@ -157,11 +157,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0) return ret; s->frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(s->frame->data[1], s->palette, 16 * 4); if (avctx->codec_id == AV_CODEC_ID_XBIN) { diff --git a/libavcodec/bit_depth_template.c b/libavcodec/bit_depth_template.c index d44d47ea45..ca5037148a 100644 --- a/libavcodec/bit_depth_template.c +++ b/libavcodec/bit_depth_template.c @@ -30,7 +30,6 @@ # undef pixel4 # undef dctcoef # undef idctin -# undef INIT_CLIP # undef no_rnd_avg_pixel4 # undef rnd_avg_pixel4 # undef AV_RN2P @@ -64,7 +63,6 @@ # define idctin int16_t #endif -# define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg64 # define rnd_avg_pixel4 rnd_avg64 # define AV_RN2P AV_RN32 @@ -84,7 +82,6 @@ # define dctcoef int16_t # define idctin int16_t -# define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg32 # define rnd_avg_pixel4 rnd_avg32 # define AV_RN2P AV_RN16 diff --git a/libavcodec/bitpacked_enc.c b/libavcodec/bitpacked_enc.c index 3c4e11293d..cde3cf83ee 100644 --- a/libavcodec/bitpacked_enc.c +++ b/libavcodec/bitpacked_enc.c @@ -114,6 +114,5 @@ const FFCodec ff_bitpacked_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10), }; diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h index 35b7873b9c..e4d96af710 100644 --- a/libavcodec/bitstream.h +++ b/libavcodec/bitstream.h @@ -82,6 +82,7 @@ # define bits_init8 bits_init8_le # define bits_tell bits_tell_le # define bits_size bits_size_le +# define bits_bytesize bits_bytesize_le # define bits_left bits_left_le # define bits_read_bit bits_read_bit_le # define bits_read_nz bits_read_nz_le @@ -111,6 +112,7 @@ # define bits_init8 bits_init8_be # define bits_tell bits_tell_be # define bits_size bits_size_be +# define bits_bytesize bits_bytesize_be # define bits_left bits_left_be # define bits_read_bit bits_read_bit_be # define bits_read_nz bits_read_nz_be diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index f923411bee..c277bc1a71 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -25,6 +25,7 @@ #include "bsf_internal.h" extern const FFBitStreamFilter ff_aac_adtstoasc_bsf; +extern const FFBitStreamFilter ff_apv_metadata_bsf; extern const FFBitStreamFilter ff_av1_frame_merge_bsf; extern const FFBitStreamFilter ff_av1_frame_split_bsf; extern const FFBitStreamFilter ff_av1_metadata_bsf; @@ -35,6 +36,7 @@ extern const FFBitStreamFilter ff_dovi_rpu_bsf; extern const FFBitStreamFilter ff_dts2pts_bsf; extern const FFBitStreamFilter ff_dv_error_marker_bsf; extern const FFBitStreamFilter ff_eac3_core_bsf; +extern const FFBitStreamFilter ff_eia608_to_smpte436m_bsf; extern const FFBitStreamFilter ff_evc_frame_merge_bsf; extern const FFBitStreamFilter ff_extract_extradata_bsf; extern const FFBitStreamFilter ff_filter_units_bsf; @@ -60,6 +62,7 @@ extern const FFBitStreamFilter ff_prores_metadata_bsf; extern const FFBitStreamFilter ff_remove_extradata_bsf; extern const FFBitStreamFilter ff_setts_bsf; extern const FFBitStreamFilter ff_showinfo_bsf; +extern const FFBitStreamFilter ff_smpte436m_to_eia608_bsf; extern const FFBitStreamFilter ff_text2movsub_bsf; extern const FFBitStreamFilter ff_trace_headers_bsf; extern const FFBitStreamFilter ff_truehd_core_bsf; diff --git a/libavcodec/bitstream_template.h b/libavcodec/bitstream_template.h index bbb8dfa555..773d40ef14 100644 --- a/libavcodec/bitstream_template.h +++ b/libavcodec/bitstream_template.h @@ -156,6 +156,14 @@ static inline int BS_FUNC(size)(const BSCTX *bc) return bc->size_in_bits; } +/** + * Return buffer size in bytes. + */ +static inline int BS_FUNC(bytesize)(const BSCTX *bc, int round_up) +{ + return (bc->size_in_bits + (round_up ? 7 : 0)) >> 3; +} + /** * Return the number of the bits left in a buffer. */ diff --git a/libavcodec/blockdsp.h b/libavcodec/blockdsp.h index 6d751d797b..f83068ce53 100644 --- a/libavcodec/blockdsp.h +++ b/libavcodec/blockdsp.h @@ -38,7 +38,6 @@ typedef struct BlockDSPContext { void ff_blockdsp_init(BlockDSPContext *c); -void ff_blockdsp_init_alpha(BlockDSPContext *c); void ff_blockdsp_init_arm(BlockDSPContext *c); void ff_blockdsp_init_ppc(BlockDSPContext *c); void ff_blockdsp_init_riscv(BlockDSPContext *c); diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c index 48f25170ba..15d6778f24 100644 --- a/libavcodec/bmpenc.c +++ b/libavcodec/bmpenc.c @@ -164,11 +164,9 @@ const FFCodec ff_bmp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = bmp_encode_init, FF_CODEC_ENCODE_CB(bmp_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, + AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/bmvvideo.c b/libavcodec/bmvvideo.c index 20f07ca556..e83b7e64d6 100644 --- a/libavcodec/bmvvideo.c +++ b/libavcodec/bmvvideo.c @@ -251,11 +251,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = type & BMV_PALETTE; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->frame; diff --git a/libavcodec/bonk.c b/libavcodec/bonk.c index 14b7457a1a..99098ef2b0 100644 --- a/libavcodec/bonk.c +++ b/libavcodec/bonk.c @@ -427,11 +427,7 @@ const FFCodec ff_bonk_decoder = { FF_CODEC_DECODE_CB(bonk_decode), .close = bonk_close, .p.capabilities = AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/brenderpix.c b/libavcodec/brenderpix.c index 07bb47fff9..dd48b40b37 100644 --- a/libavcodec/brenderpix.c +++ b/libavcodec/brenderpix.c @@ -245,12 +245,6 @@ static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame, *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb); bytestream2_skip(&gb, 8); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - chunk_type = bytestream2_get_be32(&gb); } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { /* no palette supplied, use the default one */ @@ -260,12 +254,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_WARNING, "Using default palette, colors might be off.\n"); memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256); - -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } data_len = bytestream2_get_be32(&gb); diff --git a/libavcodec/bsf/Makefile b/libavcodec/bsf/Makefile index 40b7fc6e9b..8e2e6f7b14 100644 --- a/libavcodec/bsf/Makefile +++ b/libavcodec/bsf/Makefile @@ -2,6 +2,7 @@ clean:: $(RM) $(CLEANSUFFIXES:%=libavcodec/bsf/%) OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += bsf/aac_adtstoasc.o +OBJS-$(CONFIG_APV_METADATA_BSF) += bsf/apv_metadata.o OBJS-$(CONFIG_AV1_FRAME_MERGE_BSF) += bsf/av1_frame_merge.o OBJS-$(CONFIG_AV1_FRAME_SPLIT_BSF) += bsf/av1_frame_split.o OBJS-$(CONFIG_AV1_METADATA_BSF) += bsf/av1_metadata.o @@ -11,6 +12,7 @@ OBJS-$(CONFIG_DTS2PTS_BSF) += bsf/dts2pts.o OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += bsf/dump_extradata.o OBJS-$(CONFIG_DV_ERROR_MARKER_BSF) += bsf/dv_error_marker.o OBJS-$(CONFIG_EAC3_CORE_BSF) += bsf/eac3_core.o +OBJS-$(CONFIG_EIA608_TO_SMPTE436M_BSF) += bsf/eia608_to_smpte436m.o OBJS-$(CONFIG_EVC_FRAME_MERGE_BSF) += bsf/evc_frame_merge.o OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += bsf/extract_extradata.o OBJS-$(CONFIG_FILTER_UNITS_BSF) += bsf/filter_units.o @@ -37,6 +39,7 @@ OBJS-$(CONFIG_PRORES_METADATA_BSF) += bsf/prores_metadata.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += bsf/remove_extradata.o OBJS-$(CONFIG_SETTS_BSF) += bsf/setts.o OBJS-$(CONFIG_SHOWINFO_BSF) += bsf/showinfo.o +OBJS-$(CONFIG_SMPTE436M_TO_EIA608_BSF) += bsf/smpte436m_to_eia608.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += bsf/movsub.o OBJS-$(CONFIG_TRACE_HEADERS_BSF) += bsf/trace_headers.o OBJS-$(CONFIG_TRUEHD_CORE_BSF) += bsf/truehd_core.o diff --git a/libavcodec/bsf/apv_metadata.c b/libavcodec/bsf/apv_metadata.c new file mode 100644 index 0000000000..a1cdcf86c8 --- /dev/null +++ b/libavcodec/bsf/apv_metadata.c @@ -0,0 +1,134 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "bsf_internal.h" +#include "cbs.h" +#include "cbs_bsf.h" +#include "cbs_apv.h" + +typedef struct APVMetadataContext { + CBSBSFContext common; + + int color_primaries; + int transfer_characteristics; + int matrix_coefficients; + int full_range_flag; +} APVMetadataContext; + + +static int apv_metadata_update_frame_header(AVBSFContext *bsf, + APVRawFrameHeader *hdr) +{ + APVMetadataContext *ctx = bsf->priv_data; + + if (ctx->color_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0 || + ctx->full_range_flag >= 0) { + hdr->color_description_present_flag = 1; + + if (ctx->color_primaries >= 0) + hdr->color_primaries = ctx->color_primaries; + if (ctx->transfer_characteristics >= 0) + hdr->transfer_characteristics = ctx->transfer_characteristics; + if (ctx->matrix_coefficients >= 0) + hdr->matrix_coefficients = ctx->matrix_coefficients; + if (ctx->full_range_flag >= 0) + hdr->full_range_flag = ctx->full_range_flag; + } + + return 0; +} + +static int apv_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + int err, i; + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == APV_PBU_PRIMARY_FRAME) { + APVRawFrame *pbu = frag->units[i].content; + err = apv_metadata_update_frame_header(bsf, &pbu->frame_header); + if (err < 0) + return err; + } + } + + return 0; +} + +static const CBSBSFType apv_metadata_type = { + .codec_id = AV_CODEC_ID_APV, + .fragment_name = "access unit", + .unit_name = "PBU", + .update_fragment = &apv_metadata_update_fragment, +}; + +static int apv_metadata_init(AVBSFContext *bsf) +{ + return ff_cbs_bsf_generic_init(bsf, &apv_metadata_type); +} + +#define OFFSET(x) offsetof(APVMetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption apv_metadata_options[] = { + { "color_primaries", "Set color primaries (section 5.3.5)", + OFFSET(color_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (section 5.3.5)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (section 5.3.5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "full_range_flag", "Set full range flag flag (section 5.3.5)", + OFFSET(full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS, .unit = "cr" }, + { "tv", "TV (limited) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, .flags = FLAGS, .unit = "cr" }, + { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, + + { NULL } +}; + +static const AVClass apv_metadata_class = { + .class_name = "apv_metadata_bsf", + .item_name = av_default_item_name, + .option = apv_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID apv_metadata_codec_ids[] = { + AV_CODEC_ID_APV, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_apv_metadata_bsf = { + .p.name = "apv_metadata", + .p.codec_ids = apv_metadata_codec_ids, + .p.priv_class = &apv_metadata_class, + .priv_data_size = sizeof(APVMetadataContext), + .init = &apv_metadata_init, + .close = &ff_cbs_bsf_generic_close, + .filter = &ff_cbs_bsf_generic_filter, +}; diff --git a/libavcodec/bsf/dovi_rpu.c b/libavcodec/bsf/dovi_rpu.c index ae04d16360..84b271f736 100644 --- a/libavcodec/bsf/dovi_rpu.c +++ b/libavcodec/bsf/dovi_rpu.c @@ -84,7 +84,8 @@ static int dovi_rpu_update_fragment_hevc(AVBSFContext *bsf, AVPacket *pkt, uint8_t *rpu = NULL; int rpu_size, ret; - if (!nal || nal->type != HEVC_NAL_UNSPEC62) + // HEVC_NAL_UNSPEC62 is Dolby Vision PRU and HEVC_NAL_UNSPEC63 is Dolby Vision EL + if (!nal || (nal->type != HEVC_NAL_UNSPEC62 && nal->type != HEVC_NAL_UNSPEC63)) return 0; if (s->strip) { @@ -92,6 +93,9 @@ static int dovi_rpu_update_fragment_hevc(AVBSFContext *bsf, AVPacket *pkt, return 0; } + if (nal->type == HEVC_NAL_UNSPEC63) + return 0; + ret = update_rpu(bsf, pkt, 0, nal->data + 2, nal->data_size - 2, &rpu, &rpu_size); if (ret < 0) return ret; @@ -224,8 +228,8 @@ static int dovi_rpu_init(AVBSFContext *bsf) } else { av_log(bsf, AV_LOG_WARNING, "No Dolby Vision configuration record " "found? Generating one, but results may be invalid.\n"); - ret = ff_dovi_configure_ext(&s->enc, bsf->par_out, NULL, s->compression, - FF_COMPLIANCE_NORMAL); + ret = ff_dovi_configure_from_codedpar(&s->enc, bsf->par_out, NULL, s->compression, + FF_COMPLIANCE_NORMAL); if (ret < 0) return ret; /* Be conservative in accepting all compressed RPUs */ diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c index 62838d4f7b..9d31d7dc08 100644 --- a/libavcodec/bsf/dts2pts.c +++ b/libavcodec/bsf/dts2pts.c @@ -34,7 +34,7 @@ #include "cbs_h264.h" #include "h264_parse.h" #include "h264_ps.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" typedef struct DTS2PTSNode { int64_t dts; @@ -62,7 +62,7 @@ typedef struct DTS2PTSH264Context { typedef struct DTS2PTSContext { struct AVTreeNode *root; AVFifo *fifo; - FFRefStructPool *node_pool; + AVRefStructPool *node_pool; // Codec specific function pointers and constants int (*init)(AVBSFContext *ctx); @@ -112,7 +112,7 @@ static int dec_poc(void *opaque, void *elem) static int free_node(void *opaque, void *elem) { DTS2PTSNode *node = elem; - ff_refstruct_unref(&node); + av_refstruct_unref(&node); return 0; } @@ -126,7 +126,7 @@ static int alloc_and_insert_node(AVBSFContext *ctx, int64_t ts, int64_t duration DTS2PTSNode *poc_node, *ret; if (!node) return AVERROR(ENOMEM); - poc_node = ff_refstruct_pool_get(s->node_pool); + poc_node = av_refstruct_pool_get(s->node_pool); if (!poc_node) { av_free(node); return AVERROR(ENOMEM); @@ -137,7 +137,7 @@ static int alloc_and_insert_node(AVBSFContext *ctx, int64_t ts, int64_t duration ret = av_tree_insert(&s->root, poc_node, cmp_insert, &node); if (ret && ret != poc_node) { *ret = *poc_node; - ff_refstruct_unref(&poc_node); + av_refstruct_unref(&poc_node); av_free(node); } } @@ -396,8 +396,8 @@ static int dts2pts_init(AVBSFContext *ctx) if (!s->fifo) return AVERROR(ENOMEM); - s->node_pool = ff_refstruct_pool_alloc(sizeof(DTS2PTSNode), - FF_REFSTRUCT_POOL_FLAG_NO_ZEROING); + s->node_pool = av_refstruct_pool_alloc(sizeof(DTS2PTSNode), + AV_REFSTRUCT_POOL_FLAG_NO_ZEROING); if (!s->node_pool) return AVERROR(ENOMEM); @@ -467,7 +467,7 @@ static int dts2pts_filter(AVBSFContext *ctx, AVPacket *out) if (!poc_node || poc_node->dts != out->pts) continue; av_tree_insert(&s->root, poc_node, cmp_insert, &node); - ff_refstruct_unref(&poc_node); + av_refstruct_unref(&poc_node); av_free(node); poc_node = av_tree_find(s->root, &dup, cmp_find, NULL); } @@ -529,7 +529,7 @@ static void dts2pts_close(AVBSFContext *ctx) dts2pts_flush(ctx); av_fifo_freep2(&s->fifo); - ff_refstruct_pool_uninit(&s->node_pool); + av_refstruct_pool_uninit(&s->node_pool); ff_cbs_fragment_free(&s->au); ff_cbs_close(&s->cbc); } diff --git a/libavcodec/bsf/eia608_to_smpte436m.c b/libavcodec/bsf/eia608_to_smpte436m.c new file mode 100644 index 0000000000..096acb596c --- /dev/null +++ b/libavcodec/bsf/eia608_to_smpte436m.c @@ -0,0 +1,277 @@ +/* + * EIA-608 to MXF SMPTE-436M ANC bitstream filter + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bsf.h" +#include "bsf_internal.h" +#include "codec_id.h" +#include "libavcodec/smpte_436m.h" +#include "libavcodec/smpte_436m_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/avutil.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/macros.h" +#include "libavutil/opt.h" +#include "libavutil/rational.h" + +typedef struct EIA608ToSMPTE436MContext { + const AVClass *class; + unsigned line_number; + unsigned cdp_sequence_cntr; + unsigned wrapping_type_opt; + unsigned sample_coding_opt; + AVSmpte436mWrappingType wrapping_type; + AVSmpte436mPayloadSampleCoding sample_coding; + AVRational cdp_frame_rate; + uint8_t cdp_frame_rate_byte; +} EIA608ToSMPTE436MContext; + +// clang-format off +static const AVSmpte291mAnc8bit test_anc = { + .did = 0x61, + .sdid_or_dbn = 0x01, + .data_count = 0x49, + .payload = { + // header + 0x96, 0x69, 0x49, 0x7F, 0x43, 0xFA, 0x8D, 0x72, 0xF4, + + // 608 triples + 0xFC, 0x80, 0x80, 0xFD, 0x80, 0x80, + + // 708 padding + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, + + // footer + 0x74, 0xFA, 0x8D, 0x81, + }, + .checksum = 0xAB, +}; +// clang-format on + +static av_cold int ff_eia608_to_smpte436m_init(AVBSFContext *ctx) +{ + EIA608ToSMPTE436MContext *priv = ctx->priv_data; + + priv->wrapping_type = priv->wrapping_type_opt; + priv->sample_coding = priv->sample_coding_opt; + + // validate we can handle the selected wrapping type and sample coding + + AVSmpte436mCodedAnc coded_anc; + + int ret = av_smpte_291m_anc_8bit_encode( + &coded_anc, priv->line_number, priv->wrapping_type, priv->sample_coding, &test_anc, ctx); + if (ret < 0) + return ret; + + ctx->par_out->codec_type = AVMEDIA_TYPE_DATA; + ctx->par_out->codec_id = AV_CODEC_ID_SMPTE_436M_ANC; + + static const struct { + AVRational frame_rate; + uint8_t cdp_frame_rate; + } known_frame_rates[] = { + { .frame_rate = { .num = 24000, .den = 1001 }, .cdp_frame_rate = 0x1F }, + { .frame_rate = { .num = 24, .den = 1 }, .cdp_frame_rate = 0x2F }, + { .frame_rate = { .num = 25, .den = 1 }, .cdp_frame_rate = 0x3F }, + { .frame_rate = { .num = 30000, .den = 1001 }, .cdp_frame_rate = 0x4F }, + { .frame_rate = { .num = 30, .den = 1 }, .cdp_frame_rate = 0x5F }, + { .frame_rate = { .num = 50, .den = 1 }, .cdp_frame_rate = 0x6F }, + { .frame_rate = { .num = 60000, .den = 1001 }, .cdp_frame_rate = 0x7F }, + { .frame_rate = { .num = 60, .den = 1 }, .cdp_frame_rate = 0x8F }, + }; + + priv->cdp_frame_rate_byte = 0; + + for (int i = 0; i < FF_ARRAY_ELEMS(known_frame_rates); i++) { + if (known_frame_rates[i].frame_rate.num == priv->cdp_frame_rate.num && known_frame_rates[i].frame_rate.den == priv->cdp_frame_rate.den) { + priv->cdp_frame_rate_byte = known_frame_rates[i].cdp_frame_rate; + break; + } + } + + if (priv->cdp_frame_rate_byte == 0) { + av_log(ctx, + AV_LOG_FATAL, + "cdp_frame_rate not supported: %d/%d\n", + priv->cdp_frame_rate.num, + priv->cdp_frame_rate.den); + return AVERROR(EINVAL); + } + + return 0; +} + +static int ff_eia608_to_smpte436m_filter(AVBSFContext *ctx, AVPacket *out) +{ + EIA608ToSMPTE436MContext *priv = ctx->priv_data; + AVPacket *in; + + int ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + AVSmpte291mAnc8bit anc; + anc.did = 0x61; + anc.sdid_or_dbn = 0x1; + + uint8_t *p = anc.payload; + + *p++ = 0x96; // cdp_identifier -- always 0x9669 + *p++ = 0x69; + + uint8_t *cdp_length_p = p++; + + *p++ = priv->cdp_frame_rate_byte; + + const uint8_t FLAG_CC_DATA_PRESENT = 0x40; + const uint8_t FLAG_CAPTION_SERVICE_ACTIVE = 0x2; + const uint8_t FLAG_RESERVED = 0x1; // must always be set + + *p++ = FLAG_CC_DATA_PRESENT | FLAG_CAPTION_SERVICE_ACTIVE | FLAG_RESERVED; + + AV_WB16(p, priv->cdp_sequence_cntr); + p += 2; + + const uint8_t CC_DATA_SECTION_ID = 0x72; + + *p++ = CC_DATA_SECTION_ID; + + uint8_t *cc_count_p = p++; + + const uint8_t CC_COUNT_MASK = 0x1F; + const int CDP_FOOTER_SIZE = 4; + + int cc_count = in->size / 3; + int space_left = AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY - (p - anc.payload); + int cc_data_space_left = space_left - CDP_FOOTER_SIZE; + int max_cc_count = FFMAX(cc_data_space_left / 3, CC_COUNT_MASK); + + if (cc_count > max_cc_count) { + av_log(ctx, + AV_LOG_ERROR, + "cc_count (%d) is bigger than the maximum supported (%d), truncating captions packet\n", + cc_count, + max_cc_count); + cc_count = max_cc_count; + } + + *cc_count_p = cc_count | ~CC_COUNT_MASK; // other bits are reserved and set to ones + + for (size_t i = 0; i < cc_count; i++) { + size_t start = i * 3; + *p++ = in->data[start] | 0xF8; // fill reserved bits with ones + *p++ = in->data[start + 1]; + *p++ = in->data[start + 2]; + } + + const uint8_t CDP_FOOTER_ID = 0x74; + + *p++ = CDP_FOOTER_ID; + + AV_WB16(p, priv->cdp_sequence_cntr); + p += 2; + + uint8_t *packet_checksum_p = p; + *p++ = 0; + + anc.data_count = p - anc.payload; + *cdp_length_p = anc.data_count; + + int sum = 0; + for (int i = 0; i < anc.data_count; i++) { + sum += anc.payload[i]; + } + // set to an 8-bit value such that the sum of the bytes of the whole CDP mod 2^8 is 0 + *packet_checksum_p = -sum; + + priv->cdp_sequence_cntr++; + // cdp_sequence_cntr wraps around at 16-bits + priv->cdp_sequence_cntr &= 0xFFFFU; + + av_smpte_291m_anc_8bit_fill_checksum(&anc); + + AVSmpte436mCodedAnc coded_anc; + ret = av_smpte_291m_anc_8bit_encode( + &coded_anc, priv->line_number, (AVSmpte436mWrappingType)priv->wrapping_type, priv->sample_coding, &anc, ctx); + if (ret < 0) + goto fail; + + ret = av_smpte_436m_anc_encode(NULL, 0, 1, &coded_anc); + if (ret < 0) + goto fail; + + ret = av_new_packet(out, ret); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + ret = av_smpte_436m_anc_encode(out->data, out->size, 1, &coded_anc); + if (ret < 0) + goto fail; + + ret = 0; + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; +} + +#define OFFSET(x) offsetof(EIA608ToSMPTE436MContext, x) +#define FLAGS AV_OPT_FLAG_BSF_PARAM +// clang-format off +static const AVOption options[] = { + { "line_number", "line number -- you probably want 9 or 11", OFFSET(line_number), AV_OPT_TYPE_UINT, { .i64 = 9 }, 0, 0xFFFF, FLAGS }, + { "wrapping_type", "wrapping type", OFFSET(wrapping_type_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME }, 0, 0xFF, FLAGS, .unit = "wrapping_type" }, + FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(FLAGS, "wrapping_type"), + { "sample_coding", "payload sample coding", OFFSET(sample_coding_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA }, 0, 0xFF, FLAGS, .unit = "sample_coding" }, + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ANC_AVOPTIONS(FLAGS, "sample_coding"), + { "initial_cdp_sequence_cntr", "initial cdp_*_sequence_cntr value", OFFSET(cdp_sequence_cntr), AV_OPT_TYPE_UINT, { .i64 = 0 }, 0, 0xFFFF, FLAGS }, + { "cdp_frame_rate", "set the `cdp_frame_rate` fields", OFFSET(cdp_frame_rate), AV_OPT_TYPE_VIDEO_RATE, { .str = "30000/1001" }, 0, INT_MAX, FLAGS }, + { NULL }, +}; +// clang-format on + +static const AVClass eia608_to_smpte436m_class = { + .class_name = "eia608_to_smpte436m bitstream filter", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFBitStreamFilter ff_eia608_to_smpte436m_bsf = { + .p.name = "eia608_to_smpte436m", + .p.codec_ids = (const enum AVCodecID[]){ AV_CODEC_ID_EIA_608, AV_CODEC_ID_NONE }, + .p.priv_class = &eia608_to_smpte436m_class, + .priv_data_size = sizeof(EIA608ToSMPTE436MContext), + .init = ff_eia608_to_smpte436m_init, + .filter = ff_eia608_to_smpte436m_filter, +}; diff --git a/libavcodec/bsf/h264_mp4toannexb.c b/libavcodec/bsf/h264_mp4toannexb.c index dda064287e..36b09b4dd6 100644 --- a/libavcodec/bsf/h264_mp4toannexb.c +++ b/libavcodec/bsf/h264_mp4toannexb.c @@ -93,6 +93,11 @@ static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding = AV_INPUT_BUFFER_PADDING_SIZE; int length_size, pps_offset = 0; + if (extradata_size < 7) { + av_log(ctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", extradata_size); + return AVERROR_INVALIDDATA; + } + bytestream2_init(gb, extradata, extradata_size); bytestream2_skipu(gb, 4); @@ -262,16 +267,11 @@ static int h264_mp4toannexb_init(AVBSFContext *ctx) (extra_size >= 4 && AV_RB32(ctx->par_in->extradata) == 1)) { av_log(ctx, AV_LOG_VERBOSE, "The input looks like it is Annex B already\n"); - } else if (extra_size >= 7) { - return h264_extradata_to_annexb(ctx, - ctx->par_in->extradata, - ctx->par_in->extradata_size); - } else { - av_log(ctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", extra_size); - return AVERROR_INVALIDDATA; + return 0; } - - return 0; + return h264_extradata_to_annexb(ctx, + ctx->par_in->extradata, + ctx->par_in->extradata_size); } static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt) @@ -293,10 +293,12 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt) extradata = av_packet_get_side_data(in, AV_PKT_DATA_NEW_EXTRADATA, &extradata_size); - if (extradata) { + if (extradata && extradata[0] == 1) { ret = h264_extradata_to_annexb(ctx, extradata, extradata_size); if (ret < 0) goto fail; + av_packet_side_data_remove(in->side_data, &in->side_data_elems, + AV_PKT_DATA_NEW_EXTRADATA); } /* nothing to filter */ diff --git a/libavcodec/bsf/h266_metadata.c b/libavcodec/bsf/h266_metadata.c index 1f0f875cfe..2242c620fa 100644 --- a/libavcodec/bsf/h266_metadata.c +++ b/libavcodec/bsf/h266_metadata.c @@ -80,7 +80,7 @@ static int h266_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, } } if (!ph) { - av_log(bsf, AV_LOG_ERROR, "no avaliable picture header"); + av_log(bsf, AV_LOG_ERROR, "no available picture header"); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/bsf/hevc_mp4toannexb.c b/libavcodec/bsf/hevc_mp4toannexb.c index f281185769..60f38ac414 100644 --- a/libavcodec/bsf/hevc_mp4toannexb.c +++ b/libavcodec/bsf/hevc_mp4toannexb.c @@ -126,6 +126,7 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) GetByteContext gb; int got_irap = 0; + int got_ps = 0, seen_irap_ps = 0; int i, ret = 0; ret = ff_bsf_get_packet(ctx, &in); @@ -140,10 +141,37 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) bytestream2_init(&gb, in->data, in->size); + while (!got_irap && bytestream2_get_bytes_left(&gb)) { + uint32_t nalu_size = 0; + int nalu_type; + + if (bytestream2_get_bytes_left(&gb) < s->length_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + for (i = 0; i < s->length_size; i++) + nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); + + if (nalu_size < 2 || nalu_size > bytestream2_get_bytes_left(&gb)) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; + bytestream2_skip(&gb, nalu_size); + got_irap |= nalu_type >= HEVC_NAL_BLA_W_LP && + nalu_type <= HEVC_NAL_RSV_IRAP_VCL23; + got_ps |= nalu_type >= HEVC_NAL_VPS && nalu_type <= HEVC_NAL_PPS; + } + seen_irap_ps = got_irap && got_ps; + got_irap = got_ps = 0; + + bytestream2_init(&gb, in->data, in->size); + while (bytestream2_get_bytes_left(&gb)) { uint32_t nalu_size = 0; int nalu_type; - int is_irap, add_extradata, extra_size, prev_size; + int is_irap, is_ps, add_extradata, extra_size, prev_size; if (bytestream2_get_bytes_left(&gb) < s->length_size) { ret = AVERROR_INVALIDDATA; @@ -162,9 +190,11 @@ static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) /* prepend extradata to IRAP frames */ is_irap = nalu_type >= HEVC_NAL_BLA_W_LP && nalu_type <= HEVC_NAL_RSV_IRAP_VCL23; - add_extradata = is_irap && !got_irap; + is_ps = nalu_type >= HEVC_NAL_VPS && nalu_type <= HEVC_NAL_PPS && seen_irap_ps; + add_extradata = (is_ps || is_irap) && !got_ps && !got_irap; extra_size = add_extradata * ctx->par_out->extradata_size; got_irap |= is_irap; + got_ps |= is_ps; if (FFMIN(INT_MAX, SIZE_MAX) < 4ULL + nalu_size + extra_size) { ret = AVERROR_INVALIDDATA; diff --git a/libavcodec/bsf/smpte436m_to_eia608.c b/libavcodec/bsf/smpte436m_to_eia608.c new file mode 100644 index 0000000000..529ae88794 --- /dev/null +++ b/libavcodec/bsf/smpte436m_to_eia608.c @@ -0,0 +1,91 @@ +/* + * MXF SMPTE-436M ANC to EIA-608 bitstream filter + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bsf.h" +#include "bsf_internal.h" +#include "codec_id.h" +#include "libavcodec/smpte_436m.h" +#include "libavutil/error.h" + +static av_cold int ff_smpte436m_to_eia608_init(AVBSFContext *ctx) +{ + ctx->par_out->codec_type = AVMEDIA_TYPE_SUBTITLE; + ctx->par_out->codec_id = AV_CODEC_ID_EIA_608; + return 0; +} + +static int ff_smpte436m_to_eia608_filter(AVBSFContext *ctx, AVPacket *out) +{ + AVPacket *in; + int ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + AVSmpte436mAncIterator iter; + ret = av_smpte_436m_anc_iter_init(&iter, in->data, in->size); + if (ret < 0) + goto fail; + AVSmpte436mCodedAnc coded_anc; + while ((ret = av_smpte_436m_anc_iter_next(&iter, &coded_anc)) >= 0) { + AVSmpte291mAnc8bit anc; + ret = av_smpte_291m_anc_8bit_decode( + &anc, coded_anc.payload_sample_coding, coded_anc.payload_sample_count, coded_anc.payload, ctx); + if (ret < 0) + goto fail; + ret = av_smpte_291m_anc_8bit_extract_cta_708(&anc, NULL, ctx); + if (ret == AVERROR(EAGAIN)) + continue; + if (ret < 0) + goto fail; + int cc_count = ret; + + ret = av_new_packet(out, 3 * cc_count); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + // verified it won't fail by running it above + av_smpte_291m_anc_8bit_extract_cta_708(&anc, out->data, ctx); + + av_packet_free(&in); + + return 0; + } + if (ret != AVERROR_EOF) + return ret; + ret = AVERROR(EAGAIN); + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; +} + +const FFBitStreamFilter ff_smpte436m_to_eia608_bsf = { + .p.name = "smpte436m_to_eia608", + .p.codec_ids = (const enum AVCodecID[]){ AV_CODEC_ID_SMPTE_436M_ANC, AV_CODEC_ID_NONE }, + .init = ff_smpte436m_to_eia608_init, + .filter = ff_smpte436m_to_eia608_filter, +}; diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h index 67080604b9..9c13a2791b 100644 --- a/libavcodec/bytestream.h +++ b/libavcodec/bytestream.h @@ -77,11 +77,11 @@ static av_always_inline type bytestream2_get_ ## name(GetByteContext *g) \ } \ return bytestream2_get_ ## name ## u(g); \ } \ -static av_always_inline type bytestream2_peek_ ## name ## u(GetByteContext *g) \ +static av_always_inline type bytestream2_peek_ ## name ## u(const GetByteContext *g) \ { \ return read(g->buffer); \ } \ -static av_always_inline type bytestream2_peek_ ## name(GetByteContext *g) \ +static av_always_inline type bytestream2_peek_ ## name(const GetByteContext *g)\ { \ if (g->buffer_end - g->buffer < bytes) \ return 0; \ @@ -155,12 +155,12 @@ static av_always_inline void bytestream2_init_writer(PutByteContext *p, p->eof = 0; } -static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g) +static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g) { return g->buffer_end - g->buffer; } -static av_always_inline int bytestream2_get_bytes_left_p(PutByteContext *p) +static av_always_inline int bytestream2_get_bytes_left_p(const PutByteContext *p) { return p->buffer_end - p->buffer; } @@ -189,22 +189,22 @@ static av_always_inline void bytestream2_skip_p(PutByteContext *p, p->buffer += size2; } -static av_always_inline int bytestream2_tell(GetByteContext *g) +static av_always_inline int bytestream2_tell(const GetByteContext *g) { return (int)(g->buffer - g->buffer_start); } -static av_always_inline int bytestream2_tell_p(PutByteContext *p) +static av_always_inline int bytestream2_tell_p(const PutByteContext *p) { return (int)(p->buffer - p->buffer_start); } -static av_always_inline int bytestream2_size(GetByteContext *g) +static av_always_inline int bytestream2_size(const GetByteContext *g) { return (int)(g->buffer_end - g->buffer_start); } -static av_always_inline int bytestream2_size_p(PutByteContext *p) +static av_always_inline int bytestream2_size_p(const PutByteContext *p) { return (int)(p->buffer_end - p->buffer_start); } diff --git a/libavcodec/c93.c b/libavcodec/c93.c index 2a4fe45958..288b1f0ea7 100644 --- a/libavcodec/c93.c +++ b/libavcodec/c93.c @@ -246,11 +246,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, for (i = 0; i < 256; i++) { palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - newpic->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else { if (oldpic->data[1]) memcpy(newpic->data[1], oldpic->data[1], 256 * 4); diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h index 244c322b35..d3a88ca403 100644 --- a/libavcodec/cavs.h +++ b/libavcodec/cavs.h @@ -146,7 +146,7 @@ enum cavs_mv_loc { MV_BWD_X3 }; -DECLARE_ALIGNED(8, typedef, struct) { +typedef struct cavs_vector { int16_t x; int16_t y; int16_t dist; @@ -207,7 +207,7 @@ typedef struct AVSContext { D is the macroblock to the top-left (0) the same is repeated for backward motion vectors */ - cavs_vector mv[2*4*3]; + DECLARE_ALIGNED(8, cavs_vector, mv)[2*4*3]; cavs_vector *top_mv[2]; cavs_vector *col_mv; diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index 3cf8c9fb3a..e076cfc47f 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1184,7 +1184,7 @@ static int decode_seq_header(AVSContext *h) h->profile = get_bits(&h->gb, 8); if (h->profile != 0x20) { avpriv_report_missing_feature(h->avctx, - "only supprt JiZhun profile"); + "only support JiZhun profile"); return AVERROR_PATCHWELCOME; } h->level = get_bits(&h->gb, 8); diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index b26e39eab4..6b2ebe597d 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -18,8 +18,6 @@ #include -#include "config.h" - #include "libavutil/avassert.h" #include "libavutil/buffer.h" #include "libavutil/common.h" @@ -29,65 +27,71 @@ #include "avcodec.h" #include "cbs.h" #include "cbs_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" static const CodedBitstreamType *const cbs_type_table[] = { -#if CONFIG_CBS_AV1 - &ff_cbs_type_av1, +#if CBS_APV + &CBS_FUNC(type_apv), #endif -#if CONFIG_CBS_H264 - &ff_cbs_type_h264, +#if CBS_AV1 + &CBS_FUNC(type_av1), #endif -#if CONFIG_CBS_H265 - &ff_cbs_type_h265, +#if CBS_H264 + &CBS_FUNC(type_h264), #endif -#if CONFIG_CBS_H266 - &ff_cbs_type_h266, +#if CBS_H265 + &CBS_FUNC(type_h265), #endif -#if CONFIG_CBS_JPEG - &ff_cbs_type_jpeg, +#if CBS_H266 + &CBS_FUNC(type_h266), #endif -#if CONFIG_CBS_MPEG2 - &ff_cbs_type_mpeg2, +#if CBS_JPEG + &CBS_FUNC(type_jpeg), #endif -#if CONFIG_CBS_VP8 - &ff_cbs_type_vp8, +#if CBS_MPEG2 + &CBS_FUNC(type_mpeg2), #endif -#if CONFIG_CBS_VP9 - &ff_cbs_type_vp9, +#if CBS_VP8 + &CBS_FUNC(type_vp8), +#endif +#if CBS_VP9 + &CBS_FUNC(type_vp9), #endif }; -const enum AVCodecID ff_cbs_all_codec_ids[] = { -#if CONFIG_CBS_AV1 +const enum AVCodecID CBS_FUNC(all_codec_ids)[] = { +#if CBS_APV + AV_CODEC_ID_APV, +#endif +#if CBS_AV1 AV_CODEC_ID_AV1, #endif -#if CONFIG_CBS_H264 +#if CBS_H264 AV_CODEC_ID_H264, #endif -#if CONFIG_CBS_H265 +#if CBS_H265 AV_CODEC_ID_H265, #endif -#if CONFIG_CBS_H266 +#if CBS_H266 AV_CODEC_ID_H266, #endif -#if CONFIG_CBS_JPEG +#if CBS_JPEG AV_CODEC_ID_MJPEG, #endif -#if CONFIG_CBS_MPEG2 +#if CBS_MPEG2 AV_CODEC_ID_MPEG2VIDEO, #endif -#if CONFIG_CBS_VP8 +#if CBS_VP8 AV_CODEC_ID_VP8, #endif -#if CONFIG_CBS_VP9 +#if CBS_VP9 AV_CODEC_ID_VP9, #endif AV_CODEC_ID_NONE }; -av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr, +av_cold int CBS_FUNC(init)(CodedBitstreamContext **ctx_ptr, enum AVCodecID codec_id, void *log_ctx) { CodedBitstreamContext *ctx; @@ -133,13 +137,13 @@ av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr, return 0; } -av_cold void ff_cbs_flush(CodedBitstreamContext *ctx) +av_cold void CBS_FUNC(flush)(CodedBitstreamContext *ctx) { if (ctx->codec->flush) ctx->codec->flush(ctx); } -av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr) +av_cold void CBS_FUNC(close)(CodedBitstreamContext **ctx_ptr) { CodedBitstreamContext *ctx = *ctx_ptr; @@ -160,7 +164,7 @@ av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr) static void cbs_unit_uninit(CodedBitstreamUnit *unit) { - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; av_buffer_unref(&unit->data_ref); @@ -169,7 +173,7 @@ static void cbs_unit_uninit(CodedBitstreamUnit *unit) unit->data_bit_padding = 0; } -void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) +void CBS_FUNC(fragment_reset)(CodedBitstreamFragment *frag) { int i; @@ -183,14 +187,15 @@ void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) frag->data_bit_padding = 0; } -av_cold void ff_cbs_fragment_free(CodedBitstreamFragment *frag) +av_cold void CBS_FUNC(fragment_free)(CodedBitstreamFragment *frag) { - ff_cbs_fragment_reset(frag); + CBS_FUNC(fragment_reset)(frag); av_freep(&frag->units); frag->nb_units_allocated = 0; } +#if CBS_READ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { @@ -208,7 +213,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, continue; } - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; av_assert0(unit->data && unit->data_ref); @@ -222,7 +227,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, av_log(ctx->log_ctx, AV_LOG_VERBOSE, "Skipping decomposition of unit %d " "(type %"PRIu32").\n", i, unit->type); - ff_refstruct_unref(&unit->content_ref); + av_refstruct_unref(&unit->content_ref); unit->content = NULL; } else if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " @@ -256,7 +261,7 @@ static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, static int cbs_read_data(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, - AVBufferRef *buf, + const AVBufferRef *buf, const uint8_t *data, size_t size, int header) { @@ -283,7 +288,7 @@ static int cbs_read_data(CodedBitstreamContext *ctx, return cbs_read_fragment_content(ctx, frag); } -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecParameters *par) { @@ -292,7 +297,7 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, par->extradata_size, 1); } -int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata_from_codec)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecContext *avctx) { @@ -301,7 +306,7 @@ int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, avctx->extradata_size, 1); } -int ff_cbs_read_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt) { @@ -309,7 +314,7 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, pkt->data, pkt->size, 0); } -int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet_side_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt) { @@ -322,14 +327,17 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, side_data, side_data_size, 1); } -int ff_cbs_read(CodedBitstreamContext *ctx, +int CBS_FUNC(read)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, + const AVBufferRef *buf, const uint8_t *data, size_t size) { - return cbs_read_data(ctx, frag, NULL, + return cbs_read_data(ctx, frag, buf, data, size, 0); } +#endif +#if CBS_WRITE /** * Allocate a new internal data buffer of the given size in the unit. * @@ -406,7 +414,7 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, +int CBS_FUNC(write_fragment_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { int err, i; @@ -442,13 +450,13 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(write_extradata)(CodedBitstreamContext *ctx, AVCodecParameters *par, CodedBitstreamFragment *frag) { int err; - err = ff_cbs_write_fragment_data(ctx, frag); + err = CBS_FUNC(write_fragment_data)(ctx, frag); if (err < 0) return err; @@ -471,14 +479,14 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_write_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(write_packet)(CodedBitstreamContext *ctx, AVPacket *pkt, CodedBitstreamFragment *frag) { AVBufferRef *buf; int err; - err = ff_cbs_write_fragment_data(ctx, frag); + err = CBS_FUNC(write_fragment_data)(ctx, frag); if (err < 0) return err; @@ -494,22 +502,26 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, return 0; } +#endif -void ff_cbs_trace_header(CodedBitstreamContext *ctx, +void CBS_FUNC(trace_header)(CodedBitstreamContext *ctx, const char *name) { +#if CBS_TRACE if (!ctx->trace_enable) return; av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +#endif } -void ff_cbs_trace_read_log(void *trace_context, +void CBS_FUNC(trace_read_log)(void *trace_context, GetBitContext *gbc, int length, const char *str, const int *subscripts, int64_t value) { +#if CBS_TRACE CodedBitstreamContext *ctx = trace_context; char name[256]; char bits[256]; @@ -561,13 +573,15 @@ void ff_cbs_trace_read_log(void *trace_context, av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", position, name, pad, bits, value); +#endif } -void ff_cbs_trace_write_log(void *trace_context, +void CBS_FUNC(trace_write_log)(void *trace_context, PutBitContext *pbc, int length, const char *str, const int *subscripts, int64_t value) { +#if CBS_TRACE CodedBitstreamContext *ctx = trace_context; // Ensure that the syntax element is written to the output buffer, @@ -590,9 +604,11 @@ void ff_cbs_trace_write_log(void *trace_context, skip_bits_long(&gbc, position - length); - ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value); + CBS_FUNC(trace_read_log)(ctx, &gbc, length, str, subscripts, value); +#endif } +#if CBS_READ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, @@ -628,7 +644,7 @@ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max) @@ -637,14 +653,16 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, write_to, range_min, range_max); } -int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_simple_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, uint32_t *write_to) { return cbs_read_unsigned(ctx, gbc, width, name, NULL, write_to, 0, UINT32_MAX); } +#endif -int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +#if CBS_WRITE +int CBS_FUNC(write_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max) @@ -663,24 +681,23 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, if (put_bits_left(pbc) < width) return AVERROR(ENOSPC); - if (width < 32) - put_bits(pbc, width, value); - else - put_bits32(pbc, value); + put_bits63(pbc, width, value); CBS_TRACE_WRITE_END(); return 0; } -int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_simple_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, uint32_t value) { - return ff_cbs_write_unsigned(ctx, pbc, width, name, NULL, + return CBS_FUNC(write_unsigned)(ctx, pbc, width, name, NULL, value, 0, MAX_UINT_BITS(width)); } +#endif -int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, +#if CBS_READ +int CBS_FUNC(read_signed)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, int32_t *write_to, int32_t range_min, int32_t range_max) @@ -711,8 +728,10 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif -int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, +#if CBS_WRITE +int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, int32_t value, int32_t range_min, int32_t range_max) @@ -731,15 +750,13 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, if (put_bits_left(pbc) < width) return AVERROR(ENOSPC); - if (width < 32) - put_sbits(pbc, width, value); - else - put_bits32(pbc, value); + put_bits63(pbc, width, zero_extend(value, width)); CBS_TRACE_WRITE_END(); return 0; } +#endif static int cbs_insert_unit(CodedBitstreamFragment *frag, @@ -766,21 +783,19 @@ static int cbs_insert_unit(CodedBitstreamFragment *frag, if (position < frag->nb_units) memcpy(units + position + 1, frag->units + position, (frag->nb_units - position) * sizeof(*units)); - } - memset(units + position, 0, sizeof(*units)); - - if (units != frag->units) { av_free(frag->units); frag->units = units; } + memset(units + position, 0, sizeof(*units)); + ++frag->nb_units; return 0; } -int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, +int CBS_FUNC(insert_unit_content)(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, @@ -799,7 +814,7 @@ int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, if (content_ref) { // Create our own reference out of the user-supplied one. - content_ref = ff_refstruct_ref(content_ref); + content_ref = av_refstruct_ref(content_ref); } unit = &frag->units[position]; @@ -847,7 +862,7 @@ static int cbs_insert_unit_data(CodedBitstreamFragment *frag, return 0; } -int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, +int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, CodedBitstreamUnitType type, uint8_t *data, size_t data_size, AVBufferRef *data_buf) @@ -857,7 +872,7 @@ int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, frag->nb_units); } -void ff_cbs_delete_unit(CodedBitstreamFragment *frag, +void CBS_FUNC(delete_unit)(CodedBitstreamFragment *frag, int position) { av_assert0(0 <= position && position < frag->nb_units @@ -873,7 +888,7 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag, (frag->nb_units - position) * sizeof(*frag->units)); } -static void cbs_default_free_unit_content(FFRefStructOpaque opaque, void *content) +static void cbs_default_free_unit_content(AVRefStructOpaque opaque, void *content) { const CodedBitstreamUnitTypeDescriptor *desc = opaque.c; @@ -913,14 +928,14 @@ static const CodedBitstreamUnitTypeDescriptor static void *cbs_alloc_content(const CodedBitstreamUnitTypeDescriptor *desc) { - return ff_refstruct_alloc_ext_c(desc->content_size, 0, - (FFRefStructOpaque){ .c = desc }, + return av_refstruct_alloc_ext_c(desc->content_size, 0, + (AVRefStructOpaque){ .c = desc }, desc->content_type == CBS_CONTENT_TYPE_COMPLEX ? desc->type.complex.content_free : cbs_default_free_unit_content); } -int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, +int CBS_FUNC(alloc_unit_content)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { const CodedBitstreamUnitTypeDescriptor *desc; @@ -989,7 +1004,7 @@ static int cbs_clone_noncomplex_unit_content(void **clonep, return 0; fail: - ff_refstruct_unref(©); + av_refstruct_unref(©); return err; } @@ -1032,7 +1047,7 @@ static int cbs_clone_unit_content(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_refcounted)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { av_assert0(unit->content); @@ -1041,24 +1056,24 @@ int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, return cbs_clone_unit_content(ctx, unit); } -int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_writable)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { void *ref = unit->content_ref; int err; av_assert0(unit->content); - if (ref && ff_refstruct_exclusive(ref)) + if (ref && av_refstruct_exclusive(ref)) return 0; err = cbs_clone_unit_content(ctx, unit); if (err < 0) return err; - ff_refstruct_unref(&ref); + av_refstruct_unref(&ref); return 0; } -void ff_cbs_discard_units(CodedBitstreamContext *ctx, +void CBS_FUNC(discard_units)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, enum AVDiscard skip, int flags) @@ -1070,11 +1085,11 @@ void ff_cbs_discard_units(CodedBitstreamContext *ctx, if (ctx->codec->discarded_unit(ctx, &frag->units[i], skip)) { // discard all units if (!(flags & DISCARD_FLAG_KEEP_NON_VCL)) { - ff_cbs_fragment_free(frag); + CBS_FUNC(fragment_free)(frag); return; } - ff_cbs_delete_unit(frag, i); + CBS_FUNC(delete_unit)(frag, i); } } } diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index d479b1ac2d..8c4614479f 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -29,6 +29,13 @@ #include "defs.h" #include "packet.h" +#ifndef CBS_PREFIX +#define CBS_PREFIX cbs +#endif + +#define CBS_FUNC_PREFIX_NAME(prefix, name) ff_ ## prefix ## _ ## name +#define CBS_FUNC_NAME(prefix, name) CBS_FUNC_PREFIX_NAME(prefix, name) +#define CBS_FUNC(name) CBS_FUNC_NAME(CBS_PREFIX, name) /* * This defines a framework for converting between a coded bitstream @@ -294,24 +301,24 @@ typedef struct CodedBitstreamContext { * * Terminated by AV_CODEC_ID_NONE. */ -extern const enum AVCodecID ff_cbs_all_codec_ids[]; +extern const enum AVCodecID CBS_FUNC(all_codec_ids)[]; /** * Create and initialise a new context for the given codec. */ -int ff_cbs_init(CodedBitstreamContext **ctx, +int CBS_FUNC(init)(CodedBitstreamContext **ctx, enum AVCodecID codec_id, void *log_ctx); /** * Reset all internal state in a context. */ -void ff_cbs_flush(CodedBitstreamContext *ctx); +void CBS_FUNC(flush)(CodedBitstreamContext *ctx); /** * Close a context and free all internal state. */ -void ff_cbs_close(CodedBitstreamContext **ctx); +void CBS_FUNC(close)(CodedBitstreamContext **ctx); /** @@ -325,7 +332,7 @@ void ff_cbs_close(CodedBitstreamContext **ctx); * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVCodecParameters *par); @@ -336,11 +343,11 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, * This acts identical to ff_cbs_read_extradata() for the case where * you already have a codec context. */ -int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, +int CBS_FUNC(read_extradata_from_codec)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const struct AVCodecContext *avctx); -int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet_side_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt); @@ -355,7 +362,7 @@ int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx, * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(read_packet)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt); @@ -370,8 +377,9 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, * The fragment must have been zeroed or reset via ff_cbs_fragment_reset * before use. */ -int ff_cbs_read(CodedBitstreamContext *ctx, +int CBS_FUNC(read)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, + const AVBufferRef *buf, const uint8_t *data, size_t size); @@ -387,7 +395,7 @@ int ff_cbs_read(CodedBitstreamContext *ctx, * 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, +int CBS_FUNC(write_fragment_data)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag); /** @@ -396,7 +404,7 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, * Modifies context and fragment as ff_cbs_write_fragment_data does and * replaces any existing extradata in the structure. */ -int ff_cbs_write_extradata(CodedBitstreamContext *ctx, +int CBS_FUNC(write_extradata)(CodedBitstreamContext *ctx, AVCodecParameters *par, CodedBitstreamFragment *frag); @@ -410,7 +418,7 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, * fragment; other fields are not touched. On failure, the packet is not * touched at all. */ -int ff_cbs_write_packet(CodedBitstreamContext *ctx, +int CBS_FUNC(write_packet)(CodedBitstreamContext *ctx, AVPacket *pkt, CodedBitstreamFragment *frag); @@ -419,20 +427,20 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, * Free the units contained in a fragment as well as the fragment's * own data buffer, but not the units array itself. */ -void ff_cbs_fragment_reset(CodedBitstreamFragment *frag); +void CBS_FUNC(fragment_reset)(CodedBitstreamFragment *frag); /** * Free the units array of a fragment in addition to what * ff_cbs_fragment_reset does. */ -void ff_cbs_fragment_free(CodedBitstreamFragment *frag); +void CBS_FUNC(fragment_free)(CodedBitstreamFragment *frag); /** * Allocate a new internal content buffer matching the type of the unit. * * The content will be zeroed. */ -int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, +int CBS_FUNC(alloc_unit_content)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); /** @@ -443,7 +451,7 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, * The content structure continues to be owned by the caller if * content_ref is not supplied. */ -int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, +int CBS_FUNC(insert_unit_content)(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, @@ -456,7 +464,7 @@ int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, * av_malloc() and will on success become owned by the unit after this * call or freed on error. */ -int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, +int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, CodedBitstreamUnitType type, uint8_t *data, size_t data_size, AVBufferRef *data_buf); @@ -466,7 +474,7 @@ int ff_cbs_append_unit_data(CodedBitstreamFragment *frag, * * Requires position to be >= 0 and < frag->nb_units. */ -void ff_cbs_delete_unit(CodedBitstreamFragment *frag, +void CBS_FUNC(delete_unit)(CodedBitstreamFragment *frag, int position); @@ -479,7 +487,7 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag, * It is not valid to call this function on a unit which does not have * decomposed content. */ -int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_refcounted)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); /** @@ -495,7 +503,7 @@ int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, * It is not valid to call this function on a unit which does not have * decomposed content. */ -int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, +int CBS_FUNC(make_unit_writable)(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); enum CbsDiscardFlags { @@ -508,9 +516,9 @@ enum CbsDiscardFlags { }; /** - * Discard units accroding to 'skip'. + * Discard units according to 'skip'. */ -void ff_cbs_discard_units(CodedBitstreamContext *ctx, +void CBS_FUNC(discard_units)(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, enum AVDiscard skip, int flags); @@ -522,7 +530,7 @@ void ff_cbs_discard_units(CodedBitstreamContext *ctx, * * Trace context should be set to the CodedBitstreamContext. */ -void ff_cbs_trace_read_log(void *trace_context, +void CBS_FUNC(trace_read_log)(void *trace_context, struct GetBitContext *gbc, int length, const char *str, const int *subscripts, int64_t value); @@ -533,7 +541,7 @@ void ff_cbs_trace_read_log(void *trace_context, * * Trace context should be set to the CodedBitstreamContext. */ -void ff_cbs_trace_write_log(void *trace_context, +void CBS_FUNC(trace_write_log)(void *trace_context, struct PutBitContext *pbc, int length, const char *str, const int *subscripts, int64_t value); diff --git a/libavcodec/cbs_apv.c b/libavcodec/cbs_apv.c new file mode 100644 index 0000000000..fdc9042939 --- /dev/null +++ b/libavcodec/cbs_apv.c @@ -0,0 +1,460 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_apv.h" + + +static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh) +{ + switch (fh->frame_info.chroma_format_idc) { + case APV_CHROMA_FORMAT_400: + return 1; + case APV_CHROMA_FORMAT_422: + case APV_CHROMA_FORMAT_444: + return 3; + case APV_CHROMA_FORMAT_4444: + return 4; + default: + av_assert0(0 && "Invalid chroma_format_idc"); + } +} + +static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx, + const APVRawFrameHeader *fh) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; + int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; + int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs; + int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs; + + av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS); + + priv->num_tiles = tile_cols * tile_rows; +} + + +#define HEADER(name) do { \ + CBS_FUNC(trace_header)(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0, ) +#define ub(width, name) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0, ) +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0, ); \ + } while (0) + + +#if CBS_READ +#define READ +#define READWRITE read +#define RWContext GetBitContext +#define FUNC(name) cbs_apv_read_ ## name + +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value; \ + CHECK(CBS_FUNC(read_unsigned)(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_apv_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu +#undef infer +#undef byte_alignment +#endif // CBS_READ + +#if CBS_WRITE +#define WRITE +#define READWRITE write +#define RWContext PutBitContext +#define FUNC(name) cbs_apv_write_ ## name + +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = var; \ + CHECK(CBS_FUNC(write_unsigned)(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_apv_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu +#undef infer +#undef byte_alignment +#endif // CBS_WRITE + + +static int cbs_apv_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ +#if CBS_READ + uint8_t *data = frag->data; + size_t size = frag->data_size; + uint32_t signature; + int err, trace; + + if (header || !frag->data_size) { + // Ignore empty or extradata fragments. + return 0; + } + + if (frag->data_size < 4) { + // Too small to be a valid fragment. + return AVERROR_INVALIDDATA; + } + + // Don't include parsing here in trace output. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + signature = AV_RB32(data); + if (signature != APV_SIGNATURE) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid APV access unit: bad signature %08x.\n", + signature); + err = AVERROR_INVALIDDATA; + goto fail; + } + data += 4; + size -= 4; + + while (size > 0) { + GetBitContext gbc; + uint32_t pbu_size; + APVRawPBUHeader pbu_header; + + if (size < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "fragment too short (%"SIZE_SPECIFIER" bytes).\n", + size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + pbu_size = AV_RB32(data); + if (pbu_size < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "pbu_size too small (%"PRIu32" bytes).\n", + pbu_size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + data += 4; + size -= 4; + + if (pbu_size > size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: " + "pbu_size too large (%"PRIu32" bytes).\n", + pbu_size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + init_get_bits(&gbc, data, 8 * pbu_size); + + err = cbs_apv_read_pbu_header(ctx, &gbc, &pbu_header); + if (err < 0) + goto fail; + + // Could select/skip frames based on type/group_id here. + + err = CBS_FUNC(append_unit_data)(frag, pbu_header.pbu_type, + data, pbu_size, frag->data_ref); + if (err < 0) + goto fail; + + data += pbu_size; + size -= pbu_size; + } + + err = 0; +fail: + ctx->trace_enable = trace; + return err; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ +#if CBS_READ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = CBS_FUNC(alloc_unit_content)(ctx, unit); + if (err < 0) + return err; + + switch (unit->type) { + case APV_PBU_PRIMARY_FRAME: + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + { + APVRawFrame *frame = unit->content; + + err = cbs_apv_read_frame(ctx, &gbc, frame); + if (err < 0) + return err; + + // Each tile inside the frame has pointers into the unit + // data buffer; make a single reference here for all of + // them together. + frame->tile_data_ref = av_buffer_ref(unit->data_ref); + if (!frame->tile_data_ref) + return AVERROR(ENOMEM); + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + { + err = cbs_apv_read_au_info(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_METADATA: + { + err = cbs_apv_read_metadata(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_FILLER: + { + err = cbs_apv_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ +#if CBS_WRITE + int err; + + switch (unit->type) { + case APV_PBU_PRIMARY_FRAME: + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + { + APVRawFrame *frame = unit->content; + + err = cbs_apv_write_frame(ctx, pbc, frame); + if (err < 0) + return err; + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + { + err = cbs_apv_write_au_info(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_METADATA: + { + err = cbs_apv_write_metadata(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + case APV_PBU_FILLER: + { + err = cbs_apv_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + +static int cbs_apv_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ +#if CBS_WRITE + size_t size = 4, pos; + + for (int i = 0; i < frag->nb_units; i++) + size += frag->units[i].data_size + 4; + + 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; + memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + AV_WB32(frag->data, APV_SIGNATURE); + pos = 4; + for (int i = 0; i < frag->nb_units; i++) { + AV_WB32(frag->data + pos, frag->units[i].data_size); + pos += 4; + + memcpy(frag->data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(pos == size); + frag->data_size = size; + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + + +static void cbs_apv_free_metadata(AVRefStructOpaque unused, void *content) +{ + APVRawMetadata *md = content; + av_assert0(md->pbu_header.pbu_type == APV_PBU_METADATA); + + for (int i = 0; i < md->metadata_count; i++) { + APVRawMetadataPayload *pl = &md->payloads[i]; + + switch (pl->payload_type) { + case APV_METADATA_MDCV: + case APV_METADATA_CLL: + case APV_METADATA_FILLER: + break; + case APV_METADATA_ITU_T_T35: + av_buffer_unref(&pl->itu_t_t35.data_ref); + break; + case APV_METADATA_USER_DEFINED: + av_buffer_unref(&pl->user_defined.data_ref); + break; + default: + av_buffer_unref(&pl->undefined.data_ref); + } + } +} + +static const CodedBitstreamUnitTypeDescriptor cbs_apv_unit_types[] = { + { + .nb_unit_types = CBS_UNIT_TYPE_RANGE, + .unit_type.range = { + .start = APV_PBU_PRIMARY_FRAME, + .end = APV_PBU_ALPHA_FRAME, + }, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(APVRawFrame), + .type.ref = { + .nb_offsets = 1, + .offsets = { offsetof(APVRawFrame, tile_data_ref) - + sizeof(void*) }, + }, + }, + + CBS_UNIT_TYPE_COMPLEX(APV_PBU_METADATA, APVRawMetadata, + &cbs_apv_free_metadata), + + CBS_UNIT_TYPE_POD(APV_PBU_ACCESS_UNIT_INFORMATION, APVRawAUInfo), + CBS_UNIT_TYPE_POD(APV_PBU_FILLER, APVRawFiller), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType CBS_FUNC(type_apv) = { + .codec_id = AV_CODEC_ID_APV, + + .priv_data_size = sizeof(CodedBitstreamAPVContext), + + .unit_types = cbs_apv_unit_types, + + .split_fragment = &cbs_apv_split_fragment, + .read_unit = &cbs_apv_read_unit, + .write_unit = &cbs_apv_write_unit, + .assemble_fragment = &cbs_apv_assemble_fragment, +}; diff --git a/libavcodec/cbs_apv.h b/libavcodec/cbs_apv.h new file mode 100644 index 0000000000..d91372e644 --- /dev/null +++ b/libavcodec/cbs_apv.h @@ -0,0 +1,197 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_APV_H +#define AVCODEC_CBS_APV_H + +#include +#include + +#include "libavutil/buffer.h" +#include "apv.h" + +// Arbitrary limits to avoid large structures. +#define CBS_APV_MAX_AU_FRAMES 8 +#define CBS_APV_MAX_METADATA_PAYLOADS 8 + + +typedef struct APVRawPBUHeader { + uint8_t pbu_type; + uint16_t group_id; + uint8_t reserved_zero_8bits; +} APVRawPBUHeader; + +typedef struct APVRawFiller { + size_t filler_size; +} APVRawFiller; + +typedef struct APVRawFrameInfo { + uint8_t profile_idc; + uint8_t level_idc; + uint8_t band_idc; + uint8_t reserved_zero_5bits; + uint32_t frame_width; + uint32_t frame_height; + uint8_t chroma_format_idc; + uint8_t bit_depth_minus8; + uint8_t capture_time_distance; + uint8_t reserved_zero_8bits; +} APVRawFrameInfo; + +typedef struct APVRawQuantizationMatrix { + uint8_t q_matrix[APV_MAX_NUM_COMP][APV_TR_SIZE][APV_TR_SIZE]; +} APVRawQuantizationMatrix; + +typedef struct APVRawTileInfo { + uint32_t tile_width_in_mbs; + uint32_t tile_height_in_mbs; + uint8_t tile_size_present_in_fh_flag; + uint32_t tile_size_in_fh[APV_MAX_TILE_COUNT]; +} APVRawTileInfo; + +typedef struct APVRawFrameHeader { + APVRawFrameInfo frame_info; + uint8_t reserved_zero_8bits; + + uint8_t color_description_present_flag; + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t full_range_flag; + + uint8_t use_q_matrix; + APVRawQuantizationMatrix quantization_matrix; + + APVRawTileInfo tile_info; + + uint8_t reserved_zero_8bits_2; +} APVRawFrameHeader; + +typedef struct APVRawTileHeader { + uint16_t tile_header_size; + uint16_t tile_index; + uint32_t tile_data_size[APV_MAX_NUM_COMP]; + uint8_t tile_qp [APV_MAX_NUM_COMP]; + uint8_t reserved_zero_8bits; +} APVRawTileHeader; + +typedef struct APVRawTile { + APVRawTileHeader tile_header; + + uint8_t *tile_data[APV_MAX_NUM_COMP]; + uint8_t *tile_dummy_byte; + uint32_t tile_dummy_byte_size; +} APVRawTile; + +typedef struct APVRawFrame { + APVRawPBUHeader pbu_header; + APVRawFrameHeader frame_header; + uint32_t tile_size[APV_MAX_TILE_COUNT]; + APVRawTile tile [APV_MAX_TILE_COUNT]; + APVRawFiller filler; + + AVBufferRef *tile_data_ref; +} APVRawFrame; + +typedef struct APVRawAUInfo { + uint16_t num_frames; + + uint8_t pbu_type [CBS_APV_MAX_AU_FRAMES]; + uint8_t group_id [CBS_APV_MAX_AU_FRAMES]; + uint8_t reserved_zero_8bits[CBS_APV_MAX_AU_FRAMES]; + APVRawFrameInfo frame_info [CBS_APV_MAX_AU_FRAMES]; + + uint8_t reserved_zero_8bits_2; + + APVRawFiller filler; +} APVRawAUInfo; + +typedef struct APVRawMetadataITUTT35 { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataITUTT35; + +typedef struct APVRawMetadataMDCV { + uint16_t primary_chromaticity_x[3]; + uint16_t primary_chromaticity_y[3]; + uint16_t white_point_chromaticity_x; + uint16_t white_point_chromaticity_y; + uint32_t max_mastering_luminance; + uint32_t min_mastering_luminance; +} APVRawMetadataMDCV; + +typedef struct APVRawMetadataCLL { + uint16_t max_cll; + uint16_t max_fall; +} APVRawMetadataCLL; + +typedef struct APVRawMetadataFiller { + uint32_t payload_size; +} APVRawMetadataFiller; + +typedef struct APVRawMetadataUserDefined { + uint8_t uuid[16]; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataUserDefined; + +typedef struct APVRawMetadataUndefined { + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} APVRawMetadataUndefined; + +typedef struct APVRawMetadataPayload { + uint32_t payload_type; + uint32_t payload_size; + union { + APVRawMetadataITUTT35 itu_t_t35; + APVRawMetadataMDCV mdcv; + APVRawMetadataCLL cll; + APVRawMetadataFiller filler; + APVRawMetadataUserDefined user_defined; + APVRawMetadataUndefined undefined; + }; +} APVRawMetadataPayload; + +typedef struct APVRawMetadata { + APVRawPBUHeader pbu_header; + + uint32_t metadata_size; + uint32_t metadata_count; + + APVRawMetadataPayload payloads[CBS_APV_MAX_METADATA_PAYLOADS]; + + APVRawFiller filler; +} APVRawMetadata; + + +typedef struct CodedBitstreamAPVContext { + int bit_depth; + int num_comp; + + uint16_t num_tiles; +} CodedBitstreamAPVContext; + +#endif /* AVCODEC_CBS_APV_H */ diff --git a/libavcodec/cbs_apv_syntax_template.c b/libavcodec/cbs_apv_syntax_template.c new file mode 100644 index 0000000000..621595ffbf --- /dev/null +++ b/libavcodec/cbs_apv_syntax_template.c @@ -0,0 +1,614 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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(pbu_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawPBUHeader *current) +{ + int err; + + ub(8, pbu_type); + ub(16, group_id); + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + + while (byte_alignment(rw) != 0) + fixed(1, alignment_bit_equal_to_zero, 0); + + return 0; +} + +static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFiller *current) +{ + int err; + +#ifdef READ + current->filler_size = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + ++current->filler_size; + } +#else + { + uint32_t i; + for (i = 0; i < current->filler_size; i++) + fixed(8, ff_byte, 0xff); + } +#endif + + return 0; +} + +static int FUNC(frame_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrameInfo *current) +{ + int err; + + ub(8, profile_idc); + ub(8, level_idc); + ub(3, band_idc); + + u(5, reserved_zero_5bits, 0, 0); + + ub(24, frame_width); + ub(24, frame_height); + + u(4, chroma_format_idc, 0, 4); + if (current->chroma_format_idc == 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "chroma_format_idc 1 for 4:2:0 is not allowed in APV.\n"); + return AVERROR_INVALIDDATA; + } + + u(4, bit_depth_minus8, 2, 8); + + ub(8, capture_time_distance); + + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(quantization_matrix)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawQuantizationMatrix *current) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + for (int c = 0; c < priv->num_comp; c++) { + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8 ; x++) { + us(8, q_matrix[c][x][y], 1, 255, 3, c, x, y); + } + } + } + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTileInfo *current, + const APVRawFrameHeader *fh) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; + int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; + uint32_t min_tile_width = FFMAX(APV_MIN_TILE_WIDTH_IN_MBS, + (frame_width_in_mbs + APV_MAX_TILE_COLS - 1) / + APV_MAX_TILE_COLS); + uint32_t min_tile_height = FFMAX(APV_MIN_TILE_HEIGHT_IN_MBS, + (frame_height_in_mbs + APV_MAX_TILE_ROWS - 1) / + APV_MAX_TILE_ROWS); + int err; + + u(20, tile_width_in_mbs, min_tile_width, MAX_UINT_BITS(20)); + u(20, tile_height_in_mbs, min_tile_height, MAX_UINT_BITS(20)); + + ub(1, tile_size_present_in_fh_flag); + + cbs_apv_derive_tile_info(ctx, fh); + + if (current->tile_size_present_in_fh_flag) { + for (int t = 0; t < priv->num_tiles; t++) { + us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); + } + } + + return 0; +} + +static int FUNC(frame_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrameHeader *current) +{ + CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info)); + + u(8, reserved_zero_8bits, 0, 0); + + ub(1, color_description_present_flag); + if (current->color_description_present_flag) { + ub(8, color_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); + ub(1, full_range_flag); + } else { + infer(color_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + infer(full_range_flag, 0); + } + + priv->bit_depth = current->frame_info.bit_depth_minus8 + 8; + priv->num_comp = cbs_apv_get_num_comp(current); + + ub(1, use_q_matrix); + if (current->use_q_matrix) { + CHECK(FUNC(quantization_matrix)(ctx, rw, + ¤t->quantization_matrix)); + } else { + for (int c = 0; c < priv->num_comp; c++) { + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8 ; x++) { + infer(quantization_matrix.q_matrix[c][y][x], 16); + } + } + } + } + + CHECK(FUNC(tile_info)(ctx, rw, ¤t->tile_info, current)); + + u(8, reserved_zero_8bits_2, 0, 0); + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + return 0; +} + +static int FUNC(tile_header)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTileHeader *current, + int tile_idx, uint32_t tile_size) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + uint16_t expected_tile_header_size; + uint32_t tile_size_remaining; + uint8_t max_qp; + int err; + + expected_tile_header_size = 4 + priv->num_comp * (4 + 1) + 1; + + u(16, tile_header_size, + expected_tile_header_size, expected_tile_header_size); + + u(16, tile_index, tile_idx, tile_idx); + + tile_size_remaining = tile_size - current->tile_header_size; + for (int c = 0; c < priv->num_comp; c++) { + us(32, tile_data_size[c], 1, tile_size_remaining, 1, c); + tile_size_remaining -= current->tile_data_size[c]; + } + + max_qp = 3 + priv->bit_depth * 6; + for (int c = 0; c < priv->num_comp; c++) { + us(8, tile_qp[c], 0, max_qp, 1, c); + } + + u(8, reserved_zero_8bits, 0, 0); + + return 0; +} + +static int FUNC(tile)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawTile *current, + int tile_idx, uint32_t tile_size) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + CHECK(FUNC(tile_header)(ctx, rw, ¤t->tile_header, + tile_idx, tile_size)); + + for (int c = 0; c < priv->num_comp; c++) { + uint32_t comp_size = current->tile_header.tile_data_size[c]; +#ifdef READ + int pos = get_bits_count(rw); + av_assert0(pos % 8 == 0); + if (get_bits_left(rw) < 8LL * comp_size) + return AVERROR_INVALIDDATA; + current->tile_data[c] = (uint8_t*)align_get_bits(rw); + skip_bits_long(rw, 8 * comp_size); +#else + if (put_bytes_left(rw, 0) < comp_size) + return AVERROR(ENOSPC); + ff_copy_bits(rw, current->tile_data[c], comp_size * 8); +#endif + } + + return 0; +} + +static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawFrame *current) +{ + const CodedBitstreamAPVContext *priv = ctx->priv_data; + int err; + + HEADER("Frame"); + + CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header)); + + CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); + + for (int t = 0; t < priv->num_tiles; t++) { + us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); + + CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], + t, current->tile_size[t])); + } + + CHECK(FUNC(filler)(ctx, rw, ¤t->filler)); + + return 0; +} + +static int FUNC(au_info)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawAUInfo *current) +{ + int err; + + HEADER("Access Unit Information"); + + u(16, num_frames, 1, CBS_APV_MAX_AU_FRAMES); + + for (int i = 0; i < current->num_frames; i++) { + ubs(8, pbu_type[i], 1, i); + ubs(8, group_id[i], 1, i); + + us(8, reserved_zero_8bits[i], 0, 0, 1, i); + + CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info[i])); + } + + u(8, reserved_zero_8bits_2, 0, 0); + + return 0; +} + +static int FUNC(metadata_itu_t_t35)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataITUTT35 *current, + size_t payload_size) +{ + int err; + size_t read_size = payload_size - 1; + + HEADER("ITU-T T.35 Metadata"); + + ub(8, itu_t_t35_country_code); + + if (current->itu_t_t35_country_code == 0xff) { + ub(8, itu_t_t35_country_code_extension); + --read_size; + } + +#ifdef READ + current->data_size = read_size; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != read_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, read_size); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, itu_t_t35_payload[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_mdcv)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataMDCV *current) +{ + int err, i; + + HEADER("MDCV Metadata"); + + for (i = 0; i < 3; i++) { + ubs(16, primary_chromaticity_x[i], 1, i); + ubs(16, primary_chromaticity_y[i], 1, i); + } + + ub(16, white_point_chromaticity_x); + ub(16, white_point_chromaticity_y); + + ub(32, max_mastering_luminance); + ub(32, min_mastering_luminance); + + return 0; +} + +static int FUNC(metadata_cll)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataCLL *current) +{ + int err; + + HEADER("CLL Metadata"); + + ub(16, max_cll); + ub(16, max_fall); + + return 0; +} + +static int FUNC(metadata_filler)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataFiller *current, + size_t payload_size) +{ + int err; + + HEADER("Filler Metadata"); + + for (size_t i = 0; i < payload_size; i++) + fixed(8, ff_byte, 0xff); + + return 0; +} + +static int FUNC(metadata_user_defined)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataUserDefined *current, + size_t payload_size) +{ + int err; + + HEADER("User-Defined Metadata"); + + for (int i = 0; i < 16; i++) + ubs(8, uuid[i], 1, i); + +#ifdef READ + current->data_size = payload_size - 16; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != payload_size - 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, payload_size - 16); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, user_defined_data_payload[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_undefined)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataUndefined *current, + size_t payload_size) +{ + int err; + + HEADER("Undefined Metadata"); + +#ifdef READ + current->data_size = payload_size; + current->data_ref = av_buffer_alloc(current->data_size); + if (!current->data_ref) + return AVERROR(ENOMEM); + current->data = current->data_ref->data; +#else + if (current->data_size != payload_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: " + "payload %zu but expecting %zu\n", + current->data_size, payload_size - 16); + return AVERROR(EINVAL); + } +#endif + + for (size_t i = 0; i < current->data_size; i++) { + xu(8, undefined_metadata_payload_byte[i], + current->data[i], 0x00, 0xff, 1, i); + } + + return 0; +} + +static int FUNC(metadata_payload)(CodedBitstreamContext *ctx, + RWContext *rw, + APVRawMetadataPayload *current) +{ + int err; + + switch (current->payload_type) { + case APV_METADATA_ITU_T_T35: + CHECK(FUNC(metadata_itu_t_t35)(ctx, rw, + ¤t->itu_t_t35, + current->payload_size)); + break; + case APV_METADATA_MDCV: + CHECK(FUNC(metadata_mdcv)(ctx, rw, ¤t->mdcv)); + break; + case APV_METADATA_CLL: + CHECK(FUNC(metadata_cll)(ctx, rw, ¤t->cll)); + break; + case APV_METADATA_FILLER: + CHECK(FUNC(metadata_filler)(ctx, rw, + ¤t->filler, + current->payload_size)); + break; + case APV_METADATA_USER_DEFINED: + CHECK(FUNC(metadata_user_defined)(ctx, rw, + ¤t->user_defined, + current->payload_size)); + break; + default: + CHECK(FUNC(metadata_undefined)(ctx, rw, + ¤t->undefined, + current->payload_size)); + } + + return 0; +} + +static int FUNC(metadata)(CodedBitstreamContext *ctx, RWContext *rw, + APVRawMetadata *current) +{ + int err; + +#ifdef READ + uint32_t metadata_bytes_left; +#else + PutBitContext metadata_start_state; + uint32_t metadata_start_position; + int trace; +#endif + + HEADER("Metadata"); + + CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header)); + +#ifdef READ + ub(32, metadata_size); + + metadata_bytes_left = current->metadata_size; + + for (int p = 0; p < CBS_APV_MAX_METADATA_PAYLOADS; p++) { + APVRawMetadataPayload *pl = ¤t->payloads[p]; + uint32_t tmp; + + pl->payload_type = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + pl->payload_type += 255; + --metadata_bytes_left; + } + xu(8, metadata_payload_type, tmp, 0, 254, 0); + pl->payload_type += tmp; + --metadata_bytes_left; + + pl->payload_size = 0; + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + pl->payload_size += 255; + --metadata_bytes_left; + } + xu(8, metadata_payload_size, tmp, 0, 254, 0); + pl->payload_size += tmp; + --metadata_bytes_left; + + if (pl->payload_size > metadata_bytes_left) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid metadata: " + "payload_size larger than remaining metadata size " + "(%"PRIu32" bytes).\n", pl->payload_size); + return AVERROR_INVALIDDATA; + } + + current->metadata_count = p + 1; + + CHECK(FUNC(metadata_payload)(ctx, rw, pl)); + + metadata_bytes_left -= pl->payload_size; + if (metadata_bytes_left == 0) + break; + } +#else + // Two passes: the first write finds the size (with tracing + // disabled), the second write does the real write. + + metadata_start_state = *rw; + metadata_start_position = put_bits_count(rw); + + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + for (int pass = 1; pass <= 2; pass++) { + *rw = metadata_start_state; + + ub(32, metadata_size); + + for (int p = 0; p < current->metadata_count; p++) { + APVRawMetadataPayload *pl = ¤t->payloads[p]; + uint32_t payload_start_position; + uint32_t tmp; + + tmp = pl->payload_type; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, metadata_payload_type, tmp, 0, 254, 0); + + tmp = pl->payload_size; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, metadata_payload_size, tmp, 0, 254, 0); + + payload_start_position = put_bits_count(rw); + + err = FUNC(metadata_payload)(ctx, rw, pl); + ctx->trace_enable = trace; + if (err < 0) + return err; + + if (pass == 1) { + pl->payload_size = (put_bits_count(rw) - + payload_start_position) / 8; + } + } + + if (pass == 1) { + current->metadata_size = (put_bits_count(rw) - + metadata_start_position) / 8 - 4; + ctx->trace_enable = trace; + } + } +#endif + + CHECK(FUNC(filler)(ctx, rw, ¤t->filler)); + + return 0; +} diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 458381f038..4edb6ecd50 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -24,9 +24,10 @@ #include "cbs_internal.h" #include "cbs_av1.h" #include "defs.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" +#if CBS_READ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, uint32_t *write_to, uint32_t range_min, uint32_t range_max) @@ -84,7 +85,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, uint32_t value, uint32_t range_min, uint32_t range_max) @@ -115,7 +118,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, uint64_t *write_to) { @@ -146,7 +151,9 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, const char *name, uint64_t value, int fixed_length) { @@ -182,7 +189,9 @@ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t n, const char *name, const int *subscripts, uint32_t *write_to) @@ -220,7 +229,9 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t n, const char *name, const int *subscripts, uint32_t value) @@ -256,7 +267,9 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +#endif +#if CBS_READ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t range_min, uint32_t range_max, const char *name, uint32_t *write_to) @@ -284,7 +297,9 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc *write_to = value; return 0; } +#endif +#if CBS_WRITE static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t range_min, uint32_t range_max, const char *name, uint32_t value) @@ -315,7 +330,9 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb return 0; } +#endif +#if CBS_READ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, uint32_t range_max, const char *name, const int *subscripts, uint32_t *write_to) @@ -342,7 +359,7 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, } if (len < max_len) { - err = ff_cbs_read_simple_unsigned(ctx, gbc, range_bits, + err = CBS_FUNC(read_simple_unsigned)(ctx, gbc, range_bits, "subexp_bits", &value); if (err < 0) return err; @@ -360,7 +377,9 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, *write_to = value; return err; } +#endif +#if CBS_WRITE static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, uint32_t range_max, const char *name, const int *subscripts, uint32_t value) @@ -402,7 +421,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, return err; if (len < max_len) { - err = ff_cbs_write_simple_unsigned(ctx, pbc, range_bits, + err = CBS_FUNC(write_simple_unsigned)(ctx, pbc, range_bits, "subexp_bits", value - range_offset); if (err < 0) @@ -420,6 +439,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, return err; } +#endif static int cbs_av1_tile_log2(int blksize, int target) @@ -441,7 +461,7 @@ static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq, return diff; } -static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) +static av_unused size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) { GetBitContext tmp = *gbc; size_t size = 0; @@ -454,7 +474,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define HEADER(name) do { \ - ff_cbs_trace_header(ctx, name); \ + CBS_FUNC(trace_header)(ctx, name); \ } while (0) #define CHECK(call) do { \ @@ -469,6 +489,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) +#if CBS_READ #define fc(width, name, range_min, range_max) \ xf(width, name, current->name, range_min, range_max, 0, ) #define flag(name) fb(1, name) @@ -496,14 +517,14 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define fb(width, name) do { \ uint32_t value; \ - CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, \ + CHECK(CBS_FUNC(read_simple_unsigned)(ctx, rw, width, \ #name, &value)); \ current->name = value; \ } while (0) #define xf(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value; \ - CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(read_unsigned)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ @@ -511,7 +532,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #define xsu(width, name, var, subs, ...) do { \ int32_t value; \ - CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(read_signed)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), &value, \ MIN_INT_BITS(width), \ MAX_INT_BITS(width))); \ @@ -584,25 +605,27 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #undef leb128 #undef infer #undef byte_alignment +#endif // CBS_READ +#if CBS_WRITE #define WRITE #define READWRITE write #define RWContext PutBitContext #define fb(width, name) do { \ - CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_simple_unsigned)(ctx, rw, width, #name, \ current->name)); \ } while (0) #define xf(width, name, var, range_min, range_max, subs, ...) do { \ - CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_unsigned)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), \ var, range_min, range_max)); \ } while (0) #define xsu(width, name, var, subs, ...) do { \ - CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + CHECK(CBS_FUNC(write_signed)(ctx, rw, width, #name, \ SUBSCRIPTS(subs, __VA_ARGS__), var, \ MIN_INT_BITS(width), \ MAX_INT_BITS(width))); \ @@ -668,12 +691,13 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) #undef leb128 #undef infer #undef byte_alignment - +#endif // CBS_WRITE static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, int header) { +#if CBS_READ GetBitContext gbc; uint8_t *data; size_t size; @@ -728,16 +752,16 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, } while (size > 0) { - AV1RawOBUHeader header; + AV1RawOBUHeader obu_header; uint64_t obu_size; init_get_bits(&gbc, data, 8 * size); - err = cbs_av1_read_obu_header(ctx, &gbc, &header); + err = cbs_av1_read_obu_header(ctx, &gbc, &obu_header); if (err < 0) goto fail; - if (header.obu_has_size_field) { + if (obu_header.obu_has_size_field) { if (get_bits_left(&gbc) < 8) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU: fragment " "too short (%"SIZE_SPECIFIER" bytes).\n", size); @@ -748,7 +772,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, if (err < 0) goto fail; } else - obu_size = size - 1 - header.obu_extension_flag; + obu_size = size - 1 - obu_header.obu_extension_flag; pos = get_bits_count(&gbc); av_assert0(pos % 8 == 0 && pos / 8 <= size); @@ -763,7 +787,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, goto fail; } - err = ff_cbs_append_unit_data(frag, header.obu_type, + err = CBS_FUNC(append_unit_data)(frag, obu_header.obu_type, data, obu_length, frag->data_ref); if (err < 0) goto fail; @@ -777,12 +801,17 @@ success: fail: ctx->trace_enable = trace; return err; +#else + return AVERROR(ENOSYS); +#endif } +#if CBS_READ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, GetBitContext *gbc, - AV1RawTileData *td) + AVBufferRef **data_ref, + uint8_t **data, size_t *data_size) { int pos; @@ -795,25 +824,27 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, // Must be byte-aligned at this point. av_assert0(pos % 8 == 0); - td->data_ref = av_buffer_ref(unit->data_ref); - if (!td->data_ref) + *data_ref = av_buffer_ref(unit->data_ref); + if (!*data_ref) return AVERROR(ENOMEM); - td->data = unit->data + pos / 8; - td->data_size = unit->data_size - pos / 8; + *data = unit->data + pos / 8; + *data_size = unit->data_size - pos / 8; return 0; } +#endif static int cbs_av1_read_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit) { +#if CBS_READ CodedBitstreamAV1Context *priv = ctx->priv_data; AV1RawOBU *obu; GetBitContext gbc; int err, start_pos, end_pos; - err = ff_cbs_alloc_unit_content(ctx, unit); + err = CBS_FUNC(alloc_unit_content)(ctx, unit); if (err < 0) return err; obu = unit->content; @@ -878,7 +909,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, priv->operating_point_idc = sequence_header->operating_point_idc[priv->operating_point]; } - ff_refstruct_replace(&priv->sequence_header_ref, unit->content_ref); + av_refstruct_replace(&priv->sequence_header_ref, unit->content_ref); priv->sequence_header = &obu->obu.sequence_header; } break; @@ -901,32 +932,36 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; - case AV1_OBU_TILE_GROUP: - { - err = cbs_av1_read_tile_group_obu(ctx, &gbc, - &obu->obu.tile_group); - if (err < 0) - return err; - - err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.tile_group.tile_data); - if (err < 0) - return err; - } - break; case AV1_OBU_FRAME: - { err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame, unit->data_ref); if (err < 0) return err; + // fall-through + case AV1_OBU_TILE_GROUP: + { + AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group + : &obu->obu.tile_group; + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &tile_group->data_ref, + &tile_group->data, + &tile_group->data_size); + if (err < 0) + return err; + + err = cbs_av1_read_tile_group_obu(ctx, &gbc, tile_group); + if (err < 0) + return err; err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.frame.tile_group.tile_data); + &tile_group->tile_data.data_ref, + &tile_group->tile_data.data, + &tile_group->tile_data.data_size); if (err < 0) return err; } break; +#if CBS_AV1_OBU_TILE_LIST case AV1_OBU_TILE_LIST: { err = cbs_av1_read_tile_list_obu(ctx, &gbc, @@ -935,11 +970,15 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; err = cbs_av1_ref_tile_data(ctx, unit, &gbc, - &obu->obu.tile_list.tile_data); + &obu->obu.tile_list.tile_data.data_ref, + &obu->obu.tile_list.tile_data.data, + &obu->obu.tile_list.tile_data.data_size); if (err < 0) return err; } break; +#endif +#if CBS_AV1_OBU_METADATA case AV1_OBU_METADATA: { err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata); @@ -947,6 +986,8 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; +#endif +#if CBS_AV1_OBU_PADDING case AV1_OBU_PADDING: { err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding); @@ -954,6 +995,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, return err; } break; +#endif default: return AVERROR(ENOSYS); } @@ -976,12 +1018,16 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx, } return 0; +#else + return AVERROR(ENOSYS); +#endif } static int cbs_av1_write_obu(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc) { +#if CBS_WRITE CodedBitstreamAV1Context *priv = ctx->priv_data; AV1RawOBU *obu = unit->content; PutBitContext pbc_tmp; @@ -997,7 +1043,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, av1ctx = *priv; if (priv->sequence_header_ref) { - av1ctx.sequence_header_ref = ff_refstruct_ref(priv->sequence_header_ref); + av1ctx.sequence_header_ref = av_refstruct_ref(priv->sequence_header_ref); } if (priv->frame_header_ref) { @@ -1035,14 +1081,14 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, if (err < 0) goto error; - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); priv->sequence_header = NULL; - err = ff_cbs_make_unit_refcounted(ctx, unit); + err = CBS_FUNC(make_unit_refcounted)(ctx, unit); if (err < 0) goto error; - priv->sequence_header_ref = ff_refstruct_ref(unit->content_ref); + priv->sequence_header_ref = av_refstruct_ref(unit->content_ref); priv->sequence_header = &obu->obu.sequence_header; } break; @@ -1065,25 +1111,23 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; - case AV1_OBU_TILE_GROUP: - { - err = cbs_av1_write_tile_group_obu(ctx, pbc, - &obu->obu.tile_group); - if (err < 0) - goto error; - - td = &obu->obu.tile_group.tile_data; - } - break; case AV1_OBU_FRAME: - { err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL); if (err < 0) goto error; + // fall-through + case AV1_OBU_TILE_GROUP: + { + AV1RawTileGroup *tile_group = obu->header.obu_type == AV1_OBU_FRAME ? &obu->obu.frame.tile_group + : &obu->obu.tile_group; + err = cbs_av1_write_tile_group_obu(ctx, pbc, tile_group); + if (err < 0) + goto error; - td = &obu->obu.frame.tile_group.tile_data; + td = &tile_group->tile_data; } break; +#if CBS_AV1_OBU_TILE_LIST case AV1_OBU_TILE_LIST: { err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list); @@ -1093,6 +1137,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, td = &obu->obu.tile_list.tile_data; } break; +#endif +#if CBS_AV1_OBU_METADATA case AV1_OBU_METADATA: { err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata); @@ -1100,6 +1146,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; +#endif +#if CBS_AV1_OBU_PADDING case AV1_OBU_PADDING: { err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding); @@ -1107,6 +1155,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, goto error; } break; +#endif default: err = AVERROR(ENOSYS); goto error; @@ -1146,7 +1195,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, av_assert0(data_pos <= start_pos); if (8 * obu->obu_size > put_bits_left(pbc)) { - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); av_buffer_unref(&priv->frame_header_ref); *priv = av1ctx; @@ -1175,15 +1224,19 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, err = 0; error: - ff_refstruct_unref(&av1ctx.sequence_header_ref); + av_refstruct_unref(&av1ctx.sequence_header_ref); av_buffer_unref(&av1ctx.frame_header_ref); return err; +#else + return AVERROR(ENOSYS); +#endif } static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { +#if CBS_WRITE size_t size, pos; int i; @@ -1207,6 +1260,9 @@ static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, frag->data_size = size; return 0; +#else + return AVERROR(ENOSYS); +#endif } static void cbs_av1_flush(CodedBitstreamContext *ctx) @@ -1227,11 +1283,12 @@ static void cbs_av1_close(CodedBitstreamContext *ctx) { CodedBitstreamAV1Context *priv = ctx->priv_data; - ff_refstruct_unref(&priv->sequence_header_ref); + av_refstruct_unref(&priv->sequence_header_ref); av_buffer_unref(&priv->frame_header_ref); } -static void cbs_av1_free_metadata(FFRefStructOpaque unused, void *content) +#if CBS_AV1_OBU_METADATA +static void cbs_av1_free_metadata(AVRefStructOpaque unused, void *content) { AV1RawOBU *obu = content; AV1RawMetadata *md; @@ -1252,24 +1309,49 @@ static void cbs_av1_free_metadata(FFRefStructOpaque unused, void *content) av_buffer_unref(&md->metadata.unknown.payload_ref); } } +#endif static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = { CBS_UNIT_TYPE_POD(AV1_OBU_SEQUENCE_HEADER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_TEMPORAL_DELIMITER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_FRAME_HEADER, AV1RawOBU), CBS_UNIT_TYPE_POD(AV1_OBU_REDUNDANT_FRAME_HEADER, AV1RawOBU), + { + .nb_unit_types = 1, + .unit_type.list[0] = AV1_OBU_TILE_GROUP, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(AV1RawOBU), + .type.ref = { + .nb_offsets = 2, + .offsets = { offsetof(AV1RawOBU, obu.tile_group.data), + offsetof(AV1RawOBU, obu.tile_group.tile_data.data) } + }, + }, - CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_GROUP, AV1RawOBU, - obu.tile_group.tile_data.data), - CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_FRAME, AV1RawOBU, - obu.frame.tile_group.tile_data.data), + { + .nb_unit_types = 1, + .unit_type.list[0] = AV1_OBU_FRAME, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(AV1RawOBU), + .type.ref = { + .nb_offsets = 2, + .offsets = { offsetof(AV1RawOBU, obu.frame.tile_group.data), + offsetof(AV1RawOBU, obu.frame.tile_group.tile_data.data) } + }, + }, +#if CBS_AV1_OBU_TILE_LIST CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU, obu.tile_list.tile_data.data), +#endif +#if CBS_AV1_OBU_PADDING CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU, obu.padding.payload), +#endif +#if CBS_AV1_OBU_METADATA CBS_UNIT_TYPE_COMPLEX(AV1_OBU_METADATA, AV1RawOBU, &cbs_av1_free_metadata), +#endif CBS_UNIT_TYPE_END_OF_LIST }; @@ -1290,7 +1372,7 @@ static const AVClass cbs_av1_class = { .version = LIBAVUTIL_VERSION_INT, }; -const CodedBitstreamType ff_cbs_type_av1 = { +const CodedBitstreamType CBS_FUNC(type_av1) = { .codec_id = AV_CODEC_ID_AV1, .priv_class = &cbs_av1_class, diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h index 8586f2bf4a..874f64561f 100644 --- a/libavcodec/cbs_av1.h +++ b/libavcodec/cbs_av1.h @@ -25,6 +25,15 @@ #include "av1.h" #include "cbs.h" +#ifndef CBS_AV1_OBU_METADATA +#define CBS_AV1_OBU_METADATA 1 +#endif +#ifndef CBS_AV1_OBU_TILE_LIST +#define CBS_AV1_OBU_TILE_LIST 1 +#endif +#ifndef CBS_AV1_OBU_PADDING +#define CBS_AV1_OBU_PADDING 1 +#endif typedef struct AV1RawOBUHeader { uint8_t obu_forbidden_bit; @@ -295,6 +304,10 @@ typedef struct AV1RawTileData { } AV1RawTileData; typedef struct AV1RawTileGroup { + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; + uint8_t tile_start_and_end_present_flag; uint16_t tg_start; uint16_t tg_end; @@ -407,9 +420,15 @@ typedef struct AV1RawOBU { AV1RawFrameHeader frame_header; AV1RawFrame frame; AV1RawTileGroup tile_group; +#if CBS_AV1_OBU_TILE_LIST AV1RawTileList tile_list; +#endif +#if CBS_AV1_OBU_METADATA AV1RawMetadata metadata; +#endif +#if CBS_AV1_OBU_PADDING AV1RawPadding padding; +#endif } obu; } AV1RawOBU; diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c index a4a912482c..5518544a4d 100644 --- a/libavcodec/cbs_av1_syntax_template.c +++ b/libavcodec/cbs_av1_syntax_template.c @@ -1865,11 +1865,10 @@ static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(byte_alignment)(ctx, rw)); - CHECK(FUNC(tile_group_obu)(ctx, rw, ¤t->tile_group)); - return 0; } +#if CBS_AV1_OBU_TILE_LIST static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawTileList *current) { @@ -1884,7 +1883,9 @@ static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif +#if CBS_AV1_OBU_METADATA static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawMetadataHDRCLL *current) { @@ -2103,7 +2104,9 @@ static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif +#if CBS_AV1_OBU_PADDING static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, AV1RawPadding *current) { @@ -2127,3 +2130,4 @@ static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +#endif diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 2de74691cb..fa70a8fb7b 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -28,7 +28,7 @@ #include "cbs_h266.h" #include "h264.h" #include "h2645_parse.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "vvc.h" #include "hevc/hevc.h" @@ -345,7 +345,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) /* The CBS SEI code uses the refstruct API for the allocation * of its child buffers. */ #define allocate(name, size) do { \ - name = ff_refstruct_allocz(size + \ + name = av_refstruct_allocz(size + \ AV_INPUT_BUFFER_PADDING_SIZE); \ if (!name) \ return AVERROR(ENOMEM); \ @@ -769,7 +769,7 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ if (priv->ps_var[id] == priv->active_ ## ps_var) \ priv->active_ ## ps_var = NULL ; \ av_assert0(unit->content_ref); \ - ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ + av_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ return 0; \ } @@ -790,7 +790,7 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ if (err < 0) \ return err; \ av_assert0(unit->content_ref); \ - ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ + av_refstruct_replace(&priv->ps_var[id], unit->content_ref); \ return 0; \ } @@ -810,10 +810,10 @@ static int cbs_h266_replace_sps(CodedBitstreamContext *ctx, if (priv->sps[id] && memcmp(priv->sps[id], unit->content_ref, sizeof(*priv->sps[id]))) { for (unsigned int i = 0; i < VVC_MAX_PPS_COUNT; i++) { if (priv->pps[i] && priv->pps[i]->pps_seq_parameter_set_id == id) - ff_refstruct_unref(&priv->pps[i]); + av_refstruct_unref(&priv->pps[i]); } } - ff_refstruct_replace(&priv->sps[id], unit->content_ref); + av_refstruct_replace(&priv->sps[id], unit->content_ref); return 0; } @@ -828,7 +828,7 @@ static int cbs_h266_replace_ph(CodedBitstreamContext *ctx, if (err < 0) return err; av_assert0(unit->content_ref); - ff_refstruct_replace(&h266->ph_ref, unit->content_ref); + av_refstruct_replace(&h266->ph_ref, unit->content_ref); h266->ph = ph; return 0; } @@ -1910,9 +1910,9 @@ static void cbs_h264_flush(CodedBitstreamContext *ctx) CodedBitstreamH264Context *h264 = ctx->priv_data; for (int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - ff_refstruct_unref(&h264->sps[i]); + av_refstruct_unref(&h264->sps[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - ff_refstruct_unref(&h264->pps[i]); + av_refstruct_unref(&h264->pps[i]); h264->active_sps = NULL; h264->active_pps = NULL; @@ -1927,9 +1927,9 @@ static void cbs_h264_close(CodedBitstreamContext *ctx) ff_h2645_packet_uninit(&h264->common.read_packet); for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - ff_refstruct_unref(&h264->sps[i]); + av_refstruct_unref(&h264->sps[i]); for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - ff_refstruct_unref(&h264->pps[i]); + av_refstruct_unref(&h264->pps[i]); } static void cbs_h265_flush(CodedBitstreamContext *ctx) @@ -1937,11 +1937,11 @@ static void cbs_h265_flush(CodedBitstreamContext *ctx) CodedBitstreamH265Context *h265 = ctx->priv_data; for (int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - ff_refstruct_unref(&h265->vps[i]); + av_refstruct_unref(&h265->vps[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - ff_refstruct_unref(&h265->sps[i]); + av_refstruct_unref(&h265->sps[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - ff_refstruct_unref(&h265->pps[i]); + av_refstruct_unref(&h265->pps[i]); h265->active_vps = NULL; h265->active_sps = NULL; @@ -1956,11 +1956,11 @@ static void cbs_h265_close(CodedBitstreamContext *ctx) ff_h2645_packet_uninit(&h265->common.read_packet); for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - ff_refstruct_unref(&h265->vps[i]); + av_refstruct_unref(&h265->vps[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - ff_refstruct_unref(&h265->sps[i]); + av_refstruct_unref(&h265->sps[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - ff_refstruct_unref(&h265->pps[i]); + av_refstruct_unref(&h265->pps[i]); } static void cbs_h266_flush(CodedBitstreamContext *ctx) @@ -1968,12 +1968,12 @@ static void cbs_h266_flush(CodedBitstreamContext *ctx) CodedBitstreamH266Context *h266 = ctx->priv_data; for (int i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++) - ff_refstruct_unref(&h266->vps[i]); + av_refstruct_unref(&h266->vps[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++) - ff_refstruct_unref(&h266->sps[i]); + av_refstruct_unref(&h266->sps[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++) - ff_refstruct_unref(&h266->pps[i]); - ff_refstruct_unref(&h266->ph_ref); + av_refstruct_unref(&h266->pps[i]); + av_refstruct_unref(&h266->ph_ref); } static void cbs_h266_close(CodedBitstreamContext *ctx) @@ -1984,7 +1984,7 @@ static void cbs_h266_close(CodedBitstreamContext *ctx) ff_h2645_packet_uninit(&h266->common.read_packet); } -static void cbs_h264_free_sei(FFRefStructOpaque unused, void *content) +static void cbs_h264_free_sei(AVRefStructOpaque unused, void *content) { H264RawSEI *sei = content; ff_cbs_sei_free_message_list(&sei->message_list); @@ -2010,7 +2010,7 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = { CBS_UNIT_TYPE_END_OF_LIST }; -static void cbs_h265_free_sei(FFRefStructOpaque unused, void *content) +static void cbs_h265_free_sei(AVRefStructOpaque unused, void *content) { H265RawSEI *sei = content; ff_cbs_sei_free_message_list(&sei->message_list); @@ -2037,7 +2037,7 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = { CBS_UNIT_TYPE_END_OF_LIST }; -static void cbs_h266_free_sei(FFRefStructOpaque unused, void *content) +static void cbs_h266_free_sei(AVRefStructOpaque unused, void *content) { H266RawSEI *sei = content; ff_cbs_sei_free_message_list(&sei->message_list); @@ -2310,6 +2310,28 @@ static const SEIMessageTypeDescriptor cbs_sei_h266_types[] = { SEI_MESSAGE_TYPE_END }; +static const SEIMessageTypeDescriptor cbs_sei_h274_types[] = { + { + SEI_TYPE_FILM_GRAIN_CHARACTERISTICS, + 1, 0, + sizeof(SEIRawFilmGrainCharacteristics), + SEI_MESSAGE_RW(sei, film_grain_characteristics), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, 0, + sizeof(SEIRawDisplayOrientation), + SEI_MESSAGE_RW(sei, display_orientation) + }, + { + SEI_TYPE_FRAME_FIELD_INFO, + 1, 0, + sizeof(SEIRawFrameFieldInformation), + SEI_MESSAGE_RW(sei, frame_field_information) + }, + SEI_MESSAGE_TYPE_END, +}; + const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, int payload_type) { @@ -2335,6 +2357,13 @@ const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, return &codec_list[i]; } + if (ctx->codec->codec_id == AV_CODEC_ID_H266) { + for (i = 0; cbs_sei_h274_types[i].type >= 0; i++) { + if (cbs_sei_h274_types[i].type == payload_type) + return &cbs_sei_h274_types[i]; + } + } + for (i = 0; cbs_sei_common_types[i].type >= 0; i++) { if (cbs_sei_common_types[i].type == payload_type) return &cbs_sei_common_types[i]; diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h index 26a5a34fe9..bb7a29c2e5 100644 --- a/libavcodec/cbs_h265.h +++ b/libavcodec/cbs_h265.h @@ -725,14 +725,14 @@ typedef struct H265RawSEI3DReferenceDisplaysInfo { uint8_t ref_viewing_distance_flag; uint8_t prec_ref_viewing_dist; uint8_t num_ref_displays_minus1; - uint8_t left_view_id[31]; - uint8_t right_view_id[31]; - uint8_t exponent_ref_display_width[31]; - uint8_t mantissa_ref_display_width[31]; - uint8_t exponent_ref_viewing_distance[31]; - uint8_t mantissa_ref_viewing_distance[31]; - uint8_t additional_shift_present_flag[31]; - uint16_t num_sample_shift_plus512[31]; + uint16_t left_view_id[32]; + uint16_t right_view_id[32]; + uint8_t exponent_ref_display_width[32]; + uint8_t mantissa_ref_display_width[32]; + uint8_t exponent_ref_viewing_distance[32]; + uint8_t mantissa_ref_viewing_distance[32]; + uint8_t additional_shift_present_flag[32]; + uint16_t num_sample_shift_plus512[32]; uint8_t three_dimensional_reference_displays_extension_flag; } H265RawSEI3DReferenceDisplaysInfo; diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c index 1c11514435..e976c38b8d 100644 --- a/libavcodec/cbs_h265_syntax_template.c +++ b/libavcodec/cbs_h265_syntax_template.c @@ -2299,8 +2299,8 @@ SEI_FUNC(sei_3d_reference_displays_info, (CodedBitstreamContext *ctx, RWContext ue(prec_ref_viewing_dist, 0, 31); ue(num_ref_displays_minus1, 0, 31); for (i = 0; i <= current->num_ref_displays_minus1; i++) { - ues(left_view_id[i], 0, UINT8_MAX, 1, i); - ues(right_view_id[i], 0, UINT8_MAX, 1, i); + ues(left_view_id[i], 0, MAX_UINT_BITS(15), 1, i); + ues(right_view_id[i], 0, MAX_UINT_BITS(15), 1, i); us(6, exponent_ref_display_width[i], 0, 62, 1, i); if (!current->exponent_ref_display_width[i]) length = FFMAX(0, (int)current->prec_ref_display_width - 30); diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h index d24a8e9313..67a3ff6151 100644 --- a/libavcodec/cbs_h266.h +++ b/libavcodec/cbs_h266.h @@ -593,6 +593,8 @@ typedef struct H266RawPPS { uint16_t sub_pic_id_val[VVC_MAX_SLICES]; ///< SubpicIdVal uint16_t col_width_val[VVC_MAX_TILE_COLUMNS]; ///< ColWidthVal uint16_t row_height_val[VVC_MAX_TILE_ROWS]; ///< RowHeightVal + uint16_t slice_top_left_tile_idx[VVC_MAX_SLICES]; + uint16_t num_slices_in_tile[VVC_MAX_SLICES]; } H266RawPPS; typedef struct H266RawAPS { diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index b4165b43b3..8b337c75d0 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -1057,7 +1057,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, H266RawSPS *current) { CodedBitstreamH266Context *h266 = ctx->priv_data; - int err, i, j; + int err, i, j, max_width_minus1, max_height_minus1; unsigned int ctb_log2_size_y, min_cb_log2_size_y, min_qt_log2_size_intra_y, min_qt_log2_size_inter_y, ctb_size_y, max_num_merge_cand, tmp_width_val, tmp_height_val; @@ -1078,7 +1078,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ub(4, sps_seq_parameter_set_id); ub(4, sps_video_parameter_set_id); if (current->sps_video_parameter_set_id == 0 && !h266->vps[0]) { - H266RawVPS *vps = ff_refstruct_allocz(sizeof(*vps)); + H266RawVPS *vps = av_refstruct_allocz(sizeof(*vps)); if (!vps) return AVERROR(ENOMEM); vps->vps_max_layers_minus1 = 0; @@ -1130,6 +1130,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ctb_log2_size_y); tmp_height_val = AV_CEIL_RSHIFT(current->sps_pic_height_max_in_luma_samples, ctb_log2_size_y); + max_width_minus1 = tmp_width_val - 1; + max_height_minus1 = tmp_height_val - 1; flag(sps_subpic_info_present_flag); if (current->sps_subpic_info_present_flag) { @@ -1145,13 +1147,13 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) - ubs(wlen, sps_subpic_width_minus1[0], 1, 0); + us(wlen, sps_subpic_width_minus1[0], 0, max_width_minus1, 1, 0); else - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); if (current->sps_pic_height_max_in_luma_samples > ctb_size_y) - ubs(hlen, sps_subpic_height_minus1[0], 1, 0); + us(hlen, sps_subpic_height_minus1[0], 0, max_height_minus1, 1, 0); else - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_height_minus1[0], max_height_minus1); if (!current->sps_independent_subpics_flag) { flags(sps_subpic_treated_as_pic_flag[0], 1, 0); flags(sps_loop_filter_across_subpic_enabled_flag[0], 1, 0); @@ -1161,58 +1163,54 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, } for (i = 1; i <= current->sps_num_subpics_minus1; i++) { if (!current->sps_subpic_same_size_flag) { - if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) { - const unsigned int win_right_edge = - current->sps_pic_width_max_in_luma_samples - - current->sps_conf_win_right_offset * sub_width_c; - us(wlen, sps_subpic_ctu_top_left_x[i], 0, - AV_CEIL_RSHIFT(win_right_edge, ctb_log2_size_y) - 1, - 1, i); - } else + const int win_right_edge = + current->sps_pic_width_max_in_luma_samples - + current->sps_conf_win_right_offset * sub_width_c; + const int win_bottom_edge = + current->sps_pic_height_max_in_luma_samples - + current->sps_conf_win_bottom_offset * sub_height_c; + const int win_left_edge = + current->sps_conf_win_left_offset * sub_width_c; + const int win_top_edge = + current->sps_conf_win_top_offset * sub_height_c; + const int win_left_edge_ctus = + AV_CEIL_RSHIFT(win_left_edge, ctb_log2_size_y); + const int win_right_edge_ctus = + AV_CEIL_RSHIFT(win_right_edge, ctb_log2_size_y); + const int win_top_edge_ctus = + AV_CEIL_RSHIFT(win_top_edge, ctb_log2_size_y); + const int win_bottom_edge_ctus = + AV_CEIL_RSHIFT(win_bottom_edge, ctb_log2_size_y); + const int min_width = + FFMAX(win_left_edge_ctus - current->sps_subpic_ctu_top_left_x[i], 0); + const int min_height = + FFMAX(win_top_edge_ctus - current->sps_subpic_ctu_top_left_y[i], 0); + + if (current->sps_pic_width_max_in_luma_samples > ctb_size_y) + us(wlen, sps_subpic_ctu_top_left_x[i], 0, win_right_edge_ctus - 1, 1, i); + else infer(sps_subpic_ctu_top_left_x[i], 0); - if (current->sps_pic_height_max_in_luma_samples > - ctb_size_y) { - const unsigned int win_bottom_edge = - current->sps_pic_height_max_in_luma_samples - - current->sps_conf_win_bottom_offset * sub_height_c; - us(hlen, sps_subpic_ctu_top_left_y[i], 0, - AV_CEIL_RSHIFT(win_bottom_edge, ctb_log2_size_y) - 1, - 1, i); - } else + + if (current->sps_pic_height_max_in_luma_samples > ctb_size_y) + us(hlen, sps_subpic_ctu_top_left_y[i], 0, win_bottom_edge_ctus - 1, 1, i); + else infer(sps_subpic_ctu_top_left_y[i], 0); + + max_width_minus1 = tmp_width_val - current->sps_subpic_ctu_top_left_x[i] - 1; + max_height_minus1 = tmp_height_val - current->sps_subpic_ctu_top_left_y[i] - 1; + if (i < current->sps_num_subpics_minus1 && - current->sps_pic_width_max_in_luma_samples > - ctb_size_y) { - const unsigned int win_left_edge = - current->sps_conf_win_left_offset * sub_width_c; - const unsigned int win_left_edge_ctus = - AV_CEIL_RSHIFT(win_left_edge, ctb_log2_size_y); - us(wlen, sps_subpic_width_minus1[i], - win_left_edge_ctus > current->sps_subpic_ctu_top_left_x[i] - ? win_left_edge_ctus - current->sps_subpic_ctu_top_left_x[i] - : 0, - MAX_UINT_BITS(wlen), 1, i); + current->sps_pic_width_max_in_luma_samples > ctb_size_y) { + us(wlen, sps_subpic_width_minus1[i], min_width, max_width_minus1, 1, i); } else { - infer(sps_subpic_width_minus1[i], - tmp_width_val - - current->sps_subpic_ctu_top_left_x[i] - 1); + infer(sps_subpic_width_minus1[i], max_width_minus1); } + if (i < current->sps_num_subpics_minus1 && - current->sps_pic_height_max_in_luma_samples > - ctb_size_y) { - const unsigned int win_top_edge = - current->sps_conf_win_top_offset * sub_height_c; - const unsigned int win_top_edge_ctus = - AV_CEIL_RSHIFT(win_top_edge, ctb_log2_size_y); - us(hlen, sps_subpic_height_minus1[i], - win_top_edge_ctus > current->sps_subpic_ctu_top_left_y[i] - ? win_top_edge_ctus - current->sps_subpic_ctu_top_left_y[i] - : 0, - MAX_UINT_BITS(hlen), 1, i); + current->sps_pic_height_max_in_luma_samples > ctb_size_y) { + us(hlen, sps_subpic_height_minus1[i], min_height, max_height_minus1, 1, i); } else { - infer(sps_subpic_height_minus1[i], - tmp_height_val - - current->sps_subpic_ctu_top_left_y[i] - 1); + infer(sps_subpic_height_minus1[i], max_height_minus1); } } else { int num_subpic_cols = tmp_width_val / @@ -1245,8 +1243,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, } else { infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); + infer(sps_subpic_height_minus1[0], max_height_minus1); } ue(sps_subpic_id_len_minus1, 0, 15); if ((1 << (current->sps_subpic_id_len_minus1 + 1)) < @@ -1273,8 +1271,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, infer(sps_subpic_id_mapping_explicitly_signalled_flag, 0); infer(sps_subpic_ctu_top_left_x[0], 0); infer(sps_subpic_ctu_top_left_y[0], 0); - infer(sps_subpic_width_minus1[0], tmp_width_val - 1); - infer(sps_subpic_height_minus1[0], tmp_height_val - 1); + infer(sps_subpic_width_minus1[0], max_width_minus1); + infer(sps_subpic_height_minus1[0], max_height_minus1); } @@ -1727,7 +1725,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, current->pps_pic_height_in_luma_samples != sps->sps_pic_height_max_in_luma_samples)) { av_log(ctx->log_ctx, AV_LOG_ERROR, - "Resoltuion change is not allowed, " + "Resolution change is not allowed, " "in max resolution (%ux%u) mismatched with pps(%ux%u).\n", sps->sps_pic_width_max_in_luma_samples, sps->sps_pic_height_max_in_luma_samples, @@ -1899,10 +1897,10 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, } unified_size = current->pps_tile_column_width_minus1[i - 1] + 1; while (remaining_size > 0) { - if (current->num_tile_columns > VVC_MAX_TILE_COLUMNS) { + if (i == VVC_MAX_TILE_COLUMNS) { av_log(ctx->log_ctx, AV_LOG_ERROR, - "NumTileColumns(%d) > than VVC_MAX_TILE_COLUMNS(%d)\n", - current->num_tile_columns, VVC_MAX_TILE_COLUMNS); + "Exceeded maximum tile columns (%d) (remaining size: %u)\n", + VVC_MAX_TILE_COLUMNS, remaining_size); return AVERROR_INVALIDDATA; } unified_size = FFMIN(remaining_size, unified_size); @@ -1911,12 +1909,6 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, i++; } current->num_tile_columns = i; - if (current->num_tile_columns > VVC_MAX_TILE_COLUMNS) { - av_log(ctx->log_ctx, AV_LOG_ERROR, - "NumTileColumns(%d) > than VVC_MAX_TILE_COLUMNS(%d)\n", - current->num_tile_columns, VVC_MAX_TILE_COLUMNS); - return AVERROR_INVALIDDATA; - } remaining_size = pic_height_in_ctbs_y; for (i = 0; i <= current->pps_num_exp_tile_rows_minus1; i++) { @@ -1931,18 +1923,18 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, unified_size = current->pps_tile_row_height_minus1[i - 1] + 1; while (remaining_size > 0) { + if (i == VVC_MAX_TILE_ROWS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Exceeded maximum tile rows (%d) (remaining size: %u)\n", + VVC_MAX_TILE_ROWS, remaining_size); + return AVERROR_INVALIDDATA; + } unified_size = FFMIN(remaining_size, unified_size); current->row_height_val[i] = unified_size; remaining_size -= unified_size; i++; } current->num_tile_rows=i; - if (current->num_tile_rows > VVC_MAX_TILE_ROWS) { - av_log(ctx->log_ctx, AV_LOG_ERROR, - "NumTileRows(%d) > than VVC_MAX_TILE_ROWS(%d)\n", - current->num_tile_rows, VVC_MAX_TILE_ROWS); - return AVERROR_INVALIDDATA; - } current->num_tiles_in_pic = current->num_tile_columns * current->num_tile_rows; @@ -1966,7 +1958,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, infer(pps_single_slice_per_subpic_flag, 1); if (current->pps_rect_slice_flag && !current->pps_single_slice_per_subpic_flag) { - int j; + int j, num_slices = 0; uint16_t tile_idx = 0, tile_x, tile_y, ctu_x, ctu_y; uint16_t slice_top_left_ctu_x[VVC_MAX_SLICES]; uint16_t slice_top_left_ctu_y[VVC_MAX_SLICES]; @@ -1976,6 +1968,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, else infer(pps_tile_idx_delta_present_flag, 0); for (i = 0; i < current->pps_num_slices_in_pic_minus1; i++) { + current->slice_top_left_tile_idx[i] = tile_idx; tile_x = tile_idx % current->num_tile_columns; tile_y = tile_idx / current->num_tile_columns; if (tile_x != current->num_tile_columns - 1) { @@ -2006,14 +1999,13 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, if (current->pps_slice_width_in_tiles_minus1[i] == 0 && current->pps_slice_height_in_tiles_minus1[i] == 0 && current->row_height_val[tile_y] > 1) { - int num_slices_in_tile, - uniform_slice_height, remaining_height_in_ctbs_y; + int uniform_slice_height, remaining_height_in_ctbs_y; remaining_height_in_ctbs_y = current->row_height_val[tile_y]; ues(pps_num_exp_slices_in_tile[i], 0, current->row_height_val[tile_y] - 1, 1, i); if (current->pps_num_exp_slices_in_tile[i] == 0) { - num_slices_in_tile = 1; + current->num_slices_in_tile[i] = 1; current->slice_height_in_ctus[i] = current->row_height_val[tile_y]; slice_top_left_ctu_x[i] = ctu_x; slice_top_left_ctu_y[i] = ctu_y; @@ -2022,7 +2014,7 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, for (j = 0; j < current->pps_num_exp_slices_in_tile[i]; j++) { ues(pps_exp_slice_height_in_ctus_minus1[i][j], 0, - current->row_height_val[tile_y] - 1, 2, + remaining_height_in_ctbs_y - 1, 2, i, j); slice_height_in_ctus = current-> @@ -2056,12 +2048,18 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, slice_top_left_ctu_y[i + j] = ctu_y; j++; } - num_slices_in_tile = j; + current->num_slices_in_tile[i] = j; } - i += num_slices_in_tile - 1; + for (int k = 0; k < current->num_slices_in_tile[i]; k++) + current->slice_top_left_tile_idx[i + k] = tile_idx; + i += current->num_slices_in_tile[i] - 1; } else { uint16_t height = 0; infer(pps_num_exp_slices_in_tile[i], 0); + if (current->pps_slice_width_in_tiles_minus1[i] == 0 && + current->pps_slice_height_in_tiles_minus1[i] == 0) + current->num_slices_in_tile[i] = 1; + for (j = 0; j <= current->pps_slice_height_in_tiles_minus1[i]; j++) { @@ -2101,6 +2099,8 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, if (i == current->pps_num_slices_in_pic_minus1) { uint16_t height = 0; + current->slice_top_left_tile_idx[i] = tile_idx; + current->num_slices_in_tile[i] = 1; tile_x = tile_idx % current->num_tile_columns; tile_y = tile_idx / current->num_tile_columns; if (tile_y >= current->num_tile_rows) @@ -2147,7 +2147,10 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, current->num_slices_in_subpic[i]++; } } + num_slices += current->num_slices_in_subpic[i]; } + if (current->pps_num_slices_in_pic_minus1 + 1 != num_slices) + return AVERROR_INVALIDDATA; } else { if (current->pps_no_pic_partition_flag) infer(pps_num_slices_in_pic_minus1, 0); @@ -2803,7 +2806,7 @@ static int FUNC(picture_header) (CodedBitstreamContext *ctx, RWContext *rw, 0, 2 * (ctb_log2_size_y - min_cb_log2_size_y)); if (sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma != 0) { unsigned int min_qt_log2_size_intra_c = - sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma + + current->ph_log2_diff_min_qt_min_cb_intra_slice_chroma + min_cb_log2_size_y; ue(ph_log2_diff_max_bt_min_qt_intra_slice_chroma, 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_intra_c); @@ -3431,13 +3434,50 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i < current->curr_subpic_idx; i++) { slice_idx += pps->num_slices_in_subpic[i]; } - width_in_tiles = - pps->pps_slice_width_in_tiles_minus1[slice_idx] + 1; - if (entropy_sync) - height = pps->slice_height_in_ctus[slice_idx]; - else - height = pps->pps_slice_height_in_tiles_minus1[slice_idx] + 1; + if (pps->pps_single_slice_per_subpic_flag) { + const int width_in_ctus = sps->sps_subpic_width_minus1[slice_idx] + 1; + const int subpic_l = sps->sps_subpic_ctu_top_left_x[slice_idx]; + const int subpic_r = subpic_l + width_in_ctus; + + int ctb_x = 0, tile_x = 0; + for (; ctb_x < subpic_l && tile_x < pps->num_tile_columns; tile_x++) + ctb_x += pps->col_width_val[tile_x]; + + width_in_tiles = 0; + for (; ctb_x < subpic_r && tile_x < pps->num_tile_columns; tile_x++) { + ctb_x += pps->col_width_val[tile_x]; + width_in_tiles++; + } + + if (entropy_sync) { + height = sps->sps_subpic_height_minus1[slice_idx] + 1; + } else { + const int height_in_ctus = sps->sps_subpic_height_minus1[slice_idx] + 1; + const int subpic_t = sps->sps_subpic_ctu_top_left_y[slice_idx]; + const int subpic_b = subpic_t + height_in_ctus; + + int ctb_y = 0, tile_y = 0, height_in_tiles; + for (; ctb_y < subpic_t && tile_y < pps->num_tile_rows; tile_y++) + ctb_y += pps->row_height_val[tile_y]; + + height_in_tiles = 0; + for (; ctb_y < subpic_b && tile_y < pps->num_tile_rows; tile_y++) { + ctb_y += pps->row_height_val[tile_y]; + height_in_tiles++; + } + + height = height_in_tiles; + } + } else { + width_in_tiles = + pps->pps_slice_width_in_tiles_minus1[slice_idx] + 1; + + if (entropy_sync) + height = pps->slice_height_in_ctus[slice_idx]; + else + height = pps->pps_slice_height_in_tiles_minus1[slice_idx] + 1; + } current->num_entry_points = width_in_tiles * height; } else { diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index d982262bd9..37398ef416 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -22,14 +22,53 @@ #include #include +#include "config.h" + #include "libavutil/log.h" #include "cbs.h" #include "codec_id.h" #include "get_bits.h" #include "put_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" +#ifndef CBS_READ +#define CBS_READ 1 +#endif +#ifndef CBS_WRITE +#define CBS_WRITE 1 +#endif +#ifndef CBS_TRACE +#define CBS_TRACE 1 +#endif + +#ifndef CBS_APV +#define CBS_APV CONFIG_CBS_APV +#endif +#ifndef CBS_AV1 +#define CBS_AV1 CONFIG_CBS_AV1 +#endif +#ifndef CBS_H264 +#define CBS_H264 CONFIG_CBS_H264 +#endif +#ifndef CBS_H265 +#define CBS_H265 CONFIG_CBS_H265 +#endif +#ifndef CBS_H266 +#define CBS_H266 CONFIG_CBS_H266 +#endif +#ifndef CBS_JPEG +#define CBS_JPEG CONFIG_CBS_JPEG +#endif +#ifndef CBS_MPEG2 +#define CBS_MPEG2 CONFIG_CBS_MPEG2 +#endif +#ifndef CBS_VP8 +#define CBS_VP8 CONFIG_CBS_VP8 +#endif +#ifndef CBS_VP9 +#define CBS_VP9 CONFIG_CBS_VP9 +#endif enum CBSContentType { // Unit content may contain some references to other structures, but all @@ -93,7 +132,7 @@ typedef const struct CodedBitstreamUnitTypeDescriptor { } ref; struct { - void (*content_free)(FFRefStructOpaque opaque, void *content); + void (*content_free)(AVRefStructOpaque opaque, void *content); int (*content_clone)(void **new_content, CodedBitstreamUnit *unit); } complex; } type; @@ -155,7 +194,7 @@ typedef struct CodedBitstreamType { // Helper functions for trace output. -void ff_cbs_trace_header(CodedBitstreamContext *ctx, +void CBS_FUNC(trace_header)(CodedBitstreamContext *ctx, const char *name); @@ -165,28 +204,28 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx, // (i.e. only limited by the amount of bits used) and they lack // the ability to use subscripts. -int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max); -int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_simple_unsigned)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, uint32_t *write_to); -int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max); -int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_simple_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, uint32_t value); -int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, +int CBS_FUNC(read_signed)(CodedBitstreamContext *ctx, GetBitContext *gbc, int width, const char *name, const int *subscripts, int32_t *write_to, int32_t range_min, int32_t range_max); -int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, +int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc, int width, const char *name, const int *subscripts, int32_t value, int32_t range_min, int32_t range_max); @@ -204,6 +243,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1))) +#if CBS_TRACE // Start of a syntax element during read tracing. #define CBS_TRACE_READ_START() \ GetBitContext trace_start; \ @@ -233,7 +273,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } while (0) // End of a syntax element which is made up of subelements which -// are aleady traced, so we are only showing the value. +// are already traced, so we are only showing the value. #define CBS_TRACE_READ_END_VALUE_ONLY() \ do { \ if (ctx->trace_enable) { \ @@ -270,7 +310,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } while (0) // End of a syntax element which is made up of subelements which are -// aleady traced, so we are only showing the value. This forges a +// already traced, so we are only showing the value. This forges a // PutBitContext to point to the position of the start of the syntax // element, but the other state doesn't matter because length is zero. #define CBS_TRACE_WRITE_END_VALUE_ONLY() \ @@ -284,6 +324,17 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, } \ } while (0) +#else // CBS_TRACE +#define CBS_TRACE_READ_START() do { } while (0) +#define CBS_TRACE_READ_END() do { } while (0) +#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() do { } while (0) +#define CBS_TRACE_READ_END_VALUE_ONLY() do { } while (0) +#define CBS_TRACE_WRITE_START() do { } while (0) +#define CBS_TRACE_WRITE_END() do { } while (0) +#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() do { } while (0) +#define CBS_TRACE_WRITE_END_VALUE_ONLY() do { } while (0) +#endif // CBS_TRACE + #define TYPE_LIST(...) { __VA_ARGS__ } #define CBS_UNIT_TYPE_POD(type_, structure) { \ .nb_unit_types = 1, \ @@ -335,14 +386,15 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, #define CBS_UNIT_TYPE_END_OF_LIST { .nb_unit_types = 0 } -extern const CodedBitstreamType ff_cbs_type_av1; -extern const CodedBitstreamType ff_cbs_type_h264; -extern const CodedBitstreamType ff_cbs_type_h265; -extern const CodedBitstreamType ff_cbs_type_h266; -extern const CodedBitstreamType ff_cbs_type_jpeg; -extern const CodedBitstreamType ff_cbs_type_mpeg2; -extern const CodedBitstreamType ff_cbs_type_vp8; -extern const CodedBitstreamType ff_cbs_type_vp9; +extern const CodedBitstreamType CBS_FUNC(type_apv); +extern const CodedBitstreamType CBS_FUNC(type_av1); +extern const CodedBitstreamType CBS_FUNC(type_h264); +extern const CodedBitstreamType CBS_FUNC(type_h265); +extern const CodedBitstreamType CBS_FUNC(type_h266); +extern const CodedBitstreamType CBS_FUNC(type_jpeg); +extern const CodedBitstreamType CBS_FUNC(type_mpeg2); +extern const CodedBitstreamType CBS_FUNC(type_vp8); +extern const CodedBitstreamType CBS_FUNC(type_vp9); #endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c index 458751d92e..acc3578aa9 100644 --- a/libavcodec/cbs_sei.c +++ b/libavcodec/cbs_sei.c @@ -23,24 +23,24 @@ #include "cbs_h265.h" #include "cbs_h266.h" #include "cbs_sei.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj) +static void cbs_free_user_data_registered(AVRefStructOpaque unused, void *obj) { SEIRawUserDataRegistered *udr = obj; - ff_refstruct_unref(&udr->data); + av_refstruct_unref(&udr->data); } -static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj) +static void cbs_free_user_data_unregistered(AVRefStructOpaque unused, void *obj) { SEIRawUserDataUnregistered *udu = obj; - ff_refstruct_unref(&udu->data); + av_refstruct_unref(&udu->data); } int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, const SEIMessageTypeDescriptor *desc) { - void (*free_func)(FFRefStructOpaque, void*); + void (*free_func)(AVRefStructOpaque, void*); av_assert0(message->payload == NULL && message->payload_ref == NULL); @@ -54,7 +54,7 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, free_func = NULL; } - message->payload_ref = ff_refstruct_alloc_ext(desc->size, 0, + message->payload_ref = av_refstruct_alloc_ext(desc->size, 0, NULL, free_func); if (!message->payload_ref) return AVERROR(ENOMEM); @@ -92,8 +92,8 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list) { for (int i = 0; i < list->nb_messages; i++) { SEIRawMessage *message = &list->messages[i]; - ff_refstruct_unref(&message->payload_ref); - ff_refstruct_unref(&message->extension_data); + av_refstruct_unref(&message->payload_ref); + av_refstruct_unref(&message->extension_data); } av_free(list->messages); } @@ -299,7 +299,7 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, if (payload_ref) { /* The following just increments payload_ref's refcount, * so that payload_ref is now owned by us. */ - payload_ref = ff_refstruct_ref(payload_ref); + payload_ref = av_refstruct_ref(payload_ref); } message = &list->messages[list->nb_messages - 1]; @@ -352,8 +352,8 @@ static void cbs_sei_delete_message(SEIRawMessageList *list, av_assert0(0 <= position && position < list->nb_messages); message = &list->messages[position]; - ff_refstruct_unref(&message->payload_ref); - ff_refstruct_unref(&message->extension_data); + av_refstruct_unref(&message->payload_ref); + av_refstruct_unref(&message->extension_data); --list->nb_messages; diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h index 15ef3415ab..81867b79a7 100644 --- a/libavcodec/cbs_sei.h +++ b/libavcodec/cbs_sei.h @@ -97,6 +97,46 @@ typedef struct SEIRawAmbientViewingEnvironment { uint16_t ambient_light_y; } SEIRawAmbientViewingEnvironment; +typedef struct SEIRawFilmGrainCharacteristics { + uint8_t fg_characteristics_cancel_flag; + uint8_t fg_model_id; + uint8_t fg_separate_colour_description_present_flag; + uint8_t fg_bit_depth_luma_minus8; + uint8_t fg_bit_depth_chroma_minus8; + uint8_t fg_full_range_flag; + uint8_t fg_colour_primaries; + uint8_t fg_transfer_characteristics; + uint8_t fg_matrix_coeffs; + uint8_t fg_blending_mode_id; + uint8_t fg_log2_scale_factor; + uint8_t fg_comp_model_present_flag[3]; + uint8_t fg_num_intensity_intervals_minus1[3]; + uint8_t fg_num_model_values_minus1[3]; + uint8_t fg_intensity_interval_lower_bound[3][256]; + uint8_t fg_intensity_interval_upper_bound[3][256]; + int16_t fg_comp_model_value[3][256][6]; + uint8_t fg_characteristics_persistence_flag; +} SEIRawFilmGrainCharacteristics; + +typedef struct SEIRawDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t display_orientation_persistence_flag; + uint8_t display_orientation_transform_type; + uint8_t display_orientation_reserved_zero_3bits; +} SEIRawDisplayOrientation; + +typedef struct SEIRawFrameFieldInformation { + uint8_t ffi_field_pic_flag; + uint8_t ffi_bottom_field_flag; + uint8_t ffi_pairing_indicated_flag; + uint8_t ffi_paired_with_next_field_flag; + uint8_t ffi_display_fields_from_frame_flag; + uint8_t ffi_top_field_first_flag; + uint8_t ffi_display_elemental_periods_minus1; + uint8_t ffi_source_scan_type; + uint8_t ffi_duplicate_flag; +} SEIRawFrameFieldInformation; + typedef struct SEIRawMessage { uint32_t payload_type; uint32_t payload_size; diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c index 0205bb47aa..e6863a0fd7 100644 --- a/libavcodec/cbs_sei_syntax_template.c +++ b/libavcodec/cbs_sei_syntax_template.c @@ -224,6 +224,103 @@ SEI_FUNC(ambient_viewing_environment, return 0; } +SEI_FUNC(film_grain_characteristics, + (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFilmGrainCharacteristics *current, + SEIMessageState *state)) +{ + int err, c, i, j; + + HEADER("Film Grain Characteristics"); + + flag(fg_characteristics_cancel_flag); + if (!current->fg_characteristics_cancel_flag) { + int filmGrainBitDepth[3]; + + u(2, fg_model_id, 0, 1); + flag(fg_separate_colour_description_present_flag); + if (current->fg_separate_colour_description_present_flag) { + ub(3, fg_bit_depth_luma_minus8); + ub(3, fg_bit_depth_chroma_minus8); + flag(fg_full_range_flag); + ub(8, fg_colour_primaries); + ub(8, fg_transfer_characteristics); + ub(8, fg_matrix_coeffs); + } + + filmGrainBitDepth[0] = current->fg_bit_depth_luma_minus8 + 8; + filmGrainBitDepth[1] = + filmGrainBitDepth[2] = current->fg_bit_depth_chroma_minus8 + 8; + + u(2, fg_blending_mode_id, 0, 1); + ub(4, fg_log2_scale_factor); + for (c = 0; c < 3; c++) + flags(fg_comp_model_present_flag[c], 1, c); + + for (c = 0; c < 3; c++) { + if (current->fg_comp_model_present_flag[c]) { + ubs(8, fg_num_intensity_intervals_minus1[c], 1, c); + us(3, fg_num_model_values_minus1[c], 0, 5, 1, c); + for (i = 0; i <= current->fg_num_intensity_intervals_minus1[c]; i++) { + ubs(8, fg_intensity_interval_lower_bound[c][i], 2, c, i); + ubs(8, fg_intensity_interval_upper_bound[c][i], 2, c, i); + for (j = 0; j <= current->fg_num_model_values_minus1[c]; j++) + ses(fg_comp_model_value[c][i][j], 0 - current->fg_model_id * (1 << (filmGrainBitDepth[c] - 1)), + ((1 << filmGrainBitDepth[c]) - 1) - current->fg_model_id * (1 << (filmGrainBitDepth[c] - 1)), + 3, c, i, j); + } + } + } + flag(fg_characteristics_persistence_flag); + } + + return 0; +} + +SEI_FUNC(display_orientation, (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawDisplayOrientation *current, + SEIMessageState *state)) +{ + int err; + + HEADER("Display Orientation"); + + flag(display_orientation_cancel_flag); + if (!current->display_orientation_cancel_flag) { + flag(display_orientation_persistence_flag); + u(3, display_orientation_transform_type, 0, 7); + ub(3, display_orientation_reserved_zero_3bits); + } + + return 0; +} + +SEI_FUNC(frame_field_information, (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFrameFieldInformation *current, + SEIMessageState *state)) +{ + int err; + + HEADER("Frame-field information"); + + flag(ffi_field_pic_flag); + if (current->ffi_field_pic_flag) { + flag(ffi_bottom_field_flag); + flag(ffi_pairing_indicated_flag); + if (current->ffi_pairing_indicated_flag) + flag(ffi_paired_with_next_field_flag); + } else { + flag(ffi_display_fields_from_frame_flag); + if (current->ffi_display_fields_from_frame_flag) + flag(ffi_top_field_first_flag); + u(8, ffi_display_elemental_periods_minus1, 0, 0xff); + } + u(2, ffi_source_scan_type, 0, 3); + flag(ffi_duplicate_flag); + + return 0; +} + static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current) { diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c index 816d06da04..ff99fe32fb 100644 --- a/libavcodec/cbs_vp9.c +++ b/libavcodec/cbs_vp9.c @@ -375,7 +375,7 @@ static int cbs_vp9_split_fragment(CodedBitstreamContext *ctx, superframe_header = frag->data[frag->data_size - 1]; if ((superframe_header & 0xe0) == 0xc0) { - VP9RawSuperframeIndex sfi; + VP9RawSuperframeIndex sfi = {0}; GetBitContext gbc; size_t index_size, pos; int i; diff --git a/libavcodec/cbs_vp9.h b/libavcodec/cbs_vp9.h index af15eb4bac..588765b873 100644 --- a/libavcodec/cbs_vp9.h +++ b/libavcodec/cbs_vp9.h @@ -206,6 +206,14 @@ typedef struct CodedBitstreamVP9Context { uint8_t subsampling_y; int bit_depth; + int8_t loop_filter_ref_deltas[VP9_MAX_REF_FRAMES]; + int8_t loop_filter_mode_deltas[2]; + uint8_t segmentation_tree_probs[7]; + uint8_t segmentation_pred_prob[3]; + uint8_t feature_enabled[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_value[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_sign[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; } CodedBitstreamVP9Context; diff --git a/libavcodec/cbs_vp9_syntax_template.c b/libavcodec/cbs_vp9_syntax_template.c index 2f08eccf18..9d01debb6d 100644 --- a/libavcodec/cbs_vp9_syntax_template.c +++ b/libavcodec/cbs_vp9_syntax_template.c @@ -172,6 +172,8 @@ static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, ss(6, loop_filter_mode_deltas[i], 1, i); } } + } else { + infer(loop_filter_delta_update, 0); } return 0; @@ -196,7 +198,6 @@ static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, { static const uint8_t segmentation_feature_bits[VP9_SEG_LVL_MAX] = { 8, 6, 2, 0 }; static const uint8_t segmentation_feature_signed[VP9_SEG_LVL_MAX] = { 1, 1, 0, 0 }; - int err, i, j; f(1, segmentation_enabled); @@ -236,6 +237,8 @@ static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, } } } + } else { + infer(segmentation_update_data, 0); } return 0; @@ -371,6 +374,60 @@ static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, } } + // Update top-level loop filter and segmentation state with changes + // from this frame. + if (current->frame_type == VP9_KEY_FRAME || + current->intra_only || + current->error_resilient_mode) { + // setup_past_independence() - fill with the initial values. + + vp9->loop_filter_ref_deltas[VP9_INTRA_FRAME] = 1; + vp9->loop_filter_ref_deltas[VP9_LAST_FRAME] = 0; + vp9->loop_filter_ref_deltas[VP9_GOLDEN_FRAME] = -1; + vp9->loop_filter_ref_deltas[VP9_ALTREF_FRAME] = -1; + + vp9->loop_filter_mode_deltas[0] = 0; + vp9->loop_filter_mode_deltas[1] = 0; + + memset(vp9->feature_enabled, 0, sizeof(vp9->feature_enabled)); + memset(vp9->feature_value, 0, sizeof(vp9->feature_value)); + memset(vp9->feature_sign, 0, sizeof(vp9->feature_sign)); + + } else { + // Modify previous state based on updates in this frame. + + if (current->loop_filter_delta_update) { + for (i = 0; i < 4; i++) { + if (current->update_ref_delta[i]) + vp9->loop_filter_ref_deltas[i] = + current->loop_filter_ref_deltas[i]; + } + for (i = 0; i < 2; i++) { + if (current->update_mode_delta[i]) + vp9->loop_filter_mode_deltas[i] = + current->loop_filter_mode_deltas[i]; + } + } + + if (current->segmentation_update_data) { + memcpy(vp9->feature_enabled, current->feature_enabled, + sizeof(vp9->feature_enabled)); + memcpy(vp9->feature_value, current->feature_value, + sizeof(vp9->feature_value)); + memcpy(vp9->feature_sign, current->feature_sign, + sizeof(vp9->feature_sign)); + + if (current->segmentation_update_map) { + memcpy(vp9->segmentation_tree_probs, + current->segmentation_tree_probs, + sizeof(vp9->segmentation_tree_probs)); + memcpy(vp9->segmentation_pred_prob, + current->segmentation_pred_prob, + sizeof(vp9->segmentation_pred_prob)); + } + } + } + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame: size %dx%d " "subsample %dx%d bit_depth %d tiles %dx%d.\n", vp9->frame_width, vp9->frame_height, diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c index d8b992bb94..6f4d4fca41 100644 --- a/libavcodec/ccaption_dec.c +++ b/libavcodec/ccaption_dec.c @@ -253,6 +253,7 @@ struct Screen { typedef struct CCaptionSubContext { AVClass *class; + void *logctx; int real_time; int real_time_latency_msec; int data_field; @@ -280,6 +281,8 @@ static av_cold int init_decoder(AVCodecContext *avctx) { CCaptionSubContext *ctx = avctx->priv_data; + ctx->logctx = avctx; + av_bprint_init(&ctx->buffer[0], 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&ctx->buffer[1], 0, AV_BPRINT_SIZE_UNLIMITED); /* taking by default roll up to 2 */ @@ -359,7 +362,7 @@ static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch) return; } else { - av_log(ctx, AV_LOG_WARNING, "Data ignored due to columns exceeding screen width\n"); + av_log(ctx->logctx, AV_LOG_WARNING, "Data ignored due to columns exceeding screen width\n"); return; } } @@ -649,7 +652,7 @@ static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) int indent, i; if (row_map[index] <= 0) { - av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n"); + av_log(ctx->logctx, AV_LOG_DEBUG, "Invalid pac index encountered\n"); return; } @@ -749,9 +752,9 @@ static void handle_char(CCaptionSubContext *ctx, char hi, char lo) ctx->screen_touched = 1; if (lo) - ff_dlog(ctx, "(%c,%c)\n", hi, lo); + ff_dlog(ctx->logctx, "(%c,%c)\n", hi, lo); else - ff_dlog(ctx, "(%c)\n", hi); + ff_dlog(ctx->logctx, "(%c)\n", hi); } static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) @@ -803,7 +806,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2d: /* carriage return */ - ff_dlog(ctx, "carriage return\n"); + ff_dlog(ctx->logctx, "carriage return\n"); if (!ctx->real_time) ret = capture_screen(ctx); roll_up(ctx); @@ -811,7 +814,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2e: /* erase buffered (non displayed) memory */ - // Only in realtime mode. In buffered mode, we re-use the inactive screen + // Only in realtime mode. In buffered mode, we reuse the inactive screen // for our own buffering. if (ctx->real_time) { struct Screen *screen = ctx->screen + !ctx->active_screen; @@ -820,11 +823,11 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) break; case 0x2f: /* end of caption */ - ff_dlog(ctx, "handle_eoc\n"); + ff_dlog(ctx->logctx, "handle_eoc\n"); ret = handle_eoc(ctx); break; default: - ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); + ff_dlog(ctx->logctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); break; } } else if (hi >= 0x11 && hi <= 0x13) { @@ -842,7 +845,7 @@ static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) } } else { /* Ignoring all other non data code */ - ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); + ff_dlog(ctx->logctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); } return ret; @@ -888,7 +891,7 @@ static int decode(AVCodecContext *avctx, AVSubtitle *sub, update_time(ctx, in_time); if (ctx->buffer[bidx].str[0] || ctx->real_time) { - ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str); + ff_dlog(avctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str); start_time = ctx->buffer_time[0]; sub->pts = start_time; end_time = ctx->buffer_time[1]; diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c index f33f7fbf00..518c75081b 100644 --- a/libavcodec/cdgraphics.c +++ b/libavcodec/cdgraphics.c @@ -125,11 +125,6 @@ static void cdg_load_palette(CDGraphicsContext *cc, uint8_t *data, int low) b = ((color ) & 0x000F) * 17; palette[i + array_offset] = (uint32_t)cc->alpha[i + array_offset] << 24 | r << 16 | g << 8 | b; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - cc->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } static int cdg_tile_block(CDGraphicsContext *cc, uint8_t *data, int b) diff --git a/libavcodec/cdtoons.c b/libavcodec/cdtoons.c index 89b6d76d84..adc6cf3f44 100644 --- a/libavcodec/cdtoons.c +++ b/libavcodec/cdtoons.c @@ -385,11 +385,6 @@ static int cdtoons_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } /* first palette entry indicates transparency */ c->pal[0] = 0; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - c->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } diff --git a/libavcodec/celp_math.c b/libavcodec/celp_math.c index a5fe7f2ea9..658937dccc 100644 --- a/libavcodec/celp_math.c +++ b/libavcodec/celp_math.c @@ -23,12 +23,16 @@ #include #include "config.h" -#include "libavutil/avassert.h" + +#include "libavutil/attributes.h" +#include "libavutil/float_dsp.h" #include "libavutil/intmath.h" #include "mathops.h" #include "celp_math.h" #ifdef G729_BITEXACT +#include "libavutil/avassert.h" + static const uint16_t exp2a[]= { 0, 1435, 2901, 4400, 5931, 7496, 9096, 10730, @@ -107,20 +111,9 @@ int64_t ff_dot_product(const int16_t *a, const int16_t *b, int length) return sum; } -float ff_dot_productf(const float* a, const float* b, int length) +av_cold void ff_celp_math_init(CELPMContext *c) { - float sum = 0; - int i; - - for(i=0; idot_productf = ff_dot_productf; + c->dot_productf = ff_scalarproduct_float_c; #if HAVE_MIPSFPU ff_celp_math_init_mips(c); diff --git a/libavcodec/celp_math.h b/libavcodec/celp_math.h index 99a0470719..8228d560e0 100644 --- a/libavcodec/celp_math.h +++ b/libavcodec/celp_math.h @@ -84,14 +84,4 @@ static inline unsigned bidir_sal(unsigned value, int offset) else return value << offset; } -/** - * Return the dot product. - * @param a input data array - * @param b input data array - * @param length number of elements - * - * @return dot product = sum of elementwise products - */ -float ff_dot_productf(const float* a, const float* b, int length); - #endif /* AVCODEC_CELP_MATH_H */ diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 6f1d960058..f110b91f0b 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -25,6 +25,7 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" +#include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" @@ -117,10 +118,8 @@ static inline int dequant_and_decompand(CFHDContext *s, int level, int quantisat static inline void difference_coding(int16_t *band, int width, int height) { - - int i,j; - for (i = 0; i < height; i++) { - for (j = 1; j < width; j++) { + for (int i = 0; i < height; i++) { + for (int j = 1; j < width; j++) { band[j] += band[j-1]; } band += width; @@ -129,17 +128,15 @@ static inline void difference_coding(int16_t *band, int width, int height) static inline void peak_table(int16_t *band, Peak *peak, int length) { - int i; - for (i = 0; i < length; i++) + for (int i = 0; i < length; i++) if (abs(band[i]) > peak->level) band[i] = bytestream2_get_le16(&peak->base); } static inline void process_alpha(int16_t *alpha, int width) { - int i, channel; - for (i = 0; i < width; i++) { - channel = alpha[i]; + for (int i = 0; i < width; i++) { + int channel = alpha[i]; channel -= ALPHA_COMPAND_DC_OFFSET; channel <<= 3; channel *= ALPHA_COMPAND_GAIN; @@ -196,11 +193,9 @@ static inline void process_bayer(AVFrame *frame, int bpc) static inline void interlaced_vertical_filter(int16_t *output, int16_t *low, int16_t *high, int width, int linesize, int plane) { - int i; - int16_t even, odd; - for (i = 0; i < width; i++) { - even = (low[i] - high[i])/2; - odd = (low[i] + high[i])/2; + for (int i = 0; i < width; i++) { + int16_t even = (low[i] - high[i])/2; + int16_t odd = (low[i] + high[i])/2; output[i] = av_clip_uintp2(even, 10); output[i + linesize] = av_clip_uintp2(odd, 10); } @@ -219,21 +214,19 @@ static inline void inverse_temporal_filter(int16_t *low, int16_t *high, int widt static void free_buffers(CFHDContext *s) { - int i, j; - - for (i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { + for (size_t i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { Plane *p = &s->plane[i]; av_freep(&s->plane[i].idwt_buf); av_freep(&s->plane[i].idwt_tmp); s->plane[i].idwt_size = 0; - for (j = 0; j < SUBBAND_COUNT_3D; j++) + for (int j = 0; j < SUBBAND_COUNT_3D; j++) s->plane[i].subband[j] = NULL; - for (j = 0; j < 10; j++) + for (int j = 0; j < 10; j++) s->plane[i].l_h[j] = NULL; - for (j = 0; j < DWT_LEVELS_3D; j++) + for (int j = 0; j < DWT_LEVELS_3D; j++) p->band[j][0].read_ok = p->band[j][1].read_ok = p->band[j][2].read_ok = @@ -247,9 +240,8 @@ static void free_buffers(CFHDContext *s) static int alloc_buffers(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - int i, j, ret, planes, bayer = 0; + int ret, planes, bayer = 0; int chroma_x_shift, chroma_y_shift; - unsigned k; if ((ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height)) < 0) return ret; @@ -269,12 +261,15 @@ static int alloc_buffers(AVCodecContext *avctx) bayer = 1; } - for (i = 0; i < planes; i++) { + for (int i = 0; i < planes; i++) { int w8, h8, w4, h4, w2, h2; int width = (i || bayer) ? s->coded_width >> chroma_x_shift : s->coded_width; int height = (i || bayer) ? s->coded_height >> chroma_y_shift : s->coded_height; ptrdiff_t stride = (FFALIGN(width / 8, 8) + 64) * 8; + if ((ret = av_image_check_size2(stride, height, avctx->max_pixels, s->coded_format, 0, avctx)) < 0) + return ret; + if (chroma_y_shift && !bayer) height = FFALIGN(height / 8, 2) * 8; s->plane[i].width = width; @@ -331,17 +326,17 @@ static int alloc_buffers(AVCodecContext *avctx) } if (s->transform_type == 0) { - for (j = 0; j < DWT_LEVELS; j++) { - for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { + for (int j = 0; j < DWT_LEVELS; j++) { + for (unsigned 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; } } } else { - for (j = 0; j < DWT_LEVELS_3D; j++) { + for (int j = 0; j < DWT_LEVELS_3D; j++) { int t = j < 1 ? 0 : (j < 3 ? 1 : 2); - for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { + for (unsigned k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { s->plane[i].band[j][k].a_width = w8 << t; s->plane[i].band[j][k].a_height = h8 << t; } @@ -379,8 +374,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, CFHDContext *s = avctx->priv_data; CFHDDSPContext *dsp = &s->dsp; GetByteContext gb; - int ret = 0, i, j, plane, got_buffer = 0; - int16_t *coeff_data; + int ret = 0, got_buffer = 0; init_frame_defaults(s); s->planes = av_pix_fmt_count_planes(s->coded_format); @@ -395,6 +389,8 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, uint16_t abstag = abs(tag); int8_t abs_tag8 = abs(tag8); uint16_t data = bytestream2_get_be16(&gb); + int16_t *coeff_data; + if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); } else if (tag == SampleFlags) { @@ -477,7 +473,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, s->quantisation = data; av_log(avctx, AV_LOG_DEBUG, "Quantisation: %"PRIu16"\n", data); } else if (tag == PrescaleTable) { - for (i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) s->prescale_table[i] = (data >> (14 - i * 2)) & 0x3; av_log(avctx, AV_LOG_DEBUG, "Prescale table: %x\n", data); } else if (tag == BandEncoding) { @@ -529,7 +525,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, ret = AVERROR_INVALIDDATA; goto end; } - for (i = 0; i < data; i++) { + for (int i = 0; i < data; i++) { uint32_t offset = bytestream2_get_be32(&gb); av_log(avctx, AV_LOG_DEBUG, "Offset = %"PRIu32"\n", offset); } @@ -746,8 +742,8 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, } av_log(avctx, AV_LOG_DEBUG, "Start of lowpass coeffs component %d height:%d, width:%d\n", s->channel_num, lowpass_height, lowpass_width); - for (i = 0; i < lowpass_height; i++) { - for (j = 0; j < lowpass_width; j++) + for (int i = 0; i < lowpass_height; i++) { + for (int j = 0; j < lowpass_width; j++) coeff_data[j] = bytestream2_get_be16u(&gb); coeff_data += lowpass_width; @@ -772,7 +768,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandHeader || tag == BandSecondPass) { int highpass_height, highpass_width, highpass_a_width, highpass_a_height, highpass_stride, a_expected; int expected; - int level, run, coeff; + GetBitContext gbit; int count = 0, bytes; if (!s->a_width || !s->a_height) { @@ -802,11 +798,11 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, av_log(avctx, AV_LOG_DEBUG, "Start subband coeffs plane %i level %i codebook %i expected %i\n", s->channel_num, s->level, s->codebook, expected); - ret = init_get_bits8(&s->gb, gb.buffer, bytestream2_get_bytes_left(&gb)); + ret = init_get_bits8(&gbit, gb.buffer, bytestream2_get_bytes_left(&gb)); if (ret < 0) goto end; { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &gbit); const int lossless = s->band_encoding == 5; @@ -814,8 +810,10 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, s->codebook = 1; if (!s->codebook) { while (1) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, s->table_9_rl_vlc, + int level, run, coeff; + + UPDATE_CACHE(re, &gbit); + GET_RL_VLC(level, run, re, &gbit, s->table_9_rl_vlc, VLC_BITS, 3, 1); /* escape */ @@ -834,19 +832,21 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandSecondPass) { const uint16_t q = s->quantisation; - for (i = 0; i < run; i++) { + for (int i = 0; i < run; i++) { *coeff_data |= coeff * 256U; *coeff_data++ *= q; } } else { - for (i = 0; i < run; i++) + for (int i = 0; i < run; i++) *coeff_data++ = coeff; } } } else { while (1) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, s->table_18_rl_vlc, + int level, run, coeff; + + UPDATE_CACHE(re, &gbit); + GET_RL_VLC(level, run, re, &gbit, s->table_18_rl_vlc, VLC_BITS, 3, 1); /* escape */ @@ -865,17 +865,17 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (tag == BandSecondPass) { const uint16_t q = s->quantisation; - for (i = 0; i < run; i++) { + for (int i = 0; i < run; i++) { *coeff_data |= coeff * 256U; *coeff_data++ *= q; } } else { - for (i = 0; i < run; i++) + for (int i = 0; i < run; i++) *coeff_data++ = coeff; } } } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &gbit); } if (count > expected) { @@ -888,7 +888,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (s->difference_coding) difference_coding(s->plane[s->channel_num].subband[s->subband_num_actual], highpass_width, highpass_height); - bytes = FFALIGN(AV_CEIL_RSHIFT(get_bits_count(&s->gb), 3), 4); + bytes = FFALIGN(AV_CEIL_RSHIFT(get_bits_count(&gbit), 3), 4); if (bytes > bytestream2_get_bytes_left(&gb)) { av_log(avctx, AV_LOG_ERROR, "Bitstream overread error\n"); ret = AVERROR(EINVAL); @@ -926,14 +926,12 @@ finish: goto end; } - for (plane = 0; plane < s->planes; plane++) { - int o, level; - - for (level = 0; level < (s->transform_type == 0 ? DWT_LEVELS : DWT_LEVELS_3D) ; level++) { + for (int plane = 0; plane < s->planes; plane++) { + for (int level = 0; level < (s->transform_type == 0 ? DWT_LEVELS : DWT_LEVELS_3D) ; level++) { if (s->transform_type == 2) if (level == 2 || level == 5) continue; - for (o = !!level; o < 4 ; o++) { + for (int o = !!level; o < 4 ; o++) { if (!s->plane[plane].band[level][o].read_ok) { ret = AVERROR_INVALIDDATA; goto end; @@ -943,7 +941,7 @@ finish: } if (s->transform_type == 0 && s->sample_type != 1) { - for (plane = 0; plane < s->planes && !ret; plane++) { + for (int plane = 0; plane < s->planes && !ret; plane++) { /* level 1 */ int lowpass_height = s->plane[plane].band[0][0].height; int output_stride = s->plane[plane].band[0][0].a_width; @@ -987,8 +985,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); if (s->bpc == 12) { output = s->plane[plane].subband[0]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1027,8 +1025,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); output = s->plane[plane].subband[0]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1078,7 +1076,7 @@ finish: goto end; } - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); if (avctx->pix_fmt == AV_PIX_FMT_GBRAP12 && act_plane == 3) process_alpha(dst, lowpass_width * 2); @@ -1102,7 +1100,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; @@ -1111,7 +1109,7 @@ finish: } } } else if (s->transform_type == 2 && (avctx->internal->is_copy || s->frame_index == 1 || s->sample_type != 1)) { - for (plane = 0; plane < s->planes && !ret; plane++) { + for (int plane = 0; plane < s->planes && !ret; plane++) { int lowpass_height = s->plane[plane].band[0][0].height; int output_stride = s->plane[plane].band[0][0].a_width; int lowpass_width = s->plane[plane].band[0][0].width; @@ -1153,8 +1151,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); if (s->bpc == 12) { output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; @@ -1192,8 +1190,8 @@ finish: dsp->horiz_filter(output, output_stride, low, output_stride, high, output_stride, lowpass_width, lowpass_height * 2); output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height * 2; i++) { - for (j = 0; j < lowpass_width * 2; j++) + for (int i = 0; i < lowpass_height * 2; i++) { + for (int j = 0; j < lowpass_width * 2; j++) output[j] *= 4; output += output_stride * 2; } @@ -1230,7 +1228,7 @@ finish: low = s->plane[plane].l_h[7]; high = s->plane[plane].l_h[9]; output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height; i++) { + for (int i = 0; i < lowpass_height; i++) { inverse_temporal_filter(low, high, lowpass_width); low += output_stride; high += output_stride; @@ -1277,7 +1275,7 @@ finish: low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); low += output_stride; high += output_stride; @@ -1311,7 +1309,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[6]; high = s->plane[plane].l_h[7]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; @@ -1326,7 +1324,7 @@ finish: int output_stride, lowpass_height, lowpass_width; ptrdiff_t dst_linesize; - for (plane = 0; plane < s->planes; plane++) { + for (int plane = 0; plane < s->planes; plane++) { int act_plane = plane == 1 ? 2 : plane == 2 ? 1 : plane; if (avctx->pix_fmt == AV_PIX_FMT_BAYER_RGGB16) { @@ -1368,7 +1366,7 @@ finish: goto end; } - for (i = 0; i < s->plane[act_plane].height; i++) { + for (int i = 0; i < s->plane[act_plane].height; i++) { dsp->horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); low += output_stride; high += output_stride; @@ -1378,7 +1376,7 @@ finish: dst = (int16_t *)pic->data[act_plane]; low = s->plane[plane].l_h[8]; high = s->plane[plane].l_h[9]; - for (i = 0; i < s->plane[act_plane].height / 2; i++) { + for (int i = 0; i < s->plane[act_plane].height / 2; i++) { interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); low += output_stride * 2; high += output_stride * 2; diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 9b09c91262..2dbac80c66 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -25,7 +25,6 @@ #include "avcodec.h" #include "bytestream.h" -#include "get_bits.h" #include "cfhddsp.h" enum CFHDParam { @@ -98,7 +97,7 @@ enum CFHDParam { typedef struct CFHD_RL_VLC_ELEM { int16_t level; - int8_t len; + int8_t len8; uint16_t run; } CFHD_RL_VLC_ELEM; @@ -144,8 +143,6 @@ typedef struct CFHDContext { int lut[2][256]; - GetBitContext gb; - int planes; int frame_type; int frame_index; diff --git a/libavcodec/cfhddata.c b/libavcodec/cfhddata.c index a3948a14ca..72b14baf27 100644 --- a/libavcodec/cfhddata.c +++ b/libavcodec/cfhddata.c @@ -136,22 +136,22 @@ static av_cold int cfhd_init_vlc(CFHD_RL_VLC_ELEM out[], unsigned out_size, /** Similar to dv.c, generate signed VLC tables **/ for (unsigned i = j = 0; i < table_size; i++, j++) { - tmp[j].len = table_vlc[i].len; + tmp[j].len8 = table_vlc[i].len; tmp[j].run = table_vlc[i].run; tmp[j].level = table_vlc[i].level; /* Don't include the zero level nor escape bits */ if (table_vlc[i].level && table_vlc[i].run) { - tmp[j].len++; + tmp[j].len8++; j++; - tmp[j].len = table_vlc[i].len + 1; + tmp[j].len8 = table_vlc[i].len + 1; tmp[j].run = table_vlc[i].run; tmp[j].level = -table_vlc[i].level; } } ret = ff_vlc_init_from_lengths(&vlc, VLC_BITS, j, - &tmp[0].len, sizeof(tmp[0]), + &tmp[0].len8, sizeof(tmp[0]), NULL, 0, 0, 0, 0, logctx); if (ret < 0) return ret; @@ -169,7 +169,7 @@ static av_cold int cfhd_init_vlc(CFHD_RL_VLC_ELEM out[], unsigned out_size, run = tmp[code].run; level = tmp[code].level; } - out[i].len = len; + out[i].len8 = len; out[i].level = level; out[i].run = run; } diff --git a/libavcodec/cfhdenc.c b/libavcodec/cfhdenc.c index 3be6798d8d..42e01bfd85 100644 --- a/libavcodec/cfhdenc.c +++ b/libavcodec/cfhdenc.c @@ -285,7 +285,7 @@ static av_cold int cfhd_encode_init(AVCodecContext *avctx) s->plane[i].dwt_buf = av_calloc(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_buf)); s->plane[i].dwt_tmp = - av_malloc_array(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_tmp)); + av_calloc(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_tmp)); if (!s->plane[i].dwt_buf || !s->plane[i].dwt_tmp) return AVERROR(ENOMEM); @@ -864,12 +864,7 @@ const FFCodec ff_cfhd_encoder = { .init = cfhd_encode_init, .close = cfhd_encode_close, FF_CODEC_ENCODE_CB(cfhd_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_GBRP12, - AV_PIX_FMT_GBRAP12, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c index 2ec0ce8882..9ec7ac5a8f 100644 --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@ -476,14 +476,7 @@ static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (s->palette_video) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if ((ret = cinepak_decode(s)) < 0) { diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c index f6145131a2..104a9f485e 100644 --- a/libavcodec/cinepakenc.c +++ b/libavcodec/cinepakenc.c @@ -1223,7 +1223,7 @@ const FFCodec ff_cinepak_encoder = { .init = cinepak_encode_init, FF_CODEC_ENCODE_CB(cinepak_encode_frame), .close = cinepak_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8), .p.priv_class = &cinepak_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cljrdec.c b/libavcodec/cljrdec.c index 66e9d56e0e..79fbea990f 100644 --- a/libavcodec/cljrdec.c +++ b/libavcodec/cljrdec.c @@ -88,4 +88,3 @@ const FFCodec ff_cljr_decoder = { FF_CODEC_DECODE_CB(decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, }; - diff --git a/libavcodec/cljrenc.c b/libavcodec/cljrenc.c index 4698dfd725..3b71a85aa9 100644 --- a/libavcodec/cljrenc.c +++ b/libavcodec/cljrenc.c @@ -116,8 +116,7 @@ const FFCodec ff_cljr_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(CLJRContext), FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &cljr_class, }; diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index bacbd54fab..dfcc685e7e 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -173,8 +173,7 @@ const FFCodec ff_comfortnoise_decoder = { FF_CODEC_DECODE_CB(cng_decode_frame), .flush = cng_decode_flush, .close = cng_decode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cngenc.c b/libavcodec/cngenc.c index c430136809..69501dae6f 100644 --- a/libavcodec/cngenc.c +++ b/libavcodec/cngenc.c @@ -108,8 +108,7 @@ const FFCodec ff_comfortnoise_encoder = { .init = cng_encode_init, FF_CODEC_ENCODE_CB(cng_encode_frame), .close = cng_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/codec.h b/libavcodec/codec.h index f7541ffc42..f509e5d94e 100644 --- a/libavcodec/codec.h +++ b/libavcodec/codec.h @@ -80,21 +80,6 @@ */ #define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) -#if FF_API_SUBFRAMES -/** - * Codec can output multiple frames per AVPacket - * Normally demuxers return one frame at a time, demuxers which do not do - * are connected to a parser to split what they return into proper frames. - * This flag is reserved to the very rare category of codecs which have a - * bitstream that cannot be split into frames without timeconsuming - * operations like full decoding. Demuxers carrying such bitstreams thus - * may return multiple frames in a packet. This has many disadvantages like - * prohibiting stream copy in many cases thus it should only be considered - * as a last resort. - */ -#define AV_CODEC_CAP_SUBFRAMES (1 << 8) -#endif - /** * Codec is experimental and is thus avoided in favor of non experimental * encoders diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 03dea5751a..a065556e51 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -905,7 +905,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "tgq", .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGQ video"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_TQI, @@ -1146,6 +1146,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Dxtory"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#if FF_API_V408_CODECID { .id = AV_CODEC_ID_V410, .type = AVMEDIA_TYPE_VIDEO, @@ -1153,6 +1154,7 @@ 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, }, +#endif { .id = AV_CODEC_ID_XWD, .type = AVMEDIA_TYPE_VIDEO, @@ -1477,6 +1479,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#if FF_API_V408_CODECID { .id = AV_CODEC_ID_V308, .type = AVMEDIA_TYPE_VIDEO, @@ -1491,6 +1494,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, +#endif { .id = AV_CODEC_ID_YUV4, .type = AVMEDIA_TYPE_VIDEO, @@ -1959,6 +1963,43 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("LEAD MCMP"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_DNXUC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dnxuc", + .long_name = NULL_IF_CONFIG_SMALL("DNxUncompressed / SMPTE RDD 50"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RV60, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv60", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 6.0"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_JPEGXL_ANIM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpegxl_anim", + .long_name = NULL_IF_CONFIG_SMALL("JPEG XL animated"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/jxl"), + }, + { + .id = AV_CODEC_ID_APV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "apv", + .long_name = NULL_IF_CONFIG_SMALL("Advanced Professional Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PRORES_RAW, + .type = AVMEDIA_TYPE_VIDEO, + .name = "prores_raw", + .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes RAW"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_raw_profiles), + }, /* various PCM "codecs" */ { @@ -2579,6 +2620,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Konami XMD"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_XBOX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_xbox", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Xbox"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SANYO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_sanyo", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sanyo"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { @@ -2697,7 +2752,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_AUDIO, .name = "aac", .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }, { @@ -3031,7 +3086,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_AUDIO, .name = "aac_latm", .long_name = NULL_IF_CONFIG_SMALL("AAC LATM (Advanced Audio Coding LATM syntax)"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }, { @@ -3433,6 +3488,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication Codec)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_G728, + .type = AVMEDIA_TYPE_AUDIO, + .name = "g728", + .long_name = NULL_IF_CONFIG_SMALL("G.728"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { @@ -3616,6 +3678,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption"), .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), }, + { + .id = AV_CODEC_ID_IVTV_VBI, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ivtv_vbi", + .long_name = NULL_IF_CONFIG_SMALL("ivtv VBI captions"), + }, /* other kind of codecs and pseudo-codecs */ { @@ -3702,6 +3770,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .name = "lcevc", .long_name = NULL_IF_CONFIG_SMALL("LCEVC (Low Complexity Enhancement Video Coding) / MPEG-5 LCEVC / MPEG-5 part 2"), }, + { + .id = AV_CODEC_ID_SMPTE_436M_ANC, + .type = AVMEDIA_TYPE_DATA, + .name = "smpte_436m_anc", + .long_name = NULL_IF_CONFIG_SMALL("MXF SMPTE-436M ANC"), + }, { .id = AV_CODEC_ID_MPEG2TS, .type = AVMEDIA_TYPE_DATA, diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 0a8d3bed1e..c4842e61ff 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -206,7 +206,9 @@ enum AVCodecID { AV_CODEC_ID_BMV_VIDEO, AV_CODEC_ID_VBLE, AV_CODEC_ID_DXTORY, +#if FF_API_V408_CODECID AV_CODEC_ID_V410, +#endif AV_CODEC_ID_XWD, AV_CODEC_ID_CDXL, AV_CODEC_ID_XBM, @@ -254,8 +256,10 @@ enum AVCodecID { AV_CODEC_ID_012V, AV_CODEC_ID_AVUI, AV_CODEC_ID_TARGA_Y216, +#if FF_API_V408_CODECID AV_CODEC_ID_V308, AV_CODEC_ID_V408, +#endif AV_CODEC_ID_YUV4, AV_CODEC_ID_AVRN, AV_CODEC_ID_CPIA, @@ -322,6 +326,11 @@ enum AVCodecID { AV_CODEC_ID_RTV1, AV_CODEC_ID_VMIX, AV_CODEC_ID_LEAD, + AV_CODEC_ID_DNXUC, + AV_CODEC_ID_RV60, + AV_CODEC_ID_JPEGXL_ANIM, + AV_CODEC_ID_APV, + AV_CODEC_ID_PRORES_RAW, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs @@ -416,6 +425,8 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_MOFLEX, AV_CODEC_ID_ADPCM_IMA_ACORN, AV_CODEC_ID_ADPCM_XMD, + AV_CODEC_ID_ADPCM_IMA_XBOX, + AV_CODEC_ID_ADPCM_SANYO, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, @@ -544,6 +555,7 @@ enum AVCodecID { AV_CODEC_ID_OSQ, AV_CODEC_ID_QOA, AV_CODEC_ID_LC3, + AV_CODEC_ID_G728, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -573,6 +585,7 @@ enum AVCodecID { AV_CODEC_ID_HDMV_TEXT_SUBTITLE, AV_CODEC_ID_TTML, AV_CODEC_ID_ARIB_CAPTION, + AV_CODEC_ID_IVTV_VBI, /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. @@ -590,6 +603,7 @@ enum AVCodecID { AV_CODEC_ID_BIN_DATA, AV_CODEC_ID_SMPTE_2038, AV_CODEC_ID_LCEVC, + AV_CODEC_ID_SMPTE_436M_ANC, AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h index 5b2db74590..7fa3097aa9 100644 --- a/libavcodec/codec_internal.h +++ b/libavcodec/codec_internal.h @@ -22,7 +22,6 @@ #include #include "libavutil/attributes.h" -#include "avcodec.h" #include "codec.h" #include "config.h" @@ -102,6 +101,7 @@ typedef struct FFCodecDefault { struct AVCodecContext; struct AVSubtitle; struct AVPacket; +enum AVCodecConfig; enum FFCodecType { /* The codec is a decoder using the decode callback; @@ -133,7 +133,12 @@ typedef struct FFCodec { /** * Internal codec capabilities FF_CODEC_CAP_*. */ - unsigned caps_internal:27; + unsigned caps_internal:26; + + /** + * Is this a decoder? + */ + unsigned is_decoder:1; /** * This field determines the video color ranges supported by an encoder. @@ -268,7 +273,7 @@ typedef struct FFCodec { * ff_default_get_supported_config() will be used. `out_num_configs` will * always be set to a valid pointer. */ - int (*get_supported_config)(const AVCodecContext *avctx, + int (*get_supported_config)(const struct AVCodecContext *avctx, const AVCodec *codec, enum AVCodecConfig config, unsigned flags, @@ -276,6 +281,31 @@ typedef struct FFCodec { int *out_num_configs); } FFCodec; +static av_always_inline const FFCodec *ffcodec(const AVCodec *codec) +{ + return (const FFCodec*)codec; +} + +/** + * Internal version of av_codec_is_encoder(). Must not be called with + * a NULL AVCodec*. + */ +static inline int ff_codec_is_encoder(const AVCodec *avcodec) +{ + const FFCodec *const codec = ffcodec(avcodec); + return !codec->is_decoder; +} + +/** + * Internal version of av_codec_is_decoder(). Must not be called with + * a NULL AVCodec*. + */ +static inline int ff_codec_is_decoder(const AVCodec *avcodec) +{ + const FFCodec *const codec = ffcodec(avcodec); + return codec->is_decoder; +} + /** * Default implementation for avcodec_get_supported_config(). Will return the * relevant fields from AVCodec if present, or NULL otherwise. @@ -283,7 +313,7 @@ typedef struct FFCodec { * For AVCODEC_CONFIG_COLOR_RANGE, the output will depend on the bitmask in * FFCodec.color_ranges, with a value of 0 returning NULL. */ -int ff_default_get_supported_config(const AVCodecContext *avctx, +int ff_default_get_supported_config(const struct AVCodecContext *avctx, const AVCodec *codec, enum AVCodecConfig config, unsigned flags, @@ -309,27 +339,56 @@ int ff_default_get_supported_config(const AVCodecContext *avctx, #endif #define FF_CODEC_DECODE_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_DECODE, \ .cb.decode = (func) #define FF_CODEC_DECODE_SUB_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_DECODE_SUB, \ .cb.decode_sub = (func) #define FF_CODEC_RECEIVE_FRAME_CB(func) \ + .is_decoder = 1, \ .cb_type = FF_CODEC_CB_TYPE_RECEIVE_FRAME, \ .cb.receive_frame = (func) #define FF_CODEC_ENCODE_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_ENCODE, \ .cb.encode = (func) #define FF_CODEC_ENCODE_SUB_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_ENCODE_SUB, \ .cb.encode_sub = (func) #define FF_CODEC_RECEIVE_PACKET_CB(func) \ + .is_decoder = 0, \ .cb_type = FF_CODEC_CB_TYPE_RECEIVE_PACKET, \ .cb.receive_packet = (func) -static av_always_inline const FFCodec *ffcodec(const AVCodec *codec) -{ - return (const FFCodec*)codec; -} +#ifdef __clang__ +#define DISABLE_DEPRECATION_WARNINGS FF_DISABLE_DEPRECATION_WARNINGS +#define ENABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS +#else +#define DISABLE_DEPRECATION_WARNINGS +#define ENABLE_DEPRECATION_WARNINGS +#endif + +#define CODEC_CH_LAYOUTS(...) CODEC_CH_LAYOUTS_ARRAY(((const AVChannelLayout[]) { __VA_ARGS__, { 0 } })) +#define CODEC_CH_LAYOUTS_ARRAY(array) CODEC_ARRAY(ch_layouts, (array)) + +#define CODEC_SAMPLERATES(...) CODEC_SAMPLERATES_ARRAY(((const int[]) { __VA_ARGS__, 0 })) +#define CODEC_SAMPLERATES_ARRAY(array) CODEC_ARRAY(supported_samplerates, (array)) + +#define CODEC_SAMPLEFMTS(...) CODEC_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE })) +#define CODEC_SAMPLEFMTS_ARRAY(array) CODEC_ARRAY(sample_fmts, (array)) + +#define CODEC_FRAMERATES(...) CODEC_FRAMERATES_ARRAY(((const AVRational[]) { __VA_ARGS__, { 0, 0 } })) +#define CODEC_FRAMERATES_ARRAY(array) CODEC_ARRAY(supported_framerates, (array)) + +#define CODEC_PIXFMTS(...) CODEC_PIXFMTS_ARRAY(((const enum AVPixelFormat[]) { __VA_ARGS__, AV_PIX_FMT_NONE })) +#define CODEC_PIXFMTS_ARRAY(array) CODEC_ARRAY(pix_fmts, (array)) + +#define CODEC_ARRAY(field, array) \ + DISABLE_DEPRECATION_WARNINGS \ + .p.field = (array) \ + ENABLE_DEPRECATION_WARNINGS #endif /* AVCODEC_CODEC_INTERNAL_H */ diff --git a/libavcodec/codec_par.h b/libavcodec/codec_par.h index f4b9bb5c06..64b01f7e02 100644 --- a/libavcodec/codec_par.h +++ b/libavcodec/codec_par.h @@ -148,7 +148,7 @@ typedef struct AVCodecParameters { * durations. Should be set to { 0, 1 } when some frames have differing * durations or if the value is not known. * - * @note This field correponds to values that are stored in codec-level + * @note This field corresponds to values that are stored in codec-level * headers and is typically overridden by container/transport-layer * timestamps, when available. It should thus be used only as a last resort, * when no higher-level timing information is available. diff --git a/libavcodec/container_fifo.c b/libavcodec/container_fifo.c deleted file mode 100644 index 82e86d9465..0000000000 --- a/libavcodec/container_fifo.c +++ /dev/null @@ -1,195 +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 "libavutil/error.h" -#include "libavutil/fifo.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" - -#include "container_fifo.h" -#include "refstruct.h" - -struct ContainerFifo { - AVFifo *fifo; - FFRefStructPool *pool; - - void* (*container_alloc)(void); - void (*container_reset)(void *obj); - void (*container_free) (void *obj); - int (*fifo_write) (void *dst, void *src); - int (*fifo_read) (void *dst, void *src); - -}; - -static int container_fifo_init_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - void **pobj = obj; - - *pobj = cf->container_alloc(); - if (!*pobj) - return AVERROR(ENOMEM); - - return 0; -} - -static void container_fifo_reset_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - cf->container_reset(*(void**)obj); -} - -static void container_fifo_free_entry(FFRefStructOpaque opaque, void *obj) -{ - ContainerFifo *cf = opaque.nc; - cf->container_free(*(void**)obj); -} - -ContainerFifo* -ff_container_fifo_alloc(void* (*container_alloc)(void), - void (*container_reset)(void *obj), - void (*container_free) (void *obj), - int (*fifo_write) (void *dst, void *src), - int (*fifo_read) (void *dst, void *src)) -{ - ContainerFifo *cf; - - cf = av_mallocz(sizeof(*cf)); - if (!cf) - return NULL; - - cf->container_alloc = container_alloc; - cf->container_reset = container_reset; - cf->container_free = container_free; - cf->fifo_write = fifo_write; - cf->fifo_read = fifo_read; - - cf->fifo = av_fifo_alloc2(1, sizeof(void*), AV_FIFO_FLAG_AUTO_GROW); - if (!cf->fifo) - goto fail; - - cf->pool = ff_refstruct_pool_alloc_ext(sizeof(void*), 0, cf, - container_fifo_init_entry, - container_fifo_reset_entry, - container_fifo_free_entry, - NULL); - if (!cf->pool) - goto fail; - - return cf; -fail: - ff_container_fifo_free(&cf); - return NULL; -} - -void ff_container_fifo_free(ContainerFifo **pcf) -{ - ContainerFifo *cf; - - if (!*pcf) - return; - - cf = *pcf; - - if (cf->fifo) { - void *obj; - while (av_fifo_read(cf->fifo, &obj, 1) >= 0) - ff_refstruct_unref(&obj); - av_fifo_freep2(&cf->fifo); - } - - ff_refstruct_pool_uninit(&cf->pool); - - av_freep(pcf); -} - -int ff_container_fifo_read(ContainerFifo *cf, void *obj) -{ - void **psrc; - int ret; - - ret = av_fifo_read(cf->fifo, &psrc, 1); - if (ret < 0) - return ret; - - ret = cf->fifo_read(obj, *psrc); - ff_refstruct_unref(&psrc); - - return ret; -} - -int ff_container_fifo_write(ContainerFifo *cf, void *obj) -{ - void **pdst; - int ret; - - pdst = ff_refstruct_pool_get(cf->pool); - if (!pdst) - return AVERROR(ENOMEM); - - ret = cf->fifo_write(*pdst, obj); - if (ret < 0) - goto fail; - - ret = av_fifo_write(cf->fifo, &pdst, 1); - if (ret < 0) - goto fail; - - return 0; -fail: - ff_refstruct_unref(&pdst); - return ret; -} - -size_t ff_container_fifo_can_read(ContainerFifo *cf) -{ - return av_fifo_can_read(cf->fifo); -} - -static void *frame_alloc(void) -{ - return av_frame_alloc(); -} - -static void frame_reset(void *obj) -{ - av_frame_unref(obj); -} - -static void frame_free(void *obj) -{ - AVFrame *frame = obj; - av_frame_free(&frame); -} - -static int frame_ref(void *dst, void *src) -{ - return av_frame_ref(dst, src); -} - -static int frame_move_ref(void *dst, void *src) -{ - av_frame_move_ref(dst, src); - return 0; -} - -ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags) -{ - return ff_container_fifo_alloc(frame_alloc, frame_reset, frame_free, - frame_ref, frame_move_ref); -} diff --git a/libavcodec/container_fifo.h b/libavcodec/container_fifo.h deleted file mode 100644 index dd8b1d380f..0000000000 --- a/libavcodec/container_fifo.h +++ /dev/null @@ -1,89 +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_CONTAINER_FIFO_H -#define AVCODEC_CONTAINER_FIFO_H - -#include - -/** - * ContainerFifo is a FIFO for "containers" - dynamically allocated reusable - * structs (e.g. AVFrame or AVPacket). ContainerFifo uses an internal pool of - * such containers to avoid allocating and freeing them repeatedly. - */ -typedef struct ContainerFifo ContainerFifo; - -/** - * Allocate a new ContainerFifo for the container type defined by provided - * callbacks. - * - * @param container_alloc allocate a new container instance and return a pointer - * to it, or NULL on failure - * @param container_reset reset the provided container instance to a clean state - * @param container_free free the provided container instance - * @param fifo_write transfer the contents of src to dst, where src is a - * container instance provided to ff_container_fifo_write() - * @param fifo_read transfer the contents of src to dst in other cases - * - * @note fifo_read() and fifo_write() are different parameters in order to allow - * fifo_write() implementations that make a new reference in dst, leaving - * src untouched (see e.g. ff_container_fifo_alloc_avframe()) - */ -ContainerFifo* -ff_container_fifo_alloc(void* (*container_alloc)(void), - void (*container_reset)(void *obj), - void (*container_free) (void *obj), - int (*fifo_write) (void *dst, void *src), - int (*fifo_read) (void *dst, void *src)); - -/** - * Allocate a ContainerFifo instance for AVFrames. - * Note that ff_container_fifo_write() will call av_frame_ref() on src, making a - * new reference in dst and leaving src untouched. - * - * @param flags unused currently - */ -ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags); - -/** - * Free a ContainerFifo and everything in it. - */ -void ff_container_fifo_free(ContainerFifo **pf); - -/** - * Write the contents of obj to the FIFO. - * - * The fifo_write() callback previously provided to ff_container_fifo_alloc() - * will be called with obj as src in order to perform the actual transfer. - */ -int ff_container_fifo_write(ContainerFifo *pf, void *obj); - -/** - * Read the next available object from the FIFO into obj. - * - * The fifo_read() callback previously provided to ff_container_fifo_alloc() - * will be called with obj as dst in order to perform the actual transfer. - */ -int ff_container_fifo_read(ContainerFifo *pf, void *obj); - -/** - * @return number of objects available for reading - */ -size_t ff_container_fifo_can_read(ContainerFifo *pf); - -#endif // AVCODEC_CONTAINER_FIFO_H diff --git a/libavcodec/cook.c b/libavcodec/cook.c index dbe6b5b96c..f627967ffb 100644 --- a/libavcodec/cook.c +++ b/libavcodec/cook.c @@ -1308,7 +1308,6 @@ const FFCodec ff_cook_decoder = { .close = cook_decode_close, FF_CODEC_DECODE_CB(cook_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cri.c b/libavcodec/cri.c index 6932bb6745..f380597238 100644 --- a/libavcodec/cri.c +++ b/libavcodec/cri.c @@ -27,6 +27,7 @@ #define BITSTREAM_READER_LE +#include "libavutil/attributes_internal.h" #include "libavutil/intfloat.h" #include "libavutil/display.h" #include "avcodec.h" @@ -51,7 +52,6 @@ typedef struct CRIContext { static av_cold int cri_decode_init(AVCodecContext *avctx) { CRIContext *s = avctx->priv_data; - const AVCodec *codec; int ret; s->jpgframe = av_frame_alloc(); @@ -62,16 +62,14 @@ static av_cold int cri_decode_init(AVCodecContext *avctx) if (!s->jpkt) return AVERROR(ENOMEM); - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - s->jpeg_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + s->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!s->jpeg_avctx) return AVERROR(ENOMEM); s->jpeg_avctx->flags = avctx->flags; s->jpeg_avctx->flags2 = avctx->flags2; s->jpeg_avctx->idct_algo = avctx->idct_algo; - ret = avcodec_open2(s->jpeg_avctx, codec, NULL); + ret = avcodec_open2(s->jpeg_avctx, NULL, NULL); if (ret < 0) return ret; @@ -220,10 +218,12 @@ static int cri_decode_frame(AVCodecContext *avctx, AVFrame *p, if (bytestream2_get_le32(gb) != 0) return AVERROR_INVALIDDATA; break; - case 102: - bytestream2_get_buffer(gb, codec_name, FFMIN(length, sizeof(codec_name) - 1)); - length -= FFMIN(length, sizeof(codec_name) - 1); - if (strncmp(codec_name, "cintel_craw", FFMIN(length, sizeof(codec_name) - 1))) + case 102:; + int read_len = FFMIN(length, sizeof(codec_name) - 1); + if (read_len != bytestream2_get_buffer(gb, codec_name, read_len)) + return AVERROR_INVALIDDATA; + length -= read_len; + if (strncmp(codec_name, "cintel_craw", read_len)) return AVERROR_INVALIDDATA; compressed = 1; goto skip; diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index 3fae9c12eb..be183fce35 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -131,7 +131,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form CUVIDDECODECREATEINFO cuinfo; int surface_fmt; int chroma_444; - int fifo_size_inc; + int old_nb_surfaces, fifo_size_inc, fifo_size_mul = 1; int old_width = avctx->width; int old_height = avctx->height; @@ -178,15 +178,59 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form switch (format->bit_depth_luma_minus8) { case 0: // 8-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + if (chroma_444) { + pix_fmts[1] = AV_PIX_FMT_YUV444P; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { + pix_fmts[1] = AV_PIX_FMT_NV16; +#endif + } else { + pix_fmts[1] = AV_PIX_FMT_NV12; + } caps = &ctx->caps8; break; case 2: // 10-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_YUV444P16; +#else + pix_fmts[1] = AV_PIX_FMT_YUV444P10MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P216; +#else + pix_fmts[1] = AV_PIX_FMT_P210; +#endif +#endif + } else { + pix_fmts[1] = AV_PIX_FMT_P010; + } caps = &ctx->caps10; break; case 4: // 12-bit - pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_YUV444P16; +#else + pix_fmts[1] = AV_PIX_FMT_YUV444P12MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (format->chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P216; +#else + pix_fmts[1] = AV_PIX_FMT_P212; +#endif +#endif + } else { +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = AV_PIX_FMT_P016; +#else + pix_fmts[1] = AV_PIX_FMT_P012; +#endif + } caps = &ctx->caps12; break; default: @@ -304,6 +348,14 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form case AV_PIX_FMT_P016: cuinfo.OutputFormat = cudaVideoSurfaceFormat_P016; break; +#ifdef NVDEC_HAVE_422_SUPPORT + case AV_PIX_FMT_NV16: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV16; + break; + case AV_PIX_FMT_P216: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_P216; + break; +#endif case AV_PIX_FMT_YUV444P: cuinfo.OutputFormat = cudaVideoSurfaceFormat_YUV444; break; @@ -317,20 +369,24 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form return 0; } - fifo_size_inc = ctx->nb_surfaces; - ctx->nb_surfaces = FFMAX(ctx->nb_surfaces, format->min_num_decode_surfaces + 3); + if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) { + avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1}); + fifo_size_mul = 2; + } + old_nb_surfaces = ctx->nb_surfaces; + ctx->nb_surfaces = FFMAX(ctx->nb_surfaces, format->min_num_decode_surfaces + 3); if (avctx->extra_hw_frames > 0) ctx->nb_surfaces += avctx->extra_hw_frames; - fifo_size_inc = ctx->nb_surfaces - fifo_size_inc; + fifo_size_inc = ctx->nb_surfaces * fifo_size_mul - av_fifo_can_read(ctx->frame_queue) - av_fifo_can_write(ctx->frame_queue); if (fifo_size_inc > 0 && av_fifo_grow2(ctx->frame_queue, fifo_size_inc) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to grow frame queue on video sequence callback\n"); ctx->internal_error = AVERROR(ENOMEM); return 0; } - if (fifo_size_inc > 0 && av_reallocp_array(&ctx->key_frame, ctx->nb_surfaces, sizeof(int)) < 0) { + if (ctx->nb_surfaces > old_nb_surfaces && av_reallocp_array(&ctx->key_frame, ctx->nb_surfaces, sizeof(int)) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to grow key frame array on video sequence callback\n"); ctx->internal_error = AVERROR(ENOMEM); return 0; @@ -342,9 +398,6 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form cuinfo.bitDepthMinus8 = format->bit_depth_luma_minus8; cuinfo.DeinterlaceMode = ctx->deint_mode_current; - if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) - avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1}); - ctx->internal_error = CHECK_CU(ctx->cvdl->cuvidCreateDecoder(&ctx->cudecoder, &cuinfo)); if (ctx->internal_error < 0) return 0; @@ -391,6 +444,7 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF AVCodecContext *avctx = opaque; CuvidContext *ctx = avctx->priv_data; CuvidParsedFrame parsed_frame = { { 0 } }; + int ret; parsed_frame.dispinfo = *dispinfo; ctx->internal_error = 0; @@ -399,13 +453,20 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF parsed_frame.dispinfo.progressive_frame = ctx->progressive_sequence; if (ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave) { - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing frame to fifo failed!\n"); } else { parsed_frame.is_deinterlacing = 1; - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing first frame to fifo failed!\n"); + if (!ctx->drop_second_field) { parsed_frame.second_field = 1; - av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + ret = av_fifo_write(ctx->frame_queue, &parsed_frame, 1); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Writing second frame to fifo failed!\n"); } } @@ -416,11 +477,12 @@ static int cuvid_is_buffer_full(AVCodecContext *avctx) { CuvidContext *ctx = avctx->priv_data; - int delay = ctx->cuparseinfo.ulMaxDisplayDelay; + int shift = 0; if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field) - delay *= 2; + shift = 1; - return av_fifo_can_read(ctx->frame_queue) + delay >= ctx->nb_surfaces; + // shift/divide frame count to ensure the buffer is still signalled full if one half-frame has already been returned when deinterlacing. + return ((av_fifo_can_read(ctx->frame_queue) + shift) >> shift) + ctx->cuparseinfo.ulMaxDisplayDelay >= ctx->nb_surfaces; } static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt) @@ -463,7 +525,12 @@ static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt) ctx->decoder_flushing = 1; } - ret = CHECK_CU(ctx->cvdl->cuvidParseVideoData(ctx->cuparser, &cupkt)); + // When flushing, only actually flush cuvid when the output buffer has been fully emptied. + // CUVID happily dumps out a ton of frames with no regard for its own available surfaces. + if (!ctx->decoder_flushing || (ctx->decoder_flushing && !av_fifo_can_read(ctx->frame_queue))) + ret = CHECK_CU(ctx->cvdl->cuvidParseVideoData(ctx->cuparser, &cupkt)); + else + ret = 0; if (ret < 0) goto error; @@ -578,6 +645,10 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || avctx->pix_fmt == AV_PIX_FMT_P010 || avctx->pix_fmt == AV_PIX_FMT_P016 || +#ifdef NVDEC_HAVE_422_SUPPORT + avctx->pix_fmt == AV_PIX_FMT_NV16 || + avctx->pix_fmt == AV_PIX_FMT_P216 || +#endif avctx->pix_fmt == AV_PIX_FMT_YUV444P || avctx->pix_fmt == AV_PIX_FMT_YUV444P16) { unsigned int offset = 0; @@ -659,12 +730,6 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) * So set pkt_pts and clear all the other pkt_ fields. */ frame->duration = 0; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_pos = -1; - frame->pkt_size = -1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (!parsed_frame.is_deinterlacing && !parsed_frame.dispinfo.progressive_frame) frame->flags |= AV_FRAME_FLAG_INTERLACED; @@ -730,7 +795,7 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, const CUVIDPARSERPARAMS *cuparseinfo, int probed_width, int probed_height, - int bit_depth) + int bit_depth, int is_yuv422, int is_yuv444) { CuvidContext *ctx = avctx->priv_data; CUVIDDECODECAPS *caps; @@ -753,8 +818,14 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, ctx->caps8.eCodecType = ctx->caps10.eCodecType = ctx->caps12.eCodecType = cuparseinfo->CodecType; + ctx->caps8.eChromaFormat = ctx->caps10.eChromaFormat = ctx->caps12.eChromaFormat - = cudaVideoChromaFormat_420; + = is_yuv444 ? cudaVideoChromaFormat_444 : +#ifdef NVDEC_HAVE_422_SUPPORT + (is_yuv422 ? cudaVideoChromaFormat_422 : cudaVideoChromaFormat_420); +#else + cudaVideoChromaFormat_420; +#endif ctx->caps8.nBitDepthMinus8 = 0; ctx->caps10.nBitDepthMinus8 = 2; @@ -790,12 +861,12 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, } if (!ctx->caps8.bIsSupported) { - av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported.\n", avctx->codec->name); + av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported with this chroma format.\n", avctx->codec->name); return AVERROR(EINVAL); } if (!caps->bIsSupported) { - av_log(avctx, AV_LOG_ERROR, "Bit depth %d is not supported.\n", bit_depth); + av_log(avctx, AV_LOG_ERROR, "Bit depth %d with this chroma format is not supported.\n", bit_depth); return AVERROR(EINVAL); } @@ -839,7 +910,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) int probed_width = avctx->coded_width ? avctx->coded_width : 1280; int probed_height = avctx->coded_height ? avctx->coded_height : 720; - int probed_bit_depth = 8, is_yuv444 = 0; + int probed_bit_depth = 8, is_yuv444 = 0, is_yuv422 = 0; const AVPixFmtDescriptor *probe_desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (probe_desc && probe_desc->nb_components) @@ -848,17 +919,29 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) if (probe_desc && !probe_desc->log2_chroma_w && !probe_desc->log2_chroma_h) is_yuv444 = 1; +#ifdef NVDEC_HAVE_422_SUPPORT + if (probe_desc && probe_desc->log2_chroma_w && !probe_desc->log2_chroma_h) + is_yuv422 = 1; +#endif + // Pick pixel format based on bit depth and chroma sampling. - // Only 420 and 444 sampling are supported by HW so far, no need to check for 422. switch (probed_bit_depth) { case 10: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : (is_yuv422 ? AV_PIX_FMT_P216 : AV_PIX_FMT_P010); +#else + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P10MSB : (is_yuv422 ? AV_PIX_FMT_P210 : AV_PIX_FMT_P010); +#endif break; case 12: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; +#if FF_API_NVDEC_OLD_PIX_FMTS + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : (is_yuv422 ? AV_PIX_FMT_P216 : AV_PIX_FMT_P016); +#else + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P12MSB : (is_yuv422 ? AV_PIX_FMT_P212 : AV_PIX_FMT_P012); +#endif break; default: - pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P : (is_yuv422 ? AV_PIX_FMT_NV16 : AV_PIX_FMT_NV12); break; } @@ -1059,7 +1142,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) ret = cuvid_test_capabilities(avctx, &ctx->cuparseinfo, probed_width, probed_height, - probed_bit_depth); + probed_bit_depth, is_yuv422, is_yuv444); if (ret < 0) goto error; @@ -1162,6 +1245,7 @@ static const AVCodecHWConfigInternal *const cuvid_hw_configs[] = { .public = { .pix_fmt = AV_PIX_FMT_CUDA, .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | AV_CODEC_HW_CONFIG_METHOD_INTERNAL, .device_type = AV_HWDEVICE_TYPE_CUDA }, diff --git a/libavcodec/d3d12va_av1.c b/libavcodec/d3d12va_av1.c index 4a4d207b4f..fdc7195d12 100644 --- a/libavcodec/d3d12va_av1.c +++ b/libavcodec/d3d12va_av1.c @@ -45,7 +45,10 @@ typedef struct AV1DecodePictureContext { unsigned bitstream_size; } AV1DecodePictureContext; -static int d3d12va_av1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const AV1DecContext *h = avctx->priv_data; AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private; @@ -151,7 +154,7 @@ static int d3d12va_av1_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_av1_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_av1_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); D3D12AV1DecodeContext *av1_ctx = D3D12_AV1_DECODE_CONTEXT(avctx); @@ -179,7 +182,7 @@ static int d3d12va_av1_decode_init(AVCodecContext *avctx) return 0; } -static int d3d12va_av1_decode_uninit(AVCodecContext *avctx) +static av_cold int d3d12va_av1_decode_uninit(AVCodecContext *avctx) { D3D12AV1DecodeContext *ctx = D3D12_AV1_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_decode.c b/libavcodec/d3d12va_decode.c index 3b8978635e..4e714efb1a 100644 --- a/libavcodec/d3d12va_decode.c +++ b/libavcodec/d3d12va_decode.c @@ -41,6 +41,100 @@ typedef struct HelperObjects { uint64_t fence_value; } HelperObjects; +typedef struct ReferenceFrame { + ID3D12Resource *resource; + int used; + ID3D12Resource *output_resource; +} ReferenceFrame; + +static ID3D12Resource *get_reference_only_resource(AVCodecContext *avctx, ID3D12Resource *output_resource) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx; + int i = 0; + ID3D12Resource *resource = NULL; + D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT }; + D3D12_RESOURCE_DESC desc; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map == NULL) { + av_log(avctx, AV_LOG_ERROR, "Reference frames are not allocated!\n"); + return NULL; + } + + // find unused resource + for (i = 0; i < ctx->max_num_ref; i++) { + if (!reference_only_map[i].used && reference_only_map[i].resource != NULL) { + reference_only_map[i].used = 1; + resource = reference_only_map[i].resource; + reference_only_map[i].output_resource = output_resource; + return resource; + } + } + + // find space to allocate + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[i].resource == NULL) + break; + } + + if (i == ctx->max_num_ref) { + av_log(avctx, AV_LOG_ERROR, "No space for new Reference frame!\n"); + return NULL; + } + + // allocate frame + output_resource->lpVtbl->GetDesc(output_resource, &desc); + desc.Flags = D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + + if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&reference_only_map[i].resource))) { + av_log(ctx, AV_LOG_ERROR, "Failed to create D3D12 Reference Resource!\n"); + return NULL; + } + + reference_only_map[i].used = 1; + resource = reference_only_map[i].resource; + reference_only_map[i].output_resource = output_resource; + + return resource; +} + +static void free_reference_only_resources(AVCodecContext *avctx) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + int i; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map != NULL) { + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[i].resource != NULL) { + D3D12_OBJECT_RELEASE(reference_only_map[i].resource); + } + } + av_freep(&ctx->reference_only_map); + av_freep(&ctx->ref_only_resources); + } +} + +static void prepare_reference_only_resources(AVCodecContext *avctx) +{ + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + int i, j; + ReferenceFrame *reference_only_map = ctx->reference_only_map; + if (reference_only_map == NULL) + return; + memset(ctx->ref_only_resources, 0, ctx->max_num_ref * sizeof(*(ctx->ref_only_resources))); + for (j = 0; j < ctx->max_num_ref; j++) { + for (i = 0; i < ctx->max_num_ref; i++) { + if (reference_only_map[j].used && reference_only_map[j].output_resource == ctx->ref_resources[i]) { + ctx->ref_only_resources[i] = reference_only_map[j].resource; + break; + } + } + if (i == ctx->max_num_ref) + reference_only_map[j].used = 0; + } +} + int ff_d3d12va_get_suitable_max_bitstream_size(AVCodecContext *avctx) { AVHWFramesContext *frames_ctx = D3D12VA_FRAMES_CONTEXT(avctx); @@ -250,6 +344,18 @@ static int d3d12va_create_decoder(AVCodecContext *avctx) return AVERROR_PATCHWELCOME; } + ctx->reference_only_map = NULL; + ctx->ref_only_resources = NULL; + if (feature.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATIONS_REQUIRED) { + av_log(avctx, AV_LOG_VERBOSE, "Reference-Only Allocations are required for this D3D12 decoder configuration.\n"); + ctx->reference_only_map = av_calloc(ctx->max_num_ref + 1, sizeof(ReferenceFrame)); + if (!ctx->reference_only_map) + return AVERROR(ENOMEM); + ctx->ref_only_resources = av_calloc(ctx->max_num_ref, sizeof(*ctx->ref_only_resources)); + if (!ctx->ref_only_resources) + return AVERROR(ENOMEM); + } + desc = (D3D12_VIDEO_DECODER_DESC) { .NodeMask = 0, .Configuration = ctx->cfg, @@ -280,7 +386,7 @@ int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames return 0; } -int ff_d3d12va_decode_init(AVCodecContext *avctx) +av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx) { int ret; AVHWFramesContext *frames_ctx; @@ -370,7 +476,7 @@ fail: return AVERROR(EINVAL); } -int ff_d3d12va_decode_uninit(AVCodecContext *avctx) +av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx) { int num_allocator = 0; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -394,6 +500,7 @@ int ff_d3d12va_decode_uninit(AVCodecContext *avctx) av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator); } + free_reference_only_resources(avctx); av_fifo_freep2(&ctx->objects_queue); @@ -412,14 +519,15 @@ static inline int d3d12va_update_reference_frames_state(AVCodecContext *avctx, D ID3D12Resource *current_resource, int state_before, int state_end) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + ID3D12Resource **ref_resources = ctx->ref_only_resources ? ctx->ref_only_resources : ctx->ref_resources; int num_barrier = 0; for (int i = 0; i < ctx->max_num_ref; i++) { - if (((ctx->used_mask >> i) & 0x1) && ctx->ref_resources[i] && ctx->ref_resources[i] != current_resource) { + if (((ctx->used_mask >> i) & 0x1) && ref_resources[i] && ref_resources[i] != current_resource) { barriers[num_barrier].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barriers[num_barrier].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barriers[num_barrier].Transition = (D3D12_RESOURCE_TRANSITION_BARRIER){ - .pResource = ctx->ref_resources[i], + barriers[num_barrier].Transition = (D3D12_RESOURCE_TRANSITION_BARRIER) { + .pResource = ref_resources[i], .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, .StateBefore = state_before, .StateAfter = state_end, @@ -440,8 +548,9 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); ID3D12Resource *buffer = NULL; ID3D12CommandAllocator *command_allocator = NULL; - AVD3D12VAFrame *f = (AVD3D12VAFrame *)frame->data[0]; - ID3D12Resource *resource = (ID3D12Resource *)f->texture; + AVD3D12VAFrame *f = (AVD3D12VAFrame*)frame->data[0]; + ID3D12Resource *output_resource = (ID3D12Resource*)f->texture; + ID3D12Resource *ref_resource = NULL; ID3D12VideoDecodeCommandList *cmd_list = ctx->command_list; D3D12_RESOURCE_BARRIER barriers[32] = { 0 }; @@ -466,25 +575,55 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS output_args = { .ConversionArguments = { 0 }, .OutputSubresource = 0, - .pOutputTexture2D = resource, + .pOutputTexture2D = output_resource, }; + memset(ctx->ref_subresources, 0, sizeof(UINT) * ctx->max_num_ref); + input_args.ReferenceFrames.NumTexture2Ds = ctx->max_num_ref; + input_args.ReferenceFrames.pSubresources = ctx->ref_subresources; + + if (ctx->reference_only_map) { + ref_resource = get_reference_only_resource(avctx, output_resource); + if (ref_resource == NULL) { + av_log(avctx, AV_LOG_ERROR, "Failed to get reference frame!\n"); + goto fail; + } + prepare_reference_only_resources(avctx); + + output_args.ConversionArguments.Enable = 1; + input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_only_resources; + output_args.ConversionArguments.pReferenceTexture2D = ref_resource; + output_args.ConversionArguments.ReferenceSubresource = 0; + } else { + ref_resource = output_resource; + input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_resources; + } + UINT num_barrier = 1; barriers[0] = (D3D12_RESOURCE_BARRIER) { .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, .Transition = { - .pResource = resource, + .pResource = output_resource, .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, .StateBefore = D3D12_RESOURCE_STATE_COMMON, .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, }, }; - memset(ctx->ref_subresources, 0, sizeof(UINT) * ctx->max_num_ref); - input_args.ReferenceFrames.NumTexture2Ds = ctx->max_num_ref; - input_args.ReferenceFrames.ppTexture2Ds = ctx->ref_resources; - input_args.ReferenceFrames.pSubresources = ctx->ref_subresources; + if (ctx->reference_only_map) { + barriers[1] = (D3D12_RESOURCE_BARRIER) { + .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, + .Transition = { + .pResource = ref_resource, + .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + .StateBefore = D3D12_RESOURCE_STATE_COMMON, + .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, + }, + }; + num_barrier++; + } ret = d3d12va_fence_completion(&f->sync_ctx); if (ret < 0) @@ -505,7 +644,7 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, DX_CHECK(ID3D12VideoDecodeCommandList_Reset(cmd_list, command_allocator)); - num_barrier += d3d12va_update_reference_frames_state(avctx, &barriers[1], resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_DECODE_READ); + num_barrier += d3d12va_update_reference_frames_state(avctx, &barriers[num_barrier], ref_resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_DECODE_READ); ID3D12VideoDecodeCommandList_ResourceBarrier(cmd_list, num_barrier, barriers); diff --git a/libavcodec/d3d12va_decode.h b/libavcodec/d3d12va_decode.h index b64994760a..c771004222 100644 --- a/libavcodec/d3d12va_decode.h +++ b/libavcodec/d3d12va_decode.h @@ -119,6 +119,19 @@ typedef struct D3D12VADecodeContext { * Private to the FFmpeg AVHWAccel implementation */ unsigned report_id; + + /** + * The Reference-Only feature in DirectX 12 is a memory optimization + * technique designed for video decoding/encoding scenarios. + * This feature requires that reference resources must be allocated + * with the `D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY` resource flag. + * Reference textures must also be separated from output textures. + * reference_only_map used as a storage for reference only frames + * ref_only_resources used as a shadow for ref_resources + */ + void *reference_only_map; + ID3D12Resource **ref_only_resources; + } D3D12VADecodeContext; /** diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c index 68fb9927a8..1ecaee3b6d 100644 --- a/libavcodec/d3d12va_encode.c +++ b/libavcodec/d3d12va_encode.c @@ -299,21 +299,20 @@ static int d3d12va_encode_issue(AVCodecContext *avctx, "header: %d.\n", err); goto fail; } + pic->header_size = (int)bit_len / 8; + pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ? + FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) : + pic->header_size; + + hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + memcpy(ptr, data, pic->aligned_header_size); + ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); } - - pic->header_size = (int)bit_len / 8; - pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ? - FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) : - pic->header_size; - - hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr); - if (FAILED(hr)) { - err = AVERROR_UNKNOWN; - goto fail; - } - - memcpy(ptr, data, pic->aligned_header_size); - ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); } d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1]; @@ -634,7 +633,7 @@ static int d3d12va_encode_get_coded_data(AVCodecContext *avctx, goto end; total_size += pic->header_size; - av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"PRId64"\n", total_size); + av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"SIZE_SPECIFIER"\n", total_size); hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data); if (FAILED(hr)) { @@ -974,8 +973,7 @@ rc_mode_found: case RC_MODE_CQP: // cqp ConfigParams will be updated in ctx->codec->configure. break; - - case RC_MODE_CBR: + case RC_MODE_CBR: { D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl; ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR); @@ -996,8 +994,8 @@ rc_mode_found: ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl; break; - - case RC_MODE_VBR: + } + case RC_MODE_VBR: { D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl; ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR); @@ -1019,8 +1017,8 @@ rc_mode_found: ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl; break; - - case RC_MODE_QVBR: + } + case RC_MODE_QVBR: { D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl; ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR); @@ -1040,7 +1038,7 @@ rc_mode_found: ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl; break; - + } default: break; } @@ -1088,13 +1086,15 @@ static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) switch (ctx->codec->d3d12_codec) { case D3D12_VIDEO_ENCODER_CODEC_H264: ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP, - support.PictureSupport.pH264Support->MaxL1ReferencesForB); + support.PictureSupport.pH264Support->MaxL1ReferencesForB ? + support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX); ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB; break; case D3D12_VIDEO_ENCODER_CODEC_HEVC: ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP, - support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB); + support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ? + support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX); ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB; break; @@ -1152,7 +1152,7 @@ static int d3d12va_create_encoder_heap(AVCodecContext *avctx) D3D12_VIDEO_ENCODER_HEAP_DESC desc = { .NodeMask = 0, - .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE, + .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE, .EncodeCodec = ctx->codec->d3d12_codec, .EncodeProfile = ctx->profile->d3d12_profile, .EncodeLevel = ctx->level, @@ -1264,7 +1264,7 @@ static int d3d12va_encode_create_command_objects(AVCodecContext *avctx) { D3D12VAEncodeContext *ctx = avctx->priv_data; ID3D12CommandAllocator *command_allocator = NULL; - int err; + int err = AVERROR_UNKNOWN; HRESULT hr; D3D12_COMMAND_QUEUE_DESC queue_desc = { diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c index 571ce57385..0aa1a1d3a4 100644 --- a/libavcodec/d3d12va_encode_hevc.c +++ b/libavcodec/d3d12va_encode_hevc.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "cbs.h" #include "cbs_h265.h" +#include "hw_base_encode_h265.h" #include "h2645data.h" #include "h265_profile_level.h" #include "codec_internal.h" @@ -44,13 +45,11 @@ typedef struct D3D12VAEncodeHEVCContext { // User options. int qp; int profile; - int tier; int level; // Writer structures. - H265RawVPS raw_vps; - H265RawSPS raw_sps; - H265RawPPS raw_pps; + FFHWBaseEncodeH265 units; + FFHWBaseEncodeH265Opts unit_opts; CodedBitstreamContext *cbc; CodedBitstreamFragment current_access_unit; @@ -212,15 +211,15 @@ static int d3d12va_encode_hevc_write_sequence_header(AVCodecContext *avctx, CodedBitstreamFragment *au = &priv->current_access_unit; int err; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_vps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_vps); if (err < 0) goto fail; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_sps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_sps); if (err < 0) goto fail; - err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_pps); + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->units.raw_pps); if (err < 0) goto fail; @@ -237,18 +236,14 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) D3D12VAEncodeContext *ctx = avctx->priv_data; D3D12VAEncodeHEVCContext *priv = avctx->priv_data; AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx; - H265RawVPS *vps = &priv->raw_vps; - H265RawSPS *sps = &priv->raw_sps; - H265RawPPS *pps = &priv->raw_pps; - H265RawProfileTierLevel *ptl = &vps->profile_tier_level; - H265RawVUI *vui = &sps->vui; + H265RawSPS *sps = &priv->units.raw_sps; + H265RawPPS *pps = &priv->units.raw_pps; D3D12_VIDEO_ENCODER_PROFILE_HEVC profile = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN; D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC level = { 0 }; const AVPixFmtDescriptor *desc; uint8_t min_cu_size, max_cu_size, min_tu_size, max_tu_size; - int chroma_format, bit_depth; HRESULT hr; - int i; + int err; D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = { .NodeIndex = 0, @@ -289,137 +284,24 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) return AVERROR_PATCHWELCOME; } - memset(vps, 0, sizeof(*vps)); - memset(sps, 0, sizeof(*sps)); - memset(pps, 0, sizeof(*pps)); - desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); av_assert0(desc); - if (desc->nb_components == 1) { - chroma_format = 0; - } else { - if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1) { - chroma_format = 1; - } else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 0) { - chroma_format = 2; - } else if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) { - chroma_format = 3; - } else { - av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format " - "%s is not supported.\n", desc->name); - return AVERROR(EINVAL); - } - } - bit_depth = desc->comp[0].depth; min_cu_size = d3d12va_encode_hevc_map_cusize(ctx->codec_conf.pHEVCConfig->MinLumaCodingUnitSize); max_cu_size = d3d12va_encode_hevc_map_cusize(ctx->codec_conf.pHEVCConfig->MaxLumaCodingUnitSize); min_tu_size = d3d12va_encode_hevc_map_tusize(ctx->codec_conf.pHEVCConfig->MinLumaTransformUnitSize); max_tu_size = d3d12va_encode_hevc_map_tusize(ctx->codec_conf.pHEVCConfig->MaxLumaTransformUnitSize); - // VPS + // cu_qp_delta always required to be 1 in https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md + priv->unit_opts.cu_qp_delta_enabled_flag = 1; + priv->unit_opts.nb_slices = 1; - vps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_VPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; + err = ff_hw_base_encode_init_params_h265(base_ctx, avctx, + &priv->units, &priv->unit_opts); + if (err < 0) + return err; - vps->vps_video_parameter_set_id = 0; - - vps->vps_base_layer_internal_flag = 1; - vps->vps_base_layer_available_flag = 1; - vps->vps_max_layers_minus1 = 0; - vps->vps_max_sub_layers_minus1 = 0; - vps->vps_temporal_id_nesting_flag = 1; - - ptl->general_profile_space = 0; - ptl->general_profile_idc = avctx->profile; - ptl->general_tier_flag = priv->tier; - - ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1; - - ptl->general_progressive_source_flag = 1; - ptl->general_interlaced_source_flag = 0; - ptl->general_non_packed_constraint_flag = 1; - ptl->general_frame_only_constraint_flag = 1; - - ptl->general_max_14bit_constraint_flag = bit_depth <= 14; - ptl->general_max_12bit_constraint_flag = bit_depth <= 12; - ptl->general_max_10bit_constraint_flag = bit_depth <= 10; - ptl->general_max_8bit_constraint_flag = bit_depth == 8; - - ptl->general_max_422chroma_constraint_flag = chroma_format <= 2; - ptl->general_max_420chroma_constraint_flag = chroma_format <= 1; - ptl->general_max_monochrome_constraint_flag = chroma_format == 0; - - ptl->general_intra_constraint_flag = base_ctx->gop_size == 1; - ptl->general_one_picture_only_constraint_flag = 0; - - ptl->general_lower_bit_rate_constraint_flag = 1; - - if (avctx->level != FF_LEVEL_UNKNOWN) { - ptl->general_level_idc = avctx->level; - } else { - const H265LevelDescriptor *level; - - level = ff_h265_guess_level(ptl, avctx->bit_rate, - base_ctx->surface_width, base_ctx->surface_height, - 1, 1, 1, (base_ctx->b_per_p > 0) + 1); - if (level) { - av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); - ptl->general_level_idc = level->level_idc; - } else { - av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " - "any normal level; using level 8.5.\n"); - ptl->general_level_idc = 255; - // The tier flag must be set in level 8.5. - ptl->general_tier_flag = 1; - } - avctx->level = ptl->general_level_idc; - } - - vps->vps_sub_layer_ordering_info_present_flag = 0; - vps->vps_max_dec_pic_buffering_minus1[0] = base_ctx->max_b_depth + 1; - vps->vps_max_num_reorder_pics[0] = base_ctx->max_b_depth; - vps->vps_max_latency_increase_plus1[0] = 0; - - vps->vps_max_layer_id = 0; - vps->vps_num_layer_sets_minus1 = 0; - vps->layer_id_included_flag[0][0] = 1; - - vps->vps_timing_info_present_flag = 1; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vps->vps_num_units_in_tick = avctx->framerate.den; - vps->vps_time_scale = avctx->framerate.num; - vps->vps_poc_proportional_to_timing_flag = 1; - vps->vps_num_ticks_poc_diff_one_minus1 = 0; - } else { - vps->vps_num_units_in_tick = avctx->time_base.num; - vps->vps_time_scale = avctx->time_base.den; - vps->vps_poc_proportional_to_timing_flag = 0; - } - vps->vps_num_hrd_parameters = 0; - - // SPS - - sps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_SPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; - - sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id; - - sps->sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; - sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag; - - sps->profile_tier_level = vps->profile_tier_level; - - sps->sps_seq_parameter_set_id = 0; - - sps->chroma_format_idc = chroma_format; - sps->separate_colour_plane_flag = 0; + avctx->level = priv->units.raw_vps.profile_tier_level.general_level_idc; av_assert0(ctx->res_limits.SubregionBlockPixelsSize % min_cu_size == 0); @@ -441,22 +323,8 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) sps->conformance_window_flag = 0; } - sps->bit_depth_luma_minus8 = bit_depth - 8; - sps->bit_depth_chroma_minus8 = bit_depth - 8; - sps->log2_max_pic_order_cnt_lsb_minus4 = ctx->gop.pHEVCGroupOfPictures->log2_max_pic_order_cnt_lsb_minus4; - 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]; - } - sps->log2_min_luma_coding_block_size_minus3 = (uint8_t)(av_log2(min_cu_size) - 3); sps->log2_diff_max_min_luma_coding_block_size = (uint8_t)(av_log2(max_cu_size) - av_log2(min_cu_size)); sps->log2_min_luma_transform_block_size_minus2 = (uint8_t)(av_log2(min_tu_size) - 2); @@ -469,100 +337,21 @@ static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION); sps->sample_adaptive_offset_enabled_flag = !!(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER); - sps->sps_temporal_mvp_enabled_flag = 0; - sps->pcm_enabled_flag = 0; - - sps->vui_parameters_present_flag = 1; - - if (avctx->sample_aspect_ratio.num != 0 && - avctx->sample_aspect_ratio.den != 0) { - int num, den, i; - av_reduce(&num, &den, avctx->sample_aspect_ratio.num, - avctx->sample_aspect_ratio.den, 65535); - for (i = 0; i < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect); i++) { - if (num == ff_h2645_pixel_aspect[i].num && - den == ff_h2645_pixel_aspect[i].den) { - vui->aspect_ratio_idc = i; - break; - } - } - if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) { - vui->aspect_ratio_idc = 255; - vui->sar_width = num; - vui->sar_height = den; - } - vui->aspect_ratio_info_present_flag = 1; - } - - // Unspecified video format, from table E-2. - vui->video_format = 5; - vui->video_full_range_flag = - avctx->color_range == AVCOL_RANGE_JPEG; - vui->colour_primaries = avctx->color_primaries; - vui->transfer_characteristics = avctx->color_trc; - vui->matrix_coefficients = avctx->colorspace; - if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || - avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - avctx->colorspace != AVCOL_SPC_UNSPECIFIED) - vui->colour_description_present_flag = 1; - if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || - vui->colour_description_present_flag) - vui->video_signal_type_present_flag = 1; - - if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { - vui->chroma_loc_info_present_flag = 1; - vui->chroma_sample_loc_type_top_field = - vui->chroma_sample_loc_type_bottom_field = - avctx->chroma_sample_location - 1; - } - - vui->vui_timing_info_present_flag = 1; - vui->vui_num_units_in_tick = vps->vps_num_units_in_tick; - vui->vui_time_scale = vps->vps_time_scale; - vui->vui_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag; - vui->vui_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1; - vui->vui_hrd_parameters_present_flag = 0; - - vui->bitstream_restriction_flag = 1; - vui->motion_vectors_over_pic_boundaries_flag = 1; - vui->restricted_ref_pic_lists_flag = 1; - vui->max_bytes_per_pic_denom = 0; - vui->max_bits_per_min_cu_denom = 0; - vui->log2_max_mv_length_horizontal = 15; - vui->log2_max_mv_length_vertical = 15; - - // PPS - - pps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_PPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; - - pps->pps_pic_parameter_set_id = 0; - pps->pps_seq_parameter_set_id = sps->sps_seq_parameter_set_id; pps->cabac_init_present_flag = 1; - pps->num_ref_idx_l0_default_active_minus1 = 0; - pps->num_ref_idx_l1_default_active_minus1 = 0; - pps->init_qp_minus26 = 0; pps->transform_skip_enabled_flag = !!(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING); - // cu_qp_delta always required to be 1 in https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md - pps->cu_qp_delta_enabled_flag = 1; - - pps->diff_cu_qp_delta_depth = 0; - pps->pps_slice_chroma_qp_offsets_present_flag = 1; pps->tiles_enabled_flag = 0; // no tiling in D3D12 pps->pps_loop_filter_across_slices_enabled_flag = !(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES); + pps->deblocking_filter_control_present_flag = 1; return 0; @@ -729,7 +518,7 @@ static int d3d12va_encode_hevc_set_level(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->level.pHEVCLevelSetting->Tier = priv->raw_vps.profile_tier_level.general_tier_flag == 0 ? + ctx->level.pHEVCLevelSetting->Tier = priv->units.raw_vps.profile_tier_level.general_tier_flag == 0 ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH; @@ -883,10 +672,10 @@ static int d3d12va_encode_hevc_init(AVCodecContext *avctx) if (avctx->profile == AV_PROFILE_UNKNOWN) avctx->profile = priv->profile; - if (avctx->level == FF_LEVEL_UNKNOWN) + if (avctx->level == AV_LEVEL_UNKNOWN) avctx->level = priv->level; - if (avctx->level != FF_LEVEL_UNKNOWN && avctx->level & ~0xff) { + if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0xff) { av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " "in 8-bit unsigned integer.\n", avctx->level); return AVERROR(EINVAL); @@ -932,7 +721,7 @@ static const AVOption d3d12va_encode_hevc_options[] = { #undef PROFILE { "tier", "Set tier (general_tier_flag)", - OFFSET(tier), AV_OPT_TYPE_INT, + OFFSET(unit_opts.tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "tier" }, { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "tier" }, @@ -941,7 +730,7 @@ static const AVOption d3d12va_encode_hevc_options[] = { { "level", "Set level (general_level_idc)", OFFSET(level), AV_OPT_TYPE_INT, - { .i64 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "level" @@ -973,6 +762,7 @@ static const FFCodecDefault d3d12va_encode_hevc_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -998,10 +788,7 @@ const FFCodec ff_hevc_d3d12va_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = d3d12va_encode_hevc_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_D3D12, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_D3D12), .hw_configs = ff_d3d12va_encode_hw_configs, .p.wrapper_name = "d3d12va", }; diff --git a/libavcodec/d3d12va_h264.c b/libavcodec/d3d12va_h264.c index b2fe2955c8..dec9344aad 100644 --- a/libavcodec/d3d12va_h264.c +++ b/libavcodec/d3d12va_h264.c @@ -50,8 +50,9 @@ static void fill_slice_short(DXVA_Slice_H264_Short *slice, } static int d3d12va_h264_start_frame(AVCodecContext *avctx, - av_unused const uint8_t *buffer, - av_unused uint32_t size) + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const H264Context *h = avctx->priv_data; H264DecodePictureContext *ctx_pic = h->cur_pic_ptr->hwaccel_picture_private; @@ -173,7 +174,7 @@ static int d3d12va_h264_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_h264_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_h264_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_H264 pp; diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c index 7686f0eb6c..e72d49b7d9 100644 --- a/libavcodec/d3d12va_hevc.c +++ b/libavcodec/d3d12va_hevc.c @@ -49,7 +49,10 @@ static void fill_slice_short(DXVA_Slice_HEVC_Short *slice, unsigned position, un slice->wBadSliceChopping = 0; } -static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const HEVCContext *h = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -160,7 +163,7 @@ static int d3d12va_hevc_end_frame(AVCodecContext *avctx) scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0, update_input_arguments); } -static int d3d12va_hevc_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_hevc_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_HEVC pp; diff --git a/libavcodec/d3d12va_mpeg2.c b/libavcodec/d3d12va_mpeg2.c index 86a7d97b34..47e453dd5e 100644 --- a/libavcodec/d3d12va_mpeg2.c +++ b/libavcodec/d3d12va_mpeg2.c @@ -40,7 +40,10 @@ typedef struct D3D12DecodePictureContext { unsigned bitstream_size; } D3D12DecodePictureContext; -static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const MpegEncContext *s = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -150,7 +153,7 @@ static int d3d12va_mpeg2_end_frame(AVCodecContext *avctx) return ret; } -static int d3d12va_mpeg2_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_mpeg2_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_vc1.c b/libavcodec/d3d12va_vc1.c index dccc0fbffa..e64a8e0630 100644 --- a/libavcodec/d3d12va_vc1.c +++ b/libavcodec/d3d12va_vc1.c @@ -41,7 +41,10 @@ typedef struct D3D12DecodePictureContext { unsigned bitstream_size; } D3D12DecodePictureContext; -static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VC1Context *v = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -162,7 +165,7 @@ static int d3d12va_vc1_end_frame(AVCodecContext *avctx) update_input_arguments); } -static int d3d12va_vc1_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_vc1_decode_init(AVCodecContext *avctx) { int ret; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); diff --git a/libavcodec/d3d12va_vp9.c b/libavcodec/d3d12va_vp9.c index 3476768e61..6f1f933fdd 100644 --- a/libavcodec/d3d12va_vp9.c +++ b/libavcodec/d3d12va_vp9.c @@ -45,7 +45,10 @@ static void fill_slice_short(DXVA_Slice_VPx_Short *slice, unsigned position, uns slice->wBadSliceChopping = 0; } -static int d3d12va_vp9_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int d3d12va_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VP9SharedContext *h = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); @@ -126,7 +129,7 @@ static int d3d12va_vp9_end_frame(AVCodecContext *avctx) &ctx_pic->pp, sizeof(ctx_pic->pp), NULL, 0, update_input_arguments); } -static int d3d12va_vp9_decode_init(AVCodecContext *avctx) +static av_cold int d3d12va_vp9_decode_init(AVCodecContext *avctx) { D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); DXVA_PicParams_VP9 pp; diff --git a/libavcodec/dca_xll.c b/libavcodec/dca_xll.c index 005a51ed69..0e9a4e77e7 100644 --- a/libavcodec/dca_xll.c +++ b/libavcodec/dca_xll.c @@ -311,7 +311,7 @@ static int chs_parse_header(DCAXllDecoder *s, DCAXllChSet *c, DCAExssAsset *asse b->highest_pred_order = b->adapt_pred_order[i]; } if (b->highest_pred_order > s->nsegsamples) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL adaptive predicition order\n"); + av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL adaptive prediction order\n"); return AVERROR_INVALIDDATA; } @@ -666,7 +666,7 @@ static void chs_filter_band_data(DCAXllDecoder *s, DCAXllChSet *c, int band) } } - // Inverse pairwise channel decorrellation + // Inverse pairwise channel decorrelation if (b->decor_enabled) { int32_t *tmp[DCA_XLL_CHANNELS_MAX]; diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c index 86d86ea458..4572cf4490 100644 --- a/libavcodec/dcadec.c +++ b/libavcodec/dcadec.c @@ -416,8 +416,7 @@ const FFCodec ff_dca_decoder = { .close = dcadec_close, .flush = dcadec_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP), .p.priv_class = &dcadec_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_dca_profiles), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index 83f13472d3..6387f7b5ec 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -199,7 +199,7 @@ static av_cold void dcaenc_init_static_tables(void) create_enc_table(&bitalloc_12_table[i][1], 12, &src_table); } -static int encode_init(AVCodecContext *avctx) +static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; DCAEncContext *c = avctx->priv_data; @@ -854,7 +854,7 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) if (c->lfe_channel) c->consumed_bits += 72; - /* attempt to guess the bit distribution based on the prevoius frame */ + /* attempt to guess the bit distribution based on the previous frame */ for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { int snr_cb = c->peak_cb[ch][band] - c->band_masking_cb[band] - noise; @@ -1322,17 +1322,11 @@ const FFCodec ff_dca_encoder = { .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = sample_rates, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_2_2, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32), + CODEC_SAMPLERATES_ARRAY(sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_2_2, AV_CHANNEL_LAYOUT_5POINT0, + AV_CHANNEL_LAYOUT_5POINT1), .defaults = defaults, .p.priv_class = &dcaenc_class, }; diff --git a/libavcodec/dct.h b/libavcodec/dct.h index 17c881a695..17135207bd 100644 --- a/libavcodec/dct.h +++ b/libavcodec/dct.h @@ -27,11 +27,11 @@ #include #include -void ff_j_rev_dct(int16_t *data); -void ff_j_rev_dct4(int16_t *data); -void ff_j_rev_dct2(int16_t *data); -void ff_j_rev_dct1(int16_t *data); -void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_j_rev_dct(int16_t data[64]); +void ff_j_rev_dct4(int16_t data[64]); +void ff_j_rev_dct2(int16_t data[64]); +void ff_j_rev_dct1(int16_t data[64]); +void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]); +void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]); #endif /* AVCODEC_DCT_H */ diff --git a/libavcodec/dds.c b/libavcodec/dds.c index 2af7f5c98f..bd16b41e49 100644 --- a/libavcodec/dds.c +++ b/libavcodec/dds.c @@ -653,11 +653,6 @@ static int dds_decode(AVCodecContext *avctx, AVFrame *frame, ((unsigned)frame->data[1][3+i*4]<<24) ); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) { av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n", @@ -687,12 +682,6 @@ FF_ENABLE_DEPRECATION_WARNINGS (frame->data[1][0+i*4]<<16)+ ((unsigned)frame->data[1][3+i*4]<<24) ); - -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) { diff --git a/libavcodec/decode.c b/libavcodec/decode.c index c331bb8596..2319e76e4b 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -19,6 +19,7 @@ */ #include +#include #include #include "config.h" @@ -52,7 +53,7 @@ #include "lcevcdec.h" #include "packet_internal.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" @@ -171,10 +172,6 @@ static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt) av_packet_unref(avci->last_pkt_props); if (pkt) { ret = av_packet_copy_props(avci->last_pkt_props, pkt); -#if FF_API_FRAME_PKT - if (!ret) - avci->last_pkt_props->stream_index = pkt->size; // Needed for ff_decode_frame_props(). -#endif } return ret; } @@ -443,14 +440,6 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)) frame->pkt_dts = pkt->dts; - if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - if(!avctx->has_b_frames) - frame->pkt_pos = pkt->pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } emms_c(); if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { @@ -506,10 +495,6 @@ FF_ENABLE_DEPRECATION_WARNINGS pkt->pts = AV_NOPTS_VALUE; pkt->dts = AV_NOPTS_VALUE; if (!(codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { -#if FF_API_FRAME_PKT - // See extract_packet_props() comment. - avci->last_pkt_props->stream_index = avci->last_pkt_props->stream_index - consumed; -#endif avci->last_pkt_props->pts = AV_NOPTS_VALUE; avci->last_pkt_props->dts = AV_NOPTS_VALUE; } @@ -685,28 +670,17 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) return ret; } -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - frame->key_frame = !!(frame->flags & AV_FRAME_FLAG_KEY); -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - frame->interlaced_frame = !!(frame->flags & AV_FRAME_FLAG_INTERLACED); - frame->top_field_first = !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST); -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->best_effort_timestamp = guess_correct_pts(dc, frame->pts, frame->pkt_dts); /* 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)) || + av_assert0(frame->private_ref || !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)); if (frame->private_ref) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; if (fdd->post_process) { ret = fdd->post_process(avctx, frame); @@ -719,7 +693,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } /* free the per-frame decode data */ - av_buffer_unref(&frame->private_ref); + av_refstruct_unref(&frame->private_ref); return ret; } @@ -816,9 +790,6 @@ int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) AVCodecInternal *avci = avctx->internal; int ret; - if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) - return AVERROR(EINVAL); - if (avci->buffer_frame->buf[0]) { av_frame_move_ref(frame, avci->buffer_frame); } else { @@ -839,53 +810,6 @@ int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) avctx->frame_num++; -#if FF_API_DROPCHANGED - if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) { - - if (avctx->frame_num == 1) { - avci->initial_format = frame->format; - switch(avctx->codec_type) { - case AVMEDIA_TYPE_VIDEO: - avci->initial_width = frame->width; - avci->initial_height = frame->height; - break; - case AVMEDIA_TYPE_AUDIO: - avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate : - avctx->sample_rate; - ret = av_channel_layout_copy(&avci->initial_ch_layout, &frame->ch_layout); - if (ret < 0) - goto fail; - break; - } - } - - if (avctx->frame_num > 1) { - int changed = avci->initial_format != frame->format; - - switch(avctx->codec_type) { - case AVMEDIA_TYPE_VIDEO: - changed |= avci->initial_width != frame->width || - avci->initial_height != frame->height; - break; - case AVMEDIA_TYPE_AUDIO: - changed |= avci->initial_sample_rate != frame->sample_rate || - avci->initial_sample_rate != avctx->sample_rate || - av_channel_layout_compare(&avci->initial_ch_layout, &frame->ch_layout); - break; - } - - if (changed) { - avci->changed_frames_dropped++; - av_log(avctx, AV_LOG_INFO, "dropped changed frame #%"PRId64" pts %"PRId64 - " drop count: %d \n", - avctx->frame_num, frame->pts, - avci->changed_frames_dropped); - ret = AVERROR_INPUT_CHANGED; - goto fail; - } - } - } -#endif return 0; fail: av_frame_unref(frame); @@ -1173,6 +1097,7 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, const AVCodecHWConfigInternal *hw_config; const FFHWAccel *hwa; int i, ret; + bool clean_priv_data = false; for (i = 0;; i++) { hw_config = ffcodec(avctx->codec)->hw_configs[i]; @@ -1197,6 +1122,7 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, av_buffer_unref(&frames_ref); return AVERROR(ENOMEM); } + clean_priv_data = true; } ret = hwa->frame_params(avctx, frames_ref); @@ -1217,6 +1143,8 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, *out_frames_ref = frames_ref; } else { + if (clean_priv_data) + av_freep(&avctx->internal->hwaccel_priv_data); av_buffer_unref(&frames_ref); } return ret; @@ -1466,8 +1394,8 @@ static int side_data_map(AVFrame *dst, { for (int i = 0; map[i].packet < AV_PKT_DATA_NB; i++) { - const enum AVFrameSideDataType type_pkt = map[i].packet; - const enum AVFrameSideDataType type_frame = map[i].frame; + const enum AVPacketSideDataType type_pkt = map[i].packet; + const enum AVFrameSideDataType type_frame = map[i].frame; const AVPacketSideData *sd_pkt; AVFrameSideData *sd_frame; @@ -1525,12 +1453,6 @@ int ff_decode_frame_props_from_pkt(const AVCodecContext *avctx, frame->pts = pkt->pts; frame->duration = pkt->duration; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_pos = pkt->pos; - frame->pkt_size = pkt->size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, ff_sd_global_map); if (ret < 0) @@ -1565,17 +1487,21 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) if (ret < 0) return ret; + for (int i = 0; i < avctx->nb_decoded_side_data; i++) { + const AVFrameSideData *src = avctx->decoded_side_data[i]; + if (av_frame_get_side_data(frame, src->type)) + continue; + ret = av_frame_side_data_clone(&frame->side_data, &frame->nb_side_data, src, 0); + if (ret < 0) + return ret; + } + if (!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { const AVPacket *pkt = avctx->internal->last_pkt_props; ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt); if (ret < 0) return ret; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_size = pkt->stream_index; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } ret = fill_frame_props(avctx, frame); @@ -1618,39 +1544,29 @@ static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) } } -static void decode_data_free(void *opaque, uint8_t *data) +static void decode_data_free(AVRefStructOpaque unused, void *obj) { - FrameDecodeData *fdd = (FrameDecodeData*)data; + FrameDecodeData *fdd = obj; 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); + av_refstruct_unref(&frame->private_ref); - fdd = av_mallocz(sizeof(*fdd)); + fdd = av_refstruct_alloc_ext(sizeof(*fdd), 0, NULL, decode_data_free); 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; + frame->private_ref = fdd; return 0; } @@ -1671,22 +1587,49 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) } } -static void attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) +static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); if (dc->lcevc_frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; + FFLCEVCFrame *frame_ctx; + int ret; - fdd->post_process_opaque = ff_refstruct_ref(dc->lcevc); - fdd->post_process_opaque_free = ff_lcevc_unref; - fdd->post_process = ff_lcevc_process; + frame_ctx = av_mallocz(sizeof(*frame_ctx)); + if (!frame_ctx) + return AVERROR(ENOMEM); + + frame_ctx->frame = av_frame_alloc(); + if (!frame_ctx->frame) { + av_free(frame_ctx); + return AVERROR(ENOMEM); + } + + frame_ctx->lcevc = av_refstruct_ref(dc->lcevc); + frame_ctx->frame->width = frame->width; + frame_ctx->frame->height = frame->height; + frame_ctx->frame->format = frame->format; frame->width = dc->width; frame->height = dc->height; + + ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0); + if (ret < 0) { + ff_lcevc_unref(frame_ctx); + return ret; + } + + validate_avframe_allocation(avctx, frame_ctx->frame); + + fdd->post_process_opaque = frame_ctx; + fdd->post_process_opaque_free = ff_lcevc_unref; + fdd->post_process = ff_lcevc_process; } dc->lcevc_frame = 0; + + return 0; } int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) @@ -1695,7 +1638,7 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) int override_dimensions = 1; int ret; - av_assert0(av_codec_is_decoder(avctx->codec)); + av_assert0(ff_codec_is_decoder(avctx->codec)); if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { if ((unsigned)avctx->width > INT_MAX - STRIDE_ALIGN || @@ -1747,7 +1690,9 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) if (ret < 0) goto fail; - attach_post_process_data(avctx, frame); + ret = attach_post_process_data(avctx, frame); + if (ret < 0) + goto fail; end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && @@ -1828,11 +1773,11 @@ static void check_progress_consistency(const ProgressFrame *f) int ff_progress_frame_alloc(AVCodecContext *avctx, ProgressFrame *f) { - FFRefStructPool *pool = avctx->internal->progress_frame_pool; + AVRefStructPool *pool = avctx->internal->progress_frame_pool; av_assert1(!f->f && !f->progress); - f->progress = ff_refstruct_pool_get(pool); + f->progress = av_refstruct_pool_get(pool); if (!f->progress) return AVERROR(ENOMEM); @@ -1842,19 +1787,14 @@ int ff_progress_frame_alloc(AVCodecContext *avctx, ProgressFrame *f) int ff_progress_frame_get_buffer(AVCodecContext *avctx, ProgressFrame *f, int flags) { - int ret; - - check_progress_consistency(f); - if (!f->f) { - ret = ff_progress_frame_alloc(avctx, f); - if (ret < 0) - return ret; - } + int ret = ff_progress_frame_alloc(avctx, f); + if (ret < 0) + return ret; ret = ff_thread_get_buffer(avctx, f->progress->f, flags); if (ret < 0) { f->f = NULL; - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); return ret; } return 0; @@ -1865,14 +1805,14 @@ void ff_progress_frame_ref(ProgressFrame *dst, const ProgressFrame *src) av_assert1(src->progress && src->f && src->f == src->progress->f); av_assert1(!dst->f && !dst->progress); dst->f = src->f; - dst->progress = ff_refstruct_ref(src->progress); + dst->progress = av_refstruct_ref(src->progress); } void ff_progress_frame_unref(ProgressFrame *f) { check_progress_consistency(f); f->f = NULL; - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); } void ff_progress_frame_replace(ProgressFrame *dst, const ProgressFrame *src) @@ -1902,7 +1842,7 @@ enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) } #endif /* !HAVE_THREADS */ -static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *obj) +static av_cold int progress_frame_pool_init_cb(AVRefStructOpaque opaque, void *obj) { const AVCodecContext *avctx = opaque.nc; ProgressInternal *progress = obj; @@ -1919,7 +1859,7 @@ static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *o return 0; } -static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj) +static void progress_frame_pool_reset_cb(AVRefStructOpaque unused, void *obj) { ProgressInternal *progress = obj; @@ -1927,7 +1867,7 @@ static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj) av_frame_unref(progress->f); } -static av_cold void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +static av_cold void progress_frame_pool_free_entry_cb(AVRefStructOpaque opaque, void *obj) { ProgressInternal *progress = obj; @@ -2042,8 +1982,8 @@ int ff_decode_preinit(AVCodecContext *avctx) if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_USES_PROGRESSFRAMES) { avci->progress_frame_pool = - ff_refstruct_pool_alloc_ext(sizeof(ProgressInternal), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, + av_refstruct_pool_alloc_ext(sizeof(ProgressInternal), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, avctx, progress_frame_pool_init_cb, progress_frame_pool_reset_cb, progress_frame_pool_free_entry_cb, NULL); @@ -2060,11 +2000,6 @@ int ff_decode_preinit(AVCodecContext *avctx) return ret; } -#if FF_API_DROPCHANGED - if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) - av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n"); -#endif - return 0; } @@ -2259,11 +2194,11 @@ int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_pr return AVERROR(EINVAL); frames_ctx = (AVHWFramesContext *) avctx->hw_frames_ctx->data; - *hwaccel_picture_private = ff_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0, + *hwaccel_picture_private = av_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0, frames_ctx->device_ctx, hwaccel->free_frame_priv); } else { - *hwaccel_picture_private = ff_refstruct_allocz(hwaccel->frame_priv_data_size); + *hwaccel_picture_private = av_refstruct_allocz(hwaccel->frame_priv_data_size); } if (!*hwaccel_picture_private) @@ -2300,7 +2235,7 @@ void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src) const DecodeContext *src_dc = decode_ctx(src->internal); DecodeContext *dst_dc = decode_ctx(dst->internal); - ff_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc); + av_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc); } void ff_decode_internal_uninit(AVCodecContext *avctx) @@ -2308,5 +2243,5 @@ void ff_decode_internal_uninit(AVCodecContext *avctx) AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); - ff_refstruct_unref(&dc->lcevc); + av_refstruct_unref(&dc->lcevc); } diff --git a/libavcodec/decode_bsf.h b/libavcodec/decode_bsf.h new file mode 100644 index 0000000000..9ea9ab70c1 --- /dev/null +++ b/libavcodec/decode_bsf.h @@ -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 + */ + +#ifndef AVCODEC_DECODE_BSF_H +#define AVCODEC_DECODE_BSF_H + +#include + +#include "avcodec.h" +#include "bsf.h" +#include "internal.h" + +/** + * Helper function for decoders that may use a BSF that changes extradata. + * This function will get the extradata from the BSF. + */ +static inline void ff_decode_get_extradata(const AVCodecContext *avctx, + const uint8_t **extradata, + int *extradata_size) +{ + // Given that we unconditionally insert a null BSF when no BSF is + // explicitly requested, we can just use the BSF's par_out here. + *extradata = avctx->internal->bsf->par_out->extradata; + *extradata_size = avctx->internal->bsf->par_out->extradata_size; +} + +#endif /* AVCODEC_DECODE_BSF_H */ diff --git a/libavcodec/defs.h b/libavcodec/defs.h index 24250f8af5..b13e983b13 100644 --- a/libavcodec/defs.h +++ b/libavcodec/defs.h @@ -185,6 +185,9 @@ #define AV_PROFILE_PRORES_4444 4 #define AV_PROFILE_PRORES_XQ 5 +#define AV_PROFILE_PRORES_RAW 0 +#define AV_PROFILE_PRORES_RAW_HQ 1 + #define AV_PROFILE_ARIB_PROFILE_A 0 #define AV_PROFILE_ARIB_PROFILE_C 1 @@ -194,6 +197,14 @@ #define AV_PROFILE_EVC_BASELINE 0 #define AV_PROFILE_EVC_MAIN 1 +#define AV_PROFILE_APV_422_10 33 +#define AV_PROFILE_APV_422_12 44 +#define AV_PROFILE_APV_444_10 55 +#define AV_PROFILE_APV_444_12 66 +#define AV_PROFILE_APV_4444_10 77 +#define AV_PROFILE_APV_4444_12 88 +#define AV_PROFILE_APV_400_10 99 + #define AV_LEVEL_UNKNOWN -99 @@ -325,6 +336,20 @@ typedef struct AVProducerReferenceTime { int flags; } AVProducerReferenceTime; +/** + * RTCP SR (Sender Report) information + * + * The received sender report information for an RTSP + * stream, exposed as AV_PKT_DATA_RTCP_SR side data. + */ +typedef struct AVRTCPSenderReport { + uint32_t ssrc; ///< Synchronization source identifier + uint64_t ntp_timestamp; ///< NTP time when the report was sent + uint32_t rtp_timestamp; ///< RTP time when the report was sent + uint32_t sender_nb_packets; ///< Total number of packets sent + uint32_t sender_nb_bytes; ///< Total number of bytes sent (excluding headers or padding) +} AVRTCPSenderReport; + /** * Encode extradata length to a buffer. Used by xiph codecs. * diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c index 9114feb0b3..1efaefcb69 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -367,11 +367,6 @@ static int dfa_decode_frame(AVCodecContext *avctx, AVFrame *frame, s->pal[i] = bytestream2_get_be24(&gb) << 2; s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else if (chunk_type <= 9) { if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", diff --git a/libavcodec/dfpwmenc.c b/libavcodec/dfpwmenc.c index 5318b04a39..1adc4c754f 100644 --- a/libavcodec/dfpwmenc.c +++ b/libavcodec/dfpwmenc.c @@ -25,14 +25,14 @@ * DFPWM1a encoder */ -#include "libavutil/internal.h" #include "avcodec.h" #include "codec_id.h" #include "codec_internal.h" #include "encode.h" +#include "internal.h" typedef struct { - int fq, q, s, lt; + int q, s, lt; } DFPWMState; // DFPWM codec from https://github.com/ChenThread/dfpwm/blob/master/1a/ @@ -79,12 +79,15 @@ static av_cold int dfpwm_enc_init(struct AVCodecContext *ctx) { DFPWMState *state = ctx->priv_data; - state->fq = 0; state->q = 0; state->s = 0; state->lt = -128; ctx->bits_per_coded_sample = 1; + // Pad so that nb_samples * nb_channels is always a multiple of eight. + ctx->internal->pad_samples = (const uint8_t[]){ 1, 8, 4, 8, 2, 8, 4, 8 }[ctx->ch_layout.nb_channels & 7]; + if (ctx->frame_size <= 0 || ctx->frame_size * ctx->ch_layout.nb_channels % 8U) + ctx->frame_size = 4096; return 0; } @@ -93,7 +96,7 @@ static int dfpwm_enc_frame(struct AVCodecContext *ctx, struct AVPacket *packet, const struct AVFrame *frame, int *got_packet) { DFPWMState *state = ctx->priv_data; - int size = frame->nb_samples * frame->ch_layout.nb_channels / 8 + (frame->nb_samples % 8 > 0 ? 1 : 0); + int size = frame->nb_samples * frame->ch_layout.nb_channels / 8U; int ret = ff_get_encode_buffer(ctx, packet, size, 0); if (ret) { @@ -112,10 +115,9 @@ const FFCodec ff_dfpwm_encoder = { CODEC_LONG_NAME("DFPWM1a audio"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_DFPWM, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(DFPWMState), .init = dfpwm_enc_init, FF_CODEC_ENCODE_CB(dfpwm_enc_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NONE}, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | - AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8), }; diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 76209aebba..2eabf74274 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -826,7 +826,7 @@ static int subband_coeffs(const DiracContext *s, int x, int y, int p, int level, coef = 0; for (level = 0; level < s->wavelet_depth; level++) { SliceCoeffs *o = &c[level]; - const SubBand *b = &s->plane[p].band[level][3]; /* orientation doens't matter */ + const SubBand *b = &s->plane[p].band[level][3]; /* orientation doesn't matter */ o->top = b->height * y / s->num_y; o->left = b->width * x / s->num_x; o->tot_h = ((b->width * (x + 1)) / s->num_x) - o->left; diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index b12a2e8851..7a5978c137 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -117,12 +117,12 @@ void dnxhd_10bit_get_pixels_8x4_sym(int16_t *restrict block, memcpy(block + 4 * 8, pixels + 3 * line_size, 8 * sizeof(*block)); } -static int dnxhd_10bit_dct_quantize_444(MpegEncContext *ctx, int16_t *block, +static int dnxhd_10bit_dct_quantize_444(MPVEncContext *ctx, int16_t *block, int n, int qscale, int *overflow) { int i, j, level, last_non_zero, start_i; const int *qmat; - const uint8_t *scantable= ctx->intra_scantable.scantable; + const uint8_t *scantable = ctx->c.intra_scantable.scantable; int bias; int max = 0; unsigned int threshold1, threshold2; @@ -169,17 +169,17 @@ static int dnxhd_10bit_dct_quantize_444(MpegEncContext *ctx, int16_t *block, *overflow = ctx->max_qcoeff < max; //overflow might have happened /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (ctx->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, ctx->idsp.idct_permutation, + if (ctx->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, ctx->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; } -static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, +static int dnxhd_10bit_dct_quantize(MPVEncContext *ctx, int16_t *block, int n, int qscale, int *overflow) { - const uint8_t *scantable= ctx->intra_scantable.scantable; + const uint8_t *scantable = ctx->c.intra_scantable.scantable; const int *qmat = n<4 ? ctx->q_intra_matrix[qscale] : ctx->q_chroma_intra_matrix[qscale]; int last_non_zero = 0; int i; @@ -200,8 +200,8 @@ static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, } /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (ctx->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, ctx->idsp.idct_permutation, + if (ctx->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, ctx->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; @@ -266,34 +266,33 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) { // init first elem to 1 to avoid div by 0 in convert_matrix uint16_t weight_matrix[64] = { 1, }; // convert_matrix needs uint16_t* - int qscale, i; const uint8_t *luma_weight_table = ctx->cid_table->luma_weight; const uint8_t *chroma_weight_table = ctx->cid_table->chroma_weight; - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l16, ctx->m.avctx->qmax + 1) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c16, ctx->m.avctx->qmax + 1)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_l16, ctx->m.c.avctx->qmax + 1) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->qmatrix_c16, ctx->m.c.avctx->qmax + 1)) return AVERROR(ENOMEM); if (ctx->bit_depth == 8) { - for (i = 1; i < 64; i++) { - int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]]; + for (int i = 1; i < 64; i++) { + int j = ctx->m.c.idsp.idct_permutation[ff_zigzag_direct[i]]; weight_matrix[j] = ctx->cid_table->luma_weight[i]; } ff_convert_matrix(&ctx->m, ctx->qmatrix_l, ctx->qmatrix_l16, weight_matrix, ctx->intra_quant_bias, 1, - ctx->m.avctx->qmax, 1); - for (i = 1; i < 64; i++) { - int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]]; + ctx->m.c.avctx->qmax, 1); + for (int i = 1; i < 64; i++) { + int j = ctx->m.c.idsp.idct_permutation[ff_zigzag_direct[i]]; weight_matrix[j] = ctx->cid_table->chroma_weight[i]; } ff_convert_matrix(&ctx->m, ctx->qmatrix_c, ctx->qmatrix_c16, weight_matrix, ctx->intra_quant_bias, 1, - ctx->m.avctx->qmax, 1); + ctx->m.c.avctx->qmax, 1); - for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) { - for (i = 0; i < 64; i++) { + for (int qscale = 1; qscale <= ctx->m.c.avctx->qmax; qscale++) { + for (int i = 0; i < 64; i++) { ctx->qmatrix_l[qscale][i] <<= 2; ctx->qmatrix_c[qscale][i] <<= 2; ctx->qmatrix_l16[qscale][0][i] <<= 2; @@ -304,8 +303,8 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) } } else { // 10-bit - for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) { - for (i = 1; i < 64; i++) { + for (int qscale = 1; qscale <= ctx->m.c.avctx->qmax; qscale++) { + for (int i = 1; i < 64; i++) { int j = ff_zigzag_direct[i]; /* The quantization formula from the VC-3 standard is: @@ -337,12 +336,12 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) static av_cold int dnxhd_init_rc(DNXHDEncContext *ctx) { - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_rc, (ctx->m.avctx->qmax + 1) * ctx->m.mb_num)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_rc, (ctx->m.c.avctx->qmax + 1) * ctx->m.c.mb_num)) return AVERROR(ENOMEM); - if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD) { - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp, ctx->m.mb_num) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp_tmp, ctx->m.mb_num)) + if (ctx->m.c.avctx->mb_decision != FF_MB_DECISION_RD) { + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp, ctx->m.c.mb_num) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_cmp_tmp, ctx->m.c.mb_num)) return AVERROR(ENOMEM); } ctx->frame_bits = (ctx->coding_unit_size - @@ -414,21 +413,21 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->cid_table = ff_dnxhd_get_cid_table(ctx->cid); av_assert0(ctx->cid_table); - ctx->m.avctx = avctx; - ctx->m.mb_intra = 1; - ctx->m.h263_aic = 1; + ctx->m.c.avctx = avctx; + ctx->m.c.mb_intra = 1; + ctx->m.c.h263_aic = 1; avctx->bits_per_raw_sample = ctx->bit_depth; - ff_blockdsp_init(&ctx->m.bdsp); + ff_blockdsp_init(&ctx->m.c.bdsp); ff_fdctdsp_init(&ctx->m.fdsp, avctx); - ff_mpv_idct_init(&ctx->m); + ff_mpv_idct_init(&ctx->m.c); ff_mpegvideoencdsp_init(&ctx->m.mpvencdsp, avctx); - ff_pixblockdsp_init(&ctx->m.pdsp, avctx); + ff_pixblockdsp_init(&ctx->m.pdsp, ctx->bit_depth); ff_dct_encode_init(&ctx->m); if (ctx->profile != AV_PROFILE_DNXHD) - ff_videodsp_init(&ctx->m.vdsp, ctx->bit_depth); + ff_videodsp_init(&ctx->m.c.vdsp, ctx->bit_depth); if (ctx->is_444 || ctx->profile == AV_PROFILE_DNXHR_HQX) { ctx->m.dct_quantize = dnxhd_10bit_dct_quantize_444; @@ -445,12 +444,12 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ff_dnxhdenc_init(ctx); - ctx->m.mb_height = (avctx->height + 15) / 16; - ctx->m.mb_width = (avctx->width + 15) / 16; + ctx->m.c.mb_height = (avctx->height + 15) / 16; + ctx->m.c.mb_width = (avctx->width + 15) / 16; if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { ctx->interlaced = 1; - ctx->m.mb_height /= 2; + ctx->m.c.mb_height /= 2; } if (ctx->interlaced && ctx->profile != AV_PROFILE_DNXHD) { @@ -459,7 +458,7 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->m.mb_num = ctx->m.mb_height * ctx->m.mb_width; + ctx->m.c.mb_num = ctx->m.c.mb_height * ctx->m.c.mb_width; if (ctx->cid_table->frame_size == DNXHD_VARIABLE) { ctx->frame_size = ff_dnxhd_get_hr_frame_size(ctx->cid, @@ -471,8 +470,8 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->coding_unit_size = ctx->cid_table->coding_unit_size; } - if (ctx->m.mb_height > 68) - ctx->data_offset = 0x170 + (ctx->m.mb_height << 2); + if (ctx->m.c.mb_height > 68) + ctx->data_offset = 0x170 + (ctx->m.c.mb_height << 2); else ctx->data_offset = 0x280; @@ -490,10 +489,10 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) if ((ret = dnxhd_init_rc(ctx)) < 0) return ret; - if (!FF_ALLOCZ_TYPED_ARRAY(ctx->slice_size, ctx->m.mb_height) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->slice_offs, ctx->m.mb_height) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_bits, ctx->m.mb_num) || - !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_qscale, ctx->m.mb_num)) + if (!FF_ALLOCZ_TYPED_ARRAY(ctx->slice_size, ctx->m.c.mb_height) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->slice_offs, ctx->m.c.mb_height) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_bits, ctx->m.c.mb_num) || + !FF_ALLOCZ_TYPED_ARRAY(ctx->mb_qscale, ctx->m.c.mb_num)) return AVERROR(ENOMEM); if (avctx->active_thread_type == FF_THREAD_SLICE) { @@ -548,8 +547,8 @@ static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf) buf[0x5f] = 0x01; // UDL buf[0x167] = 0x02; // reserved - AV_WB16(buf + 0x16a, ctx->m.mb_height * 4 + 4); // MSIPS - AV_WB16(buf + 0x16c, ctx->m.mb_height); // Ns + AV_WB16(buf + 0x16a, ctx->m.c.mb_height * 4 + 4); // MSIPS + AV_WB16(buf + 0x16c, ctx->m.c.mb_height); // Ns buf[0x16f] = 0x10; // reserved ctx->msip = buf + 0x170; @@ -577,11 +576,11 @@ void dnxhd_encode_block(PutBitContext *pb, DNXHDEncContext *ctx, int last_non_zero = 0; int slevel, i, j; - dnxhd_encode_dc(pb, ctx, block[0] - ctx->m.last_dc[n]); - ctx->m.last_dc[n] = block[0]; + dnxhd_encode_dc(pb, ctx, block[0] - ctx->m.c.last_dc[n]); + ctx->m.c.last_dc[n] = block[0]; for (i = 1; i <= last_index; i++) { - j = ctx->m.intra_scantable.permutated[i]; + j = ctx->m.c.intra_scantable.permutated[i]; slevel = block[j]; if (slevel) { int run_level = i - last_non_zero - 1; @@ -613,7 +612,7 @@ void dnxhd_unquantize_c(DNXHDEncContext *ctx, int16_t *block, int n, } for (i = 1; i <= last_index; i++) { - int j = ctx->m.intra_scantable.permutated[i]; + int j = ctx->m.c.intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { @@ -661,7 +660,7 @@ int dnxhd_calc_ac_bits(DNXHDEncContext *ctx, int16_t *block, int last_index) int bits = 0; int i, j, level; for (i = 1; i <= last_index; i++) { - j = ctx->m.intra_scantable.permutated[i]; + j = ctx->m.c.intra_scantable.permutated[i]; level = block[j]; if (level) { int run_level = i - last_non_zero - 1; @@ -680,36 +679,36 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) const int bw = 1 << bs; int dct_y_offset = ctx->dct_y_offset; int dct_uv_offset = ctx->dct_uv_offset; - int linesize = ctx->m.linesize; - int uvlinesize = ctx->m.uvlinesize; + int linesize = ctx->m.c.linesize; + int uvlinesize = ctx->m.c.uvlinesize; const uint8_t *ptr_y = ctx->thread[0]->src[0] + - ((mb_y << 4) * ctx->m.linesize) + (mb_x << bs + 1); + ((mb_y << 4) * ctx->m.c.linesize) + (mb_x << bs + 1); const uint8_t *ptr_u = ctx->thread[0]->src[1] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); + ((mb_y << 4) * ctx->m.c.uvlinesize) + (mb_x << bs + ctx->is_444); const uint8_t *ptr_v = ctx->thread[0]->src[2] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); + ((mb_y << 4) * ctx->m.c.uvlinesize) + (mb_x << bs + ctx->is_444); PixblockDSPContext *pdsp = &ctx->m.pdsp; - VideoDSPContext *vdsp = &ctx->m.vdsp; + VideoDSPContext *vdsp = &ctx->m.c.vdsp; - if (ctx->bit_depth != 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || - (mb_y << 4) + 16 > ctx->m.avctx->height)) { - int y_w = ctx->m.avctx->width - (mb_x << 4); - int y_h = ctx->m.avctx->height - (mb_y << 4); + if (ctx->bit_depth != 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.c.avctx->width || + (mb_y << 4) + 16 > ctx->m.c.avctx->height)) { + int y_w = ctx->m.c.avctx->width - (mb_x << 4); + int y_h = ctx->m.c.avctx->height - (mb_y << 4); int uv_w = (y_w + 1) / 2; int uv_h = y_h; linesize = 16; uvlinesize = 8; vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y, - linesize, ctx->m.linesize, + linesize, ctx->m.c.linesize, linesize, 16, 0, 0, y_w, y_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize, 16, 0, 0, uv_w, uv_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize, 16, 0, 0, uv_w, uv_h); @@ -718,25 +717,25 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_y = &ctx->edge_buf_y[0]; ptr_u = &ctx->edge_buf_uv[0][0]; ptr_v = &ctx->edge_buf_uv[1][0]; - } else if (ctx->bit_depth == 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || - (mb_y << 4) + 16 > ctx->m.avctx->height)) { - int y_w = ctx->m.avctx->width - (mb_x << 4); - int y_h = ctx->m.avctx->height - (mb_y << 4); + } else if (ctx->bit_depth == 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.c.avctx->width || + (mb_y << 4) + 16 > ctx->m.c.avctx->height)) { + int y_w = ctx->m.c.avctx->width - (mb_x << 4); + int y_h = ctx->m.c.avctx->height - (mb_y << 4); int uv_w = ctx->is_444 ? y_w : (y_w + 1) / 2; int uv_h = y_h; linesize = 32; uvlinesize = 16 + 16 * ctx->is_444; vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y, - linesize, ctx->m.linesize, + linesize, ctx->m.c.linesize, linesize / 2, 16, 0, 0, y_w, y_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize / 2, 16, 0, 0, uv_w, uv_h); vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v, - uvlinesize, ctx->m.uvlinesize, + uvlinesize, ctx->m.c.uvlinesize, uvlinesize / 2, 16, 0, 0, uv_w, uv_h); @@ -753,7 +752,7 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) pdsp->get_pixels(ctx->blocks[2], ptr_u, uvlinesize); pdsp->get_pixels(ctx->blocks[3], ptr_v, uvlinesize); - if (mb_y + 1 == ctx->m.mb_height && ctx->m.avctx->height == 1080) { + if (mb_y + 1 == ctx->m.c.mb_height && ctx->m.c.avctx->height == 1080) { if (ctx->interlaced) { ctx->get_pixels_8x4_sym(ctx->blocks[4], ptr_y + dct_y_offset, @@ -768,10 +767,10 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_v + dct_uv_offset, uvlinesize); } else { - ctx->m.bdsp.clear_block(ctx->blocks[4]); - ctx->m.bdsp.clear_block(ctx->blocks[5]); - ctx->m.bdsp.clear_block(ctx->blocks[6]); - ctx->m.bdsp.clear_block(ctx->blocks[7]); + ctx->m.c.bdsp.clear_block(ctx->blocks[4]); + ctx->m.c.bdsp.clear_block(ctx->blocks[5]); + ctx->m.c.bdsp.clear_block(ctx->blocks[6]); + ctx->m.c.bdsp.clear_block(ctx->blocks[7]); } } else { pdsp->get_pixels(ctx->blocks[4], @@ -819,17 +818,17 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) { DNXHDEncContext *ctx = avctx->priv_data; - int mb_y = jobnr, mb_x; + int mb_y = jobnr; int qscale = ctx->qscale; LOCAL_ALIGNED_16(int16_t, block, [64]); ctx = ctx->thread[threadnr]; - ctx->m.last_dc[0] = - ctx->m.last_dc[1] = - ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); + ctx->m.c.last_dc[0] = + ctx->m.c.last_dc[1] = + ctx->m.c.last_dc[2] = 1 << (ctx->bit_depth + 2); - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int ssd = 0; int ac_bits = 0; int dc_bits = 0; @@ -848,7 +847,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, qscale, &overflow); ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index); - diff = block[0] - ctx->m.last_dc[n]; + diff = block[0] - ctx->m.c.last_dc[n]; if (diff < 0) nbits = av_log2_16bit(-2 * diff); else @@ -857,16 +856,16 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, av_assert1(nbits < ctx->bit_depth + 4); dc_bits += ctx->cid_table->dc_bits[nbits] + nbits; - ctx->m.last_dc[n] = block[0]; + ctx->m.c.last_dc[n] = block[0]; if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) { dnxhd_unquantize_c(ctx, block, i, qscale, last_index); - ctx->m.idsp.idct(block); + ctx->m.c.idsp.idct(block); ssd += dnxhd_ssd_block(block, src_block); } } - ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].ssd = ssd; - ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].bits = ac_bits + dc_bits + 12 + + ctx->mb_rc[(qscale * ctx->m.c.mb_num) + mb].ssd = ssd; + ctx->mb_rc[(qscale * ctx->m.c.mb_num) + mb].bits = ac_bits + dc_bits + 12 + (1 + ctx->is_444) * 8 * ctx->vlc_bits[0]; } return 0; @@ -877,16 +876,16 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, { DNXHDEncContext *ctx = avctx->priv_data; PutBitContext pb0, *const pb = &pb0; - int mb_y = jobnr, mb_x; + int mb_y = jobnr; ctx = ctx->thread[threadnr]; init_put_bits(pb, (uint8_t *)arg + ctx->data_offset + ctx->slice_offs[jobnr], ctx->slice_size[jobnr]); - ctx->m.last_dc[0] = - ctx->m.last_dc[1] = - ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + ctx->m.c.last_dc[0] = + ctx->m.c.last_dc[1] = + ctx->m.c.last_dc[2] = 1 << (ctx->bit_depth + 2); + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int qscale = ctx->mb_qscale[mb]; int i; @@ -912,14 +911,12 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, static void dnxhd_setup_threads_slices(DNXHDEncContext *ctx) { - int mb_y, mb_x; - int offset = 0; - for (mb_y = 0; mb_y < ctx->m.mb_height; mb_y++) { + for (int mb_y = 0, offset = 0; mb_y < ctx->m.c.mb_height; mb_y++) { int thread_size; ctx->slice_offs[mb_y] = offset; ctx->slice_size[mb_y] = 0; - for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; mb_x++) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; ctx->slice_size[mb_y] += ctx->mb_bits[mb]; } ctx->slice_size[mb_y] = (ctx->slice_size[mb_y] + 31U) & ~31U; @@ -933,28 +930,28 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) { DNXHDEncContext *ctx = avctx->priv_data; - int mb_y = jobnr, mb_x, x, y; - int partial_last_row = (mb_y == ctx->m.mb_height - 1) && + int mb_y = jobnr, x, y; + int partial_last_row = (mb_y == ctx->m.c.mb_height - 1) && ((avctx->height >> ctx->interlaced) & 0xF); ctx = ctx->thread[threadnr]; if (ctx->bit_depth == 8) { - const uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.linesize); - for (mb_x = 0; mb_x < ctx->m.mb_width; ++mb_x, pix += 16) { - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + const uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.c.linesize); + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; ++mb_x, pix += 16) { + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int sum; int varc; if (!partial_last_row && mb_x * 16 <= avctx->width - 16 && (avctx->width % 16) == 0) { - sum = ctx->m.mpvencdsp.pix_sum(pix, ctx->m.linesize); - varc = ctx->m.mpvencdsp.pix_norm1(pix, ctx->m.linesize); + sum = ctx->m.mpvencdsp.pix_sum(pix, ctx->m.c.linesize); + varc = ctx->m.mpvencdsp.pix_norm1(pix, ctx->m.c.linesize); } else { int bw = FFMIN(avctx->width - 16 * mb_x, 16); int bh = FFMIN((avctx->height >> ctx->interlaced) - 16 * mb_y, 16); sum = varc = 0; for (y = 0; y < bh; y++) { for (x = 0; x < bw; x++) { - uint8_t val = pix[x + y * ctx->m.linesize]; + uint8_t val = pix[x + y * ctx->m.c.linesize]; sum += val; varc += val * val; } @@ -966,11 +963,11 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg, ctx->mb_cmp[mb].mb = mb; } } else { // 10-bit - const int linesize = ctx->m.linesize >> 1; - for (mb_x = 0; mb_x < ctx->m.mb_width; ++mb_x) { + const int linesize = ctx->m.c.linesize >> 1; + for (int mb_x = 0; mb_x < ctx->m.c.mb_width; ++mb_x) { const uint16_t *pix = (const uint16_t *)ctx->thread[0]->src[0] + ((mb_y << 4) * linesize) + (mb_x << 4); - unsigned mb = mb_y * ctx->m.mb_width + mb_x; + unsigned mb = mb_y * ctx->m.c.mb_width + mb_x; int sum = 0; int sqsum = 0; int bw = FFMIN(avctx->width - 16 * mb_x, 16); @@ -1001,12 +998,11 @@ static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx) { int lambda, up_step, down_step; int last_lower = INT_MAX, last_higher = 0; - int x, y, q; - for (q = 1; q < avctx->qmax; q++) { + for (int q = 1; q < avctx->qmax; q++) { ctx->qscale = q; avctx->execute2(avctx, dnxhd_calc_bits_thread, - NULL, NULL, ctx->m.mb_height); + NULL, NULL, ctx->m.c.mb_height); } up_step = down_step = 2 << LAMBDA_FRAC_BITS; lambda = ctx->lambda; @@ -1018,14 +1014,14 @@ static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx) lambda++; end = 1; // need to set final qscales/bits } - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) { + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) { unsigned min = UINT_MAX; int qscale = 1; - int mb = y * ctx->m.mb_width + x; + int mb = y * ctx->m.c.mb_width + x; int rc = 0; - for (q = 1; q < avctx->qmax; q++) { - int i = (q*ctx->m.mb_num) + mb; + for (int q = 1; q < avctx->qmax; q++) { + int i = (q*ctx->m.c.mb_num) + mb; unsigned score = ctx->mb_rc[i].bits * lambda + ((unsigned) ctx->mb_rc[i].ssd << LAMBDA_FRAC_BITS); if (score < min) { @@ -1082,18 +1078,17 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx) int last_higher = 0; int last_lower = INT_MAX; int qscale; - int x, y; qscale = ctx->qscale; for (;;) { bits = 0; ctx->qscale = qscale; // XXX avoid recalculating bits - ctx->m.avctx->execute2(ctx->m.avctx, dnxhd_calc_bits_thread, - NULL, NULL, ctx->m.mb_height); - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) - bits += ctx->mb_rc[(qscale*ctx->m.mb_num) + (y*ctx->m.mb_width+x)].bits; + ctx->m.c.avctx->execute2(ctx->m.c.avctx, dnxhd_calc_bits_thread, + NULL, NULL, ctx->m.c.mb_height); + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) + bits += ctx->mb_rc[(qscale*ctx->m.c.mb_num) + (y*ctx->m.c.mb_width+x)].bits; bits = (bits+31)&~31; // padding if (bits > ctx->frame_bits) break; @@ -1122,7 +1117,7 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx) else qscale += up_step++; down_step = 1; - if (qscale >= ctx->m.avctx->qmax) + if (qscale >= ctx->m.c.avctx->qmax) return AVERROR(EINVAL); } } @@ -1189,24 +1184,24 @@ static void radix_sort(RCCMPEntry *data, RCCMPEntry *tmp, int size) static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) { int max_bits = 0; - int ret, x, y; + int ret; if ((ret = dnxhd_find_qscale(ctx)) < 0) return ret; - for (y = 0; y < ctx->m.mb_height; y++) { - for (x = 0; x < ctx->m.mb_width; x++) { - int mb = y * ctx->m.mb_width + x; - int rc = (ctx->qscale * ctx->m.mb_num ) + mb; + for (int y = 0; y < ctx->m.c.mb_height; y++) { + for (int x = 0; x < ctx->m.c.mb_width; x++) { + int mb = y * ctx->m.c.mb_width + x; + int rc = (ctx->qscale * ctx->m.c.mb_num ) + mb; int delta_bits; ctx->mb_qscale[mb] = ctx->qscale; ctx->mb_bits[mb] = ctx->mb_rc[rc].bits; max_bits += ctx->mb_rc[rc].bits; if (!RC_VARIANCE) { delta_bits = ctx->mb_rc[rc].bits - - ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_rc[rc + ctx->m.c.mb_num].bits; ctx->mb_cmp[mb].mb = mb; ctx->mb_cmp[mb].value = delta_bits ? ((ctx->mb_rc[rc].ssd - - ctx->mb_rc[rc + ctx->m.mb_num].ssd) * 100) / + ctx->mb_rc[rc + ctx->m.c.mb_num].ssd) * 100) / delta_bits : INT_MIN; // avoid increasing qscale } @@ -1216,17 +1211,17 @@ static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) if (!ret) { if (RC_VARIANCE) avctx->execute2(avctx, dnxhd_mb_var_thread, - NULL, NULL, ctx->m.mb_height); - radix_sort(ctx->mb_cmp, ctx->mb_cmp_tmp, ctx->m.mb_num); + NULL, NULL, ctx->m.c.mb_height); + radix_sort(ctx->mb_cmp, ctx->mb_cmp_tmp, ctx->m.c.mb_num); retry: - for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) { + for (int x = 0; x < ctx->m.c.mb_num && max_bits > ctx->frame_bits; x++) { int mb = ctx->mb_cmp[x].mb; - int rc = (ctx->qscale * ctx->m.mb_num ) + mb; + int rc = (ctx->qscale * ctx->m.c.mb_num ) + mb; max_bits -= ctx->mb_rc[rc].bits - - ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_rc[rc + ctx->m.c.mb_num].bits; if (ctx->mb_qscale[mb] < 255) ctx->mb_qscale[mb]++; - ctx->mb_bits[mb] = ctx->mb_rc[rc + ctx->m.mb_num].bits; + ctx->mb_bits[mb] = ctx->mb_rc[rc + ctx->m.c.mb_num].bits; } if (max_bits > ctx->frame_bits) @@ -1237,13 +1232,11 @@ retry: static void dnxhd_load_picture(DNXHDEncContext *ctx, const AVFrame *frame) { - int i; - - for (i = 0; i < ctx->m.avctx->thread_count; i++) { - ctx->thread[i]->m.linesize = frame->linesize[0] << ctx->interlaced; - ctx->thread[i]->m.uvlinesize = frame->linesize[1] << ctx->interlaced; - ctx->thread[i]->dct_y_offset = ctx->m.linesize *8; - ctx->thread[i]->dct_uv_offset = ctx->m.uvlinesize*8; + for (int i = 0; i < ctx->m.c.avctx->thread_count; i++) { + ctx->thread[i]->m.c.linesize = frame->linesize[0] << ctx->interlaced; + ctx->thread[i]->m.c.uvlinesize = frame->linesize[1] << ctx->interlaced; + ctx->thread[i]->dct_y_offset = ctx->m.c.linesize *8; + ctx->thread[i]->dct_uv_offset = ctx->m.c.uvlinesize*8; } ctx->cur_field = (frame->flags & AV_FRAME_FLAG_INTERLACED) && @@ -1286,13 +1279,13 @@ encode_coding_unit: dnxhd_setup_threads_slices(ctx); offset = 0; - for (i = 0; i < ctx->m.mb_height; i++) { + for (i = 0; i < ctx->m.c.mb_height; i++) { AV_WB32(ctx->msip + i * 4, offset); offset += ctx->slice_size[i]; av_assert1(!(ctx->slice_size[i] & 3)); } - avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.mb_height); + avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.c.mb_height); av_assert1(ctx->data_offset + offset + 4 <= ctx->coding_unit_size); memset(buf + ctx->data_offset + offset, 0, @@ -1360,13 +1353,8 @@ const FFCodec ff_dnxhd_encoder = { .init = dnxhd_encode_init, FF_CODEC_ENCODE_CB(dnxhd_encode_picture), .close = dnxhd_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV422P10, - AV_PIX_FMT_YUV444P10, - AV_PIX_FMT_GBRP10, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, AV_PIX_FMT_GBRP10), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dnxhd_class, .defaults = dnxhd_defaults, diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h index 00d486babd..7540607cdc 100644 --- a/libavcodec/dnxhdenc.h +++ b/libavcodec/dnxhdenc.h @@ -28,7 +28,7 @@ #include "libavutil/mem_internal.h" -#include "mpegvideo.h" +#include "mpegvideoenc.h" #include "dnxhddata.h" typedef struct RCCMPEntry { @@ -43,7 +43,7 @@ typedef struct RCEntry { typedef struct DNXHDEncContext { AVClass *class; - MpegEncContext m; ///< Used for quantization dsp functions + MPVEncContext m; ///< Used for quantization dsp functions int cid; int profile; diff --git a/libavcodec/dnxuc_parser.c b/libavcodec/dnxuc_parser.c new file mode 100644 index 0000000000..34088ac3b1 --- /dev/null +++ b/libavcodec/dnxuc_parser.c @@ -0,0 +1,89 @@ +/* + * Avid DNxUncomressed / SMPTE RDD 50 parser + * Copyright (c) 2024 Martin Schitter + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This parser for DNxUncompressed video data is mostly based on the public + * SMPTE RDD 50:2019 specification. + */ + +#include "parser.h" +#include "libavutil/bswap.h" + +typedef struct DNxUcParseContext { + ParseContext pc; + uint32_t remaining; +} DNxUcParseContext; + +static int dnxuc_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + DNxUcParseContext *ipc = s->priv_data; + int next = END_NOT_FOUND; + + s->pict_type = AV_PICTURE_TYPE_NONE; + + *poutbuf_size = 0; + *poutbuf = NULL; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + if (ipc->remaining == 0) { + uint64_t state = ipc->pc.state64; + for (int i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if (ipc->pc.index + i >= 7 && (uint32_t)state == MKBETAG('p','a','c','k')) { + uint32_t size = av_bswap32(state >> 32); + if (size >= 8) { + next = i - 7; + ipc->remaining = size + FFMIN(next, 0); + break; + } + } + } + ipc->pc.state64 = state; + } else if (ipc->remaining <= buf_size) { + next = ipc->remaining; + ipc->remaining = 0; + } else { + ipc->remaining -= buf_size; + } + if (ff_combine_frame(&ipc->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +const AVCodecParser ff_dnxuc_parser = { + .codec_ids = { AV_CODEC_ID_DNXUC }, + .priv_data_size = sizeof(DNxUcParseContext), + .parser_parse = dnxuc_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/dolby_e.c b/libavcodec/dolby_e.c index 9c3f6006c2..bbcb747c06 100644 --- a/libavcodec/dolby_e.c +++ b/libavcodec/dolby_e.c @@ -1310,6 +1310,6 @@ const FFCodec ff_dolby_e_decoder = { .close = dolby_e_close, .flush = dolby_e_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/dolby_e_parse.c b/libavcodec/dolby_e_parse.c index ffedcd99a4..fc20eae5b4 100644 --- a/libavcodec/dolby_e_parse.c +++ b/libavcodec/dolby_e_parse.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "get_bits.h" #include "put_bits.h" #include "dolby_e.h" @@ -88,7 +89,7 @@ int ff_dolby_e_convert_input(DBEContext *s, int nb_words, int key) AV_WB24(dst, AV_RB24(src) ^ key); break; default: - av_assert0(0); + av_unreachable("ff_dolby_e_parse_header() only sets 16, 20, 24 and errors out otherwise"); } return init_get_bits(&s->gb, s->buffer, nb_words * s->word_bits); diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 5130a9598d..04e48d2b95 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -24,14 +24,14 @@ #include "libavutil/mem.h" #include "dovi_rpu.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" void ff_dovi_ctx_unref(DOVIContext *s) { - ff_refstruct_unref(&s->dm); + av_refstruct_unref(&s->dm); for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++) - ff_refstruct_unref(&s->vdr[i]); - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->ext_blocks); av_free(s->rpu_buf); *s = (DOVIContext) { @@ -41,10 +41,10 @@ void ff_dovi_ctx_unref(DOVIContext *s) void ff_dovi_ctx_flush(DOVIContext *s) { - ff_refstruct_unref(&s->dm); + av_refstruct_unref(&s->dm); for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++) - ff_refstruct_unref(&s->vdr[i]); - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->ext_blocks); *s = (DOVIContext) { .logctx = s->logctx, @@ -62,10 +62,10 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) s->header = s0->header; s->mapping = s0->mapping; s->color = s0->color; - ff_refstruct_replace(&s->dm, s0->dm); + av_refstruct_replace(&s->dm, s0->dm); for (int i = 0; i <= DOVI_MAX_DM_ID; i++) - ff_refstruct_replace(&s->vdr[i], s0->vdr[i]); - ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks); + av_refstruct_replace(&s->vdr[i], s0->vdr[i]); + av_refstruct_replace(&s->ext_blocks, s0->ext_blocks); } int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index f3ccc27ae8..1b74983205 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -133,9 +133,10 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); /** * Configure the encoder for Dolby Vision encoding. Generates a configuration - * record in s->cfg, and attaches it to avctx->coded_side_data. Sets the correct - * profile and compatibility ID based on the tagged AVCodecParameters colorspace - * metadata, and the correct level based on the resolution and tagged framerate. + * record in s->cfg, and attaches it to codecpar->coded_side_data. Sets the + * correct profile and compatibility ID based on the tagged AVCodecParameters + * colorspace metadata, and the correct level based on the resolution and + * tagged framerate. * * `metadata` should point to the first frame's RPU, if available. If absent, * auto-detection will be performed, but this can sometimes lead to inaccurate @@ -143,13 +144,13 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); * * Returns 0 or a negative error code. */ -int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, - const AVDOVIMetadata *metadata, - enum AVDOVICompression compression, - int strict_std_compliance); +int ff_dovi_configure_from_codedpar(DOVIContext *s, AVCodecParameters *codecpar, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance); /** - * Helper wrapper around `ff_dovi_configure_ext` which infers the codec + * Variant of `ff_dovi_configure_from_codedpar` which infers the codec * parameters from an AVCodecContext. */ int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx); diff --git a/libavcodec/dovi_rpudec.c b/libavcodec/dovi_rpudec.c index 878950d66d..4750d48337 100644 --- a/libavcodec/dovi_rpudec.c +++ b/libavcodec/dovi_rpudec.c @@ -28,7 +28,7 @@ #include "dovi_rpu.h" #include "golomb.h" #include "get_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" int ff_dovi_get_metadata(DOVIContext *s, AVDOVIMetadata **out_metadata) { @@ -188,8 +188,7 @@ static int parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm) dm->l255.dm_debug[i] = get_bits(gb, 8); break; default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v1 level: %u\n", dm->level); + avpriv_request_sample(s->logctx, "Dolby Vision DM v1 level %u", dm->level); } return 0; @@ -274,8 +273,7 @@ static int parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, dm->l254.dm_version_index = get_bits(gb, 8); break; default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v2 level: %u\n", dm->level); + avpriv_request_sample(s->logctx, "Dolby Vision DM v2 level %u", dm->level); } return 0; @@ -291,7 +289,7 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver, align_get_bits(gb); if (num_ext_blocks && !ext) { - ext = s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + ext = s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks)); if (!ext) return AVERROR(ENOMEM); } @@ -328,12 +326,15 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver, switch (ver) { case 1: ret = parse_ext_v1(s, gb, dm); break; case 2: ret = parse_ext_v2(s, gb, dm, ext_block_length); break; - default: return AVERROR_BUG; + default: + avpriv_request_sample(s->logctx, "Dolby Vision DM v%d", ver); + goto skip; } if (ret < 0) return ret; +skip: parsed_bits = get_bits_count(gb) - start_pos; if (parsed_bits > ext_block_length * 8) return AVERROR_INVALIDDATA; @@ -364,7 +365,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, /* Container */ if (s->cfg.dv_profile == 10 /* dav1.10 */) { - /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed + /* DV inside AV1 reuses an EMDF container skeleton, but with fixed * values - so we can effectively treat this as a magic byte sequence. * * The exact fields are, as follows: @@ -408,22 +409,6 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, VALIDATE(rpu[0], 25, 25); /* NAL prefix */ rpu++; rpu_size--; - /* Strip trailing padding bytes */ - while (rpu_size && rpu[rpu_size - 1] == 0) - rpu_size--; - } - - if (!rpu_size || rpu[rpu_size - 1] != 0x80) - return AVERROR_INVALIDDATA; - - if (err_recognition & AV_EF_CRCCHECK) { - uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), - -1, rpu, rpu_size - 1)); /* exclude 0x80 */ - if (crc) { - av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); - if (err_recognition & AV_EF_EXPLODE) - return AVERROR_INVALIDDATA; - } } if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) @@ -556,7 +541,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, int vdr_rpu_id = get_ue_golomb_31(gb); VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); if (!s->vdr[vdr_rpu_id]) { - s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(AVDOVIDataMapping)); + s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping)); if (!s->vdr[vdr_rpu_id]) { ff_dovi_ctx_unref(s); return AVERROR(ENOMEM); @@ -675,7 +660,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, } if (!s->dm) { - s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata)); if (!s->dm) { ff_dovi_ctx_unref(s); return AVERROR(ENOMEM); @@ -735,7 +720,28 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, } } else { s->color = &ff_dovi_color_default; - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->ext_blocks); + } + + align_get_bits(gb); + skip_bits(gb, 32); /* CRC32 */ + if (get_bits(gb, 8) != 0x80) { + avpriv_request_sample(s->logctx, "Unexpected RPU format"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + + if (err_recognition & AV_EF_CRCCHECK) { + rpu_size = get_bits_count(gb) / 8; + uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), + -1, rpu, rpu_size - 1)); /* exclude 0x80 */ + if (crc) { + av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); + if (err_recognition & AV_EF_EXPLODE) { + ff_dovi_ctx_unref(s); + return AVERROR_INVALIDDATA; + } + } } return 0; diff --git a/libavcodec/dovi_rpuenc.c b/libavcodec/dovi_rpuenc.c index 8113ec44bf..fa351c2b55 100644 --- a/libavcodec/dovi_rpuenc.c +++ b/libavcodec/dovi_rpuenc.c @@ -20,18 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" #include "avcodec.h" #include "dovi_rpu.h" #include "itut35.h" #include "put_bits.h" #include "put_golomb.h" -#include "refstruct.h" -static struct { +static const struct { uint64_t pps; // maximum pixels per second int width; // maximum width int main; // maximum bitrate in main tier @@ -52,10 +53,18 @@ static struct { [13] = {7680*4320*120u, 7680, 240, 800}, }; -int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, - const AVDOVIMetadata *metadata, - enum AVDOVICompression compression, - int strict_std_compliance) +static av_cold int dovi_configure_ext(DOVIContext *s, enum AVCodecID codec_id, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance, + int width, int height, + AVRational framerate, + enum AVPixelFormat pix_format, + enum AVColorSpace color_space, + enum AVColorPrimaries color_primaries, + enum AVColorTransferCharacteristic color_trc, + AVPacketSideData **coded_side_data, + int *nb_coded_side_data) { AVDOVIDecoderConfigurationRecord *cfg; const AVDOVIRpuDataHeader *hdr = NULL; @@ -76,7 +85,7 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, compression > AV_DOVI_COMPRESSION_EXTENDED) return AVERROR(EINVAL); - switch (codecpar->codec_id) { + switch (codec_id) { case AV_CODEC_ID_AV1: dv_profile = 10; break; case AV_CODEC_ID_H264: dv_profile = 9; break; case AV_CODEC_ID_HEVC: @@ -86,25 +95,23 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } /* This is likely to be proprietary IPTPQc2 */ - if (codecpar->color_space == AVCOL_SPC_IPT_C2 || - (codecpar->color_space == AVCOL_SPC_UNSPECIFIED && - codecpar->color_trc == AVCOL_TRC_UNSPECIFIED)) + if (color_space == AVCOL_SPC_IPT_C2 || + (color_space == AVCOL_SPC_UNSPECIFIED && + color_trc == AVCOL_TRC_UNSPECIFIED)) dv_profile = 5; else dv_profile = 8; break; default: - /* No other encoder should be calling this! */ - av_assert0(0); - return AVERROR_BUG; + av_unreachable("ff_dovi_configure only used with AV1, H.264 and HEVC"); } if (strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { if (dv_profile == 9) { - if (codecpar->format != AV_PIX_FMT_YUV420P) + if (pix_format != AV_PIX_FMT_YUV420P) dv_profile = 0; } else { - if (codecpar->format != AV_PIX_FMT_YUV420P10) + if (pix_format != AV_PIX_FMT_YUV420P10) dv_profile = 0; } } @@ -131,17 +138,17 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } /* fall through */ case 8: /* HEVC (or AV1) with BL compatibility */ - if (codecpar->color_space == AVCOL_SPC_BT2020_NCL && - codecpar->color_primaries == AVCOL_PRI_BT2020 && - codecpar->color_trc == AVCOL_TRC_SMPTE2084) { + if (color_space == AVCOL_SPC_BT2020_NCL && + color_primaries == AVCOL_PRI_BT2020 && + color_trc == AVCOL_TRC_SMPTE2084) { bl_compat_id = 1; - } else if (codecpar->color_space == AVCOL_SPC_BT2020_NCL && - codecpar->color_primaries == AVCOL_PRI_BT2020 && - codecpar->color_trc == AVCOL_TRC_ARIB_STD_B67) { + } else if (color_space == AVCOL_SPC_BT2020_NCL && + color_primaries == AVCOL_PRI_BT2020 && + color_trc == AVCOL_TRC_ARIB_STD_B67) { bl_compat_id = 4; - } else if (codecpar->color_space == AVCOL_SPC_BT709 && - codecpar->color_primaries == AVCOL_PRI_BT709 && - codecpar->color_trc == AVCOL_TRC_BT709) { + } else if (color_space == AVCOL_SPC_BT709 && + color_primaries == AVCOL_PRI_BT709 && + color_trc == AVCOL_TRC_BT709) { bl_compat_id = 2; } } @@ -175,9 +182,9 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, } } - pps = codecpar->width * codecpar->height; - if (codecpar->framerate.num) { - pps = pps * codecpar->framerate.num / codecpar->framerate.den; + pps = width * height; + if (framerate.num) { + pps = pps * framerate.num / framerate.den; } else { pps *= 25; /* sanity fallback */ } @@ -186,7 +193,7 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, for (int i = 1; i < FF_ARRAY_ELEMS(dv_levels); i++) { if (pps > dv_levels[i].pps) continue; - if (codecpar->width > dv_levels[i].width) + if (width > dv_levels[i].width) continue; /* In theory, we should also test the bitrate when known, and * distinguish between main and high tier. In practice, just ignore @@ -199,12 +206,12 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, if (!dv_level) { if (strict_std_compliance >= FF_COMPLIANCE_STRICT) { av_log(s->logctx, AV_LOG_ERROR, "Coded PPS (%"PRIu64") and width (%d) " - "exceed Dolby Vision limitations\n", pps, codecpar->width); + "exceed Dolby Vision limitations\n", pps, width); return AVERROR(EINVAL); } else { av_log(s->logctx, AV_LOG_WARNING, "Coded PPS (%"PRIu64") and width (%d) " "exceed Dolby Vision limitations. Ignoring, resulting file " - "may be non-conforming.\n", pps, codecpar->width); + "may be non-conforming.\n", pps, width); dv_level = FF_ARRAY_ELEMS(dv_levels) - 1; } } @@ -213,8 +220,8 @@ int ff_dovi_configure_ext(DOVIContext *s, AVCodecParameters *codecpar, if (!cfg) return AVERROR(ENOMEM); - if (!av_packet_side_data_add(&codecpar->coded_side_data, - &codecpar->nb_coded_side_data, + if (!av_packet_side_data_add(coded_side_data, + nb_coded_side_data, AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) { av_free(cfg); return AVERROR(ENOMEM); @@ -238,19 +245,22 @@ skip: return 0; } -int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) +av_cold int ff_dovi_configure_from_codedpar(DOVIContext *s, AVCodecParameters *par, + const AVDOVIMetadata *metadata, + enum AVDOVICompression compression, + int strict_std_compliance) +{ + return dovi_configure_ext(s, par->codec_id, metadata, compression, + strict_std_compliance, par->width, par->height, + par->framerate, par->format, par->color_space, + par->color_primaries, par->color_trc, + &par->coded_side_data, &par->nb_coded_side_data); +} + +av_cold int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) { - int ret; - const AVFrameSideData *sd; const AVDOVIMetadata *metadata = NULL; - AVCodecParameters *codecpar = avcodec_parameters_alloc(); - if (!codecpar) - return AVERROR(ENOMEM); - - ret = avcodec_parameters_from_context(codecpar, avctx); - if (ret < 0) - goto fail; - + const AVFrameSideData *sd; sd = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_DOVI_METADATA); @@ -258,16 +268,11 @@ int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) metadata = (const AVDOVIMetadata *) sd->data; /* Current encoders cannot handle metadata compression during encoding */ - ret = ff_dovi_configure_ext(s, codecpar, metadata, AV_DOVI_COMPRESSION_NONE, - avctx->strict_std_compliance); - if (ret < 0) - goto fail; - - ret = avcodec_parameters_to_context(avctx, codecpar); - -fail: - avcodec_parameters_free(&codecpar); - return ret; + return dovi_configure_ext(s, avctx->codec_id, metadata, AV_DOVI_COMPRESSION_NONE, + avctx->strict_std_compliance, avctx->width, + avctx->height, avctx->framerate, avctx->pix_fmt, + avctx->colorspace, avctx->color_primaries, avctx->color_trc, + &avctx->coded_side_data, &avctx->nb_coded_side_data); } /* Compares only the static DM metadata parts of AVDOVIColorMetadata (excluding @@ -295,7 +300,7 @@ static int cmp_dm_level0(const AVDOVIColorMetadata *dm1, sizeof(AVDOVIColorMetadata) -offsetof(AVDOVIColorMetadata, signal_eotf)); } -/* Tries to re-use the static ext blocks. May reorder `ext->dm_static` */ +/* Tries to reuse the static ext blocks. May reorder `ext->dm_static` */ static int try_reuse_ext(DOVIExt *ext, const AVDOVIMetadata *metadata) { int i, j, idx = 0; @@ -334,12 +339,12 @@ static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr switch (hdr->coef_data_type) { case RPU_COEFF_FIXED: set_ue_golomb(pb, coef >> hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, + put_bits63(pb, hdr->coef_log2_denom, coef & ((1LL << hdr->coef_log2_denom) - 1)); break; case RPU_COEFF_FLOAT: fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + put_bits63(pb, hdr->coef_log2_denom, fpart.u32); break; } } @@ -352,12 +357,12 @@ static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr switch (hdr->coef_data_type) { case RPU_COEFF_FIXED: set_se_golomb(pb, coef >> hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, + put_bits63(pb, hdr->coef_log2_denom, coef & ((1LL << hdr->coef_log2_denom) - 1)); break; case RPU_COEFF_FLOAT: fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); - put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + put_bits63(pb, hdr->coef_log2_denom, fpart.u32); break; } } @@ -601,7 +606,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, use_prev_vdr_rpu = 0; if (!s->vdr[vdr_rpu_id]) { - s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(AVDOVIDataMapping)); + s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping)); if (!s->vdr[vdr_rpu_id]) return AVERROR(ENOMEM); } @@ -625,12 +630,12 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, * references requires extended compression */ for (int i = 0; i <= DOVI_MAX_DM_ID; i++) { if (i != vdr_rpu_id) - ff_refstruct_unref(&s->vdr[i]); + av_refstruct_unref(&s->vdr[i]); } } if (metadata->num_ext_blocks && !s->ext_blocks) { - s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks)); if (!s->ext_blocks) return AVERROR(ENOMEM); } @@ -640,7 +645,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, vdr_dm_metadata_present = 1; if (vdr_dm_metadata_present && !s->dm) { - s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata)); if (!s->dm) return AVERROR(ENOMEM); } @@ -864,7 +869,7 @@ int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, } } else { s->color = &ff_dovi_color_default; - ff_refstruct_unref(&s->ext_blocks); + av_refstruct_unref(&s->ext_blocks); } flush_put_bits(pb); diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c index e136cc1b9e..400ff98395 100644 --- a/libavcodec/dpxenc.c +++ b/libavcodec/dpxenc.c @@ -283,13 +283,11 @@ const FFCodec ff_dpx_encoder = { .priv_data_size = sizeof(DPXContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, - AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, - AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, - AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE, - AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8, + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, + AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, + AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, + AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE, + AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE), }; diff --git a/libavcodec/dsddec.c b/libavcodec/dsddec.c index dd1ea83784..793cfc9f06 100644 --- a/libavcodec/dsddec.c +++ b/libavcodec/dsddec.c @@ -126,8 +126,7 @@ const FFCodec ff_ ## name_ ## _decoder = { \ .init = decode_init, \ FF_CODEC_DECODE_CB(decode_frame), \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, \ - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, \ - AV_SAMPLE_FMT_NONE }, \ + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), \ }; DSD_DECODER(DSD_LSBF, dsd_lsbf, "DSD (Direct Stream Digital), least significant bit first") diff --git a/libavcodec/dsicinaudio.c b/libavcodec/dsicinaudio.c index aa14966c7b..abe7ba991e 100644 --- a/libavcodec/dsicinaudio.c +++ b/libavcodec/dsicinaudio.c @@ -81,6 +81,8 @@ static av_cold int cinaudio_decode_init(AVCodecContext *avctx) cin->initial_decode_frame = 1; cin->delta = 0; avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c index 10b536d405..7001a195e2 100644 --- a/libavcodec/dsicinvideo.c +++ b/libavcodec/dsicinvideo.c @@ -294,11 +294,6 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return res; memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette)); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - cin->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif for (y = 0; y < cin->avctx->height; ++y) memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0], cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, diff --git a/libavcodec/dstdec.c b/libavcodec/dstdec.c index 4b1762db33..cfb34b7b3c 100644 --- a/libavcodec/dstdec.c +++ b/libavcodec/dstdec.c @@ -392,6 +392,5 @@ const FFCodec ff_dst_decoder = { .init = decode_init, FF_CODEC_DECODE_CB(decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT), }; diff --git a/libavcodec/dv_profile.c b/libavcodec/dv_profile.c index f403114184..02ece47e01 100644 --- a/libavcodec/dv_profile.c +++ b/libavcodec/dv_profile.c @@ -337,4 +337,3 @@ const AVDVProfile *av_dv_codec_profile2(int width, int height, return p; } - diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index 4553c45b3d..9ecd96df86 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -35,7 +35,7 @@ #define DVBSUB_CLUT_SEGMENT 0x12 #define DVBSUB_OBJECT_SEGMENT 0x13 #define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14 -#define DVBSUB_DISPLAY_SEGMENT 0x80 +#define DVBSUB_END_DISPLAY_SEGMENT 0x80 #define cm (ff_crop_tab + MAX_NEG_CROP) @@ -612,15 +612,16 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, const uint8_t **srcbuf, int buf_size, int non_mod, uint8_t *map_table, int x_pos) { - const uint8_t *sbuf_end = (*srcbuf) + buf_size; int bits; int run_length; int pixels_read = x_pos; + GetByteContext gb0, *const gb = &gb0; + bytestream2_init(gb, *srcbuf, buf_size); destbuf += x_pos; - while (*srcbuf < sbuf_end && pixels_read < dbuf_len) { - bits = *(*srcbuf)++; + while (bytestream2_get_bytes_left(gb) && pixels_read < dbuf_len) { + bits = bytestream2_get_byteu(gb); if (bits) { if (non_mod != 1 || bits != 1) { @@ -631,16 +632,17 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, } pixels_read++; } else { - bits = *(*srcbuf)++; + bits = bytestream2_get_byte(gb); run_length = bits & 0x7f; if ((bits & 0x80) == 0) { if (run_length == 0) { + *srcbuf += bytestream2_tell(gb); return pixels_read; } bits = 0; } else { - bits = *(*srcbuf)++; + bits = bytestream2_get_byte(gb); } if (non_mod == 1 && bits == 1) pixels_read += run_length; @@ -655,9 +657,14 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, } } - if (*(*srcbuf)++) + if (bytestream2_get_byte(gb)) av_log(avctx, AV_LOG_ERROR, "line overflow\n"); + /* Workaround our own buggy encoder which only put one zero at the end */ + if (!bytestream2_peek_byte(gb)) + bytestream2_get_byte(gb); + + *srcbuf += bytestream2_tell(gb); return pixels_read; } @@ -1451,8 +1458,11 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, int segment_length; int i; int ret = 0; - int got_segment = 0; - int got_dds = 0; + int got_page = 0; + int got_region = 0; + int got_object = 0; + int got_end_display = 0; + int got_displaydef = 0; ff_dlog(avctx, "DVB sub packet:\n"); @@ -1497,34 +1507,28 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, switch (segment_type) { case DVBSUB_PAGE_SEGMENT: ret = dvbsub_parse_page_segment(avctx, p, segment_length, sub, got_sub_ptr); - got_segment |= 1; + got_page = 1; break; case DVBSUB_REGION_SEGMENT: ret = dvbsub_parse_region_segment(avctx, p, segment_length); - got_segment |= 2; + got_region = 1; break; case DVBSUB_CLUT_SEGMENT: ret = dvbsub_parse_clut_segment(avctx, p, segment_length); if (ret < 0) goto end; - got_segment |= 4; break; case DVBSUB_OBJECT_SEGMENT: ret = dvbsub_parse_object_segment(avctx, p, segment_length); - got_segment |= 8; + got_object = 1; break; case DVBSUB_DISPLAYDEFINITION_SEGMENT: ret = dvbsub_parse_display_definition_segment(avctx, p, segment_length); - got_dds = 1; + got_displaydef = 1; break; - case DVBSUB_DISPLAY_SEGMENT: + case DVBSUB_END_DISPLAY_SEGMENT: ret = dvbsub_display_end_segment(avctx, p, segment_length, sub, got_sub_ptr); - if (got_segment == 15 && !got_dds && !avctx->width && !avctx->height) { - // Default from ETSI EN 300 743 V1.3.1 (7.2.1) - avctx->width = 720; - avctx->height = 576; - } - got_segment |= 16; + got_end_display = 1; break; default: ff_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n", @@ -1537,13 +1541,24 @@ static int dvbsub_decode(AVCodecContext *avctx, AVSubtitle *sub, p += segment_length; } - // Some streams do not send a display segment but if we have all the other - // segments then we need no further data. - if (got_segment == 15) { - av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n"); - dvbsub_display_end_segment(avctx, p, 0, sub, got_sub_ptr); - } + // Even though not mandated by the spec, we're imposing a minimum requirement + // for a useful packet to have at least one page, region and object segment. + if (got_page && got_region && got_object) { + + if (!got_displaydef && !avctx->width && !avctx->height) { + // Default from ETSI EN 300 743 V1.3.1 (7.2.1) + avctx->width = 720; + avctx->height = 576; + } + + // Some streams do not send an end-of-display segment but if we have all the other + // segments then we need no further data. + if (!got_end_display) { + av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n"); + dvbsub_display_end_segment(avctx, p, 0, sub, got_sub_ptr); + } + } end: if (ret < 0) { return ret; diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c index 822e3a5309..6f42b1f134 100644 --- a/libavcodec/dvbsubenc.c +++ b/libavcodec/dvbsubenc.c @@ -22,9 +22,12 @@ #include "bytestream.h" #include "codec_internal.h" #include "libavutil/colorspace.h" +#include "libavutil/opt.h" typedef struct DVBSubtitleContext { + AVClass * class; int object_version; + int min_bpp; } DVBSubtitleContext; #define PUTBITS2(val)\ @@ -258,7 +261,8 @@ static int dvb_encode_rle8(uint8_t **pq, int buf_size, x += len; } /* end of line */ - // 00000000 end of 8-bit/pixel_code_string + // 00000000 00000000 end of 8-bit/pixel_code_string + *q++ = 0x00; *q++ = 0x00; *q++ = 0xf0; bitmap += linesize; @@ -274,16 +278,30 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, { DVBSubtitleContext *s = avctx->priv_data; uint8_t *q, *pseg_len; - int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; + int page_id, region_id, clut_id, object_id, i, bpp_index, page_state, min_colors; q = outbuf; page_id = 1; + switch(s->min_bpp) { + case 2: + case 4: + case 8: + min_colors = 1 << s->min_bpp; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid min_bpp value %d.\n", s->min_bpp); + return AVERROR(EINVAL); + } + if (h->num_rects && !h->rects) return AVERROR(EINVAL); + if (h->num_rects >= 256) + return AVERROR(EINVAL); + if (avctx->width > 0 && avctx->height > 0) { if (buf_size < 11) return AVERROR_BUFFER_TOO_SMALL; @@ -326,24 +344,24 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, if (h->num_rects) { for (clut_id = 0; clut_id < h->num_rects; clut_id++) { - if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6) - return AVERROR_BUFFER_TOO_SMALL; - /* CLUT segment */ + int nb_colors = FFMAX(min_colors, h->rects[clut_id]->nb_colors); - if (h->rects[clut_id]->nb_colors <= 4) { + if (nb_colors <= 4U) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[clut_id]->nb_colors <= 16) { + } else if (nb_colors <= 16U) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[clut_id]->nb_colors <= 256) { + } else if (nb_colors <= 256U) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { return AVERROR(EINVAL); } + if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6) + return AVERROR_BUFFER_TOO_SMALL; /* CLUT segment */ *q++ = 0x0f; /* sync byte */ @@ -381,14 +399,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, for (region_id = 0; region_id < h->num_rects; region_id++) { /* region composition segment */ + int nb_colors = FFMAX(min_colors, h->rects[region_id]->nb_colors); - if (h->rects[region_id]->nb_colors <= 4) { + if (nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[region_id]->nb_colors <= 16) { + } else if (nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[region_id]->nb_colors <= 256) { + } else if (nb_colors <= 256) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { @@ -424,17 +443,19 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, const uint8_t *bitmap, int linesize, int w, int h); + int nb_colors = FFMAX(min_colors, h->rects[object_id]->nb_colors); + if (buf_size < 13) return AVERROR_BUFFER_TOO_SMALL; /* bpp_index maths */ - if (h->rects[object_id]->nb_colors <= 4) { + if (nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ dvb_encode_rle = dvb_encode_rle2; - } else if (h->rects[object_id]->nb_colors <= 16) { + } else if (nb_colors <= 16) { /* 4 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle4; - } else if (h->rects[object_id]->nb_colors <= 256) { + } else if (nb_colors <= 256) { /* 8 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle8; } else { @@ -506,6 +527,20 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, return q - outbuf; } +#define OFFSET(x) offsetof(DVBSubtitleContext, x) +#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + {"min_bpp", "minimum bits-per-pixel for subtitle colors (2, 4 or 8)", OFFSET(min_bpp), AV_OPT_TYPE_INT, {.i64 = 4}, 2, 8, SE}, + { NULL }, +}; + +static const AVClass dvbsubenc_class = { + .class_name = "DVBSUB subtitle encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const FFCodec ff_dvbsub_encoder = { .p.name = "dvbsub", CODEC_LONG_NAME("DVB subtitles"), @@ -513,4 +548,5 @@ const FFCodec ff_dvbsub_encoder = { .p.id = AV_CODEC_ID_DVB_SUBTITLE, .priv_data_size = sizeof(DVBSubtitleContext), FF_CODEC_ENCODE_SUB_CB(dvbsub_encode), + .p.priv_class = &dvbsubenc_class, }; diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c index 8297b6d2f3..242708c70a 100644 --- a/libavcodec/dvdec.c +++ b/libavcodec/dvdec.c @@ -159,15 +159,15 @@ static av_cold void dv_init_static(void) /* it's faster to include sign bit in a generic VLC parsing scheme */ for (i = 0, j = 0; i < NB_DV_VLC; i++, j++) { - tmp[j].len = ff_dv_vlc_len[i]; + tmp[j].len8 = ff_dv_vlc_len[i]; tmp[j].run = ff_dv_vlc_run[i]; tmp[j].level = ff_dv_vlc_level[i]; if (ff_dv_vlc_level[i]) { - tmp[j].len++; + tmp[j].len8++; j++; - tmp[j].len = ff_dv_vlc_len[i] + 1; + tmp[j].len8 = ff_dv_vlc_len[i] + 1; tmp[j].run = ff_dv_vlc_run[i]; tmp[j].level = -ff_dv_vlc_level[i]; } @@ -176,7 +176,7 @@ static av_cold void dv_init_static(void) /* NOTE: as a trick, we use the fact the no codes are unused * to accelerate the parsing of partial codes */ ff_vlc_init_from_lengths(&dv_vlc, TEX_VLC_BITS, j, - &tmp[0].len, sizeof(tmp[0]), + &tmp[0].len8, sizeof(tmp[0]), NULL, 0, 0, 0, VLC_INIT_USE_STATIC, NULL); av_assert1(dv_vlc.table_size == 1664); @@ -193,7 +193,7 @@ static av_cold void dv_init_static(void) run = tmp[code].run + 1; level = tmp[code].level; } - dv_rl_vlc[i].len = len; + dv_rl_vlc[i].len8 = len; dv_rl_vlc[i].level = level; dv_rl_vlc[i].run = run; } @@ -301,7 +301,7 @@ static void dv_decode_ac(GetBitContext *gb, BlockInfo *mb, int16_t *block) pos, SHOW_UBITS(re, gb, 16), re_index); /* our own optimized GET_RL_VLC */ index = NEG_USR32(re_cache, TEX_VLC_BITS); - vlc_len = dv_rl_vlc[index].len; + vlc_len = dv_rl_vlc[index].len8; if (vlc_len < 0) { index = NEG_USR32((unsigned) re_cache << TEX_VLC_BITS, -vlc_len) + dv_rl_vlc[index].level; diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c index f8769353a0..78658f7d2f 100644 --- a/libavcodec/dvdsubdec.c +++ b/libavcodec/dvdsubdec.c @@ -217,8 +217,8 @@ static void reset_rects(AVSubtitle *sub_header) #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a)) -static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, - const uint8_t *buf, int buf_size) +static int decode_dvd_subtitles(void *logctx, DVDSubContext *ctx, + AVSubtitle *sub_header, const uint8_t *buf, int buf_size) { int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos; int big_offsets, offset_size, is_8bit = 0; @@ -248,7 +248,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) { if (cmd_pos > size) { - av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n"); + av_log(logctx, AV_LOG_ERROR, "Discarding invalid packet\n"); return 0; } return AVERROR(EAGAIN); @@ -257,7 +257,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) { date = AV_RB16(buf + cmd_pos); next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2); - ff_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n", + ff_dlog(logctx, "cmd_pos=0x%04x next=0x%04x date=%d\n", cmd_pos, next_cmd_pos, date); pos = cmd_pos + 2 + offset_size; offset1 = -1; @@ -265,7 +265,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, x1 = y1 = x2 = y2 = 0; while (pos < buf_size) { cmd = buf[pos++]; - ff_dlog(NULL, "cmd=%02x\n", cmd); + ff_dlog(logctx, "cmd=%02x\n", cmd); switch(cmd) { case 0x00: /* menu subpicture */ @@ -298,7 +298,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, alpha[1] = buf[pos + 1] >> 4; alpha[0] = buf[pos + 1] & 0x0f; pos += 2; - ff_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); + ff_dlog(logctx, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); break; case 0x05: case 0x85: @@ -310,7 +310,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5]; if (cmd & 0x80) is_8bit = 1; - ff_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); + ff_dlog(logctx, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); pos += 6; break; case 0x06: @@ -318,7 +318,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, goto fail; offset1 = AV_RB16(buf + pos); offset2 = AV_RB16(buf + pos + 2); - ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); + ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); pos += 4; break; case 0x86: @@ -326,7 +326,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, goto fail; offset1 = AV_RB32(buf + pos); offset2 = AV_RB32(buf + pos + 4); - ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); + ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); pos += 8; break; @@ -349,7 +349,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, case 0xff: goto the_end; default: - ff_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd); + ff_dlog(logctx, "unrecognised subpicture command 0x%x\n", cmd); goto the_end; } } @@ -412,7 +412,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, } } if (next_cmd_pos < cmd_pos) { - av_log(ctx, AV_LOG_ERROR, "Invalid command offset\n"); + av_log(logctx, AV_LOG_ERROR, "Invalid command offset\n"); break; } if (next_cmd_pos == cmd_pos) @@ -535,7 +535,7 @@ static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub, appended = 1; } - is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size); + is_menu = decode_dvd_subtitles(avctx, ctx, sub, buf, buf_size); if (is_menu == AVERROR(EAGAIN)) { *data_size = 0; return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size); @@ -560,7 +560,7 @@ static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub, return buf_size; } -static int parse_ifo_palette(DVDSubContext *ctx, char *p) +static int parse_ifo_palette(void *logctx, DVDSubContext *ctx, char *p) { FILE *ifo; char ifostr[12]; @@ -572,11 +572,11 @@ static int parse_ifo_palette(DVDSubContext *ctx, char *p) ctx->has_palette = 0; if ((ifo = avpriv_fopen_utf8(p, "r")) == NULL) { - av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno))); + av_log(logctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno))); return AVERROR_EOF; } if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) { - av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); + av_log(logctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); ret = AVERROR_INVALIDDATA; goto end; } @@ -612,7 +612,7 @@ static int parse_ifo_palette(DVDSubContext *ctx, char *p) } } if (ctx->has_palette == 0) { - av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); + av_log(logctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); ret = AVERROR_INVALIDDATA; } end: @@ -670,7 +670,7 @@ static av_cold int dvdsub_init(AVCodecContext *avctx) return ret; if (ctx->ifo_str) - parse_ifo_palette(ctx, ctx->ifo_str); + parse_ifo_palette(avctx, ctx, ctx->ifo_str); if (ctx->palette_str) { ctx->has_palette = 1; ff_dvdsub_parse_palette(ctx->palette, ctx->palette_str); diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c index c6110c29ff..00bab35988 100644 --- a/libavcodec/dvdsubenc.c +++ b/libavcodec/dvdsubenc.c @@ -250,9 +250,9 @@ static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[]) } } -static int encode_dvd_subtitles(AVCodecContext *avctx, - uint8_t *outbuf, int outbuf_size, - const AVSubtitle *h) +static int dvdsub_encode(AVCodecContext *avctx, + uint8_t *outbuf, int outbuf_size, + const AVSubtitle *h) { DVDSubtitleContext *dvdc = avctx->priv_data; uint8_t *q, *qq; @@ -442,7 +442,7 @@ static int bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf) return 0; } -static int dvdsub_init(AVCodecContext *avctx) +static av_cold int dvdsub_init(AVCodecContext *avctx) { DVDSubtitleContext *dvdc = avctx->priv_data; static const uint32_t default_palette[16] = { @@ -476,17 +476,6 @@ static int dvdsub_init(AVCodecContext *avctx) return 0; } -static int dvdsub_encode(AVCodecContext *avctx, - unsigned char *buf, int buf_size, - const AVSubtitle *sub) -{ - //DVDSubtitleContext *s = avctx->priv_data; - int ret; - - ret = encode_dvd_subtitles(avctx, buf, buf_size, sub); - return ret; -} - #define OFFSET(x) offsetof(DVDSubtitleContext, x) #define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { diff --git a/libavcodec/dvenc.c b/libavcodec/dvenc.c index db79497b50..a477b84261 100644 --- a/libavcodec/dvenc.c +++ b/libavcodec/dvenc.c @@ -63,6 +63,8 @@ typedef struct DVEncContext { DVwork_chunk work_chunks[4 * 12 * 27]; int quant_deadzone; + + PixblockDSPContext pdsp; } DVEncContext; @@ -70,7 +72,6 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) { DVEncContext *s = avctx->priv_data; FDCTDSPContext fdsp; - PixblockDSPContext pdsp; int ret; s->avctx = avctx; @@ -108,12 +109,10 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) } memset(&fdsp,0, sizeof(fdsp)); - memset(&pdsp,0, sizeof(pdsp)); ff_fdctdsp_init(&fdsp, avctx); - ff_pixblockdsp_init(&pdsp, avctx); - s->get_pixels = pdsp.get_pixels; s->fdct[0] = fdsp.fdct; s->fdct[1] = fdsp.fdct248; + ff_pixblockdsp_init(&s->pdsp, 8); #if !CONFIG_HARDCODED_TABLES { @@ -1201,6 +1200,14 @@ static int dvvideo_encode_frame(AVCodecContext *c, AVPacket *pkt, DVEncContext *s = c->priv_data; int ret; + if (!PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED && + ((uintptr_t)frame->data[0] & 7 || frame->linesize[0] & 7 || + (uintptr_t)frame->data[1] & 7 || frame->linesize[1] & 7 || + (uintptr_t)frame->data[2] & 7 || frame->linesize[2] & 7)) + s->get_pixels = s->pdsp.get_pixels_unaligned; + else + s->get_pixels = s->pdsp.get_pixels; + if ((ret = ff_get_encode_buffer(c, pkt, s->sys->frame_size, 0)) < 0) return ret; /* Fixme: Only zero the part that is not overwritten later. */ @@ -1247,10 +1254,7 @@ const FFCodec ff_dvvideo_encoder = { .priv_data_size = sizeof(DVEncContext), .init = dvvideo_encode_init, FF_CODEC_ENCODE_CB(dvvideo_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dvvideo_encode_class, }; diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c index 59e2411d8e..5b429781df 100644 --- a/libavcodec/dxa.c +++ b/libavcodec/dxa.c @@ -213,7 +213,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, unsigned long dsize; int i, j, compr, ret; int stride; - int pc = 0; GetByteContext gb; bytestream2_init(&gb, avpkt->data, avpkt->size); @@ -224,17 +223,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, for(i = 0; i < 256; i++){ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); } - pc = 1; } if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = pc; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->decomp_buf; diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index ba23222727..dd82e450b1 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -38,12 +38,15 @@ typedef struct DXVContext { GetByteContext gbc; uint8_t *tex_data; // Compressed texture + unsigned tex_data_size; uint8_t *ctex_data; // Compressed chroma texture + unsigned ctex_data_size; int64_t tex_size; // Texture size int64_t ctex_size; // Chroma texture size uint8_t *op_data[4]; // Opcodes + unsigned op_data_size[4]; int64_t op_size[4]; // Opcodes size } DXVContext; @@ -274,7 +277,9 @@ static int dxv_decompress_opcodes(GetByteContext *gb, void *dstp, size_t op_size if ((flag & 3) == 0) { bytestream2_skip(gb, 1); - bytestream2_get_buffer(gb, dstp, op_size); + int read_size = bytestream2_get_buffer(gb, dstp, op_size); + if (read_size != op_size) + return AVERROR_INVALIDDATA; } else if ((flag & 3) == 1) { bytestream2_skip(gb, 1); memset(dstp, bytestream2_get_byte(gb), op_size); @@ -969,9 +974,14 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, ctx->tex_size = avctx->coded_width / (texdsp_ctx.raw_ratio / (avctx->pix_fmt == AV_PIX_FMT_RGBA ? 4 : 1)) * avctx->coded_height / TEXTURE_BLOCK_H * texdsp_ctx.tex_ratio; - ret = av_reallocp(&ctx->tex_data, ctx->tex_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (ret < 0) - return ret; + unsigned old_size = ctx->tex_data_size; + void *ptr = av_fast_realloc(ctx->tex_data, &ctx->tex_data_size, ctx->tex_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ptr) + return AVERROR(ENOMEM); + ctx->tex_data = ptr; + + if (ctx->tex_data_size > old_size) + memset(ctx->tex_data + old_size, 0, ctx->tex_data_size - old_size); if (avctx->pix_fmt != AV_PIX_FMT_RGBA) { int i; @@ -985,13 +995,20 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, 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; + old_size = ctx->ctex_data_size; + ptr = av_fast_realloc(ctx->ctex_data, &ctx->ctex_data_size, ctx->ctex_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ptr) + return AVERROR(ENOMEM); + ctx->ctex_data = ptr; + if (old_size < ctx->ctex_data_size) + memset(ctx->ctex_data + old_size, 0, ctx->ctex_data_size - old_size); + for (i = 0; i < 4; i++) { - ret = av_reallocp(&ctx->op_data[i], ctx->op_size[i]); - if (ret < 0) - return ret; + old_size = ctx->op_data_size[i]; + ptr = av_fast_realloc(ctx->op_data[i], &ctx->op_data_size[i], ctx->op_size[i]); + if (!ptr) + return AVERROR(ENOMEM); + ctx->op_data[i] = ptr; } } @@ -1053,7 +1070,7 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, return avpkt->size; } -static int dxv_init(AVCodecContext *avctx) +static av_cold int dxv_init(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); @@ -1073,16 +1090,21 @@ static int dxv_init(AVCodecContext *avctx) return 0; } -static int dxv_close(AVCodecContext *avctx) +static av_cold int dxv_close(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; av_freep(&ctx->tex_data); + ctx->tex_data_size = 0; + av_freep(&ctx->ctex_data); + ctx->ctex_data_size = 0; + av_freep(&ctx->op_data[0]); av_freep(&ctx->op_data[1]); av_freep(&ctx->op_data[2]); av_freep(&ctx->op_data[3]); + memset(ctx->op_data_size, 0, sizeof(ctx->op_data_size)); return 0; } diff --git a/libavcodec/dxv.h b/libavcodec/dxv.h index 71cfddec85..184813e427 100644 --- a/libavcodec/dxv.h +++ b/libavcodec/dxv.h @@ -1,6 +1,6 @@ /* * Resolume DXV common - * Copyright (C) 2024 Connor Worley + * Copyright (C) 2024 Emma Worley * * This file is part of FFmpeg. * diff --git a/libavcodec/dxva2_av1.c b/libavcodec/dxva2_av1.c index ea97fcb87e..47866ff4c3 100644 --- a/libavcodec/dxva2_av1.c +++ b/libavcodec/dxva2_av1.c @@ -272,6 +272,7 @@ int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont } static int dxva2_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { @@ -450,7 +451,7 @@ static int dxva2_av1_end_frame(AVCodecContext *avctx) return ret; } -static int dxva2_av1_uninit(AVCodecContext *avctx) +static av_cold int dxva2_av1_uninit(AVCodecContext *avctx) { struct AV1DXVAContext *ctx = avctx->internal->hwaccel_priv_data; diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index 0fe4152625..dd9dccbf8c 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -444,6 +444,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index d01d1e76e8..85698dfcce 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -363,6 +363,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 224a867ebc..6cbd0e42d7 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -171,11 +171,15 @@ void ff_dxva2_h264_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo void ff_dxva2_h264_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_H264 *qm); +#if CONFIG_HEVC_D3D12VA_HWACCEL || CONFIG_HEVC_D3D11VA_HWACCEL || CONFIG_HEVC_D3D11VA2_HWACCEL || CONFIG_HEVC_DXVA2_HWACCEL void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp); void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm); +#endif +#if CONFIG_VP9_D3D12VA_HWACCEL || CONFIG_VP9_D3D11VA_HWACCEL || CONFIG_VP9_D3D11VA2_HWACCEL || CONFIG_VP9_DXVA2_HWACCEL int ff_dxva2_vp9_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_VP9 *pp); +#endif #if CONFIG_AV1_D3D12VA_HWACCEL || CONFIG_AV1_D3D11VA_HWACCEL || CONFIG_AV1_D3D11VA2_HWACCEL || CONFIG_AV1_DXVA2_HWACCEL int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_AV1 *pp); diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index d88e782414..7955bcdea2 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -257,6 +257,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } static int dxva2_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index bc9ad9648e..f1dcea1e84 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -108,7 +108,7 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, pp->bRcontrol = v->rnd; pp->bPicSpatialResid8 = (v->panscanflag << 7) | (v->refdist_flag << 6) | - (s->loop_filter << 5) | + (v->loop_filter << 5) | (v->fastuvmc << 4) | (v->extended_mv << 3) | (v->dquant << 1) | @@ -117,11 +117,11 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, (v->multires << 5) | (v->resync_marker << 4) | (v->rangered << 3) | - (s->max_b_frames ); + (v->max_b_frames ); pp->bPicExtrapolation = (!v->interlace || v->fcm == PROGRESSIVE) ? 1 : 2; pp->bPicDeblocked = ((!pp->bPicBackwardPrediction && v->overlap) << 6) | ((v->profile != PROFILE_ADVANCED && v->rangeredfrm) << 5) | - (s->loop_filter << 1); + (v->loop_filter << 1); pp->bPicDeblockConfined = (v->postprocflag << 7) | (v->broadcast << 6) | (v->interlace << 5) | @@ -177,7 +177,7 @@ void ff_dxva2_vc1_fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice, slice->dwSliceDataLocation = position; slice->bStartCodeBitOffset = 0; slice->bReservedBits = (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) ? v->bfraction_lut_index + 9 : 0; - slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&s->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); + slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&v->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); /* XXX We store the index of the first MB and it will be fixed later */ slice->wNumberMBsInSlice = (s->mb_y >> v->field_mode) * s->mb_width + s->mb_x; slice->wQuantizerScaleCode = v->pq; @@ -315,6 +315,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } static int dxva2_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index f4ab91c580..cffa95e1d1 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -254,6 +254,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, static int dxva2_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/dxvenc.c b/libavcodec/dxvenc.c index 8229438373..0a2dd8077b 100644 --- a/libavcodec/dxvenc.c +++ b/libavcodec/dxvenc.c @@ -1,6 +1,6 @@ /* * Resolume DXV encoder - * Copyright (C) 2024 Connor Worley + * Copyright (C) 2024 Emma Worley * * This file is part of FFmpeg. * @@ -21,7 +21,7 @@ #include -#include "libavutil/crc.h" +#include "libavcodec/hashtable.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -34,77 +34,19 @@ #define DXV_HEADER_LENGTH 12 +/* + * Resolume will refuse to display frames that are not padded to 16x16 pixels. + */ +#define DXV_ALIGN(x) FFALIGN(x, 16) + /* * DXV uses LZ-like back-references to avoid copying words that have already * appeared in the decompressed stream. Using a simple hash table (HT) * significantly speeds up the lookback process while encoding. */ -#define LOOKBACK_HT_ELEMS 0x40000 +#define LOOKBACK_HT_ELEMS 0x20202 #define LOOKBACK_WORDS 0x20202 -typedef struct HTEntry { - uint32_t key; - uint32_t pos; -} HTEntry; - -static void ht_init(HTEntry *ht) -{ - for (size_t i = 0; i < LOOKBACK_HT_ELEMS; i++) { - ht[i].pos = -1; - } -} - -static uint32_t ht_lookup_and_upsert(HTEntry *ht, const AVCRC *hash_ctx, - uint32_t key, uint32_t pos) -{ - uint32_t ret = -1; - size_t hash = av_crc(hash_ctx, 0, (uint8_t*)&key, 4) % LOOKBACK_HT_ELEMS; - for (size_t i = hash; i < hash + LOOKBACK_HT_ELEMS; i++) { - size_t wrapped_index = i % LOOKBACK_HT_ELEMS; - HTEntry *entry = &ht[wrapped_index]; - if (entry->key == key || entry->pos == -1) { - ret = entry->pos; - entry->key = key; - entry->pos = pos; - break; - } - } - return ret; -} - -static void ht_delete(HTEntry *ht, const AVCRC *hash_ctx, - uint32_t key, uint32_t pos) -{ - HTEntry *removed_entry = NULL; - size_t removed_hash; - size_t hash = av_crc(hash_ctx, 0, (uint8_t*)&key, 4) % LOOKBACK_HT_ELEMS; - - for (size_t i = hash; i < hash + LOOKBACK_HT_ELEMS; i++) { - size_t wrapped_index = i % LOOKBACK_HT_ELEMS; - HTEntry *entry = &ht[wrapped_index]; - if (entry->pos == -1) - return; - if (removed_entry) { - size_t candidate_hash = av_crc(hash_ctx, 0, (uint8_t*)&entry->key, 4) % LOOKBACK_HT_ELEMS; - if ((wrapped_index > removed_hash && (candidate_hash <= removed_hash || candidate_hash > wrapped_index)) || - (wrapped_index < removed_hash && (candidate_hash <= removed_hash && candidate_hash > wrapped_index))) { - *removed_entry = *entry; - entry->pos = -1; - removed_entry = entry; - removed_hash = wrapped_index; - } - } else if (entry->key == key) { - if (entry->pos <= pos) { - entry->pos = -1; - removed_entry = entry; - removed_hash = wrapped_index; - } else { - return; - } - } - } -} - typedef struct DXVEncContext { AVClass *class; @@ -121,10 +63,9 @@ typedef struct DXVEncContext { DXVTextureFormat tex_fmt; int (*compress_tex)(AVCodecContext *avctx); - const AVCRC *crc_ctx; - - HTEntry color_lookback_ht[LOOKBACK_HT_ELEMS]; - HTEntry lut_lookback_ht[LOOKBACK_HT_ELEMS]; + FFHashtableContext *color_ht; + FFHashtableContext *lut_ht; + FFHashtableContext *combo_ht; } DXVEncContext; /* Converts an index offset value to a 2-bit opcode and pushes it to a stream. @@ -159,58 +100,59 @@ static int dxv_compress_dxt1(AVCodecContext *avctx) DXVEncContext *ctx = avctx->priv_data; PutByteContext *pbc = &ctx->pbc; void *value; - uint32_t color, lut, idx, color_idx, lut_idx, prev_pos, state = 16, pos = 2, op = 0; + uint32_t idx, combo_idx, prev_pos, old_pos, state = 16, pos = 0, op = 0; - ht_init(ctx->color_lookback_ht); - ht_init(ctx->lut_lookback_ht); + ff_hashtable_clear(ctx->color_ht); + ff_hashtable_clear(ctx->lut_ht); + ff_hashtable_clear(ctx->combo_ht); + + ff_hashtable_set(ctx->combo_ht, ctx->tex_data, &pos); bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data)); + ff_hashtable_set(ctx->color_ht, ctx->tex_data, &pos); + pos++; bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + 4)); - - ht_lookup_and_upsert(ctx->color_lookback_ht, ctx->crc_ctx, AV_RL32(ctx->tex_data), 0); - ht_lookup_and_upsert(ctx->lut_lookback_ht, ctx->crc_ctx, AV_RL32(ctx->tex_data + 4), 1); + ff_hashtable_set(ctx->lut_ht, ctx->tex_data + 4, &pos); + pos++; while (pos + 2 <= ctx->tex_size / 4) { - idx = 0; - - color = AV_RL32(ctx->tex_data + pos * 4); - prev_pos = ht_lookup_and_upsert(ctx->color_lookback_ht, ctx->crc_ctx, color, pos); - color_idx = prev_pos != -1 ? pos - prev_pos : 0; - if (pos >= LOOKBACK_WORDS) { - uint32_t old_pos = pos - LOOKBACK_WORDS; - uint32_t old_color = AV_RL32(ctx->tex_data + old_pos * 4); - ht_delete(ctx->color_lookback_ht, ctx->crc_ctx, old_color, old_pos); - } - pos++; - - lut = AV_RL32(ctx->tex_data + pos * 4); - if (color_idx && lut == AV_RL32(ctx->tex_data + (pos - color_idx) * 4)) { - idx = color_idx; - } else { - idx = 0; - prev_pos = ht_lookup_and_upsert(ctx->lut_lookback_ht, ctx->crc_ctx, lut, pos); - lut_idx = prev_pos != -1 ? pos - prev_pos : 0; - } - if (pos >= LOOKBACK_WORDS) { - uint32_t old_pos = pos - LOOKBACK_WORDS; - uint32_t old_lut = AV_RL32(ctx->tex_data + old_pos * 4); - ht_delete(ctx->lut_lookback_ht, ctx->crc_ctx, old_lut, old_pos); - } - pos++; - + combo_idx = ff_hashtable_get(ctx->combo_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + idx = combo_idx; PUSH_OP(2); - - if (!idx) { - idx = color_idx; - PUSH_OP(2); - if (!idx) - bytestream2_put_le32(pbc, color); - - idx = lut_idx; - PUSH_OP(2); - if (!idx) - bytestream2_put_le32(pbc, lut); + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->combo_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->combo_ht, ctx->tex_data + old_pos * 4); } + ff_hashtable_set(ctx->combo_ht, ctx->tex_data + pos * 4, &pos); + + if (!combo_idx) { + idx = ff_hashtable_get(ctx->color_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + PUSH_OP(2); + if (!idx) + bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + pos * 4)); + } + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->color_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->color_ht, ctx->tex_data + old_pos * 4); + } + ff_hashtable_set(ctx->color_ht, ctx->tex_data + pos * 4, &pos); + pos++; + + if (!combo_idx) { + idx = ff_hashtable_get(ctx->lut_ht, ctx->tex_data + pos * 4, &prev_pos) ? pos - prev_pos : 0; + PUSH_OP(2); + if (!idx) + bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data + pos * 4)); + } + if (pos >= LOOKBACK_WORDS) { + old_pos = pos - LOOKBACK_WORDS; + if (ff_hashtable_get(ctx->lut_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos) + ff_hashtable_delete(ctx->lut_ht, ctx->tex_data + old_pos * 4); + } + ff_hashtable_set(ctx->lut_ht, ctx->tex_data + pos * 4, &pos); + pos++; } return 0; @@ -231,12 +173,51 @@ static int dxv_encode(AVCodecContext *avctx, AVPacket *pkt, return ret; if (ctx->enc.tex_funct) { + uint8_t *safe_data[4] = {frame->data[0], 0, 0, 0}; + int safe_linesize[4] = {frame->linesize[0], 0, 0, 0}; + + if (avctx->width != DXV_ALIGN(avctx->width) || avctx->height != DXV_ALIGN(avctx->height)) { + ret = av_image_alloc( + safe_data, + safe_linesize, + DXV_ALIGN(avctx->width), + DXV_ALIGN(avctx->height), + avctx->pix_fmt, + 1); + if (ret < 0) + return ret; + + av_image_copy2( + safe_data, + safe_linesize, + frame->data, + frame->linesize, + avctx->pix_fmt, + avctx->width, + avctx->height); + + if (avctx->width != DXV_ALIGN(avctx->width)) { + av_assert0(frame->format == AV_PIX_FMT_RGBA); + for (int y = 0; y < avctx->height; y++) { + memset(safe_data[0] + y * safe_linesize[0] + 4*avctx->width, 0, safe_linesize[0] - 4*avctx->width); + } + } + if (avctx->height != DXV_ALIGN(avctx->height)) { + for (int y = avctx->height; y < DXV_ALIGN(avctx->height); y++) { + memset(safe_data[0] + y * safe_linesize[0], 0, safe_linesize[0]); + } + } + } + ctx->enc.tex_data.out = ctx->tex_data; - ctx->enc.frame_data.in = frame->data[0]; - ctx->enc.stride = frame->linesize[0]; - ctx->enc.width = avctx->width; - ctx->enc.height = avctx->height; + ctx->enc.frame_data.in = safe_data[0]; + ctx->enc.stride = safe_linesize[0]; + ctx->enc.width = DXV_ALIGN(avctx->width); + ctx->enc.height = DXV_ALIGN(avctx->height); ff_texturedsp_exec_compress_threads(avctx, &ctx->enc); + + if (safe_data[0] != frame->data[0]) + av_freep(&safe_data[0]); } else { /* unimplemented: YCoCg formats */ return AVERROR_INVALIDDATA; @@ -275,14 +256,6 @@ static av_cold int dxv_init(AVCodecContext *avctx) return ret; } - if (avctx->width % TEXTURE_BLOCK_W || avctx->height % TEXTURE_BLOCK_H) { - av_log(avctx, - AV_LOG_ERROR, - "Video size %dx%d is not multiple of "AV_STRINGIFY(TEXTURE_BLOCK_W)"x"AV_STRINGIFY(TEXTURE_BLOCK_H)".\n", - avctx->width, avctx->height); - return AVERROR_INVALIDDATA; - } - ff_texturedspenc_init(&texdsp); switch (ctx->tex_fmt) { @@ -296,21 +269,25 @@ static av_cold int dxv_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } ctx->enc.raw_ratio = 16; - ctx->tex_size = avctx->width / TEXTURE_BLOCK_W * - avctx->height / TEXTURE_BLOCK_H * + ctx->tex_size = DXV_ALIGN(avctx->width) / TEXTURE_BLOCK_W * + DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H * ctx->enc.tex_ratio; - ctx->enc.slice_count = av_clip(avctx->thread_count, 1, avctx->height / TEXTURE_BLOCK_H); + ctx->enc.slice_count = av_clip(avctx->thread_count, 1, DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H); ctx->tex_data = av_malloc(ctx->tex_size); if (!ctx->tex_data) { return AVERROR(ENOMEM); } - ctx->crc_ctx = av_crc_get_table(AV_CRC_32_IEEE); - if (!ctx->crc_ctx) { - av_log(avctx, AV_LOG_ERROR, "Could not initialize CRC table.\n"); - return AVERROR_BUG; - } + ret = ff_hashtable_alloc(&ctx->color_ht, sizeof(uint32_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; + ret = ff_hashtable_alloc(&ctx->lut_ht, sizeof(uint32_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; + ret = ff_hashtable_alloc(&ctx->combo_ht, sizeof(uint64_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS); + if (ret < 0) + return ret; return 0; } @@ -321,6 +298,10 @@ static av_cold int dxv_close(AVCodecContext *avctx) av_freep(&ctx->tex_data); + ff_hashtable_freep(&ctx->color_ht); + ff_hashtable_freep(&ctx->lut_ht); + ff_hashtable_freep(&ctx->combo_ht); + return 0; } @@ -351,8 +332,6 @@ const FFCodec ff_dxv_encoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .p.priv_class = &dxvenc_class, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/dynamic_hdr_vivid.c b/libavcodec/dynamic_hdr_vivid.c index a9b6910798..319d13b90a 100644 --- a/libavcodec/dynamic_hdr_vivid.c +++ b/libavcodec/dynamic_hdr_vivid.c @@ -116,17 +116,6 @@ int ff_parse_itu_t_t35_to_dynamic_hdr_vivid(AVDynamicHDRVivid *s, const uint8_t three_spline->th_delta2 = (AVRational){get_bits(gb, 10), 1023}; three_spline->enable_strength = (AVRational){get_bits(gb, 8), 255}; } -#if FF_API_HDR_VIVID_THREE_SPLINE - three_spline = &tm_params->three_spline[0]; -FF_DISABLE_DEPRECATION_WARNINGS - tm_params->three_Spline_TH_mode = three_spline->th_mode; - tm_params->three_Spline_TH_enable_MB = three_spline->th_enable_mb; - tm_params->three_Spline_TH_enable = three_spline->th_enable; - tm_params->three_Spline_TH_Delta1 = three_spline->th_delta1; - tm_params->three_Spline_TH_Delta2 = three_spline->th_delta2; - tm_params->three_Spline_enable_Strength = three_spline->enable_strength; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } } diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index 2b3bffda6e..c5095b1917 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -53,8 +53,6 @@ typedef enum { EAC3_GAQ_124 } EAC3GaqMode; -#define EAC3_SR_CODE_REDUCED 3 - static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s) { int bin, bnd, ch, i; @@ -287,7 +285,7 @@ static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch) } } -static int ff_eac3_parse_header(AC3DecodeContext *s) +static int ff_eac3_parse_header(AC3DecodeContext *s, const AC3HeaderInfo *hdr) { int i, blk, ch; int ac3_exponent_strategy, parse_aht_info, parse_spx_atten_data; @@ -323,11 +321,10 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) avpriv_request_sample(s->avctx, "Reduced sampling rate"); return AVERROR_PATCHWELCOME; } - skip_bits(gbc, 5); // skip bitstream id /* volume control params */ for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - s->dialog_normalization[i] = -get_bits(gbc, 5); + s->dialog_normalization[i] = hdr->dialog_normalization[i]; if (s->dialog_normalization[i] == 0) { s->dialog_normalization[i] = -31; } @@ -335,147 +332,30 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) s->level_gain[i] = powf(2.0f, (float)(s->target_level - s->dialog_normalization[i])/6.0f); } - s->compression_exists[i] = get_bits1(gbc); - if (s->compression_exists[i]) { - s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(get_bits(gbc, 8)); + if (hdr->compression_exists[i]) { + s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr->heavy_dynamic_range[i]); } } - /* dependent stream channel map */ - if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { - if (get_bits1(gbc)) { - int64_t channel_layout = 0; - int channel_map = get_bits(gbc, 16); - av_log(s->avctx, AV_LOG_DEBUG, "channel_map: %0X\n", channel_map); - - for (i = 0; i < 16; i++) - if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1))) - channel_layout |= ff_eac3_custom_channel_map_locations[i][1]; - - if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) { - return AVERROR_INVALIDDATA; - } - s->channel_map = channel_map; - } - } + s->channel_map = hdr->channel_map; /* mixing metadata */ - if (get_bits1(gbc)) { - /* center and surround mix levels */ - if (s->channel_mode > AC3_CHMODE_STEREO) { - s->preferred_downmix = get_bits(gbc, 2); - if (s->channel_mode & 1) { - /* if three front channels exist */ - s->center_mix_level_ltrt = get_bits(gbc, 3); - s->center_mix_level = get_bits(gbc, 3); - } - if (s->channel_mode & 4) { - /* if a surround channel exists */ - s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); - s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); - } - } - - /* lfe mix level */ - if (s->lfe_on && (s->lfe_mix_level_exists = get_bits1(gbc))) { - s->lfe_mix_level = get_bits(gbc, 5); - } - - /* info for mixing with other streams and substreams */ - if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - // TODO: apply program scale factor - if (get_bits1(gbc)) { - skip_bits(gbc, 6); // skip program scale factor - } - } - if (get_bits1(gbc)) { - skip_bits(gbc, 6); // skip external program scale factor - } - /* skip mixing parameter data */ - switch(get_bits(gbc, 2)) { - case 1: skip_bits(gbc, 5); break; - case 2: skip_bits(gbc, 12); break; - case 3: { - int mix_data_size = (get_bits(gbc, 5) + 2) << 3; - skip_bits_long(gbc, mix_data_size); - break; - } - } - /* skip pan information for mono or dual mono source */ - if (s->channel_mode < AC3_CHMODE_STEREO) { - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - if (get_bits1(gbc)) { - /* note: this is not in the ATSC A/52B specification - reference: ETSI TS 102 366 V1.1.1 - section: E.1.3.1.25 */ - skip_bits(gbc, 8); // skip pan mean direction index - skip_bits(gbc, 6); // skip reserved paninfo bits - } - } - } - /* skip mixing configuration information */ - if (get_bits1(gbc)) { - for (blk = 0; blk < s->num_blocks; blk++) { - if (s->num_blocks == 1 || get_bits1(gbc)) { - skip_bits(gbc, 5); - } - } - } - } - } + s->preferred_downmix = hdr->preferred_downmix; + s->center_mix_level_ltrt = hdr->center_mix_level_ltrt; + s->center_mix_level = hdr->center_mix_level; + s->surround_mix_level_ltrt = hdr->surround_mix_level_ltrt; + s->surround_mix_level = hdr->surround_mix_level; + s->lfe_mix_level_exists = hdr->lfe_mix_level_exists; + s->lfe_mix_level = hdr->lfe_mix_level; + s->dolby_surround_mode = hdr->dolby_surround_mode; + s->dolby_headphone_mode = hdr->dolby_headphone_mode; + s->dolby_surround_ex_mode = hdr->dolby_surround_ex_mode; /* informational metadata */ - if (get_bits1(gbc)) { - s->bitstream_mode = get_bits(gbc, 3); - skip_bits(gbc, 2); // skip copyright bit and original bitstream bit - if (s->channel_mode == AC3_CHMODE_STEREO) { - s->dolby_surround_mode = get_bits(gbc, 2); - s->dolby_headphone_mode = get_bits(gbc, 2); - } - if (s->channel_mode >= AC3_CHMODE_2F2R) { - s->dolby_surround_ex_mode = get_bits(gbc, 2); - } - for (i = 0; i < (s->channel_mode ? 1 : 2); i++) { - if (get_bits1(gbc)) { - skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type - } - } - if (s->bit_alloc_params.sr_code != EAC3_SR_CODE_REDUCED) { - skip_bits1(gbc); // skip source sample rate code - } - } - - /* converter synchronization flag - If frames are less than six blocks, this bit should be turned on - once every 6 blocks to indicate the start of a frame set. - reference: RFC 4598, Section 2.1.3 Frame Sets */ - if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && s->num_blocks != 6) { - skip_bits1(gbc); // skip converter synchronization flag - } - - /* original frame size code if this stream was converted from AC-3 */ - if (s->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT && - (s->num_blocks == 6 || get_bits1(gbc))) { - skip_bits(gbc, 6); // skip frame size code - } + s->bitstream_mode = hdr->bitstream_mode; /* additional bitstream info */ - if (get_bits1(gbc)) { - int addbsil = get_bits(gbc, 6); - for (i = 0; i < addbsil + 1; i++) { - if (i == 0) { - /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a - which can be used to detect Atmos presence */ - skip_bits(gbc, 7); - if (get_bits1(gbc)) { - s->eac3_extension_type_a = 1; - } - } else { - skip_bits(gbc, 8); // skip additional bit stream info - } - } - } + s->eac3_extension_type_a = hdr->eac3_extension_type_a; /* audio frame syntax flags, strategy data, and per-frame data */ diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c index 8ef3e7e773..10b1ab337c 100644 --- a/libavcodec/eac3enc.c +++ b/libavcodec/eac3enc.c @@ -135,6 +135,8 @@ static void eac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) int blk, ch; AC3EncOptions *opt = &s->options; + put_bits_assume_flushed(pb); + put_bits(pb, 16, 0x0b77); /* sync word */ /* BSI header */ @@ -273,11 +275,10 @@ const FFCodec ff_eac3_encoder = { .init = eac3_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), .close = ff_ac3_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &eac3enc_class, - .p.supported_samplerates = ff_ac3_sample_rate_tab, - .p.ch_layouts = ff_ac3_ch_layouts, + CODEC_SAMPLERATES_ARRAY(ff_ac3_sample_rate_tab), + CODEC_CH_LAYOUTS_ARRAY(ff_ac3_ch_layouts), .defaults = ff_ac3_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/eamad.c b/libavcodec/eamad.c index 1c3f97653c..44dac46083 100644 --- a/libavcodec/eamad.c +++ b/libavcodec/eamad.c @@ -58,8 +58,6 @@ typedef struct MadContext { unsigned int bitstream_buf_size; DECLARE_ALIGNED(32, int16_t, block)[64]; uint16_t quant_matrix[64]; - int mb_x; - int mb_y; } MadContext; static av_cold int decode_init(AVCodecContext *avctx) @@ -148,11 +146,8 @@ static inline int decode_block_intra(MadContext *s, int16_t * block) break; } else if (level != 0) { i += run; - if (i > 63) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + if (i > 63) return -1; - } j = scantable[i]; level = (level*quant_matrix[j]) >> 4; level = (level-1)|1; @@ -160,18 +155,13 @@ static inline int decode_block_intra(MadContext *s, int16_t * block) LAST_SKIP_BITS(re, &s->gb, 1); } else { /* escape */ - UPDATE_CACHE(re, &s->gb); level = SHOW_SBITS(re, &s->gb, 10); SKIP_BITS(re, &s->gb, 10); - UPDATE_CACHE(re, &s->gb); run = SHOW_UBITS(re, &s->gb, 6)+1; LAST_SKIP_BITS(re, &s->gb, 6); i += run; - if (i > 63) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + if (i > 63) return -1; - } j = scantable[i]; if (level < 0) { level = -level; @@ -202,7 +192,7 @@ static int decode_motion(GetBitContext *gb) return value; } -static int decode_mb(MadContext *s, AVFrame *frame, int inter) +static int decode_mb(MadContext *s, AVFrame *frame, int inter, int mb_x, int mb_y) { int mv_map = 0; int av_uninit(mv_x), av_uninit(mv_y); @@ -221,12 +211,15 @@ static int decode_mb(MadContext *s, AVFrame *frame, int inter) if (mv_map & (1<gb); if (s->last_frame->data[0]) - comp_block(s, frame, s->mb_x, s->mb_y, j, mv_x, mv_y, add); + comp_block(s, frame, mb_x, mb_y, j, mv_x, mv_y, add); } else { s->bdsp.clear_block(s->block); - if(decode_block_intra(s, s->block) < 0) + if (decode_block_intra(s, s->block) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "ac-tex damaged at %d %d\n", mb_x, mb_y); return -1; - idct_put(s, frame, s->block, s->mb_x, s->mb_y, j); + } + idct_put(s, frame, s->block, mb_x, mb_y, j); } } return 0; @@ -310,9 +303,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, memset((uint8_t*)s->bitstream_buf + bytestream2_get_bytes_left(&gb), 0, AV_INPUT_BUFFER_PADDING_SIZE); init_get_bits(&s->gb, s->bitstream_buf, 8*(bytestream2_get_bytes_left(&gb))); - for (s->mb_y=0; s->mb_y < (avctx->height+15)/16; s->mb_y++) - for (s->mb_x=0; s->mb_x < (avctx->width +15)/16; s->mb_x++) - if(decode_mb(s, frame, inter) < 0) + for (int mb_y = 0; mb_y < (avctx->height + 15) / 16; mb_y++) + for (int mb_x = 0; mb_x < (avctx->width + 15) / 16; mb_x++) + if (decode_mb(s, frame, inter, mb_x, mb_y) < 0) return AVERROR_INVALIDDATA; *got_frame = 1; diff --git a/libavcodec/eatgq.c b/libavcodec/eatgq.c index d326c05390..efcad62df1 100644 --- a/libavcodec/eatgq.c +++ b/libavcodec/eatgq.c @@ -36,12 +36,14 @@ #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" +#include "copy_block.h" #include "decode.h" #include "eaidct.h" #include "get_bits.h" typedef struct TgqContext { AVCodecContext *avctx; + AVFrame *last_frame; int width, height; int qtable[64]; DECLARE_ALIGNED(16, int16_t, block)[6][64]; @@ -53,6 +55,9 @@ static av_cold int tgq_decode_init(AVCodecContext *avctx) s->avctx = avctx; avctx->framerate = (AVRational){ 15, 1 }; avctx->pix_fmt = AV_PIX_FMT_YUV420P; + s->last_frame = av_frame_alloc(); + if (!s->last_frame) + return AVERROR(ENOMEM); return 0; } @@ -156,7 +161,6 @@ static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte, { int mode; int i; - int8_t dc[6]; mode = bytestream2_get_byte(gbyte); if (mode > 12) { @@ -173,12 +177,40 @@ static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte, tgq_idct_put_mb(s, s->block, frame, mb_x, mb_y); bytestream2_skip(gbyte, mode); } else { - if (mode == 3) { + int8_t dc[6]; + if (mode == 1) { + int x, y; + int mv = bytestream2_get_byte(gbyte); + int mv_x = mv >> 4; + int mv_y = mv & 0x0F; + if (!s->last_frame->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return -1; + } + if (mv_x >= 8) mv_x -= 16; + if (mv_y >= 8) mv_y -= 16; + x = mb_x * 16 - mv_x; + y = mb_y * 16 - mv_y; + if (x < 0 || x + 16 > s->width || y < 0 || y + 16 > s->height) { + av_log(s->avctx, AV_LOG_ERROR, "invalid motion vector\n"); + return -1; + } + copy_block16(frame->data[0] + (mb_y * 16 * frame->linesize[0]) + mb_x * 16, + s->last_frame->data[0] + y * s->last_frame->linesize[0] + x, + frame->linesize[0], s->last_frame->linesize[0], 16); + for (int p = 1; p < 3; p++) + copy_block8(frame->data[p] + (mb_y * 8 * frame->linesize[p]) + mb_x * 8, + s->last_frame->data[p] + (y >> 1) * s->last_frame->linesize[p] + (x >> 1), + frame->linesize[p], s->last_frame->linesize[p], 8); + frame->flags &= ~AV_FRAME_FLAG_KEY; + return 0; + } else if (mode == 3) { memset(dc, bytestream2_get_byte(gbyte), 4); dc[4] = bytestream2_get_byte(gbyte); dc[5] = bytestream2_get_byte(gbyte); } else if (mode == 6) { - bytestream2_get_buffer(gbyte, dc, 6); + if (bytestream2_get_buffer(gbyte, dc, 6) != 6) + return AVERROR_INVALIDDATA; } else if (mode == 12) { for (i = 0; i < 6; i++) { dc[i] = bytestream2_get_byte(gbyte); @@ -228,9 +260,12 @@ static int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame, s->height = bytestream2_get_le16u(&gbyte); } - ret = ff_set_dimensions(s->avctx, s->width, s->height); - if (ret < 0) - return ret; + if (s->avctx->width != s->width || s->avctx->height != s->height) { + av_frame_unref(s->last_frame); + ret = ff_set_dimensions(s->avctx, s->width, s->height); + if (ret < 0) + return ret; + } tgq_calculate_qtable(s, bytestream2_get_byteu(&gbyte)); bytestream2_skipu(&gbyte, 3); @@ -238,16 +273,27 @@ static int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; + frame->flags |= AV_FRAME_FLAG_KEY; for (y = 0; y < FFALIGN(avctx->height, 16) >> 4; y++) for (x = 0; x < FFALIGN(avctx->width, 16) >> 4; x++) if (tgq_decode_mb(s, &gbyte, frame, y, x) < 0) return AVERROR_INVALIDDATA; + if ((ret = av_frame_replace(s->last_frame, frame)) < 0) + return ret; + *got_frame = 1; return avpkt->size; } +static av_cold int tgq_decode_close(AVCodecContext *avctx) +{ + TgqContext *s = avctx->priv_data; + av_frame_free(&s->last_frame); + return 0; +} + const FFCodec ff_eatgq_decoder = { .p.name = "eatgq", CODEC_LONG_NAME("Electronic Arts TGQ video"), @@ -255,6 +301,7 @@ const FFCodec ff_eatgq_decoder = { .p.id = AV_CODEC_ID_TGQ, .priv_data_size = sizeof(TgqContext), .init = tgq_decode_init, + .close = tgq_decode_close, FF_CODEC_DECODE_CB(tgq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 3baf5b8103..38833c566c 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -214,21 +214,6 @@ int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame) av_frame_move_ref(frame, avci->buffer_frame); -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - if (frame->key_frame) - frame->flags |= AV_FRAME_FLAG_KEY; -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (frame->interlaced_frame) - frame->flags |= AV_FRAME_FLAG_INTERLACED; - if (frame->top_field_first) - frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - return 0; } @@ -613,20 +598,6 @@ static int encode_preinit_video(AVCodecContext *avctx) return AVERROR(EINVAL); } -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->ticks_per_frame && avctx->time_base.num && - avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) { - av_log(avctx, AV_LOG_ERROR, - "ticks_per_frame %d too large for the timebase %d/%d.", - avctx->ticks_per_frame, - avctx->time_base.num, - avctx->time_base.den); - return AVERROR(EINVAL); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (avctx->hw_frames_ctx) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; if (frames_ctx->format != avctx->pix_fmt) { @@ -662,11 +633,6 @@ static int encode_preinit_audio(AVCodecContext *avctx) avctx->sample_fmt); return AVERROR(EINVAL); } - if (avctx->sample_rate <= 0) { - av_log(avctx, AV_LOG_ERROR, "Invalid audio sample rate: %d\n", - avctx->sample_rate); - return AVERROR(EINVAL); - } ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void **) &sample_fmts, @@ -936,3 +902,22 @@ AVCPBProperties *ff_encode_add_cpb_side_data(AVCodecContext *avctx) return props; } + +int ff_check_codec_matrices(AVCodecContext *avctx, unsigned types, uint16_t min, uint16_t max) +{ + uint16_t *matrices[] = {avctx->intra_matrix, avctx->inter_matrix, avctx->chroma_intra_matrix}; + const char *names[] = {"Intra", "Inter", "Chroma Intra"}; + static_assert(FF_ARRAY_ELEMS(matrices) == FF_ARRAY_ELEMS(names), "matrix count mismatch"); + for (int m = 0; m < FF_ARRAY_ELEMS(matrices); m++) { + uint16_t *matrix = matrices[m]; + if (matrix && (types & (1U << m))) { + for (int i = 0; i < 64; i++) { + if (matrix[i] < min || matrix[i] > max) { + av_log(avctx, AV_LOG_ERROR, "%s matrix[%d] is %d which is out of the allowed range [%"PRIu16"-%"PRIu16"].\n", names[m], i, matrix[i], min, max); + return AVERROR(EINVAL); + } + } + } + } + return 0; +} diff --git a/libavcodec/encode.h b/libavcodec/encode.h index 85331e04b7..656da135d2 100644 --- a/libavcodec/encode.h +++ b/libavcodec/encode.h @@ -96,4 +96,13 @@ static av_always_inline int64_t ff_samples_to_time_base(const AVCodecContext *av avctx->time_base); } +/** + * Check if the elements of codec context matrices (intra_matrix, inter_matrix or + * chroma_intra_matrix) are within the specified range. + */ +#define FF_MATRIX_TYPE_INTRA (1U << 0) +#define FF_MATRIX_TYPE_INTER (1U << 1) +#define FF_MATRIX_TYPE_CHROMA_INTRA (1U << 2) +int ff_check_codec_matrices(AVCodecContext *avctx, unsigned types, uint16_t min, uint16_t max); + #endif /* AVCODEC_ENCODE_H */ diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 6edc2dc15f..cf6f83e096 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -27,9 +27,11 @@ #include +#include "libavutil/avassert.h" #include "libavutil/mem.h" #include "avcodec.h" #include "error_resilience.h" +#include "mathops.h" #include "me_cmp.h" #include "mpegutils.h" #include "mpegvideo.h" diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h index a1b9b9ec1a..8e43219b09 100644 --- a/libavcodec/error_resilience.h +++ b/libavcodec/error_resilience.h @@ -23,9 +23,8 @@ #include #include "avcodec.h" -#include "me_cmp.h" -///< current MB is the first after a resync marker +/// current MB is the first after a resync marker #define VP_START 1 #define ER_AC_ERROR 2 #define ER_DC_ERROR 4 @@ -37,6 +36,8 @@ #define ER_MB_ERROR (ER_AC_ERROR|ER_DC_ERROR|ER_MV_ERROR) #define ER_MB_END (ER_AC_END|ER_DC_END|ER_MV_END) +typedef struct MPVEncContext MPVEncContext; + typedef struct ERPicture { AVFrame *f; const struct ThreadFrame *tf; @@ -53,7 +54,8 @@ typedef struct ERPicture { typedef struct ERContext { AVCodecContext *avctx; - me_cmp_func sad; + int (*sad)(MPVEncContext *unused, const uint8_t *blk1, + const uint8_t *blk2, ptrdiff_t stride, int h); int mecc_inited; int *mb_index2xy; diff --git a/libavcodec/escape130.c b/libavcodec/escape130.c index 3b0460fd79..4482a0e070 100644 --- a/libavcodec/escape130.c +++ b/libavcodec/escape130.c @@ -212,9 +212,6 @@ static int escape130_decode_frame(AVCodecContext *avctx, AVFrame *pic, return AVERROR_INVALIDDATA; } - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; - if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) return ret; skip_bits_long(&gb, 16 * 8); @@ -310,6 +307,9 @@ static int escape130_decode_frame(AVCodecContext *avctx, AVFrame *pic, skip--; } + if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) + return ret; + new_y = s->new_y; new_cb = s->new_u; new_cr = s->new_v; diff --git a/libavcodec/evc.h b/libavcodec/evc.h index d68dc74997..418c05a8e8 100644 --- a/libavcodec/evc.h +++ b/libavcodec/evc.h @@ -56,7 +56,7 @@ enum EVCNALUnitType { EVC_RSV_VCL_NUT22 = 22, EVC_RSV_VCL_NUT23 = 23, EVC_SPS_NUT = 24, /* Sequence parameter set */ - EVC_PPS_NUT = 25, /* Picture paremeter set */ + EVC_PPS_NUT = 25, /* Picture parameter set */ EVC_APS_NUT = 26, /* Adaptation parameter set */ EVC_FD_NUT = 27, /* Filler data */ EVC_SEI_NUT = 28, /* Supplemental enhancement information */ diff --git a/libavcodec/evc_parse.h b/libavcodec/evc_parse.h index 4712310826..4452c32d6a 100644 --- a/libavcodec/evc_parse.h +++ b/libavcodec/evc_parse.h @@ -31,7 +31,7 @@ #include "evc.h" #include "evc_ps.h" -// The sturcture reflects Slice Header RBSP(raw byte sequence payload) layout +// The structure reflects Slice Header RBSP(raw byte sequence payload) layout // @see ISO_IEC_23094-1 section 7.3.2.6 // // The following descriptors specify the parsing process of each element diff --git a/libavcodec/evc_ps.h b/libavcodec/evc_ps.h index 336953b176..dd0e151c46 100644 --- a/libavcodec/evc_ps.h +++ b/libavcodec/evc_ps.h @@ -102,7 +102,7 @@ typedef struct VUIParameters { HRDParameters hrd_parameters; } VUIParameters; -// The sturcture reflects SPS RBSP(raw byte sequence payload) layout +// The structure reflects SPS RBSP(raw byte sequence payload) layout // @see ISO_IEC_23094-1 section 7.3.2.1 // // The following descriptors specify the parsing process of each element diff --git a/libavcodec/evrcdec.c b/libavcodec/evrcdec.c index 44d5bee722..974c967b48 100644 --- a/libavcodec/evrcdec.c +++ b/libavcodec/evrcdec.c @@ -182,7 +182,7 @@ static evrc_packet_rate buf_size2bitrate(const int buf_size) * * @param avctx the AV codec context * @param buf_size length of the buffer - * @param buf the bufffer + * @param buf the buffer * * @return the bitrate on success, * RATE_ERRS if the bitrate cannot be satisfactorily determined @@ -239,6 +239,8 @@ static av_cold int evrc_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; for (i = 0; i < FILTER_ORDER; i++) { e->prev_lspf[i] = (i + 1) * 0.048; diff --git a/libavcodec/executor.c b/libavcodec/executor.c new file mode 100644 index 0000000000..7a86e894f8 --- /dev/null +++ b/libavcodec/executor.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include "libavutil/mem.h" +#include "libavutil/thread.h" + +#include "executor.h" + +#if !HAVE_THREADS + +#define ExecutorThread char + +#define executor_thread_create(t, a, s, ar) 0 +#define executor_thread_join(t, r) do {} while(0) + +#else + +#define ExecutorThread pthread_t + +#define executor_thread_create(t, a, s, ar) pthread_create(t, a, s, ar) +#define executor_thread_join(t, r) pthread_join(t, r) + +#endif //!HAVE_THREADS + +typedef struct ThreadInfo { + FFExecutor *e; + ExecutorThread thread; +} ThreadInfo; + +typedef struct Queue { + FFTask *head; + FFTask *tail; +} Queue; + +struct FFExecutor { + FFTaskCallbacks cb; + int thread_count; + bool recursive; + + ThreadInfo *threads; + uint8_t *local_contexts; + + AVMutex lock; + AVCond cond; + int die; + + Queue *q; +}; + +static FFTask* remove_task(Queue *q) +{ + FFTask *t = q->head; + if (t) { + q->head = t->next; + t->next = NULL; + if (!q->head) + q->tail = NULL; + } + return t; +} + +static void add_task(Queue *q, FFTask *t) +{ + t->next = NULL; + if (!q->head) + q->tail = q->head = t; + else + q->tail = q->tail->next = t; +} + +static int run_one_task(FFExecutor *e, void *lc) +{ + FFTaskCallbacks *cb = &e->cb; + FFTask *t = NULL; + + for (int i = 0; i < e->cb.priorities && !t; i++) + t = remove_task(e->q + i); + + if (t) { + if (e->thread_count > 0) + ff_mutex_unlock(&e->lock); + cb->run(t, lc, cb->user_data); + if (e->thread_count > 0) + ff_mutex_lock(&e->lock); + return 1; + } + return 0; +} + +#if HAVE_THREADS +static void *executor_worker_task(void *data) +{ + ThreadInfo *ti = (ThreadInfo*)data; + FFExecutor *e = ti->e; + void *lc = e->local_contexts + (ti - e->threads) * e->cb.local_context_size; + + ff_mutex_lock(&e->lock); + while (1) { + if (e->die) break; + + if (!run_one_task(e, lc)) { + //no task in one loop + ff_cond_wait(&e->cond, &e->lock); + } + } + ff_mutex_unlock(&e->lock); + return NULL; +} +#endif + +static void executor_free(FFExecutor *e, const int has_lock, const int has_cond) +{ + if (e->thread_count) { + //signal die + ff_mutex_lock(&e->lock); + e->die = 1; + ff_cond_broadcast(&e->cond); + ff_mutex_unlock(&e->lock); + + for (int i = 0; i < e->thread_count; i++) + executor_thread_join(e->threads[i].thread, NULL); + } + if (has_cond) + ff_cond_destroy(&e->cond); + if (has_lock) + ff_mutex_destroy(&e->lock); + + av_free(e->threads); + av_free(e->q); + av_free(e->local_contexts); + + av_free(e); +} + +FFExecutor* ff_executor_alloc(const FFTaskCallbacks *cb, int thread_count) +{ + FFExecutor *e; + int has_lock = 0, has_cond = 0; + if (!cb || !cb->user_data || !cb->run || !cb->priorities) + return NULL; + + e = av_mallocz(sizeof(*e)); + if (!e) + return NULL; + e->cb = *cb; + + e->local_contexts = av_calloc(FFMAX(thread_count, 1), e->cb.local_context_size); + if (!e->local_contexts) + goto free_executor; + + e->q = av_calloc(e->cb.priorities, sizeof(Queue)); + if (!e->q) + goto free_executor; + + e->threads = av_calloc(FFMAX(thread_count, 1), sizeof(*e->threads)); + if (!e->threads) + goto free_executor; + + if (!thread_count) + return e; + + has_lock = !ff_mutex_init(&e->lock, NULL); + has_cond = !ff_cond_init(&e->cond, NULL); + + if (!has_lock || !has_cond) + goto free_executor; + + for (/* nothing */; e->thread_count < thread_count; e->thread_count++) { + ThreadInfo *ti = e->threads + e->thread_count; + ti->e = e; + if (executor_thread_create(&ti->thread, NULL, executor_worker_task, ti)) + goto free_executor; + } + return e; + +free_executor: + executor_free(e, has_lock, has_cond); + return NULL; +} + +void ff_executor_free(FFExecutor **executor) +{ + int thread_count; + + if (!executor || !*executor) + return; + thread_count = (*executor)->thread_count; + executor_free(*executor, thread_count, thread_count); + *executor = NULL; +} + +void ff_executor_execute(FFExecutor *e, FFTask *t) +{ + if (e->thread_count) + ff_mutex_lock(&e->lock); + if (t) + add_task(e->q + t->priority % e->cb.priorities, t); + if (e->thread_count) { + ff_cond_signal(&e->cond); + ff_mutex_unlock(&e->lock); + } + + if (!e->thread_count || !HAVE_THREADS) { + if (e->recursive) + return; + e->recursive = true; + // We are running in a single-threaded environment, so we must handle all tasks ourselves + while (run_one_task(e, e->local_contexts)) + /* nothing */; + e->recursive = false; + } +} diff --git a/libavcodec/executor.h b/libavcodec/executor.h new file mode 100644 index 0000000000..cd13d4c518 --- /dev/null +++ b/libavcodec/executor.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * We still need several refactors to improve the current VVC decoder's performance, + * which will frequently break the API/ABI. To mitigate this, we've copied the executor from + * avutil to avcodec. Once the API/ABI is stable, we will move this class back to avutil + */ + +#ifndef AVCODEC_EXECUTOR_H +#define AVCODEC_EXECUTOR_H + +typedef struct FFExecutor FFExecutor; +typedef struct FFTask FFTask; + +struct FFTask { + FFTask *next; + int priority; // task priority should >= 0 and < AVTaskCallbacks.priorities +}; + +typedef struct FFTaskCallbacks { + void *user_data; + + int local_context_size; + + // how many priorities do we have? + int priorities; + + // run the task + int (*run)(FFTask *t, void *local_context, void *user_data); +} FFTaskCallbacks; + +/** + * Alloc executor + * @param callbacks callback structure for executor + * @param thread_count worker thread number, 0 for run on caller's thread directly + * @return return the executor + */ +FFExecutor* ff_executor_alloc(const FFTaskCallbacks *callbacks, int thread_count); + +/** + * Free executor + * @param e pointer to executor + */ +void ff_executor_free(FFExecutor **e); + +/** + * Add task to executor + * @param e pointer to executor + * @param t pointer to task. If NULL, it will wakeup one work thread + */ +void ff_executor_execute(FFExecutor *e, FFTask *t); + +#endif //AVCODEC_EXECUTOR_H diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 4bac0be89b..67f971ff35 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -42,6 +42,7 @@ #include "libavutil/avstring.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/float2half.h" #include "libavutil/half2float.h" #include "avcodec.h" @@ -188,12 +189,16 @@ typedef struct EXRContext { const char *layer; int selected_part; - enum AVColorTransferCharacteristic apply_trc_type; - float gamma; - union av_intfloat32 gamma_table[65536]; uint8_t *offset_table; +#if FF_API_EXR_GAMMA + enum AVColorTransferCharacteristic apply_trc_type; + float gamma; + uint16_t gamma_table[65536]; + Float2HalfTables f2h_tables; +#endif + Half2FloatTables h2f_tables; } EXRContext; @@ -991,6 +996,7 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse const int dc_h = td->ysize >> 3; GetByteContext gb, agb; int skip, ret; + int have_rle = 0; if (compressed_size <= 88) return AVERROR_INVALIDDATA; @@ -1015,6 +1021,11 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse ) return AVERROR_INVALIDDATA; + if ((uint64_t)rle_raw_size > INT_MAX) { + avpriv_request_sample(s->avctx, "Too big rle_raw_size"); + return AVERROR_INVALIDDATA; + } + bytestream2_init(&gb, src + 88, compressed_size - 88); skip = bytestream2_get_le16(&gb); if (skip < 2) @@ -1085,6 +1096,9 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse if (rle_raw_size > 0 && rle_csize > 0 && rle_usize > 0) { unsigned long dest_len = rle_usize; + if (2LL * td->xsize * td->ysize > rle_raw_size) + return AVERROR_INVALIDDATA; + av_fast_padded_malloc(&td->rle_data, &td->rle_size, rle_usize); if (!td->rle_data) return AVERROR(ENOMEM); @@ -1101,12 +1115,21 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse if (ret < 0) return ret; bytestream2_skip(&gb, rle_csize); + + have_rle = 1; } bytestream2_init(&agb, td->ac_data, ac_count * 2); for (int y = 0; y < td->ysize; y += 8) { for (int x = 0; x < td->xsize; x += 8) { + const int o = s->nb_channels == 4; + float *yb = td->block[0]; + float *ub = td->block[1]; + float *vb = td->block[2]; + int bw = FFMIN(8, td->xsize - x); + int bh = FFMIN(8, td->ysize - y); + memset(td->block, 0, sizeof(td->block)); for (int j = 0; j < 3; j++) { @@ -1122,20 +1145,40 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse dct_inverse(block); } - { - const int o = s->nb_channels == 4; + if (s->pixel_type == EXR_HALF) { + uint16_t *bo = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 0) + x; + uint16_t *go = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 1) + x; + uint16_t *ro = ((uint16_t *)td->uncompressed_data) + + y * td->xsize * s->nb_channels + td->xsize * (o + 2) + x; + + for (int yy = 0; yy < bh; yy++) { + for (int xx = 0; xx < bw; xx++) { + const int idx = xx + yy * 8; + float b, g, r; + + convert(yb[idx], ub[idx], vb[idx], &b, &g, &r); + + bo[xx] = float2half(av_float2int(to_linear(b, 1.f)), &s->f2h_tables); + go[xx] = float2half(av_float2int(to_linear(g, 1.f)), &s->f2h_tables); + ro[xx] = float2half(av_float2int(to_linear(r, 1.f)), &s->f2h_tables); + } + + bo += td->xsize * s->nb_channels; + go += td->xsize * s->nb_channels; + ro += td->xsize * s->nb_channels; + } + } else { float *bo = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 0) + x; float *go = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 1) + x; float *ro = ((float *)td->uncompressed_data) + y * td->xsize * s->nb_channels + td->xsize * (o + 2) + x; - float *yb = td->block[0]; - float *ub = td->block[1]; - float *vb = td->block[2]; - for (int yy = 0; yy < 8; yy++) { - for (int xx = 0; xx < 8; xx++) { + for (int yy = 0; yy < bh; yy++) { + for (int xx = 0; xx < bw; xx++) { const int idx = xx + yy * 8; convert(yb[idx], ub[idx], vb[idx], &bo[xx], &go[xx], &ro[xx]); @@ -1156,15 +1199,26 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse if (s->nb_channels < 4) return 0; - for (int y = 0; y < td->ysize && td->rle_raw_data; y++) { - uint32_t *ao = ((uint32_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; - uint8_t *ai0 = td->rle_raw_data + y * td->xsize; - uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; + if (s->pixel_type == EXR_HALF) { + for (int y = 0; y < td->ysize && have_rle; y++) { + uint16_t *ao = ((uint16_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; + uint8_t *ai0 = td->rle_raw_data + y * td->xsize; + uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; - for (int x = 0; x < td->xsize; x++) { - uint16_t ha = ai0[x] | (ai1[x] << 8); + for (int x = 0; x < td->xsize; x++) + ao[x] = ai0[x] | (ai1[x] << 8); + } + } else { + for (int y = 0; y < td->ysize && have_rle; y++) { + uint32_t *ao = ((uint32_t *)td->uncompressed_data) + y * td->xsize * s->nb_channels; + uint8_t *ai0 = td->rle_raw_data + y * td->xsize; + uint8_t *ai1 = td->rle_raw_data + y * td->xsize + rle_raw_size / 2; - ao[x] = half2float(ha, &s->h2f_tables); + for (int x = 0; x < td->xsize; x++) { + uint16_t ha = ai0[x] | (ai1[x] << 8); + + ao[x] = half2float(ha, &s->h2f_tables); + } } } @@ -1185,14 +1239,16 @@ static int decode_block(AVCodecContext *avctx, void *tdata, int line, col = 0; uint64_t tile_x, tile_y, tile_level_x, tile_level_y; const uint8_t *src; - int step = s->desc->flags & AV_PIX_FMT_FLAG_FLOAT ? 4 : 2 * s->desc->nb_components; + int step = s->desc->comp[0].step; int bxmin = 0, axmax = 0, window_xoffset = 0; int window_xmin, window_xmax, window_ymin, window_ymax; int data_xoffset, data_yoffset, data_window_offset, xsize, ysize; int i, x, buf_size = s->buf_size; int c, rgb_channel_count; +#if FF_API_EXR_GAMMA float one_gamma = 1.0f / s->gamma; av_csp_trc_function trc_func = av_csp_trc_func_from_id(s->apply_trc_type); +#endif int ret; line_offset = AV_RL64(s->gb.buffer + jobnr * 8); @@ -1353,77 +1409,62 @@ static int decode_block(AVCodecContext *avctx, void *tdata, data_yoffset = FFABS(FFMIN(0, line)); data_window_offset = (data_yoffset * td->channel_line_size) + data_xoffset; + if (s->channel_offsets[3] >= 0) + channel_buffer[3] = src + (td->xsize * s->channel_offsets[3]) + data_window_offset; if (!s->is_luma) { channel_buffer[0] = src + (td->xsize * s->channel_offsets[0]) + data_window_offset; channel_buffer[1] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset; channel_buffer[2] = src + (td->xsize * s->channel_offsets[2]) + data_window_offset; rgb_channel_count = 3; - } else { /* put y data in the first channel_buffer */ + } else { /* put y data in the first channel_buffer and if needed, alpha in the second */ channel_buffer[0] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset; + if (!(s->desc->flags & AV_PIX_FMT_FLAG_PLANAR)) + channel_buffer[1] = channel_buffer[3]; rgb_channel_count = 1; } - if (s->channel_offsets[3] >= 0) - channel_buffer[3] = src + (td->xsize * s->channel_offsets[3]) + data_window_offset; if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - /* todo: change this when a floating point pixel format with luma with alpha is implemented */ - int channel_count = s->channel_offsets[3] >= 0 ? 4 : rgb_channel_count; - if (s->is_luma) { - channel_buffer[1] = channel_buffer[0]; - channel_buffer[2] = channel_buffer[0]; - } - - for (c = 0; c < channel_count; c++) { + for (c = 0; c < s->desc->nb_components; c++) { int plane = s->desc->comp[c].plane; - ptr = p->data[plane] + window_ymin * p->linesize[plane] + (window_xmin * 4); + ptr = p->data[plane] + window_ymin * p->linesize[plane] + (window_xmin * step) + s->desc->comp[c].offset; for (i = 0; i < ysize; i++, ptr += p->linesize[plane]) { - const uint8_t *src; - union av_intfloat32 *ptr_x; - - src = channel_buffer[c]; - ptr_x = (union av_intfloat32 *)ptr; + const uint8_t *src = channel_buffer[c]; + uint8_t *ptr_x = ptr + window_xoffset * step; // Zero out the start if xmin is not 0 - memset(ptr_x, 0, bxmin); - ptr_x += window_xoffset; + if (s->desc->flags & AV_PIX_FMT_FLAG_PLANAR || !c) + memset(ptr, 0, bxmin); - if (s->pixel_type == EXR_FLOAT || - s->compression == EXR_DWAA || - s->compression == EXR_DWAB) { + if (s->pixel_type == EXR_FLOAT) { // 32-bit - union av_intfloat32 t; - if (trc_func && c < 3) { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - t.f = trc_func(t.f); - *ptr_x++ = t; +#if FF_API_EXR_GAMMA + if (trc_func && (!c || (c < 3 && s->desc->flags & AV_PIX_FMT_FLAG_PLANAR))) { + for (int x = 0; x < xsize; x++, ptr_x += step) { + float f = av_int2float(bytestream_get_le32(&src)); + AV_WN32A(ptr_x, av_float2int(trc_func(f))); } } else if (one_gamma != 1.f) { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - if (t.f > 0.0f && c < 3) /* avoid negative values */ - t.f = powf(t.f, one_gamma); - *ptr_x++ = t; + for (int x = 0; x < xsize; x++, ptr_x += step) { + float f = av_int2float(bytestream_get_le32(&src)); + if (f > 0.0f && c < 3) /* avoid negative values */ + f = powf(f, one_gamma); + AV_WN32A(ptr_x, av_float2int(f)); } - } else { - for (x = 0; x < xsize; x++) { - t.i = bytestream_get_le32(&src); - *ptr_x++ = t; - } - } + } else +#endif + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN32A(ptr_x, bytestream_get_le32(&src)); } else if (s->pixel_type == EXR_HALF) { // 16-bit - if (c < 3 || !trc_func) { - for (x = 0; x < xsize; x++) { - *ptr_x++ = s->gamma_table[bytestream_get_le16(&src)]; - } - } else { - for (x = 0; x < xsize; x++) { - ptr_x[0].i = half2float(bytestream_get_le16(&src), &s->h2f_tables); - ptr_x++; - } - } +#if FF_API_EXR_GAMMA + if (one_gamma != 1.f || (trc_func && (!c || (c < 3 && s->desc->flags & AV_PIX_FMT_FLAG_PLANAR)))) { + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN16A(ptr_x, s->gamma_table[bytestream_get_le16(&src)]); + } else +#endif + for (int x = 0; x < xsize; x++, ptr_x += step) + AV_WN16A(ptr_x, bytestream_get_le16(&src)); } // Zero out the end if xmax+1 is not w @@ -2045,22 +2086,39 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, if ((ret = decode_header(s, picture)) < 0) return ret; - if ((s->compression == EXR_DWAA || s->compression == EXR_DWAB) && - s->pixel_type == EXR_HALF) { - s->current_channel_offset *= 2; - for (int i = 0; i < 4; i++) - s->channel_offsets[i] *= 2; + if (s->compression == EXR_DWAA || + s->compression == EXR_DWAB) { + for (int i = 0; inb_channels; i++) { + EXRChannel *channel = &s->channels[i]; + if (channel->pixel_type != s->pixel_type) { + avpriv_request_sample(s->avctx, "mixed pixel type DWA"); + return AVERROR_PATCHWELCOME; + } + } } switch (s->pixel_type) { - case EXR_FLOAT: case EXR_HALF: + if (s->channel_offsets[3] >= 0) { + if (!s->is_luma) { + avctx->pix_fmt = AV_PIX_FMT_GBRAPF16; + } else { + avctx->pix_fmt = AV_PIX_FMT_YAF16; + } + } else { + if (!s->is_luma) { + avctx->pix_fmt = AV_PIX_FMT_GBRPF16; + } else { + avctx->pix_fmt = AV_PIX_FMT_GRAYF16; + } + } + break; + case EXR_FLOAT: if (s->channel_offsets[3] >= 0) { if (!s->is_luma) { avctx->pix_fmt = AV_PIX_FMT_GBRAPF32; } else { - /* todo: change this when a floating point pixel format with luma with alpha is implemented */ - avctx->pix_fmt = AV_PIX_FMT_GBRAPF32; + avctx->pix_fmt = AV_PIX_FMT_YAF32; } } else { if (!s->is_luma) { @@ -2090,9 +2148,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } +#if FF_API_EXR_GAMMA if (s->apply_trc_type != AVCOL_TRC_UNSPECIFIED) avctx->color_trc = s->apply_trc_type; else if (s->gamma > 0.9999f && s->gamma < 1.0001f) +#endif avctx->color_trc = AVCOL_TRC_LINEAR; switch (s->compression) { @@ -2139,13 +2199,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, if (!s->desc) return AVERROR_INVALIDDATA; - if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - planes = s->desc->nb_components; - out_line_size = avctx->width * 4; - } else { - planes = 1; - out_line_size = avctx->width * 2 * s->desc->nb_components; - } + planes = av_pix_fmt_count_planes(avctx->pix_fmt); + out_line_size = avctx->width * s->desc->comp[0].step; if (s->is_tile) { nb_blocks = ((s->xdelta + s->tile_attr.xSize - 1) / s->tile_attr.xSize) * @@ -2223,10 +2278,13 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, static av_cold int decode_init(AVCodecContext *avctx) { EXRContext *s = avctx->priv_data; +#if FF_API_EXR_GAMMA uint32_t i; union av_intfloat32 t; float one_gamma = 1.0f / s->gamma; av_csp_trc_function trc_func = NULL; + ff_init_float2half_tables(&s->f2h_tables); +#endif ff_init_half2float_tables(&s->h2f_tables); @@ -2238,31 +2296,27 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&s->bbdsp); #endif +#if FF_API_EXR_GAMMA trc_func = av_csp_trc_func_from_id(s->apply_trc_type); if (trc_func) { for (i = 0; i < 65536; ++i) { t.i = half2float(i, &s->h2f_tables); t.f = trc_func(t.f); - s->gamma_table[i] = t; + s->gamma_table[i] = float2half(av_float2int(t.f), &s->f2h_tables); } - } else { - if (one_gamma > 0.9999f && one_gamma < 1.0001f) { - for (i = 0; i < 65536; ++i) { - s->gamma_table[i].i = half2float(i, &s->h2f_tables); - } - } else { - for (i = 0; i < 65536; ++i) { - t.i = half2float(i, &s->h2f_tables); - /* If negative value we reuse half value */ - if (t.f <= 0.0f) { - s->gamma_table[i] = t; - } else { - t.f = powf(t.f, one_gamma); - s->gamma_table[i] = t; - } + } else if (one_gamma != 1.0f) { + for (i = 0; i < 65536; ++i) { + t.i = half2float(i, &s->h2f_tables); + /* If negative value we reuse half value */ + if (t.f <= 0.0f) { + s->gamma_table[i] = i; + } else { + t.f = powf(t.f, one_gamma); + s->gamma_table[i] = float2half(t.i, &s->f2h_tables); } } } +#endif // allocate thread data, used for non EXR_RAW compression types s->thread_data = av_calloc(avctx->thread_count, sizeof(*s->thread_data)); @@ -2305,12 +2359,13 @@ static const AVOption options[] = { AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD }, { "part", "Set the decoding part", OFFSET(selected_part), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VD }, - { "gamma", "Set the float gamma value when decoding", OFFSET(gamma), - AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD }, +#if FF_API_EXR_GAMMA + { "gamma", "Set the float gamma value when decoding (deprecated, use a scaler)", OFFSET(gamma), + AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD | AV_OPT_FLAG_DEPRECATED }, // XXX: Note the abuse of the enum using AVCOL_TRC_UNSPECIFIED to subsume the existing gamma option - { "apply_trc", "color transfer characteristics to apply to EXR linear input", OFFSET(apply_trc_type), - AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_UNSPECIFIED }, 1, AVCOL_TRC_NB-1, VD, .unit = "apply_trc_type"}, + { "apply_trc", "color transfer characteristics to apply to EXR linear input (deprecated, use a scaler)", OFFSET(apply_trc_type), + AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_UNSPECIFIED }, 1, AVCOL_TRC_NB-1, VD | AV_OPT_FLAG_DEPRECATED, .unit = "apply_trc_type"}, { "bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, { "gamma", "gamma", 0, @@ -2343,6 +2398,7 @@ static const AVOption options[] = { AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTEST2084 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, { "smpte428_1", "SMPTE ST 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTEST428_1 }, INT_MIN, INT_MAX, VD, .unit = "apply_trc_type"}, +#endif { NULL }, }; diff --git a/libavcodec/exrenc.c b/libavcodec/exrenc.c index 71ec07054e..c9685890ea 100644 --- a/libavcodec/exrenc.c +++ b/libavcodec/exrenc.c @@ -27,6 +27,7 @@ #include #include "libavutil/avassert.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" @@ -551,9 +552,5 @@ const FFCodec ff_exr_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_GBRAPF32, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GRAYF32, AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32), }; diff --git a/libavcodec/fastaudio.c b/libavcodec/fastaudio.c index 33ad26f8a1..ee31a06f18 100644 --- a/libavcodec/fastaudio.c +++ b/libavcodec/fastaudio.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -195,6 +196,5 @@ const FFCodec ff_fastaudio_decoder = { FF_CODEC_DECODE_CB(fastaudio_decode), .close = fastaudio_close, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c index 333fb3d79b..812989a892 100644 --- a/libavcodec/ffv1.c +++ b/libavcodec/ffv1.c @@ -31,12 +31,10 @@ #include "avcodec.h" #include "ffv1.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -av_cold int ff_ffv1_common_init(AVCodecContext *avctx) +av_cold int ff_ffv1_common_init(AVCodecContext *avctx, FFV1Context *s) { - FFV1Context *s = avctx->priv_data; - if (!avctx->width || !avctx->height) return AVERROR_INVALIDDATA; @@ -53,7 +51,7 @@ av_cold int ff_ffv1_common_init(AVCodecContext *avctx) return 0; } -static void planes_free(FFRefStructOpaque opaque, void *obj) +static void planes_free(AVRefStructOpaque opaque, void *obj) { PlaneContext *planes = obj; @@ -67,7 +65,7 @@ static void planes_free(FFRefStructOpaque opaque, void *obj) PlaneContext* ff_ffv1_planes_alloc(void) { - return ff_refstruct_alloc_ext(sizeof(PlaneContext) * MAX_PLANES, + return av_refstruct_alloc_ext(sizeof(PlaneContext) * MAX_PLANES, 0, NULL, planes_free); } @@ -81,7 +79,7 @@ av_cold int ff_ffv1_init_slice_state(const FFV1Context *f, if (f->ac != AC_GOLOMB_RICE) { if (!p->state) - p->state = av_malloc_array(p->context_count, CONTEXT_SIZE * + p->state = av_calloc(p->context_count, CONTEXT_SIZE * sizeof(uint8_t)); if (!p->state) return AVERROR(ENOMEM); @@ -119,6 +117,26 @@ av_cold int ff_ffv1_init_slices_state(FFV1Context *f) return 0; } +int ff_need_new_slices(int width, int num_h_slices, int chroma_shift) { + int mpw = 1<combined_version <= 0x40002) + return width * sx / num_h_slices; + + sx = (2LL * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw; + if (sx == awidth) + sx = width; + return sx; +} + av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f) { int max_slice_count = f->num_h_slices * f->num_v_slices; @@ -135,15 +153,17 @@ av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f) FFV1SliceContext *sc = &f->slices[i]; int sx = i % f->num_h_slices; int sy = i / f->num_h_slices; - int sxs = f->avctx->width * sx / f->num_h_slices; - int sxe = f->avctx->width * (sx + 1) / f->num_h_slices; - int sys = f->avctx->height * sy / f->num_v_slices; - int sye = f->avctx->height * (sy + 1) / f->num_v_slices; + int sxs = ff_slice_coord(f, f->avctx->width , sx , f->num_h_slices, f->chroma_h_shift); + int sxe = ff_slice_coord(f, f->avctx->width , sx + 1, f->num_h_slices, f->chroma_h_shift); + int sys = ff_slice_coord(f, f->avctx->height, sy , f->num_v_slices, f->chroma_v_shift); + int sye = ff_slice_coord(f, f->avctx->height, sy + 1, f->num_v_slices, f->chroma_v_shift); sc->slice_width = sxe - sxs; sc->slice_height = sye - sys; sc->slice_x = sxs; sc->slice_y = sys; + sc->sx = sx; + sc->sy = sy; sc->sample_buffer = av_malloc_array((f->width + 6), 3 * MAX_PLANES * sizeof(*sc->sample_buffer)); @@ -199,10 +219,50 @@ void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc) } } - -av_cold int ff_ffv1_close(AVCodecContext *avctx) +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int *offset, int mask[4], int bits_per_raw_sample) +{ + // to simplify we use the remap_count as the symbol range in each plane + if (!sc->remap) { + sc->remap_count[0] = + sc->remap_count[1] = + sc->remap_count[2] = + sc->remap_count[3] = 1 << (bits_per_raw_sample > 0 ? bits_per_raw_sample : 8); + } + + if (sc->remap) + av_assert0(bits_per_raw_sample > 8); //breaks with lbd, needs review if added + + //bits with no RCT + for (int p=0; p<3+f->transparency; p++) { + bits[p] = av_ceil_log2(sc->remap_count[p]); + if (mask) + mask[p] = (1<slice_coding_mode == 0) { + *offset = sc->remap_count[0]; + + bits[0] = av_ceil_log2(FFMAX3(sc->remap_count[0], sc->remap_count[1], sc->remap_count[2])); + bits[1] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[1]); + bits[2] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[2]); + + //old version coded a bit more than needed + if (f->combined_version < 0x40008) { + bits[0]++; + if(f->transparency) + bits[3]++; + } + } +} + +int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed) +{ + return get_symbol_inline(c, state, is_signed); +} + +av_cold void ff_ffv1_close(FFV1Context *s) { - FFV1Context *s = avctx->priv_data; int i, j; for (j = 0; j < s->max_slice_count; j++) { @@ -210,13 +270,18 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx) av_freep(&sc->sample_buffer); av_freep(&sc->sample_buffer32); + for(int p = 0; p < 4 ; p++) { + av_freep(&sc->fltmap[p]); + av_freep(&sc->fltmap32[p]); + sc->fltmap_size [p] = 0; + sc->fltmap32_size[p] = 0; + } - ff_refstruct_unref(&sc->plane); + av_refstruct_unref(&sc->plane); } - ff_refstruct_unref(&s->slice_damaged); + av_refstruct_unref(&s->slice_damaged); - av_freep(&avctx->stats_out); for (j = 0; j < s->quant_table_count; j++) { av_freep(&s->initial_states[j]); for (i = 0; i < s->max_slice_count; i++) { @@ -227,6 +292,4 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx) } av_freep(&s->slices); - - return 0; } diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 9aa0452922..d6f25737f5 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -28,6 +28,7 @@ * FF Video Codec 1 (a lossless codec) */ +#include "libavutil/attributes.h" #include "avcodec.h" #include "get_bits.h" #include "mathops.h" @@ -44,6 +45,8 @@ #define CONTEXT_SIZE 32 #define MAX_QUANT_TABLES 8 +#define MAX_QUANT_TABLE_SIZE 256 +#define MAX_QUANT_TABLE_MASK (MAX_QUANT_TABLE_SIZE - 1) #define MAX_CONTEXT_INPUTS 5 #define AC_GOLOMB_RICE 0 @@ -52,8 +55,8 @@ #define AC_RANGE_DEFAULT_TAB_FORCE -2 typedef struct VlcState { + uint32_t error_sum; int16_t drift; - uint16_t error_sum; int8_t bias; uint8_t count; } VlcState; @@ -75,11 +78,13 @@ typedef struct FFV1SliceContext { int slice_height; int slice_x; int slice_y; + int sx, sy; int run_index; int slice_coding_mode; int slice_rct_by_coef; int slice_rct_ry_coef; + int remap; // RefStruct reference, array of MAX_PLANES elements PlaneContext *plane; @@ -101,6 +106,17 @@ typedef struct FFV1SliceContext { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; }; }; + int remap_count[4]; + + uint32_t *bitmap [4]; //float encode + uint16_t *fltmap [4]; //halffloat encode & decode + uint32_t *fltmap32[4]; //float decode + unsigned int fltmap_size[4]; + unsigned int fltmap32_size[4]; + struct Unit { + uint32_t val; //this is unneeded if you accept a dereference on each access + uint32_t ndx; + } *unit[4]; } FFV1SliceContext; typedef struct FFV1Context { @@ -110,6 +126,7 @@ typedef struct FFV1Context { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; int version; int micro_version; + int combined_version; int width, height; int chroma_planes; int chroma_h_shift, chroma_v_shift; @@ -118,15 +135,23 @@ typedef struct FFV1Context { int64_t picture_number; int key_frame; ProgressFrame picture, last_picture; + void *hwaccel_picture_private, *hwaccel_last_picture_private; + uint32_t crcref; + enum AVPixelFormat pix_fmt; + enum AVPixelFormat configured_pix_fmt; const AVFrame *cur_enc_frame; int plane_count; int ac; ///< 1=range coder <-> 0=golomb rice - int16_t quant_tables[MAX_QUANT_TABLES][MAX_CONTEXT_INPUTS][256]; + int16_t quant_tables[MAX_QUANT_TABLES][MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE]; int context_count[MAX_QUANT_TABLES]; uint8_t state_transition[256]; uint8_t (*initial_states[MAX_QUANT_TABLES])[32]; int colorspace; + int flt; + int remap_mode; + int remap_optimizer; + int maxsize_warned; int use32bit; @@ -134,6 +159,7 @@ typedef struct FFV1Context { int intra; int key_frame_ok; int context_model; + int qtable; int bits_per_raw_sample; int packed_at_lsb; @@ -162,14 +188,26 @@ typedef struct FFV1Context { uint8_t frame_damaged; } FFV1Context; -int ff_ffv1_common_init(AVCodecContext *avctx); +int ff_ffv1_common_init(AVCodecContext *avctx, FFV1Context *s); int ff_ffv1_init_slice_state(const FFV1Context *f, FFV1SliceContext *sc); int ff_ffv1_init_slices_state(FFV1Context *f); int ff_ffv1_init_slice_contexts(FFV1Context *f); PlaneContext *ff_ffv1_planes_alloc(void); int ff_ffv1_allocate_initial_states(FFV1Context *f); void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc); -int ff_ffv1_close(AVCodecContext *avctx); +void ff_ffv1_close(FFV1Context *s); +int ff_need_new_slices(int width, int num_h_slices, int chroma_shift); +int ff_ffv1_parse_header(FFV1Context *f, RangeCoder *c, uint8_t *state); +int ff_ffv1_read_extra_header(FFV1Context *f); +int ff_ffv1_read_quant_tables(RangeCoder *c, + int16_t quant_table[MAX_CONTEXT_INPUTS][256]); +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int *offset, int mask[4], int bits_per_raw_sample); +int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed); + +/** + * This is intended for both width and height + */ +int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift); static av_always_inline int fold(int diff, int bits) { @@ -210,4 +248,29 @@ static inline void update_vlc_state(VlcState *const state, const int v) state->count = count; } + +static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, + int is_signed) +{ + if (get_rac(c, state + 0)) + return 0; + else { + int e; + unsigned a; + e = 0; + while (get_rac(c, state + 1 + FFMIN(e, 9))) { // 1..10 + e++; + if (e > 31) + return AVERROR_INVALIDDATA; + } + + a = 1; + for (int i = e - 1; i >= 0; i--) + a += a + get_rac(c, state + 22 + FFMIN(i, 9)); // 22..31 + + e = -(is_signed && get_rac(c, state + 11 + FFMIN(e, 10))); // 11..21 + return (a ^ e) - e; + } +} + #endif /* AVCODEC_FFV1_H */ diff --git a/libavcodec/ffv1_parse.c b/libavcodec/ffv1_parse.c new file mode 100644 index 0000000000..10f3652ff5 --- /dev/null +++ b/libavcodec/ffv1_parse.c @@ -0,0 +1,443 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/crc.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "rangecoder.h" +#include "ffv1.h" + +static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale) +{ + int v; + int i = 0; + uint8_t state[CONTEXT_SIZE]; + + memset(state, 128, sizeof(state)); + + for (v = 0; i < 128; v++) { + unsigned len = ff_ffv1_get_symbol(c, state, 0) + 1U; + + if (len > 128 - i || !len) + return AVERROR_INVALIDDATA; + + while (len--) { + quant_table[i] = scale * v; + i++; + } + } + + for (i = 1; i < 128; i++) + quant_table[256 - i] = -quant_table[i]; + quant_table[128] = -quant_table[127]; + + return 2 * v - 1; +} + +int ff_ffv1_read_quant_tables(RangeCoder *c, + int16_t quant_table[MAX_CONTEXT_INPUTS][256]) +{ + int i; + int context_count = 1; + + for (i = 0; i < 5; i++) { + int ret = read_quant_table(c, quant_table[i], context_count); + if (ret < 0) + return ret; + context_count *= ret; + if (context_count > 32768U) { + return AVERROR_INVALIDDATA; + } + } + return (context_count + 1) / 2; +} + +int ff_ffv1_read_extra_header(FFV1Context *f) +{ + RangeCoder c; + uint8_t state[CONTEXT_SIZE]; + int ret; + uint8_t state2[32][CONTEXT_SIZE]; + unsigned crc = 0; + + memset(state2, 128, sizeof(state2)); + memset(state, 128, sizeof(state)); + + ff_init_range_decoder(&c, f->avctx->extradata, f->avctx->extradata_size); + ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); + + f->version = ff_ffv1_get_symbol(&c, state, 0); + if (f->version < 2) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n"); + return AVERROR_INVALIDDATA; + } + if (f->version > 4) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported version %d\n", + f->version); + return AVERROR_PATCHWELCOME; + } + f->combined_version = f->version << 16; + if (f->version > 2) { + c.bytestream_end -= 4; + f->micro_version = ff_ffv1_get_symbol(&c, state, 0); + if (f->micro_version < 0 || f->micro_version > 65535) + return AVERROR_INVALIDDATA; + f->combined_version += f->micro_version; + } + f->ac = ff_ffv1_get_symbol(&c, state, 0); + + if (f->ac == AC_RANGE_CUSTOM_TAB) { + for (int i = 1; i < 256; i++) + f->state_transition[i] = ff_ffv1_get_symbol(&c, state, 1) + c.one_state[i]; + } else { + RangeCoder rc; + ff_build_rac_states(&rc, 0.05 * (1LL << 32), 256 - 8); + for (int i = 1; i < 256; i++) + f->state_transition[i] = rc.one_state[i]; + } + + f->colorspace = ff_ffv1_get_symbol(&c, state, 0); //YUV cs type + f->avctx->bits_per_raw_sample = ff_ffv1_get_symbol(&c, state, 0); + f->chroma_planes = get_rac(&c, state); + f->chroma_h_shift = ff_ffv1_get_symbol(&c, state, 0); + f->chroma_v_shift = ff_ffv1_get_symbol(&c, state, 0); + f->transparency = get_rac(&c, state); + f->plane_count = 1 + (f->chroma_planes || f->version<4) + f->transparency; + f->num_h_slices = 1 + ff_ffv1_get_symbol(&c, state, 0); + f->num_v_slices = 1 + ff_ffv1_get_symbol(&c, state, 0); + + if (f->chroma_h_shift > 4U || f->chroma_v_shift > 4U) { + av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", + f->chroma_h_shift, f->chroma_v_shift); + return AVERROR_INVALIDDATA; + } + + if (f->num_h_slices > (unsigned)f->width || !f->num_h_slices || + f->num_v_slices > (unsigned)f->height || !f->num_v_slices + ) { + av_log(f->avctx, AV_LOG_ERROR, "slice count invalid\n"); + return AVERROR_INVALIDDATA; + } + + if (f->num_h_slices > MAX_SLICES / f->num_v_slices) { + av_log(f->avctx, AV_LOG_ERROR, "slice count unsupported\n"); + return AVERROR_PATCHWELCOME; + } + + f->quant_table_count = ff_ffv1_get_symbol(&c, state, 0); + if (f->quant_table_count > (unsigned)MAX_QUANT_TABLES || !f->quant_table_count) { + av_log(f->avctx, AV_LOG_ERROR, "quant table count %d is invalid\n", f->quant_table_count); + f->quant_table_count = 0; + return AVERROR_INVALIDDATA; + } + + for (int i = 0; i < f->quant_table_count; i++) { + f->context_count[i] = ff_ffv1_read_quant_tables(&c, f->quant_tables[i]); + if (f->context_count[i] < 0) { + av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); + return AVERROR_INVALIDDATA; + } + } + if ((ret = ff_ffv1_allocate_initial_states(f)) < 0) + return ret; + + for (int i = 0; i < f->quant_table_count; i++) + if (get_rac(&c, state)) { + for (int j = 0; j < f->context_count[i]; j++) + for (int k = 0; k < CONTEXT_SIZE; k++) { + int pred = j ? f->initial_states[i][j - 1][k] : 128; + f->initial_states[i][j][k] = + (pred + ff_ffv1_get_symbol(&c, state2[k], 1)) & 0xFF; + } + } + + if (f->version > 2) { + f->ec = ff_ffv1_get_symbol(&c, state, 0); + if (f->ec >= 2) + f->crcref = 0x7a8c4079; + if (f->combined_version >= 0x30003) + f->intra = ff_ffv1_get_symbol(&c, state, 0); + if (f->combined_version >= 0x40004) + f->flt = ff_ffv1_get_symbol(&c, state, 0); + } + + if (f->version > 2) { + unsigned v; + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, + f->avctx->extradata, f->avctx->extradata_size); + if (v != f->crcref || f->avctx->extradata_size < 4) { + av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", v); + return AVERROR_INVALIDDATA; + } + crc = AV_RB32(f->avctx->extradata + f->avctx->extradata_size - 4); + } + + if (f->avctx->debug & FF_DEBUG_PICT_INFO) + av_log(f->avctx, AV_LOG_DEBUG, + "global: ver:%d.%d, coder:%d, colorspace: %d bpr:%d chroma:%d(%d:%d), alpha:%d slices:%dx%d qtabs:%d ec:%d intra:%d CRC:0x%08X\n", + f->version, f->micro_version, + f->ac, + f->colorspace, + f->avctx->bits_per_raw_sample, + f->chroma_planes, f->chroma_h_shift, f->chroma_v_shift, + f->transparency, + f->num_h_slices, f->num_v_slices, + f->quant_table_count, + f->ec, + f->intra, + crc + ); + return 0; +} + +int ff_ffv1_parse_header(FFV1Context *f, RangeCoder *c, uint8_t *state) +{ + if (f->version < 2) { + int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample; + unsigned v= ff_ffv1_get_symbol(c, state, 0); + if (v >= 2) { + av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v); + return AVERROR_INVALIDDATA; + } + f->version = v; + f->ac = ff_ffv1_get_symbol(c, state, 0); + + if (f->ac == AC_RANGE_CUSTOM_TAB) { + for (int i = 1; i < 256; i++) { + int st = ff_ffv1_get_symbol(c, state, 1) + c->one_state[i]; + if (st < 1 || st > 255) { + av_log(f->avctx, AV_LOG_ERROR, "invalid state transition %d\n", st); + return AVERROR_INVALIDDATA; + } + f->state_transition[i] = st; + } + } else { + RangeCoder rc; + ff_build_rac_states(&rc, 0.05 * (1LL << 32), 256 - 8); + for (int i = 1; i < 256; i++) + f->state_transition[i] = rc.one_state[i]; + } + + colorspace = ff_ffv1_get_symbol(c, state, 0); //YUV cs type + bits_per_raw_sample = f->version > 0 ? ff_ffv1_get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample; + chroma_planes = get_rac(c, state); + chroma_h_shift = ff_ffv1_get_symbol(c, state, 0); + chroma_v_shift = ff_ffv1_get_symbol(c, state, 0); + transparency = get_rac(c, state); + if (colorspace == 0 && f->avctx->skip_alpha) + transparency = 0; + + if (f->plane_count) { + if (colorspace != f->colorspace || + bits_per_raw_sample != f->avctx->bits_per_raw_sample || + chroma_planes != f->chroma_planes || + chroma_h_shift != f->chroma_h_shift || + chroma_v_shift != f->chroma_v_shift || + transparency != f->transparency) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n"); + return AVERROR_INVALIDDATA; + } + } + + if (chroma_h_shift > 4U || chroma_v_shift > 4U) { + av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", + chroma_h_shift, chroma_v_shift); + return AVERROR_INVALIDDATA; + } + + f->colorspace = colorspace; + f->avctx->bits_per_raw_sample = bits_per_raw_sample; + f->chroma_planes = chroma_planes; + f->chroma_h_shift = chroma_h_shift; + f->chroma_v_shift = chroma_v_shift; + f->transparency = transparency; + + f->plane_count = 2 + f->transparency; + } + + if (f->colorspace == 0) { + if (!f->transparency && !f->chroma_planes) { + if (f->avctx->bits_per_raw_sample <= 8) + f->pix_fmt = AV_PIX_FMT_GRAY8; + else if (f->avctx->bits_per_raw_sample == 9) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY9; + } else if (f->avctx->bits_per_raw_sample == 10) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY10; + } else if (f->avctx->bits_per_raw_sample == 12) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY12; + } else if (f->avctx->bits_per_raw_sample == 14) { + f->packed_at_lsb = 1; + f->pix_fmt = AV_PIX_FMT_GRAY14; + } else if (f->avctx->bits_per_raw_sample == 16) { + f->packed_at_lsb = 1; + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GRAYF16; + } else + f->pix_fmt = AV_PIX_FMT_GRAY16; + } else if (f->avctx->bits_per_raw_sample < 16) { + f->pix_fmt = AV_PIX_FMT_GRAY16; + } else + return AVERROR(ENOSYS); + } else if (f->transparency && !f->chroma_planes) { + if (f->avctx->bits_per_raw_sample <= 8 && !f->flt) { + f->pix_fmt = AV_PIX_FMT_YA8; + } else if (f->avctx->bits_per_raw_sample == 16 && f->flt) { + f->pix_fmt = AV_PIX_FMT_YAF16; + } else + return AVERROR(ENOSYS); + } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) { + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x20: f->pix_fmt = AV_PIX_FMT_YUV411P; break; + case 0x22: f->pix_fmt = AV_PIX_FMT_YUV410P; break; + } + } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) { + switch(16*f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P; break; + } + } else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P9; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P9; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P9; break; + } + } else if (f->avctx->bits_per_raw_sample == 9 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P9; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P9; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P9; break; + } + } else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P10; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P10; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P10; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P10; break; + } + } else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P10; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P10; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P10; break; + } + } else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P12; break; + case 0x01: f->pix_fmt = AV_PIX_FMT_YUV440P12; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P12; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P12; break; + } + } else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P12; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P12; 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->pix_fmt = AV_PIX_FMT_YUV444P14; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P14; break; + case 0x11: f->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) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUV444P16; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUV422P16; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUV420P16; 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) { + case 0x00: f->pix_fmt = AV_PIX_FMT_YUVA444P16; break; + case 0x10: f->pix_fmt = AV_PIX_FMT_YUVA422P16; break; + case 0x11: f->pix_fmt = AV_PIX_FMT_YUVA420P16; break; + } + } + } else if (f->colorspace == 1) { + if (f->chroma_h_shift || f->chroma_v_shift) { + av_log(f->avctx, AV_LOG_ERROR, + "chroma subsampling not supported in this colorspace\n"); + return AVERROR(ENOSYS); + } + if ( f->avctx->bits_per_raw_sample <= 8 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_0RGB32; + else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) + f->pix_fmt = AV_PIX_FMT_RGB32; + else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP9; + else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP10; + else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP10; + else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP12; + else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP12; + else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRP14; + else if (f->avctx->bits_per_raw_sample == 14 && f->transparency) + f->pix_fmt = AV_PIX_FMT_GBRAP14; + else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRPF16; + } else + f->pix_fmt = AV_PIX_FMT_GBRP16; + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 16 && f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRAPF16; + } else + f->pix_fmt = AV_PIX_FMT_GBRAP16; + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 32 && !f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRPF32; + } + f->use32bit = 1; + } else if (f->avctx->bits_per_raw_sample == 32 && f->transparency) { + if (f->flt) { + f->pix_fmt = AV_PIX_FMT_GBRAPF32; + } + f->use32bit = 1; + } + } else { + av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); + return AVERROR(ENOSYS); + } + if (f->pix_fmt == AV_PIX_FMT_NONE) { + av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); + return AVERROR(ENOSYS); + } + + return 0; +} diff --git a/libavcodec/ffv1_parser.c b/libavcodec/ffv1_parser.c new file mode 100644 index 0000000000..bf61e88a2e --- /dev/null +++ b/libavcodec/ffv1_parser.c @@ -0,0 +1,86 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "ffv1.h" +#include "rangecoder.h" + +typedef struct FFV1ParseContext { + FFV1Context f; + int got_first; +} FFV1ParseContext; + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + FFV1ParseContext *p = s->priv_data; + FFV1Context *f = &p->f; + RangeCoder c; + uint8_t keystate = 128; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + if (!p->got_first) { + int ret = ff_ffv1_common_init(avctx, f); + p->got_first = 1; + if (ret < 0) + return buf_size; + + if (avctx->extradata_size > 0 && (ret = ff_ffv1_read_extra_header(f)) < 0) + return buf_size; + } + + ff_init_range_decoder(&c, buf, buf_size); + ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); + + f->avctx = avctx; + s->key_frame = get_rac(&c, &keystate); + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_UNKNOWN; + s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + if (s->key_frame) { + uint8_t state[CONTEXT_SIZE]; + memset(state, 128, sizeof(state)); + ff_ffv1_parse_header(f, &c, state); + } + + s->width = f->width; + s->height = f->height; + s->format = f->pix_fmt; + + return buf_size; +} + +static void ffv1_close(AVCodecParserContext *s) +{ + FFV1ParseContext *p = s->priv_data; + + p->f.avctx = NULL; + ff_ffv1_close(&p->f); +} + +const AVCodecParser ff_ffv1_parser = { + .codec_ids = { AV_CODEC_ID_FFV1 }, + .priv_data_size = sizeof(FFV1ParseContext), + .parser_parse = parse, + .parser_close = ffv1_close, +}; diff --git a/libavcodec/ffv1_template.c b/libavcodec/ffv1_template.c index d15ad11021..005a32c296 100644 --- a/libavcodec/ffv1_template.c +++ b/libavcodec/ffv1_template.c @@ -29,7 +29,7 @@ static inline int RENAME(predict)(TYPE *src, TYPE *last) return mid_pred(L, L + T - LT, T); } -static inline int RENAME(get_context)(const int16_t quant_table[MAX_CONTEXT_INPUTS][256], +static inline int RENAME(get_context)(const int16_t quant_table[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE], TYPE *src, TYPE *last, TYPE *last2) { const int LT = last[-1]; @@ -40,14 +40,13 @@ static inline int RENAME(get_context)(const int16_t quant_table[MAX_CONTEXT_INPU if (quant_table[3][127] || quant_table[4][127]) { const int TT = last2[0]; const int LL = src[-2]; - return quant_table[0][(L - LT) & 0xFF] + - quant_table[1][(LT - T) & 0xFF] + - quant_table[2][(T - RT) & 0xFF] + - quant_table[3][(LL - L) & 0xFF] + - quant_table[4][(TT - T) & 0xFF]; + return quant_table[0][(L - LT) & MAX_QUANT_TABLE_MASK] + + quant_table[1][(LT - T) & MAX_QUANT_TABLE_MASK] + + quant_table[2][(T - RT) & MAX_QUANT_TABLE_MASK] + + quant_table[3][(LL - L) & MAX_QUANT_TABLE_MASK] + + quant_table[4][(TT - T) & MAX_QUANT_TABLE_MASK]; } else - return quant_table[0][(L - LT) & 0xFF] + - quant_table[1][(LT - T) & 0xFF] + - quant_table[2][(T - RT) & 0xFF]; + return quant_table[0][(L - LT) & MAX_QUANT_TABLE_MASK] + + quant_table[1][(LT - T) & MAX_QUANT_TABLE_MASK] + + quant_table[2][(T - RT) & MAX_QUANT_TABLE_MASK]; } - diff --git a/libavcodec/ffv1_vulkan.c b/libavcodec/ffv1_vulkan.c new file mode 100644 index 0000000000..6f49e2ebb1 --- /dev/null +++ b/libavcodec/ffv1_vulkan.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ffv1_vulkan.h" +#include "libavutil/crc.h" + +int ff_ffv1_vk_update_state_transition_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f) +{ + int err; + uint8_t *buf_mapped; + + RET(ff_vk_map_buffer(s, vkb, &buf_mapped, 0)); + + for (int i = 1; i < 256; i++) { + buf_mapped[256 + i] = f->state_transition[i]; + buf_mapped[256 - i] = 256 - (int)f->state_transition[i]; + } + + RET(ff_vk_unmap_buffer(s, vkb, 1)); + +fail: + return err; +} + +static int init_state_transition_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f, + int (*write_data)(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f)) +{ + int err; + size_t buf_len = 512*sizeof(uint8_t); + + RET(ff_vk_create_buf(s, vkb, + buf_len, + NULL, NULL, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + write_data(s, vkb, f); + +fail: + return err; +} + +int ff_ffv1_vk_init_state_transition_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f) +{ + return init_state_transition_data(s, vkb, f, + ff_ffv1_vk_update_state_transition_data); +} + +int ff_ffv1_vk_init_quant_table_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f) +{ + int err; + + int16_t *buf_mapped; + size_t buf_len = MAX_QUANT_TABLES* + MAX_CONTEXT_INPUTS* + MAX_QUANT_TABLE_SIZE*sizeof(int16_t); + + RET(ff_vk_create_buf(s, vkb, + buf_len, + NULL, NULL, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RET(ff_vk_map_buffer(s, vkb, (void *)&buf_mapped, 0)); + + memcpy(buf_mapped, f->quant_tables, + sizeof(f->quant_tables)); + + RET(ff_vk_unmap_buffer(s, vkb, 1)); + +fail: + return err; +} + +int ff_ffv1_vk_init_crc_table_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f) +{ + int err; + + uint32_t *buf_mapped; + size_t buf_len = 256*sizeof(int32_t); + + RET(ff_vk_create_buf(s, vkb, + buf_len, + NULL, NULL, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + RET(ff_vk_map_buffer(s, vkb, (void *)&buf_mapped, 0)); + + memcpy(buf_mapped, av_crc_get_table(AV_CRC_32_IEEE), buf_len); + + RET(ff_vk_unmap_buffer(s, vkb, 1)); + +fail: + return err; +} diff --git a/libavcodec/ffv1_vulkan.h b/libavcodec/ffv1_vulkan.h new file mode 100644 index 0000000000..372478f4b7 --- /dev/null +++ b/libavcodec/ffv1_vulkan.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_FFV1_VULKAN_H +#define AVCODEC_FFV1_VULKAN_H + +#include "libavutil/vulkan.h" +#include "ffv1.h" + +int ff_ffv1_vk_update_state_transition_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f); + +int ff_ffv1_vk_init_state_transition_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f); + +int ff_ffv1_vk_init_quant_table_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f); + +int ff_ffv1_vk_init_crc_table_data(FFVulkanContext *s, + FFVkBuffer *vkb, FFV1Context *f); + +typedef struct FFv1VkRCTParameters { + int fmt_lut[4]; + int offset; + uint8_t bits; + uint8_t planar_rgb; + uint8_t color_planes; + uint8_t transparency; + uint8_t version; + uint8_t micro_version; + uint8_t padding[2]; +} FFv1VkRCTParameters; + +typedef struct FFv1VkResetParameters { + uint32_t context_count[MAX_QUANT_TABLES]; + VkDeviceAddress slice_state; + uint32_t plane_state_size; + uint8_t codec_planes; + uint8_t key_frame; + uint8_t version; + uint8_t micro_version; + uint8_t padding[1]; +} FFv1VkResetParameters; + +#endif /* AVCODEC_FFV1_VULKAN_H */ diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 415c66be63..3d67798961 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -38,37 +38,12 @@ #include "mathops.h" #include "ffv1.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" - -static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, - int is_signed) -{ - if (get_rac(c, state + 0)) - return 0; - else { - int e; - unsigned a; - e = 0; - while (get_rac(c, state + 1 + FFMIN(e, 9))) { // 1..10 - e++; - if (e > 31) - return AVERROR_INVALIDDATA; - } - - a = 1; - for (int i = e - 1; i >= 0; i--) - a += a + get_rac(c, state + 22 + FFMIN(i, 9)); // 22..31 - - e = -(is_signed && get_rac(c, state + 11 + FFMIN(e, 10))); // 11..21 - return (a ^ e) - e; - } -} - -static av_noinline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed) -{ - return get_symbol_inline(c, state, is_signed); -} +#include "decode.h" +#include "hwconfig.h" +#include "hwaccel_internal.h" +#include "config_components.h" static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state, int bits) @@ -81,6 +56,11 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state, k++; i += i; } + if (k > bits) { + ff_dlog(NULL, "k-overflow bias:%d error:%d drift:%d count:%d k:%d", + state->bias, state->error_sum, state->drift, state->count, k); + k = bits; + } v = get_sr_golomb(gb, k, 12, bits); ff_dlog(NULL, "v:%d bias:%d error:%d drift:%d count:%d k:%d", @@ -120,11 +100,20 @@ static int is_input_end(RangeCoder *c, GetBitContext *gb, int ac) static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, GetBitContext *gb, uint8_t *src, int w, int h, int stride, int plane_index, - int pixel_stride) + int remap_index, int pixel_stride, int ac) { - const int ac = f->ac; int x, y; int16_t *sample[2]; + int bits; + unsigned mask; + + if (sc->remap) { + bits = av_ceil_log2(sc->remap_count[remap_index]); + mask = (1<avctx->bits_per_raw_sample; + } + sample[0] = sc->sample_buffer + 3; sample[1] = sc->sample_buffer + w + 6 + 3; @@ -145,19 +134,36 @@ static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, int ret = decode_line(f, sc, gb, w, sample, plane_index, 8, ac); if (ret < 0) return ret; + if (sc->remap) + for (x = 0; x < w; x++) + sample[1][x] = sc->fltmap[remap_index][sample[1][x]]; for (x = 0; x < w; x++) src[x*pixel_stride + stride * y] = sample[1][x]; } else { - int ret = decode_line(f, sc, gb, w, sample, plane_index, f->avctx->bits_per_raw_sample, ac); + int ret = decode_line(f, sc, gb, w, sample, plane_index, bits, ac); if (ret < 0) return ret; - if (f->packed_at_lsb) { - for (x = 0; x < w; x++) { - ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x]; + + if (sc->remap) { + if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sc->fltmap[remap_index][sample[1][x] & mask]; + } + } else { + for (x = 0; x < w; x++) { + int v = sc->fltmap[remap_index][sample[1][x] & mask]; + ((uint16_t*)(src + stride*y))[x*pixel_stride] = v << (16 - f->avctx->bits_per_raw_sample) | v >> (2 * f->avctx->bits_per_raw_sample - 16); + } } } else { - for (x = 0; x < w; x++) { - ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x] << (16 - f->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * f->avctx->bits_per_raw_sample - 16); + if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x]; + } + } else { + for (x = 0; x < w; x++) { + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x] << (16 - f->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * f->avctx->bits_per_raw_sample - 16); + } } } } @@ -174,10 +180,10 @@ static int decode_slice_header(const FFV1Context *f, int sx, sy, sw, sh; memset(state, 128, sizeof(state)); - sx = get_symbol(c, state, 0); - sy = get_symbol(c, state, 0); - sw = get_symbol(c, state, 0) + 1U; - sh = get_symbol(c, state, 0) + 1U; + sx = ff_ffv1_get_symbol(c, state, 0); + sy = ff_ffv1_get_symbol(c, state, 0); + sw = ff_ffv1_get_symbol(c, state, 0) + 1U; + sh = ff_ffv1_get_symbol(c, state, 0) + 1U; av_assert0(f->version > 2); @@ -187,10 +193,10 @@ static int decode_slice_header(const FFV1Context *f, if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh) return AVERROR_INVALIDDATA; - sc->slice_x = sx * (int64_t)f->width / f->num_h_slices; - sc->slice_y = sy * (int64_t)f->height / f->num_v_slices; - sc->slice_width = (sx + sw) * (int64_t)f->width / f->num_h_slices - sc->slice_x; - sc->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - sc->slice_y; + sc->slice_x = ff_slice_coord(f, f->width , sx , f->num_h_slices, f->chroma_h_shift); + sc->slice_y = ff_slice_coord(f, f->height, sy , f->num_v_slices, f->chroma_v_shift); + sc->slice_width = ff_slice_coord(f, f->width , sx + sw, f->num_h_slices, f->chroma_h_shift) - sc->slice_x; + sc->slice_height = ff_slice_coord(f, f->height, sy + sh, f->num_v_slices, f->chroma_v_shift) - sc->slice_y; av_assert0((unsigned)sc->slice_width <= f->width && (unsigned)sc->slice_height <= f->height); @@ -202,7 +208,7 @@ static int decode_slice_header(const FFV1Context *f, for (unsigned i = 0; i < f->plane_count; i++) { PlaneContext * const p = &sc->plane[i]; - int idx = get_symbol(c, state, 0); + int idx = ff_ffv1_get_symbol(c, state, 0); if (idx >= (unsigned)f->quant_table_count) { av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n"); return -1; @@ -217,7 +223,7 @@ static int decode_slice_header(const FFV1Context *f, p->context_count = context_count; } - ps = get_symbol(c, state, 0); + ps = ff_ffv1_get_symbol(c, state, 0); if (ps == 1) { frame->flags |= AV_FRAME_FLAG_INTERLACED; frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; @@ -227,8 +233,8 @@ static int decode_slice_header(const FFV1Context *f, } else if (ps == 3) { frame->flags &= ~AV_FRAME_FLAG_INTERLACED; } - frame->sample_aspect_ratio.num = get_symbol(c, state, 0); - frame->sample_aspect_ratio.den = get_symbol(c, state, 0); + frame->sample_aspect_ratio.num = ff_ffv1_get_symbol(c, state, 0); + frame->sample_aspect_ratio.den = ff_ffv1_get_symbol(c, state, 0); if (av_image_check_sar(f->width, f->height, frame->sample_aspect_ratio) < 0) { @@ -240,15 +246,29 @@ static int decode_slice_header(const FFV1Context *f, if (f->version > 3) { sc->slice_reset_contexts = get_rac(c, state); - sc->slice_coding_mode = get_symbol(c, state, 0); - if (sc->slice_coding_mode != 1) { - sc->slice_rct_by_coef = get_symbol(c, state, 0); - sc->slice_rct_ry_coef = get_symbol(c, state, 0); + sc->slice_coding_mode = ff_ffv1_get_symbol(c, state, 0); + if (sc->slice_coding_mode != 1 && f->colorspace == 1) { + sc->slice_rct_by_coef = ff_ffv1_get_symbol(c, state, 0); + sc->slice_rct_ry_coef = ff_ffv1_get_symbol(c, state, 0); if ((uint64_t)sc->slice_rct_by_coef + (uint64_t)sc->slice_rct_ry_coef > 4) { av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n"); return AVERROR_INVALIDDATA; } } + if (f->combined_version >= 0x40004) { + sc->remap = ff_ffv1_get_symbol(c, state, 0); + if (sc->remap > 2U || + sc->remap && !f->flt) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported remap %d\n", sc->remap); + return AVERROR_INVALIDDATA; + } + } + } + if (f->avctx->bits_per_raw_sample == 32) { + if (!sc->remap) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported remap\n"); + return AVERROR_INVALIDDATA; + } } return 0; @@ -264,15 +284,89 @@ static void slice_set_damaged(FFV1Context *f, FFV1SliceContext *sc) f->frame_damaged = 1; } +static int decode_current_mul(RangeCoder *rc, uint8_t state[32], int *mul, int mul_count, int64_t i) +{ + int ndx = (i * mul_count) >> 32; + av_assert2(ndx <= 4096U); + + if (mul[ndx] < 0) + mul[ndx] = ff_ffv1_get_symbol(rc, state, 0) & 0x3FFFFFFF; + + return mul[ndx]; +} + +static int decode_remap(FFV1Context *f, FFV1SliceContext *sc) +{ + unsigned int end = (1LL<avctx->bits_per_raw_sample) - 1; + int flip = sc->remap == 2 ? (end>>1) : 0; + const int pixel_num = sc->slice_width * sc->slice_height; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2][3][32]; + int64_t i; + int mul[4096+1]; + int mul_count; + + memset(state, 128, sizeof(state)); + mul_count = ff_ffv1_get_symbol(&sc->c, state[0][0], 0); + + if (mul_count > 4096U) + return AVERROR_INVALIDDATA; + for (int i = 0; ic, state[lu][0], 0); + unsigned run0 = lu ? 0 : run; + unsigned run1 = lu ? run : 1; + + i += run0 * current_mul; + + while (run1--) { + if (current_mul > 1) { + int delta = get_symbol_inline(&sc->c, state[lu][1], 1); + if (delta <= -current_mul || delta > current_mul/2) + return AVERROR_INVALIDDATA; //not sure we should check this + i += current_mul - 1 + delta; + } + if (i - 1 >= end) + break; + if (j >= pixel_num) + return AVERROR_INVALIDDATA; + if (end <= 0xFFFF) { + sc->fltmap [p][j++] = i ^ ((i& 0x8000) ? 0 : flip); + } else + sc->fltmap32[p][j++] = i ^ ((i&0x80000000) ? 0 : flip); + i++; + current_mul = decode_current_mul(&sc->c, state[0][2], mul, mul_count, i); + } + if (lu) { + i += current_mul; + } + lu ^= !run; + } + sc->remap_count[p] = j; + } + return 0; +} + static int decode_slice(AVCodecContext *c, void *arg) { FFV1Context *f = c->priv_data; FFV1SliceContext *sc = arg; int width, height, x, y, ret; - const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step; + const int ps = av_pix_fmt_desc_get(f->pix_fmt)->comp[0].step; AVFrame * const p = f->picture.f; const int si = sc - f->slices; GetBitContext gb; + int ac = f->ac || sc->slice_coding_mode == 1; if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f) ff_progress_frame_await(&f->last_picture, si); @@ -305,8 +399,28 @@ static int decode_slice(AVCodecContext *c, void *arg) x = sc->slice_x; y = sc->slice_y; - if (f->ac == AC_GOLOMB_RICE) { - if (f->version == 3 && f->micro_version > 1 || f->version > 3) + if (sc->remap) { + const int pixel_num = sc->slice_width * sc->slice_height; + + for(int p = 0; p < 1 + 2*f->chroma_planes + f->transparency ; p++) { + if (f->avctx->bits_per_raw_sample == 32) { + av_fast_malloc(&sc->fltmap32[p], &sc->fltmap32_size[p], pixel_num * sizeof(*sc->fltmap32[p])); + if (!sc->fltmap32[p]) + return AVERROR(ENOMEM); + } else { + av_fast_malloc(&sc->fltmap[p], &sc->fltmap_size[p], pixel_num * sizeof(*sc->fltmap[p])); + if (!sc->fltmap[p]) + return AVERROR(ENOMEM); + } + } + + ret = decode_remap(f, sc); + if (ret < 0) + return ret; + } + + if (ac == AC_GOLOMB_RICE) { + if (f->combined_version >= 0x30002) get_rac(&sc->c, (uint8_t[]) { 129 }); sc->ac_byte_count = f->version > 2 || (!x && !y) ? sc->c.bytestream - sc->c.bytestream_start - 1 : 0; init_get_bits(&gb, @@ -320,444 +434,97 @@ static int decode_slice(AVCodecContext *c, void *arg) const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); const int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 1, ac); if (f->chroma_planes) { - decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); + decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, 1, ac); + decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 2, 1, ac); } if (f->transparency) - decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, 1); + decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, + (f->version >= 4 && !f->chroma_planes) ? 1 : 3, 1, ac); } else if (f->colorspace == 0) { - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2); - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 0, 2, ac); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + (ps>>1), width, height, p->linesize[0], 1, 1, 2, ac); } else if (f->use32bit) { 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[3] + ps * x + y * p->linesize[3] }; + p->data[2] + ps * x + y * p->linesize[2] }; + if (f->transparency) + planes[3] = p->data[3] + ps * x + y * p->linesize[3]; decode_rgb_frame32(f, sc, &gb, planes, width, height, p->linesize); } else { - 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[3] + ps * x + y * p->linesize[3] }; + uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0] }; + if (f->avctx->bits_per_raw_sample > 8) { + planes[1] = p->data[1] + ps * x + y * p->linesize[1]; + planes[2] = p->data[2] + ps * x + y * p->linesize[2]; + if (f->transparency) + planes[3] = p->data[3] + ps * x + y * p->linesize[3]; + } decode_rgb_frame(f, sc, &gb, planes, width, height, p->linesize); } - if (f->ac != AC_GOLOMB_RICE && f->version > 2) { + if (ac != AC_GOLOMB_RICE && f->version > 2) { int v; get_rac(&sc->c, (uint8_t[]) { 129 }); - v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*f->ec; + v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*!!f->ec; if (v) { av_log(f->avctx, AV_LOG_ERROR, "bytestream end mismatching by %d\n", v); slice_set_damaged(f, sc); } } + if (sc->slice_damaged && (f->avctx->err_recognition & AV_EF_EXPLODE)) + return AVERROR_INVALIDDATA; + if ((c->active_thread_type & FF_THREAD_FRAME) && !f->frame_damaged) ff_progress_frame_report(&f->picture, si); return 0; } -static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale) +static enum AVPixelFormat get_pixel_format(FFV1Context *f) { - int v; - int i = 0; - uint8_t state[CONTEXT_SIZE]; + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_FFV1_VULKAN_HWACCEL + AV_PIX_FMT_VULKAN, +#endif + f->pix_fmt, + AV_PIX_FMT_NONE, + }; - memset(state, 128, sizeof(state)); - - for (v = 0; i < 128; v++) { - unsigned len = get_symbol(c, state, 0) + 1U; - - if (len > 128 - i || !len) - return AVERROR_INVALIDDATA; - - while (len--) { - quant_table[i] = scale * v; - i++; - } - } - - for (i = 1; i < 128; i++) - quant_table[256 - i] = -quant_table[i]; - quant_table[128] = -quant_table[127]; - - return 2 * v - 1; + return ff_get_format(f->avctx, pix_fmts); } -static int read_quant_tables(RangeCoder *c, - int16_t quant_table[MAX_CONTEXT_INPUTS][256]) -{ - int i; - int context_count = 1; - - for (i = 0; i < 5; i++) { - int ret = read_quant_table(c, quant_table[i], context_count); - if (ret < 0) - return ret; - context_count *= ret; - if (context_count > 32768U) { - return AVERROR_INVALIDDATA; - } - } - return (context_count + 1) / 2; -} - -static int read_extra_header(FFV1Context *f) -{ - RangeCoder c; - uint8_t state[CONTEXT_SIZE]; - int ret; - uint8_t state2[32][CONTEXT_SIZE]; - unsigned crc = 0; - - memset(state2, 128, sizeof(state2)); - memset(state, 128, sizeof(state)); - - ff_init_range_decoder(&c, f->avctx->extradata, f->avctx->extradata_size); - ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); - - f->version = get_symbol(&c, state, 0); - if (f->version < 2) { - av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n"); - return AVERROR_INVALIDDATA; - } - if (f->version > 4) { - av_log(f->avctx, AV_LOG_ERROR, "unsupported version %d\n", - f->version); - return AVERROR_PATCHWELCOME; - } - if (f->version > 2) { - c.bytestream_end -= 4; - f->micro_version = get_symbol(&c, state, 0); - if (f->micro_version < 0) - return AVERROR_INVALIDDATA; - } - f->ac = get_symbol(&c, state, 0); - - if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (int i = 1; i < 256; i++) - f->state_transition[i] = get_symbol(&c, state, 1) + c.one_state[i]; - } - - f->colorspace = get_symbol(&c, state, 0); //YUV cs type - f->avctx->bits_per_raw_sample = get_symbol(&c, state, 0); - f->chroma_planes = get_rac(&c, state); - f->chroma_h_shift = get_symbol(&c, state, 0); - f->chroma_v_shift = get_symbol(&c, state, 0); - f->transparency = get_rac(&c, state); - f->plane_count = 1 + (f->chroma_planes || f->version<4) + f->transparency; - f->num_h_slices = 1 + get_symbol(&c, state, 0); - f->num_v_slices = 1 + get_symbol(&c, state, 0); - - if (f->chroma_h_shift > 4U || f->chroma_v_shift > 4U) { - av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", - f->chroma_h_shift, f->chroma_v_shift); - return AVERROR_INVALIDDATA; - } - - if (f->num_h_slices > (unsigned)f->width || !f->num_h_slices || - f->num_v_slices > (unsigned)f->height || !f->num_v_slices - ) { - av_log(f->avctx, AV_LOG_ERROR, "slice count invalid\n"); - return AVERROR_INVALIDDATA; - } - - if (f->num_h_slices > MAX_SLICES / f->num_v_slices) { - av_log(f->avctx, AV_LOG_ERROR, "slice count unsupported\n"); - return AVERROR_PATCHWELCOME; - } - - f->quant_table_count = get_symbol(&c, state, 0); - if (f->quant_table_count > (unsigned)MAX_QUANT_TABLES || !f->quant_table_count) { - av_log(f->avctx, AV_LOG_ERROR, "quant table count %d is invalid\n", f->quant_table_count); - f->quant_table_count = 0; - return AVERROR_INVALIDDATA; - } - - for (int i = 0; i < f->quant_table_count; i++) { - f->context_count[i] = read_quant_tables(&c, f->quant_tables[i]); - if (f->context_count[i] < 0) { - av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); - return AVERROR_INVALIDDATA; - } - } - if ((ret = ff_ffv1_allocate_initial_states(f)) < 0) - return ret; - - for (int i = 0; i < f->quant_table_count; i++) - if (get_rac(&c, state)) { - for (int j = 0; j < f->context_count[i]; j++) - for (int k = 0; k < CONTEXT_SIZE; k++) { - int pred = j ? f->initial_states[i][j - 1][k] : 128; - f->initial_states[i][j][k] = - (pred + get_symbol(&c, state2[k], 1)) & 0xFF; - } - } - - if (f->version > 2) { - f->ec = get_symbol(&c, state, 0); - if (f->micro_version > 2) - f->intra = get_symbol(&c, state, 0); - } - - if (f->version > 2) { - unsigned v; - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, - f->avctx->extradata, f->avctx->extradata_size); - if (v || f->avctx->extradata_size < 4) { - av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", v); - return AVERROR_INVALIDDATA; - } - crc = AV_RB32(f->avctx->extradata + f->avctx->extradata_size - 4); - } - - if (f->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(f->avctx, AV_LOG_DEBUG, - "global: ver:%d.%d, coder:%d, colorspace: %d bpr:%d chroma:%d(%d:%d), alpha:%d slices:%dx%d qtabs:%d ec:%d intra:%d CRC:0x%08X\n", - f->version, f->micro_version, - f->ac, - f->colorspace, - f->avctx->bits_per_raw_sample, - f->chroma_planes, f->chroma_h_shift, f->chroma_v_shift, - f->transparency, - f->num_h_slices, f->num_v_slices, - f->quant_table_count, - f->ec, - f->intra, - crc - ); - return 0; -} - -static int read_header(FFV1Context *f) +static int read_header(FFV1Context *f, RangeCoder *c) { uint8_t state[CONTEXT_SIZE]; int context_count = -1; //-1 to avoid warning - RangeCoder *const c = &f->slices[0].c; + int ret; memset(state, 128, sizeof(state)); - if (f->version < 2) { - int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample; - unsigned v= get_symbol(c, state, 0); - if (v >= 2) { - av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v); - return AVERROR_INVALIDDATA; - } - f->version = v; - f->ac = get_symbol(c, state, 0); + ret = ff_ffv1_parse_header(f, c, state); + if (ret < 0) + return ret; - if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (int i = 1; i < 256; i++) { - int st = get_symbol(c, state, 1) + c->one_state[i]; - if (st < 1 || st > 255) { - av_log(f->avctx, AV_LOG_ERROR, "invalid state transition %d\n", st); - return AVERROR_INVALIDDATA; - } - f->state_transition[i] = st; - } - } - - colorspace = get_symbol(c, state, 0); //YUV cs type - bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample; - chroma_planes = get_rac(c, state); - chroma_h_shift = get_symbol(c, state, 0); - chroma_v_shift = get_symbol(c, state, 0); - transparency = get_rac(c, state); - if (colorspace == 0 && f->avctx->skip_alpha) - transparency = 0; - - if (f->plane_count) { - if (colorspace != f->colorspace || - bits_per_raw_sample != f->avctx->bits_per_raw_sample || - chroma_planes != f->chroma_planes || - chroma_h_shift != f->chroma_h_shift || - chroma_v_shift != f->chroma_v_shift || - transparency != f->transparency) { - av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n"); - return AVERROR_INVALIDDATA; - } - } - - if (chroma_h_shift > 4U || chroma_v_shift > 4U) { - av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n", - chroma_h_shift, chroma_v_shift); - return AVERROR_INVALIDDATA; - } - - f->colorspace = colorspace; - f->avctx->bits_per_raw_sample = bits_per_raw_sample; - f->chroma_planes = chroma_planes; - f->chroma_h_shift = chroma_h_shift; - f->chroma_v_shift = chroma_v_shift; - f->transparency = transparency; - - f->plane_count = 2 + f->transparency; - } - - if (f->colorspace == 0) { - 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 == 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) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY12; - } else if (f->avctx->bits_per_raw_sample == 14) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY14; - } else if (f->avctx->bits_per_raw_sample == 16) { - f->packed_at_lsb = 1; - f->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - } else if (f->avctx->bits_per_raw_sample < 16) { - f->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - } else - return AVERROR(ENOSYS); - } else if (f->transparency && !f->chroma_planes) { - if (f->avctx->bits_per_raw_sample <= 8) - f->avctx->pix_fmt = AV_PIX_FMT_YA8; - else - return AVERROR(ENOSYS); - } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) { - switch(16 * f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; - case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; - case 0x20: f->avctx->pix_fmt = AV_PIX_FMT_YUV411P; break; - case 0x22: f->avctx->pix_fmt = AV_PIX_FMT_YUV410P; break; - } - } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) { - switch(16*f->chroma_h_shift + f->chroma_v_shift) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break; - } - } else if (f->avctx->bits_per_raw_sample == 9 && !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_YUV444P9; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P9; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P9; break; - } - } else if (f->avctx->bits_per_raw_sample == 9 && 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_YUVA444P9; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P9; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P9; break; - } - } else if (f->avctx->bits_per_raw_sample == 10 && !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_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; - } - } else if (f->avctx->bits_per_raw_sample == 10 && 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_YUVA444P10; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P10; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P10; break; - } - } else if (f->avctx->bits_per_raw_sample == 12 && !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_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 == 12 && 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_YUVA444P12; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P12; 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) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; 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) { - case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P16; break; - case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P16; break; - case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16; break; - } - } - } else if (f->colorspace == 1) { - if (f->chroma_h_shift || f->chroma_v_shift) { - av_log(f->avctx, AV_LOG_ERROR, - "chroma subsampling not supported in this colorspace\n"); - return AVERROR(ENOSYS); - } - if ( f->avctx->bits_per_raw_sample <= 8 && !f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_0RGB32; - else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_RGB32; - else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) - 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 == 14 && f->transparency) - f->avctx->pix_fmt = AV_PIX_FMT_GBRAP14; - 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); - } - if (f->avctx->pix_fmt == AV_PIX_FMT_NONE) { - av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); - return AVERROR(ENOSYS); + if (f->configured_pix_fmt != f->pix_fmt) { + f->avctx->pix_fmt = get_pixel_format(f); + if (f->avctx->pix_fmt < 0) + return AVERROR(EINVAL); + f->configured_pix_fmt = f->pix_fmt; } ff_dlog(f->avctx, "%d %d %d\n", - f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt); + f->chroma_h_shift, f->chroma_v_shift, f->pix_fmt); if (f->version < 2) { - context_count = read_quant_tables(c, f->quant_tables[0]); + context_count = ff_ffv1_read_quant_tables(c, f->quant_tables[0]); if (context_count < 0) { av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); return AVERROR_INVALIDDATA; } f->slice_count = f->max_slice_count; } else if (f->version < 3) { - f->slice_count = get_symbol(c, state, 0); + f->slice_count = ff_ffv1_get_symbol(c, state, 0); } else { const uint8_t *p = c->bytestream_end; for (f->slice_count = 0; @@ -775,8 +542,8 @@ static int read_header(FFV1Context *f) return AVERROR_INVALIDDATA; } - ff_refstruct_unref(&f->slice_damaged); - f->slice_damaged = ff_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged)); + av_refstruct_unref(&f->slice_damaged); + f->slice_damaged = av_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged)); if (!f->slice_damaged) return AVERROR(ENOMEM); @@ -784,10 +551,10 @@ static int read_header(FFV1Context *f) FFV1SliceContext *sc = &f->slices[j]; if (f->version == 2) { - int sx = get_symbol(c, state, 0); - int sy = get_symbol(c, state, 0); - int sw = get_symbol(c, state, 0) + 1U; - int sh = get_symbol(c, state, 0) + 1U; + int sx = ff_ffv1_get_symbol(c, state, 0); + int sy = ff_ffv1_get_symbol(c, state, 0); + int sw = ff_ffv1_get_symbol(c, state, 0) + 1U; + int sh = ff_ffv1_get_symbol(c, state, 0) + 1U; if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0) return AVERROR_INVALIDDATA; @@ -805,7 +572,7 @@ static int read_header(FFV1Context *f) && (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height); } - ff_refstruct_unref(&sc->plane); + av_refstruct_unref(&sc->plane); sc->plane = ff_ffv1_planes_alloc(); if (!sc->plane) return AVERROR(ENOMEM); @@ -814,7 +581,7 @@ static int read_header(FFV1Context *f) PlaneContext *const p = &sc->plane[i]; if (f->version == 2) { - int idx = get_symbol(c, state, 0); + int idx = ff_ffv1_get_symbol(c, state, 0); if (idx >= (unsigned)f->quant_table_count) { av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n"); @@ -838,10 +605,13 @@ static av_cold int decode_init(AVCodecContext *avctx) FFV1Context *f = avctx->priv_data; int ret; - if ((ret = ff_ffv1_common_init(avctx)) < 0) + f->pix_fmt = AV_PIX_FMT_NONE; + f->configured_pix_fmt = AV_PIX_FMT_NONE; + + if ((ret = ff_ffv1_common_init(avctx, f)) < 0) return ret; - if (avctx->extradata_size > 0 && (ret = read_extra_header(f)) < 0) + if (avctx->extradata_size > 0 && (ret = ff_ffv1_read_extra_header(f)) < 0) return ret; if ((ret = ff_ffv1_init_slice_contexts(f)) < 0) @@ -850,31 +620,52 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } -static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, - int *got_frame, AVPacket *avpkt) +static int find_next_slice(AVCodecContext *avctx, + uint8_t *buf, uint8_t *buf_end, int idx, + uint8_t **pos, uint32_t *len) { - uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; - FFV1Context *f = avctx->priv_data; - RangeCoder *const c = &f->slices[0].c; - int ret, key_frame; + FFV1Context *f = avctx->priv_data; + + /* Length field */ + uint32_t v = buf_end - buf; + if (idx || f->version > 2) { + /* Three bytes of length, plus flush bit + CRC */ + uint32_t trailer = 3 + 5*!!f->ec; + if (trailer > buf_end - buf) + v = INT_MAX; + else + v = AV_RB24(buf_end - trailer) + trailer; + } + + if (buf_end - buf < v) { + av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n"); + ff_progress_frame_report(&f->picture, INT_MAX); + return AVERROR_INVALIDDATA; + } + + *len = v; + if (idx) + *pos = buf_end - v; + else + *pos = buf; + + return 0; +} + +static int decode_header(AVCodecContext *avctx, RangeCoder *c, + uint8_t *buf, size_t buf_size) +{ + int ret; + FFV1Context *f = avctx->priv_data; + uint8_t keystate = 128; - uint8_t *buf_p; - AVFrame *p; - - ff_progress_frame_unref(&f->last_picture); - FFSWAP(ProgressFrame, f->picture, f->last_picture); - - - f->avctx = avctx; - f->frame_damaged = 0; ff_init_range_decoder(c, buf, buf_size); ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8); if (get_rac(c, &keystate)) { - key_frame = AV_FRAME_FLAG_KEY; + f->key_frame = AV_FRAME_FLAG_KEY; f->key_frame_ok = 0; - if ((ret = read_header(f)) < 0) + if ((ret = read_header(f, c)) < 0) return ret; f->key_frame_ok = 1; } else { @@ -883,7 +674,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, "Cannot decode non-keyframe without valid keyframe\n"); return AVERROR_INVALIDDATA; } - key_frame = 0; + f->key_frame = 0; } if (f->ac != AC_GOLOMB_RICE) { @@ -902,51 +693,36 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, return AVERROR_INVALIDDATA; } - ret = ff_progress_frame_get_buffer(avctx, &f->picture, - AV_GET_BUFFER_FLAG_REF); - if (ret < 0) - return ret; + return 0; +} - p = f->picture.f; +static int decode_slices(AVCodecContext *avctx, RangeCoder c, + AVPacket *avpkt) +{ + FFV1Context *f = avctx->priv_data; + AVFrame *p = f->picture.f; - p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P - p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | key_frame; + uint8_t *buf = avpkt->data; + size_t buf_size = avpkt->size; + uint8_t *buf_end = buf + buf_size; - if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) { - /* we have interlaced material flagged in container */ - p->flags |= AV_FRAME_FLAG_INTERLACED; - if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) - p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; - } - - if (avctx->debug & FF_DEBUG_PICT_INFO) - av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n", - f->version, !!(p->flags & AV_FRAME_FLAG_KEY), f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample); - - ff_thread_finish_setup(avctx); - - buf_p = buf + buf_size; for (int i = f->slice_count - 1; i >= 0; i--) { FFV1SliceContext *sc = &f->slices[i]; - int trailer = 3 + 5*!!f->ec; - int v; + + uint8_t *pos; + uint32_t len; + int err = find_next_slice(avctx, buf, buf_end, i, + &pos, &len); + if (err < 0) + return err; + + buf_end -= len; sc->slice_damaged = 0; - if (i || f->version > 2) { - if (trailer > buf_p - buf) v = INT_MAX; - else v = AV_RB24(buf_p-trailer) + trailer; - } else v = buf_p - c->bytestream_start; - if (buf_p - c->bytestream_start < v) { - av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n"); - ff_progress_frame_report(&f->picture, INT_MAX); - return AVERROR_INVALIDDATA; - } - buf_p -= v; - if (f->ec) { - unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, buf_p, v); - if (crc) { + unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, pos, len); + if (crc != f->crcref) { int64_t ts = avpkt->pts != AV_NOPTS_VALUE ? avpkt->pts : avpkt->dts; av_log(f->avctx, AV_LOG_ERROR, "slice CRC mismatch %X!", crc); if (ts != AV_NOPTS_VALUE && avctx->pkt_timebase.num) { @@ -959,16 +735,17 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, slice_set_damaged(f, sc); } if (avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(avctx, AV_LOG_DEBUG, "slice %d, CRC: 0x%08"PRIX32"\n", i, AV_RB32(buf_p + v - 4)); + av_log(avctx, AV_LOG_DEBUG, "slice %d, CRC: 0x%08"PRIX32"\n", i, AV_RB32(pos + len - 4)); } } if (i) { - ff_init_range_decoder(&sc->c, buf_p, v); + ff_init_range_decoder(&sc->c, pos, len); ff_build_rac_states(&sc->c, 0.05 * (1LL << 32), 256 - 8); - } else - sc->c.bytestream_end = buf_p + v; - + } else { + sc->c = c; + sc->c.bytestream_end = pos + len; + } } avctx->execute(avctx, @@ -981,7 +758,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, for (int i = f->slice_count - 1; i >= 0; i--) { FFV1SliceContext *sc = &f->slices[i]; if (sc->slice_damaged && f->last_picture.f) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(f->pix_fmt); const uint8_t *src[4]; uint8_t *dst[4]; ff_progress_frame_await(&f->last_picture, INT_MAX); @@ -998,22 +775,125 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, av_image_copy(dst, p->linesize, src, f->last_picture.f->linesize, - avctx->pix_fmt, + f->pix_fmt, sc->slice_width, sc->slice_height); f->slice_damaged[i] = 1; } } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, + int *got_frame, AVPacket *avpkt) +{ + FFV1Context *f = avctx->priv_data; + int ret; + AVFrame *p; + const FFHWAccel *hwaccel = NULL; + + /* This is copied onto the first slice's range coder context */ + RangeCoder c; + + ff_progress_frame_unref(&f->last_picture); + av_refstruct_unref(&f->hwaccel_last_picture_private); + + FFSWAP(ProgressFrame, f->picture, f->last_picture); + FFSWAP(void *, f->hwaccel_picture_private, f->hwaccel_last_picture_private); + + f->avctx = avctx; + f->frame_damaged = 0; + + ret = decode_header(avctx, &c, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + + if (avctx->debug & FF_DEBUG_PICT_INFO) + av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n", + f->version, !!f->key_frame, f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample); + + if (avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + + if (avctx->hwaccel) + hwaccel = ffhwaccel(avctx->hwaccel); + + ret = ff_progress_frame_get_buffer(avctx, &f->picture, + AV_GET_BUFFER_FLAG_REF); + if (ret < 0) + return ret; + + ret = ff_hwaccel_frame_priv_alloc(avctx, &f->hwaccel_picture_private); + if (ret < 0) + return ret; + + p = f->picture.f; + + p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P + p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | f->key_frame; + + if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) { + /* we have interlaced material flagged in container */ + p->flags |= AV_FRAME_FLAG_INTERLACED; + if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) + p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + } + + /* Start */ + if (hwaccel) { + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + } + + ff_thread_finish_setup(avctx); + + /* Decode slices */ + if (hwaccel) { + uint8_t *buf_end = avpkt->data + avpkt->size; + + if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f) + ff_progress_frame_await(&f->last_picture, f->slice_count - 1); + + for (int i = f->slice_count - 1; i >= 0; i--) { + uint8_t *pos; + uint32_t len; + ret = find_next_slice(avctx, avpkt->data, buf_end, i, + &pos, &len); + if (ret < 0) + return ret; + + buf_end -= len; + + ret = hwaccel->decode_slice(avctx, pos, len); + if (ret < 0) + return ret; + } + } else { + ret = decode_slices(avctx, c, avpkt); + if (ret < 0) + return ret; + } + + /* Finalize */ + if (hwaccel) { + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + } + ff_progress_frame_report(&f->picture, INT_MAX); ff_progress_frame_unref(&f->last_picture); + av_refstruct_unref(&f->hwaccel_last_picture_private); if ((ret = av_frame_ref(rframe, f->picture.f)) < 0) return ret; *got_frame = 1; - return buf_size; + return avpkt->size; } #if HAVE_THREADS @@ -1027,6 +907,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) fdst->version = fsrc->version; fdst->micro_version = fsrc->micro_version; + fdst->combined_version = fsrc->combined_version; fdst->chroma_planes = fsrc->chroma_planes; fdst->chroma_h_shift = fsrc->chroma_h_shift; fdst->chroma_v_shift = fsrc->chroma_v_shift; @@ -1034,6 +915,8 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) fdst->plane_count = fsrc->plane_count; fdst->ac = fsrc->ac; fdst->colorspace = fsrc->colorspace; + fdst->pix_fmt = fsrc->pix_fmt; + fdst->configured_pix_fmt = fsrc->configured_pix_fmt; fdst->ec = fsrc->ec; fdst->intra = fsrc->intra; @@ -1054,7 +937,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) FFV1SliceContext *sc = &fdst->slices[i]; const FFV1SliceContext *sc0 = &fsrc->slices[i]; - ff_refstruct_replace(&sc->plane, sc0->plane); + av_refstruct_replace(&sc->plane, sc0->plane); if (fsrc->version < 3) { sc->slice_x = sc0->slice_x; @@ -1064,11 +947,13 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) } } - ff_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged); + av_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged); av_assert1(fdst->max_slice_count == fsrc->max_slice_count); ff_progress_frame_replace(&fdst->picture, &fsrc->picture); + av_refstruct_replace(&fdst->hwaccel_picture_private, + fsrc->hwaccel_picture_private); return 0; } @@ -1079,9 +964,14 @@ static av_cold int ffv1_decode_close(AVCodecContext *avctx) FFV1Context *const s = avctx->priv_data; ff_progress_frame_unref(&s->picture); - ff_progress_frame_unref(&s->last_picture); + av_refstruct_unref(&s->hwaccel_picture_private); - return ff_ffv1_close(avctx); + ff_progress_frame_unref(&s->last_picture); + av_refstruct_unref(&s->hwaccel_last_picture_private); + + ff_ffv1_close(s); + + return 0; } const FFCodec ff_ffv1_decoder = { @@ -1097,5 +987,12 @@ const FFCodec ff_ffv1_decoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_USES_PROGRESSFRAMES, + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_FFV1_VULKAN_HWACCEL + HWACCEL_VULKAN(ffv1), +#endif + NULL + }, }; diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index 2da6bd935d..b88195cfba 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -36,6 +36,12 @@ RENAME(decode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_mode = 0; int run_index = sc->run_index; + if (bits == 0) { + for (x = 0; x < w; x++) + sample[1][x] = 0; + return 0; + } + if (is_input_end(c, gb, ac)) return AVERROR_INVALIDDATA; @@ -138,10 +144,15 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int x, y, p; TYPE *sample[4][2]; int lbd = f->avctx->bits_per_raw_sample <= 8; - int bits = f->avctx->bits_per_raw_sample > 0 ? f->avctx->bits_per_raw_sample : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int ac = f->ac; + unsigned mask[4]; + + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, mask, f->avctx->bits_per_raw_sample); + + if (sc->slice_coding_mode == 1) + ac = 1; for (x = 0; x < 4; x++) { sample[x][0] = RENAME(sc->sample_buffer) + x * 2 * (w + 6) + 3; @@ -162,10 +173,10 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, sample[p][1][-1]= sample[p][0][0 ]; sample[p][0][ w]= sample[p][0][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, 9, ac); else - ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits + (sc->slice_coding_mode != 1), ac); + ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits[p], ac); if (ret < 0) return ret; } @@ -182,10 +193,31 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, b += g; r += g; } + if (sc->remap) { + if (f->avctx->bits_per_raw_sample == 32) { + g = sc->fltmap32[0][g & mask[0]]; + b = sc->fltmap32[1][b & mask[1]]; + r = sc->fltmap32[2][r & mask[2]]; + if (transparency) + a = sc->fltmap32[3][a & mask[3]]; + } else { + g = sc->fltmap[0][g & mask[0]]; + b = sc->fltmap[1][b & mask[1]]; + r = sc->fltmap[2][r & mask[2]]; + if (transparency) + a = sc->fltmap[3][a & mask[3]]; + } + } - if (lbd) + 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 || transparency) { + } else if (f->avctx->bits_per_raw_sample == 32) { + *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = g; + *((uint32_t*)(src[1] + x*4 + stride[1]*y)) = b; + *((uint32_t*)(src[2] + x*4 + stride[2]*y)) = r; + if (transparency) + *((uint32_t*)(src[3] + x*4 + stride[3]*y)) = a; + } 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; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index 1c37f61ada..97b38e4d16 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -31,6 +31,7 @@ #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/qsort.h" #include "avcodec.h" #include "encode.h" @@ -39,6 +40,7 @@ #include "put_golomb.h" #include "rangecoder.h" #include "ffv1.h" +#include "ffv1enc.h" static const int8_t quant5_10bit[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, @@ -198,7 +200,7 @@ static av_always_inline av_flatten void put_symbol_inline(RangeCoder *c, } while (0) if (v) { - const int a = FFABS(v); + const unsigned a = is_signed ? FFABS(v) : v; const int e = av_log2(a); put_rac(c, state + 0, 0); if (e <= 9) { @@ -248,7 +250,7 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state, i += i; } - av_assert2(k <= 13); + av_assert2(k <= 16); code = v ^ ((2 * state->drift + state->count) >> 31); @@ -271,15 +273,16 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state, static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, const uint8_t *src, int w, int h, - int stride, int plane_index, int pixel_stride) + int stride, int plane_index, int remap_index, int pixel_stride, int ac) { int x, y, i, ret; - const int ac = f->ac; const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); const int ring_size = f->context_model ? 3 : 2; int16_t *sample[3]; sc->run_index = 0; + sample[2] = sc->sample_buffer; // dummy to avoid UB pointer arithmetic + memset(sc->sample_buffer, 0, ring_size * (w + 6) * sizeof(*sc->sample_buffer)); for (y = 0; y < h; y++) { @@ -288,21 +291,30 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, sample[0][-1]= sample[1][0 ]; sample[1][ w]= sample[1][w-1]; + if (f->bits_per_raw_sample <= 8) { for (x = 0; x < w; x++) sample[0][x] = src[x * pixel_stride + stride * y]; + if (sc->remap) + for (x = 0; x < w; x++) + sample[0][x] = sc->fltmap[remap_index][ sample[0][x] ]; + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, 8, ac, pass1)) < 0) return ret; } else { if (f->packed_at_lsb) { for (x = 0; x < w; x++) { - sample[0][x] = ((uint16_t*)(src + stride*y))[x]; + sample[0][x] = ((uint16_t*)(src + stride*y))[x * pixel_stride]; } } else { for (x = 0; x < w; x++) { - sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample); + sample[0][x] = ((uint16_t*)(src + stride*y))[x * pixel_stride] >> (16 - f->bits_per_raw_sample); } } + if (sc->remap) + for (x = 0; x < w; x++) + sample[0][x] = sc->fltmap[remap_index][ (uint16_t)sample[0][x] ]; + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, f->bits_per_raw_sample, ac, pass1)) < 0) return ret; } @@ -310,6 +322,30 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc, return 0; } +static void load_plane(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src, int w, int h, + int stride, int remap_index, int pixel_stride) +{ + int x, y; + + memset(sc->fltmap[remap_index], 0, 65536 * sizeof(*sc->fltmap[remap_index])); + + for (y = 0; y < h; y++) { + if (f->bits_per_raw_sample <= 8) { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ src[x * pixel_stride + stride * y] ] = 1; + } else { + if (f->packed_at_lsb) { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ ((uint16_t*)(src + stride*y))[x * pixel_stride] ] = 1; + } else { + for (x = 0; x < w; x++) + sc->fltmap[remap_index][ ((uint16_t*)(src + stride*y))[x * pixel_stride] >> (16 - f->bits_per_raw_sample) ] = 1; + } + } + } +} + static void write_quant_table(RangeCoder *c, int16_t *quant_table) { int last = 0; @@ -317,7 +353,7 @@ static void write_quant_table(RangeCoder *c, int16_t *quant_table) uint8_t state[CONTEXT_SIZE]; memset(state, 128, sizeof(state)); - for (i = 1; i < 128; i++) + for (i = 1; i < MAX_QUANT_TABLE_SIZE/2; i++) if (quant_table[i] != quant_table[i - 1]) { put_symbol(c, state, i - last - 1, 0); last = i; @@ -326,7 +362,7 @@ static void write_quant_table(RangeCoder *c, int16_t *quant_table) } static void write_quant_tables(RangeCoder *c, - int16_t quant_table[MAX_CONTEXT_INPUTS][256]) + int16_t quant_table[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE]) { int i; for (i = 0; i < 5; i++) @@ -392,8 +428,26 @@ static void write_header(FFV1Context *f) } } -static int write_extradata(FFV1Context *f) +static void set_micro_version(FFV1Context *f) { + f->combined_version = f->version << 16; + if (f->version > 2) { + if (f->version == 3) { + f->micro_version = 4; + } else if (f->version == 4) { + f->micro_version = 8; + } else + av_assert0(0); + + f->combined_version += f->micro_version; + } else + av_assert0(f->micro_version == 0); +} + +av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx) +{ + FFV1Context *f = avctx->priv_data; + RangeCoder c; uint8_t state[CONTEXT_SIZE]; int i, j, k; @@ -412,13 +466,8 @@ static int write_extradata(FFV1Context *f) ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); put_symbol(&c, state, f->version, 0); - if (f->version > 2) { - if (f->version == 3) { - f->micro_version = 4; - } else if (f->version == 4) - f->micro_version = 2; + if (f->version > 2) put_symbol(&c, state, f->micro_version, 0); - } put_symbol(&c, state, f->ac, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) @@ -458,7 +507,7 @@ static int write_extradata(FFV1Context *f) } f->avctx->extradata_size = ff_rac_terminate(&c, 0); - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, f->avctx->extradata, f->avctx->extradata_size); + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, f->avctx->extradata, f->avctx->extradata_size) ^ (f->crcref ? 0x8CD88196 : 0); AV_WL32(f->avctx->extradata + f->avctx->extradata_size, v); f->avctx->extradata_size += 4; @@ -513,21 +562,56 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256]) return print; } -static av_cold int encode_init(AVCodecContext *avctx) + +int ff_ffv1_encode_determine_slices(AVCodecContext *avctx) +{ + FFV1Context *s = avctx->priv_data; + int plane_count = 1 + 2*s->chroma_planes + s->transparency; + int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift); + int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift); + s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1; + s->num_v_slices = FFMIN(s->num_v_slices, max_v_slices); + for (; s->num_v_slices <= 32; s->num_v_slices++) { + for (s->num_h_slices = s->num_v_slices; s->num_h_slices <= 2*s->num_v_slices; s->num_h_slices++) { + int maxw = (avctx->width + s->num_h_slices - 1) / s->num_h_slices; + int maxh = (avctx->height + s->num_v_slices - 1) / s->num_v_slices; + if (s->num_h_slices > max_h_slices || s->num_v_slices > max_v_slices) + continue; + if (maxw * maxh * (int64_t)(s->bits_per_raw_sample+1) * plane_count > 8<<24) + continue; + if (s->version < 4) + if ( ff_need_new_slices(avctx->width , s->num_h_slices, s->chroma_h_shift) + ||ff_need_new_slices(avctx->height, s->num_v_slices, s->chroma_v_shift)) + continue; + if (avctx->slices == s->num_h_slices * s->num_v_slices && avctx->slices <= MAX_SLICES) + return 0; + if (maxw*maxh > 360*288) + continue; + if (!avctx->slices) + return 0; + } + } + av_log(avctx, AV_LOG_ERROR, + "Unsupported number %d of slices requested, please specify a " + "supported number with -slices (ex:4,6,9,12,16, ...)\n", + avctx->slices); + return AVERROR(ENOSYS); +} + +av_cold int ff_ffv1_encode_init(AVCodecContext *avctx) { FFV1Context *s = avctx->priv_data; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); int i, j, k, m, ret; - if ((ret = ff_ffv1_common_init(avctx)) < 0) - return ret; - - s->version = 0; - if ((avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) || avctx->slices > 1) s->version = FFMAX(s->version, 2); + if ((avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) && s->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_ERROR, "2 Pass mode is not possible with golomb coding\n"); + return AVERROR(EINVAL); + } + // Unspecified level & slices, we choose version 1.2+ to ensure multithreaded decodability if (avctx->slices == 0 && avctx->level < 0 && avctx->width * avctx->height > 720*576) s->version = FFMAX(s->version, 2); @@ -541,168 +625,31 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } s->version = avctx->level; - } + } else if (s->version < 3) + s->version = 3; if (s->ec < 0) { - s->ec = (s->version >= 3); + if (s->version >= 4) { + s->ec = 2; + } else if (s->version >= 3) { + s->ec = 1; + } else + s->ec = 0; } // CRC requires version 3+ - if (s->ec) + if (s->ec == 1) s->version = FFMAX(s->version, 3); + if (s->ec == 2) { + s->version = FFMAX(s->version, 4); + s->crcref = 0x7a8c4079; + } if ((s->version == 2 || s->version>3) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "Version 2 needed for requested features but version 2 is experimental and not enabled\n"); + av_log(avctx, AV_LOG_ERROR, "Version 2 or 4 needed for requested features but version 2 or 4 is experimental and not enabled\n"); return AVERROR_INVALIDDATA; } - if (s->ac == 1) // Compatbility with common command line usage - s->ac = AC_RANGE_CUSTOM_TAB; - else if (s->ac == AC_RANGE_DEFAULT_TAB_FORCE) - s->ac = AC_RANGE_DEFAULT_TAB; - - 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: - case AV_PIX_FMT_YUVA444P9: - case AV_PIX_FMT_YUVA422P9: - case AV_PIX_FMT_YUVA420P9: - if (!avctx->bits_per_raw_sample) - 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: - case AV_PIX_FMT_YUVA422P10: - case AV_PIX_FMT_YUVA420P10: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - 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: - case AV_PIX_FMT_YUVA444P12: - case AV_PIX_FMT_YUVA422P12: - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 12; - case AV_PIX_FMT_GRAY14: - 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: - case AV_PIX_FMT_YUV420P16: - case AV_PIX_FMT_YUVA444P16: - case AV_PIX_FMT_YUVA422P16: - case AV_PIX_FMT_YUVA420P16: - 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; - } - if (s->bits_per_raw_sample <= 8) { - av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample invalid\n"); - return AVERROR_INVALIDDATA; - } - s->version = FFMAX(s->version, 1); - case AV_PIX_FMT_GRAY8: - case AV_PIX_FMT_YA8: - case AV_PIX_FMT_YUV444P: - case AV_PIX_FMT_YUV440P: - case AV_PIX_FMT_YUV422P: - case AV_PIX_FMT_YUV420P: - case AV_PIX_FMT_YUV411P: - case AV_PIX_FMT_YUV410P: - case AV_PIX_FMT_YUVA444P: - case AV_PIX_FMT_YUVA422P: - case AV_PIX_FMT_YUVA420P: - s->chroma_planes = desc->nb_components < 3 ? 0 : 1; - s->colorspace = 0; - s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); - if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) - s->bits_per_raw_sample = 8; - else if (!s->bits_per_raw_sample) - s->bits_per_raw_sample = 8; - break; - case AV_PIX_FMT_RGB32: - s->colorspace = 1; - s->transparency = 1; - 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); - break; - case AV_PIX_FMT_0RGB32: - s->colorspace = 1; - s->chroma_planes = 1; - s->bits_per_raw_sample = 8; - break; - case AV_PIX_FMT_GBRP9: - 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: - case AV_PIX_FMT_GBRAP14: - 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->flags & AV_PIX_FMT_FLAG_ALPHA); - s->colorspace = 1; - s->chroma_planes = 1; - if (s->bits_per_raw_sample >= 16) { - s->use32bit = 1; - } - s->version = FFMAX(s->version, 1); - break; - default: - av_log(avctx, AV_LOG_ERROR, "format not supported\n"); - return AVERROR(ENOSYS); - } - av_assert0(s->bits_per_raw_sample >= 8); - - if (s->bits_per_raw_sample > 8) { - if (s->ac == AC_GOLOMB_RICE) { - av_log(avctx, AV_LOG_INFO, - "bits_per_raw_sample > 8, forcing range coder\n"); - s->ac = AC_RANGE_CUSTOM_TAB; - } - } - if (s->ac == AC_RANGE_CUSTOM_TAB) { for (i = 1; i < 256; i++) s->state_transition[i] = ver2_state[i]; @@ -715,7 +662,7 @@ static av_cold int encode_init(AVCodecContext *avctx) for (i = 0; i < 256; i++) { s->quant_table_count = 2; - if (s->bits_per_raw_sample <= 8) { + if ((s->qtable == -1 && s->bits_per_raw_sample <= 8) || s->qtable == 1) { s->quant_tables[0][0][i]= quant11[i]; s->quant_tables[0][1][i]= 11*quant11[i]; s->quant_tables[0][2][i]= 11*11*quant11[i]; @@ -724,19 +671,21 @@ static av_cold int encode_init(AVCodecContext *avctx) s->quant_tables[1][2][i]= 11*11*quant5 [i]; s->quant_tables[1][3][i]= 5*11*11*quant5 [i]; s->quant_tables[1][4][i]= 5*5*11*11*quant5 [i]; + s->context_count[0] = (11 * 11 * 11 + 1) / 2; + s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2; } else { s->quant_tables[0][0][i]= quant9_10bit[i]; - s->quant_tables[0][1][i]= 11*quant9_10bit[i]; - s->quant_tables[0][2][i]= 11*11*quant9_10bit[i]; + s->quant_tables[0][1][i]= 9*quant9_10bit[i]; + s->quant_tables[0][2][i]= 9*9*quant9_10bit[i]; s->quant_tables[1][0][i]= quant9_10bit[i]; - s->quant_tables[1][1][i]= 11*quant9_10bit[i]; - s->quant_tables[1][2][i]= 11*11*quant5_10bit[i]; - s->quant_tables[1][3][i]= 5*11*11*quant5_10bit[i]; - s->quant_tables[1][4][i]= 5*5*11*11*quant5_10bit[i]; + s->quant_tables[1][1][i]= 9*quant9_10bit[i]; + s->quant_tables[1][2][i]= 9*9*quant5_10bit[i]; + s->quant_tables[1][3][i]= 5*9*9*quant5_10bit[i]; + s->quant_tables[1][4][i]= 5*5*9*9*quant5_10bit[i]; + s->context_count[0] = (9 * 9 * 9 + 1) / 2; + s->context_count[1] = (9 * 9 * 5 * 5 * 5 + 1) / 2; } } - s->context_count[0] = (11 * 11 * 11 + 1) / 2; - s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2; if ((ret = ff_ffv1_allocate_initial_states(s)) < 0) return ret; @@ -746,10 +695,6 @@ static av_cold int encode_init(AVCodecContext *avctx) if (!s->chroma_planes && s->version > 3) s->plane_count--; - 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)) { @@ -842,33 +787,225 @@ static av_cold int encode_init(AVCodecContext *avctx) av_freep(&best_state); } - if (s->version > 1) { - int plane_count = 1 + 2*s->chroma_planes + s->transparency; - int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift); - int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift); - s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1; + if (s->version <= 1) { + /* Disable slices when the version doesn't support them */ + s->num_h_slices = 1; + s->num_v_slices = 1; + } - s->num_v_slices = FFMIN(s->num_v_slices, max_v_slices); + set_micro_version(s); - for (; s->num_v_slices < 32; s->num_v_slices++) { - for (s->num_h_slices = s->num_v_slices; s->num_h_slices < 2*s->num_v_slices; s->num_h_slices++) { - int maxw = (avctx->width + s->num_h_slices - 1) / s->num_h_slices; - int maxh = (avctx->height + s->num_v_slices - 1) / s->num_v_slices; - if (s->num_h_slices > max_h_slices || s->num_v_slices > max_v_slices) - continue; - if (maxw * maxh * (int64_t)(s->bits_per_raw_sample+1) * plane_count > 8<<24) - continue; - if (avctx->slices == s->num_h_slices * s->num_v_slices && avctx->slices <= MAX_SLICES || !avctx->slices) - goto slices_ok; - } + return 0; +} + +av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt) +{ + FFV1Context *s = avctx->priv_data; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + + s->plane_count = 3; + switch(pix_fmt) { + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_YUV444P9: + case AV_PIX_FMT_YUV422P9: + case AV_PIX_FMT_YUV420P9: + case AV_PIX_FMT_YUVA444P9: + case AV_PIX_FMT_YUVA422P9: + case AV_PIX_FMT_YUVA420P9: + if (!avctx->bits_per_raw_sample) + 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: + case AV_PIX_FMT_YUVA422P10: + case AV_PIX_FMT_YUVA420P10: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + 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: + case AV_PIX_FMT_YUVA444P12: + case AV_PIX_FMT_YUVA422P12: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 12; + case AV_PIX_FMT_GRAY14: + 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_P016: + case AV_PIX_FMT_P216: + case AV_PIX_FMT_P416: + case AV_PIX_FMT_YUV444P16: + case AV_PIX_FMT_YUV422P16: + case AV_PIX_FMT_YUV420P16: + case AV_PIX_FMT_YUVA444P16: + case AV_PIX_FMT_YUVA422P16: + case AV_PIX_FMT_YUVA420P16: + case AV_PIX_FMT_GRAYF16: + case AV_PIX_FMT_YAF16: + 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; } - av_log(avctx, AV_LOG_ERROR, - "Unsupported number %d of slices requested, please specify a " - "supported number with -slices (ex:4,6,9,12,16, ...)\n", - avctx->slices); + if (s->bits_per_raw_sample <= 8) { + av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample invalid\n"); + return AVERROR_INVALIDDATA; + } + s->version = FFMAX(s->version, 1); + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_YA8: + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV16: + case AV_PIX_FMT_NV24: + case AV_PIX_FMT_YUV444P: + case AV_PIX_FMT_YUV440P: + case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV411P: + case AV_PIX_FMT_YUV410P: + case AV_PIX_FMT_YUVA444P: + case AV_PIX_FMT_YUVA422P: + case AV_PIX_FMT_YUVA420P: + s->chroma_planes = desc->nb_components < 3 ? 0 : 1; + s->colorspace = 0; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 8; + else if (!s->bits_per_raw_sample) + s->bits_per_raw_sample = 8; + break; + case AV_PIX_FMT_RGB32: + s->colorspace = 1; + s->transparency = 1; + 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); + break; + case AV_PIX_FMT_0RGB32: + s->colorspace = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 8; + break; + case AV_PIX_FMT_GBRP9: + 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: + case AV_PIX_FMT_GBRAP14: + 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: + case AV_PIX_FMT_GBRPF16: + case AV_PIX_FMT_GBRAPF16: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 16; + case AV_PIX_FMT_GBRPF32: + case AV_PIX_FMT_GBRAPF32: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 32; + else if (!s->bits_per_raw_sample) + s->bits_per_raw_sample = avctx->bits_per_raw_sample; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); + s->colorspace = 1; + s->chroma_planes = 1; + if (s->bits_per_raw_sample >= 16) { + s->use32bit = 1; + } + s->version = FFMAX(s->version, 1); + break; + default: + av_log(avctx, AV_LOG_ERROR, "format %s not supported\n", + av_get_pix_fmt_name(pix_fmt)); return AVERROR(ENOSYS); -slices_ok: - if ((ret = write_extradata(s)) < 0) + } + s->flt = !!(desc->flags & AV_PIX_FMT_FLAG_FLOAT); + if (s->flt || s->remap_mode > 0) + s->version = FFMAX(s->version, 4); + av_assert0(s->bits_per_raw_sample >= 8); + + if (s->remap_mode < 0) + s->remap_mode = s->flt ? 2 : 0; + if (s->remap_mode == 0 && s->bits_per_raw_sample == 32) { + av_log(avctx, AV_LOG_ERROR, "32bit requires remap\n"); + return AVERROR(EINVAL); + } + if (s->remap_mode == 2 && + !((s->bits_per_raw_sample == 16 || s->bits_per_raw_sample == 32 || s->bits_per_raw_sample == 64) && s->flt)) { + av_log(avctx, AV_LOG_ERROR, "remap 2 is for float16/32/64 only\n"); + return AVERROR(EINVAL); + } + + return av_pix_fmt_get_chroma_sub_sample(pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); +} + +static av_cold int encode_init_internal(AVCodecContext *avctx) +{ + int ret; + FFV1Context *s = avctx->priv_data; + + if ((ret = ff_ffv1_common_init(avctx, s)) < 0) + return ret; + + if (s->ac == 1) // Compatibility with common command line usage + s->ac = AC_RANGE_CUSTOM_TAB; + else if (s->ac == AC_RANGE_DEFAULT_TAB_FORCE) + s->ac = AC_RANGE_DEFAULT_TAB; + + ret = ff_ffv1_encode_setup_plane_info(avctx, avctx->pix_fmt); + if (ret < 0) + return ret; + + if (s->bits_per_raw_sample > (s->version > 3 ? 16 : 8) && !s->remap_mode) { + if (s->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_INFO, + "high bits_per_raw_sample, forcing range coder\n"); + s->ac = AC_RANGE_CUSTOM_TAB; + } + } + + + ret = ff_ffv1_encode_init(avctx); + if (ret < 0) + return ret; + + if (s->version > 1) { + if ((ret = ff_ffv1_encode_determine_slices(avctx)) < 0) + return ret; + + if ((ret = ff_ffv1_write_extradata(avctx)) < 0) return ret; } @@ -877,14 +1014,35 @@ slices_ok: s->slice_count = s->max_slice_count; for (int j = 0; j < s->slice_count; j++) { + FFV1SliceContext *sc = &s->slices[j]; + for (int i = 0; i < s->plane_count; i++) { PlaneContext *const p = &s->slices[j].plane[i]; p->quant_table_index = s->context_model; p->context_count = s->context_count[p->quant_table_index]; } + av_assert0(s->remap_mode >= 0); + if (s->remap_mode) { + for (int p = 0; p < 1 + 2*s->chroma_planes + s->transparency ; p++) { + if (s->bits_per_raw_sample == 32) { + sc->unit[p] = av_malloc_array(sc->slice_width, sc->slice_height * sizeof(**sc->unit)); + if (!sc->unit[p]) + return AVERROR(ENOMEM); + sc->bitmap[p] = av_malloc_array(sc->slice_width * sc->slice_height, sizeof(*sc->bitmap[p])); + if (!sc->bitmap[p]) + return AVERROR(ENOMEM); + } else { + sc->fltmap[p] = av_malloc_array(65536, sizeof(*sc->fltmap[p])); + if (!sc->fltmap[p]) + return AVERROR(ENOMEM); + } + } + } ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8); + + s->slices[j].remap = s->remap_mode; } if ((ret = ff_ffv1_init_slices_state(s)) < 0) @@ -895,8 +1053,8 @@ slices_ok: avctx->stats_out = av_mallocz(STATS_OUT_SIZE); if (!avctx->stats_out) return AVERROR(ENOMEM); - for (i = 0; i < s->quant_table_count; i++) - for (j = 0; j < s->max_slice_count; j++) { + for (int i = 0; i < s->quant_table_count; i++) + for (int j = 0; j < s->max_slice_count; j++) { FFV1SliceContext *sc = &s->slices[j]; av_assert0(!sc->rc_stat2[i]); sc->rc_stat2[i] = av_mallocz(s->context_count[i] * @@ -916,10 +1074,10 @@ static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) int j; memset(state, 128, sizeof(state)); - put_symbol(c, state, (sc->slice_x +1)*f->num_h_slices / f->width , 0); - put_symbol(c, state, (sc->slice_y +1)*f->num_v_slices / f->height , 0); - put_symbol(c, state, (sc->slice_width +1)*f->num_h_slices / f->width -1, 0); - put_symbol(c, state, (sc->slice_height+1)*f->num_v_slices / f->height-1, 0); + put_symbol(c, state, sc->sx, 0); + put_symbol(c, state, sc->sy, 0); + put_symbol(c, state, 0, 0); + put_symbol(c, state, 0, 0); for (j=0; jplane_count; j++) { put_symbol(c, state, sc->plane[j].quant_table_index, 0); av_assert0(sc->plane[j].quant_table_index == f->context_model); @@ -935,10 +1093,11 @@ static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) if (sc->slice_coding_mode == 1) ff_ffv1_clear_slice_state(f, sc); put_symbol(c, state, sc->slice_coding_mode, 0); - if (sc->slice_coding_mode != 1) { + if (sc->slice_coding_mode != 1 && f->colorspace == 1) { put_symbol(c, state, sc->slice_rct_by_coef, 0); put_symbol(c, state, sc->slice_rct_ry_coef, 0); } + put_symbol(c, state, sc->remap, 0); } } @@ -969,6 +1128,9 @@ static void choose_rct_params(const FFV1Context *f, FFV1SliceContext *sc, int x, y, i, p, best; int16_t *sample[3]; int lbd = f->bits_per_raw_sample <= 8; + int packed = !src[1]; + int transparency = f->transparency; + int packed_size = (3 + transparency)*2; for (y = 0; y < h; y++) { int lastr=0, lastg=0, lastb=0; @@ -983,6 +1145,15 @@ static void choose_rct_params(const FFV1Context *f, FFV1SliceContext *sc, b = v & 0xFF; g = (v >> 8) & 0xFF; r = (v >> 16) & 0xFF; + } else if (packed) { + 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 (f->use32bit || 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)); } else { b = *((const uint16_t*)(src[0] + x*2 + stride[0]*y)); g = *((const uint16_t*)(src[1] + x*2 + stride[1]*y)); @@ -1025,6 +1196,367 @@ static void choose_rct_params(const FFV1Context *f, FFV1SliceContext *sc, sc->slice_rct_ry_coef = rct_y_coeff[best][0]; } +static void encode_histogram_remap(FFV1Context *f, FFV1SliceContext *sc) +{ + int len = 1 << f->bits_per_raw_sample; + int flip = sc->remap == 2 ? 0x7FFF : 0; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2][32]; + int run = 0; + + memset(state, 128, sizeof(state)); + put_symbol(&sc->c, state[0], 0, 0); + memset(state, 128, sizeof(state)); + for (int i= 0; ifltmap[p][ri]; + sc->fltmap[p][ri] = j; + j+= u; + + if (lu == u) { + run ++; + } else { + put_symbol_inline(&sc->c, state[lu], run, 0, NULL, NULL); + if (run == 0) + lu = u; + run = 0; + } + } + if (run) + put_symbol(&sc->c, state[lu], run, 0); + sc->remap_count[p] = j; + } +} + +static void load_rgb_float32_frame(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], + int w, int h, const int stride[4]) +{ + int x, y; + int transparency = f->transparency; + int i = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + + g = *((const uint32_t *)(src[0] + x*4 + stride[0]*y)); + b = *((const uint32_t *)(src[1] + x*4 + stride[1]*y)); + r = *((const uint32_t *)(src[2] + x*4 + stride[2]*y)); + if (transparency) + a = *((const uint32_t *)(src[3] + x*4 + stride[3]*y)); + + if (sc->remap == 2) { +#define FLIP(f) (((f)&0x80000000) ? (f) : (f)^0x7FFFFFFF); + g = FLIP(g); + b = FLIP(b); + r = FLIP(r); + } + // We cannot build a histogram as we do for 16bit, we need a bit of magic here + // Its possible to reduce the memory needed at the cost of more dereferencing + sc->unit[0][i].val = g; + sc->unit[0][i].ndx = x + y*w; + + sc->unit[1][i].val = b; + sc->unit[1][i].ndx = x + y*w; + + sc->unit[2][i].val = r; + sc->unit[2][i].ndx = x + y*w; + + if (transparency) { + sc->unit[3][i].val = a; + sc->unit[3][i].ndx = x + y*w; + } + i++; + } + } + + //TODO switch to radix sort +#define CMP(A,B) ((A)->val - (int64_t)(B)->val) + AV_QSORT(sc->unit[0], i, struct Unit, CMP); + AV_QSORT(sc->unit[1], i, struct Unit, CMP); + AV_QSORT(sc->unit[2], i, struct Unit, CMP); + if (transparency) + AV_QSORT(sc->unit[3], i, struct Unit, CMP); +} + +static int encode_float32_remap_segment(FFV1SliceContext *sc, + int p, int mul_count, int *mul_tab, int update, int final) +{ + const int pixel_num = sc->slice_width * sc->slice_height; + uint8_t state[2][3][32]; + int mul[4096+1]; + RangeCoder rc = sc->c; + int lu = 0; + int run = 0; + int64_t last_val = -1; + int compact_index = -1; + int i = 0; + int current_mul_index = -1; + int run1final = 0; + int run1start_i; + int run1start_last_val; + int run1start_mul_index; + + memcpy(mul, mul_tab, sizeof(*mul_tab)*(mul_count+1)); + memset(state, 128, sizeof(state)); + put_symbol(&rc, state[0][0], mul_count, 0); + memset(state, 128, sizeof(state)); + + for (; i < pixel_num+1; i++) { + int current_mul = current_mul_index < 0 ? 1 : FFABS(mul[current_mul_index]); + int64_t val; + if (i == pixel_num) { + if (last_val == 0xFFFFFFFF) { + break; + } else { + val = last_val + ((1LL<<32) - last_val + current_mul - 1) / current_mul * current_mul; + av_assert2(val >= (1LL<<32)); + val += lu * current_mul; //ensure a run1 ends + } + } else + val = sc->unit[p][i].val; + + if (last_val != val) { + int64_t delta = val - last_val; + int64_t step = FFMAX(1, (delta + current_mul/2) / current_mul); + av_assert2(last_val < val); + av_assert2(current_mul > 0); + + delta -= step*current_mul; + av_assert2(delta <= current_mul/2); + av_assert2(delta > -current_mul); + + av_assert2(step > 0); + if (lu) { + if (!run) { + run1start_i = i - 1; + run1start_last_val = last_val; + run1start_mul_index= current_mul_index; + } + if (step == 1) { + if (run1final) { + if (current_mul>1) + put_symbol_inline(&rc, state[lu][1], delta, 1, NULL, NULL); + } + run ++; + av_assert2(last_val + current_mul + delta == val); + } else { + if (run1final) { + if (run == 0) + lu ^= 1; + i--; // we did not encode val so we need to backstep + last_val += current_mul; + } else { + put_symbol_inline(&rc, state[lu][0], run, 0, NULL, NULL); + i = run1start_i; + last_val = run1start_last_val; // we could compute this instead of storing + current_mul_index = run1start_mul_index; + } + run1final ^= 1; + + run = 0; + continue; + } + } else { + av_assert2(run == 0); + av_assert2(run1final == 0); + put_symbol_inline(&rc, state[lu][0], step - 1, 0, NULL, NULL); + + if (current_mul > 1) + put_symbol_inline(&rc, state[lu][1], delta, 1, NULL, NULL); + if (step == 1) + lu ^= 1; + + av_assert2(last_val + step * current_mul + delta == val); + } + last_val = val; + current_mul_index = ((last_val + 1) * mul_count) >> 32; + if (!run || run1final) { + av_assert2(mul[ current_mul_index ]); + if (mul[ current_mul_index ] < 0) { + av_assert2(i < pixel_num); + mul[ current_mul_index ] *= -1; + put_symbol_inline(&rc, state[0][2], mul[ current_mul_index ], 0, NULL, NULL); + } + if (i < pixel_num) + compact_index ++; + } + } + if (!run || run1final) + if (final && i < pixel_num) + sc->bitmap[p][sc->unit[p][i].ndx] = compact_index; + } + + if (update) { + sc->c = rc; + sc->remap_count[p] = compact_index + 1; + } + return get_rac_count(&rc); +} + +static void encode_float32_remap(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4]) +{ + int pixel_num = sc->slice_width * sc->slice_height; + const int max_log2_mul_count = ((int[]){ 1, 1, 1, 9, 9, 10})[f->remap_optimizer]; + const int log2_mul_count_step = ((int[]){ 1, 1, 1, 9, 9, 1})[f->remap_optimizer]; + const int max_log2_mul = ((int[]){ 1, 8, 8, 9, 22, 22})[f->remap_optimizer]; + const int log2_mul_step = ((int[]){ 1, 8, 1, 1, 1, 1})[f->remap_optimizer]; + const int bruteforce_count = ((int[]){ 0, 0, 0, 1, 1, 1})[f->remap_optimizer]; + const int stair_mode = ((int[]){ 0, 0, 0, 1, 0, 0})[f->remap_optimizer]; + const int magic_log2 = ((int[]){ 1, 1, 1, 1, 0, 0})[f->remap_optimizer]; + + for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) { + int best_log2_mul_count = 0; + float score_sum[11] = {0}; + int mul_all[11][1025]; + + for (int log2_mul_count= 0; log2_mul_count <= max_log2_mul_count; log2_mul_count += log2_mul_count_step) { + float score_tab_all[1025][23] = {0}; + int64_t last_val = -1; + int *mul_tab = mul_all[log2_mul_count]; + int last_mul_index = -1; + int mul_count = 1 << log2_mul_count; + + score_sum[log2_mul_count] = 2 * log2_mul_count; + if (magic_log2) + score_sum[log2_mul_count] = av_float2int((float)mul_count * mul_count); + for (int i= 0; iunit[p][i].val; + int mul_index = (val + 1LL)*mul_count >> 32; + if (val != last_val) { + float *score_tab = score_tab_all[(last_val + 1LL)*mul_count >> 32]; + av_assert2(last_val < val); + for(int si= 0; si <= max_log2_mul; si += log2_mul_step) { + int64_t delta = val - last_val; + int mul; + int64_t cost; + + if (last_val < 0) { + mul = 1; + } else if (stair_mode && mul_count == 512 && si == max_log2_mul ) { + if (mul_index >= 0x378/8 && mul_index <= 23 + 0x378/8) { + mul = (0x800080 >> (mul_index - 0x378/8)); + } else + mul = 1; + } else { + mul = (0x10001LL)<> 16; + } + + cost = FFMAX((delta + mul/2) / mul, 1); + float score = 1; + if (mul > 1) { + score *= (FFABS(delta - cost*mul)+1); + if (mul_count > 1) + score *= score; + } + score *= cost; + score *= score; + if (mul_index != last_mul_index) + score *= mul; + if (magic_log2) { + score_tab[si] += av_float2int(score); + } else + score_tab[si] += log2f(score); + } + } + last_val = val; + last_mul_index = mul_index; + } + for(int i= 0; i= 0x378/8 && i <= 23 + 0x378/8) { + mul_tab[i] = -(0x800080 >> (i - 0x378/8)); + } else + mul_tab[i] = -1; + } else + mul_tab[i] = -((0x10001LL)<> 16); + score_sum[log2_mul_count] += score_tab[ best_index ]; + } + mul_tab[mul_count] = 1; + + if (bruteforce_count) + score_sum[log2_mul_count] = encode_float32_remap_segment(sc, p, mul_count, mul_all[log2_mul_count], 0, 0); + + if (score_sum[log2_mul_count] < score_sum[best_log2_mul_count]) + best_log2_mul_count = log2_mul_count; + } + + encode_float32_remap_segment(sc, p, 1<context_model ? 3 : 2; + int32_t *sample[4][3]; + const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); + int bits[4], offset; + int transparency = f->transparency; + + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + + sc->run_index = 0; + + for (int p = 0; p < MAX_PLANES; ++p) + sample[p][2] = sc->sample_buffer32; // dummy to avoid UB pointer arithmetic + + memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * + (w + 6) * sizeof(*RENAME(sc->sample_buffer))); + + for (y = 0; y < h; y++) { + for (i = 0; i < ring_size; i++) + for (p = 0; p < MAX_PLANES; p++) + sample[p][i]= RENAME(sc->sample_buffer) + p*ring_size*(w+6) + ((h+i-y)%ring_size)*(w+6) + 3; + + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + g = sc->bitmap[0][x + w*y]; + b = sc->bitmap[1][x + w*y]; + r = sc->bitmap[2][x + w*y]; + if (transparency) + a = sc->bitmap[3][x + w*y]; + + if (sc->slice_coding_mode != 1) { + b -= g; + r -= g; + g += (b * sc->slice_rct_by_coef + r * sc->slice_rct_ry_coef) >> 2; + b += offset; + r += offset; + } + + sample[0][0][x] = g; + sample[1][0][x] = b; + sample[2][0][x] = r; + sample[3][0][x] = a; + } + 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]; + ret = encode_line32(f, sc, f->avctx, w, sample[p], (p + 1) / 2, + bits[p], ac, pass1); + if (ret < 0) + return ret; + } + } + return 0; +} + + static int encode_slice(AVCodecContext *c, void *arg) { FFV1SliceContext *sc = arg; @@ -1037,13 +1569,16 @@ 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 = sc->c; + const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift); + const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); 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[3] ? p->data[3] + ps*x + y*p->linesize[3] : NULL}; + int ac = f->ac; sc->slice_coding_mode = 0; - if (f->version > 3) { + if (f->version > 3 && f->colorspace == 1) { choose_rct_params(f, sc, planes, p->linesize, width, height); } else { sc->slice_rct_by_coef = 1; @@ -1056,43 +1591,87 @@ retry: if (f->version > 2) { encode_slice_header(f, sc); } - if (f->ac == AC_GOLOMB_RICE) { + + if (sc->remap) { + //Both the 16bit and 32bit remap do exactly the same thing but with 16bits we can + //Implement this using a "histogram" while for 32bit that would be gb sized, thus a more + //complex implementation sorting pairs is used. + if (f->bits_per_raw_sample != 32) { + if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8 && c->pix_fmt != AV_PIX_FMT_YAF16) { + const int cx = x >> f->chroma_h_shift; + const int cy = y >> f->chroma_v_shift; + + //TODO decide on the order for the encoded remaps and loads. with golomb rice it + // easier to have all range coded ones together, otherwise it may be nicer to handle each plane as a whole? + + load_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + + if (f->chroma_planes) { + load_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); + load_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 2, 1); + } + if (f->transparency) + load_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 3, 1); + } else if (c->pix_fmt == AV_PIX_FMT_YA8 || c->pix_fmt == AV_PIX_FMT_YAF16) { + load_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2); + load_plane(f, sc, p->data[0] + (ps>>1) + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2); + } else if (f->use32bit) { + load_rgb_frame32(f, sc, planes, width, height, p->linesize); + } else + load_rgb_frame (f, sc, planes, width, height, p->linesize); + + encode_histogram_remap(f, sc); + } else { + load_rgb_float32_frame(f, sc, planes, width, height, p->linesize); + encode_float32_remap(f, sc, planes); + } + } + + if (ac == AC_GOLOMB_RICE) { sc->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&sc->c, f->version > 2) : 0; init_put_bits(&sc->pb, sc->c.bytestream_start + sc->ac_byte_count, sc->c.bytestream_end - sc->c.bytestream_start - sc->ac_byte_count); } - if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8) { - const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift); - const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift); + if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8 && c->pix_fmt != AV_PIX_FMT_YAF16) { const int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1); + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 1, ac); if (f->chroma_planes) { - ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); + ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, 1, ac); + ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 2, 1, ac); } if (f->transparency) - ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1); - } else if (c->pix_fmt == AV_PIX_FMT_YA8) { - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2); - ret |= encode_plane(f, sc, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2); + ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 3, 1, ac); + } else if (c->pix_fmt == AV_PIX_FMT_YA8 || c->pix_fmt == AV_PIX_FMT_YAF16) { + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 2, ac); + ret |= encode_plane(f, sc, p->data[0] + (ps>>1) + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 1, 2, ac); + } else if (f->bits_per_raw_sample == 32) { + ret = encode_float32_rgb_frame(f, sc, planes, width, height, p->linesize, ac); } else if (f->use32bit) { - ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize); + ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize, ac); } else { - ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize); + ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize, ac); + } + + if (ac != AC_GOLOMB_RICE) { + sc->ac_byte_count = ff_rac_terminate(&sc->c, 1); + } else { + flush_put_bits(&sc->pb); // FIXME: nicer padding + sc->ac_byte_count += put_bytes_output(&sc->pb); } if (ret < 0) { av_assert0(sc->slice_coding_mode == 0); - if (f->version < 4 || !f->ac) { + if (f->version < 4) { av_log(c, AV_LOG_ERROR, "Buffer too small\n"); return ret; } av_log(c, AV_LOG_DEBUG, "Coding slice as PCM\n"); + ac = 1; sc->slice_coding_mode = 1; sc->c = c_bak; goto retry; @@ -1101,6 +1680,28 @@ retry: return 0; } +size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx) +{ + FFV1Context *f = avctx->priv_data; + + size_t maxsize = avctx->width*avctx->height * (1 + f->transparency); + if (f->chroma_planes) + maxsize += AV_CEIL_RSHIFT(avctx->width, f->chroma_h_shift) * AV_CEIL_RSHIFT(f->height, f->chroma_v_shift) * 2; + maxsize += f->slice_count * 800; //for slice header + if (f->version > 3) { + maxsize *= f->bits_per_raw_sample + 1; + if (f->remap_mode) + maxsize += f->slice_count * 70000 * (1 + 2*f->chroma_planes + f->transparency); + } else { + maxsize += f->slice_count * 2 * (avctx->width + avctx->height); //for bug with slices that code some pixels more than once + maxsize *= 8*(2*f->bits_per_raw_sample + 5); + } + maxsize >>= 3; + maxsize += FF_INPUT_BUFFER_MIN_SIZE; + + return maxsize; +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -1109,8 +1710,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, uint8_t keystate = 128; uint8_t *buf_p; int i, ret; - int64_t maxsize = FF_INPUT_BUFFER_MIN_SIZE - + avctx->width*avctx->height*37LL*4; + int64_t maxsize; if(!pict) { if (avctx->flags & AV_CODEC_FLAG_PASS1) { @@ -1158,11 +1758,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } - if (f->version > 3) - maxsize = FF_INPUT_BUFFER_MIN_SIZE + avctx->width*avctx->height*3LL*4; + /* Maximum packet size */ + maxsize = ff_ffv1_encode_buffer_size(avctx); if (maxsize > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32) { - av_log(avctx, AV_LOG_WARNING, "Cannot allocate worst case packet size, the encoding could fail\n"); + FFV1Context *f = avctx->priv_data; + if (!f->maxsize_warned) { + av_log(avctx, AV_LOG_WARNING, "Cannot allocate worst case packet size, the encoding could fail\n"); + f->maxsize_warned++; + } maxsize = INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32; } @@ -1210,14 +1814,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, buf_p = pkt->data; for (i = 0; i < f->slice_count; i++) { FFV1SliceContext *sc = &f->slices[i]; - int bytes; - - if (f->ac != AC_GOLOMB_RICE) { - bytes = ff_rac_terminate(&sc->c, 1); - } else { - flush_put_bits(&sc->pb); // FIXME: nicer padding - bytes = sc->ac_byte_count + put_bytes_output(&sc->pb); - } + int bytes = sc->ac_byte_count; if (i > 0 || f->version > 2) { av_assert0(bytes < pkt->size / f->slice_count); memmove(buf_p, sc->c.bytestream_start, bytes); @@ -1228,7 +1825,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (f->ec) { unsigned v; buf_p[bytes++] = 0; - v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, buf_p, bytes); + v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, buf_p, bytes) ^ (f->crcref ? 0x8CD88196 : 0); AV_WL32(buf_p + bytes, v); bytes += 4; } @@ -1246,10 +1843,29 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } +static av_cold int encode_close(AVCodecContext *avctx) +{ + FFV1Context *const s = avctx->priv_data; + + for (int j = 0; j < s->max_slice_count; j++) { + FFV1SliceContext *sc = &s->slices[j]; + + for(int p = 0; p<4; p++) { + av_freep(&sc->unit[p]); + av_freep(&sc->bitmap[p]); + } + } + + av_freep(&avctx->stats_out); + ff_ffv1_close(s); + + return 0; +} + #define OFFSET(x) offsetof(FFV1Context, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 2, VE }, { "coder", "Coder type", OFFSET(ac), AV_OPT_TYPE_INT, { .i64 = 0 }, -2, 2, VE, .unit = "coder" }, { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST, @@ -1262,6 +1878,24 @@ static const AVOption options[] = { { .i64 = 1 }, INT_MIN, INT_MAX, VE, .unit = "coder" }, { "context", "Context model", OFFSET(context_model), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, + { "qtable", "Quantization table", OFFSET(qtable), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE , .unit = "qtable"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "greater8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_GT8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "remap_mode", "Remap Mode", OFFSET(remap_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 2, VE, .unit = "remap_mode" }, + { "auto", "Automatic", 0, AV_OPT_TYPE_CONST, + { .i64 = -1 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "off", "Disabled", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "dualrle", "Dual RLE", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "flipdualrle", "Dual RLE", 0, AV_OPT_TYPE_CONST, + { .i64 = 2 }, INT_MIN, INT_MAX, VE, .unit = "remap_mode" }, + { "remap_optimizer", "Remap Optimizer", OFFSET(remap_optimizer), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 5, VE, .unit = "remap_optimizer" }, { NULL } }; @@ -1282,10 +1916,10 @@ const FFCodec ff_ffv1_encoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(FFV1Context), - .init = encode_init, + .init = encode_init_internal, FF_CODEC_ENCODE_CB(encode_frame), - .close = ff_ffv1_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { + .close = encode_close, + CODEC_PIXFMTS( AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, AV_PIX_FMT_YUV420P16, @@ -1306,9 +1940,9 @@ const FFCodec ff_ffv1_encoder = { 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 - - }, + AV_PIX_FMT_YAF16, + AV_PIX_FMT_GRAYF16, + AV_PIX_FMT_GBRPF16, AV_PIX_FMT_GBRPF32), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ffv1_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, diff --git a/libavcodec/ffv1enc.h b/libavcodec/ffv1enc.h new file mode 100644 index 0000000000..42d521a747 --- /dev/null +++ b/libavcodec/ffv1enc.h @@ -0,0 +1,42 @@ +/* + * FFV1 encoder + * + * Copyright (c) 2003-2013 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FFV1ENC_H +#define AVCODEC_FFV1ENC_H + +#include "avcodec.h" + +enum { + QTABLE_DEFAULT = -1, + QTABLE_8BIT, + QTABLE_GT8BIT, +}; + +av_cold int ff_ffv1_encode_init(AVCodecContext *avctx); +av_cold int ff_ffv1_encode_determine_slices(AVCodecContext *avctx); +av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx); +av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt); + +size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx); + +#endif /* AVCODEC_FFV1ENC_H */ diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index bc14926ab9..63eb99b929 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -25,7 +25,7 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, void *logctx, - int w, TYPE *sample[3], int plane_index, int bits, + int w, TYPE *const sample[3], int plane_index, int bits, int ac, int pass1) { PlaneContext *const p = &sc->plane[plane_index]; @@ -35,19 +35,16 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_count = 0; int run_mode = 0; - if (ac != AC_GOLOMB_RICE) { - if (c->bytestream_end - c->bytestream < w * 35) { - av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); - return AVERROR_INVALIDDATA; - } - } else { - if (put_bytes_left(&sc->pb, 0) < w * 4) { - av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); - return AVERROR_INVALIDDATA; - } - } + if (bits == 0) + return 0; if (sc->slice_coding_mode == 1) { + av_assert0(ac != AC_GOLOMB_RICE); + if (c->bytestream_end - c->bytestream < (w * bits + 7LL)>>3) { + av_log(logctx, AV_LOG_ERROR, "encoded Range Coder frame too large\n"); + return AVERROR_INVALIDDATA; + } + for (x = 0; x < w; x++) { int i; int v = sample[0][x]; @@ -59,6 +56,18 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, return 0; } + if (ac != AC_GOLOMB_RICE) { + if (c->bytestream_end - c->bytestream < w * 35) { + av_log(logctx, AV_LOG_ERROR, "encoded Range Coder frame too large\n"); + return AVERROR_INVALIDDATA; + } + } else { + if (put_bytes_left(&sc->pb, 0) < w * 4) { + av_log(logctx, AV_LOG_ERROR, "encoded Golomb Rice frame too large\n"); + return AVERROR_INVALIDDATA; + } + } + for (x = 0; x < w; x++) { int diff, context; @@ -127,24 +136,62 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, return 0; } +static void RENAME(load_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], + int w, int h, const int stride[4]) +{ + int x, y; + int transparency = f->transparency; + + for (int p = 0; p<3 + transparency; p++) + memset(sc->fltmap[p], 0, 65536 * sizeof(**sc->fltmap)); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + + 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)); + r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + } + + sc->fltmap[0][g] = 1; + sc->fltmap[1][b] = 1; + sc->fltmap[2][r] = 1; + if (transparency) + sc->fltmap[3][a] = 1; + } + } +} + static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, const uint8_t *src[4], - int w, int h, const int stride[4]) + int w, int h, const int stride[4], int ac) { int x, y, p, i; const int ring_size = f->context_model ? 3 : 2; TYPE *sample[4][3]; - const int ac = f->ac; const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); int lbd = f->bits_per_raw_sample <= 8; int packed = !src[1]; - int bits = f->bits_per_raw_sample > 0 ? f->bits_per_raw_sample : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int packed_size = (3 + transparency)*2; + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + sc->run_index = 0; + for (int p = 0; p < MAX_PLANES; ++p) + sample[p][2] = RENAME(sc->sample_buffer); + memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); @@ -180,6 +227,14 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); } + if (sc->remap) { + g = sc->fltmap[0][g]; + b = sc->fltmap[1][b]; + r = sc->fltmap[2][r]; + if (transparency) + a = sc->fltmap[3][a]; + } + if (sc->slice_coding_mode != 1) { b -= g; r -= g; @@ -197,15 +252,14 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int ret; sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, 9, ac, pass1); else ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, - bits + (sc->slice_coding_mode != 1), ac, pass1); + bits[p], ac, pass1); if (ret < 0) return ret; } } return 0; } - diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c new file mode 100644 index 0000000000..259bc75d4c --- /dev/null +++ b/libavcodec/ffv1enc_vulkan.c @@ -0,0 +1,1848 @@ +/* + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "libavutil/vulkan.h" +#include "libavutil/vulkan_spirv.h" + +#include "avcodec.h" +#include "internal.h" +#include "hwconfig.h" +#include "encode.h" +#include "libavutil/opt.h" +#include "codec_internal.h" + +#include "ffv1.h" +#include "ffv1enc.h" +#include "ffv1_vulkan.h" + +/* Parallel Golomb alignment */ +#define LG_ALIGN_W 32 +#define LG_ALIGN_H 32 + +/* Unlike the decoder, we need 4 lines (but really only 3) */ +#define RGB_LINECACHE 4 + +typedef struct VulkanEncodeFFv1FrameData { + /* Output data */ + AVBufferRef *out_data_ref; + + /* Results data */ + AVBufferRef *results_data_ref; + + /* Copied from the source */ + int64_t pts; + int64_t duration; + void *frame_opaque; + AVBufferRef *frame_opaque_ref; + + int key_frame; +} VulkanEncodeFFv1FrameData; + +typedef struct VulkanEncodeFFv1Context { + FFV1Context ctx; + AVFrame *frame; + + FFVulkanContext s; + AVVulkanDeviceQueueFamily *qf; + FFVkExecPool exec_pool; + + AVVulkanDeviceQueueFamily *transfer_qf; + FFVkExecPool transfer_exec_pool; + + VkBufferCopy *buf_regions; + VulkanEncodeFFv1FrameData *exec_ctx_info; + int in_flight; + int async_depth; + size_t max_heap_size; + + FFVulkanShader setup; + FFVulkanShader rct_search; + FFVulkanShader reset; + FFVulkanShader enc; + + /* Constant read-only buffers */ + FFVkBuffer quant_buf; + FFVkBuffer rangecoder_static_buf; + FFVkBuffer crc_tab_buf; + + /* Slice data buffer pool */ + AVBufferPool *slice_data_pool; + AVBufferRef *keyframe_slice_data_ref; + + /* Output data buffer */ + AVBufferPool *out_data_pool; + + /* Slice results buffer */ + AVBufferPool *results_data_pool; + + /* Intermediate frame pool */ + AVBufferRef *intermediate_frames_ref; + + /* Representation mode */ + enum FFVkShaderRepFormat rep_fmt; + + int num_h_slices; + int num_v_slices; + int force_pcm; + int optimize_rct; + + int is_rgb; + int ppi; + int chunks; +} VulkanEncodeFFv1Context; + +extern const char *ff_source_common_comp; +extern const char *ff_source_rangecoder_comp; +extern const char *ff_source_ffv1_vlc_comp; +extern const char *ff_source_ffv1_common_comp; +extern const char *ff_source_ffv1_reset_comp; +extern const char *ff_source_ffv1_rct_search_comp; +extern const char *ff_source_ffv1_enc_setup_comp; +extern const char *ff_source_ffv1_enc_comp; + +typedef struct FFv1VkParameters { + VkDeviceAddress slice_state; + VkDeviceAddress scratch_data; + VkDeviceAddress out_data; + + int32_t fmt_lut[4]; + int32_t sar[2]; + uint32_t chroma_shift[2]; + + uint32_t plane_state_size; + uint32_t context_count; + uint32_t crcref; + uint32_t slice_size_max; + int rct_offset; + + uint8_t extend_lookup[8]; + uint8_t bits_per_raw_sample; + uint8_t context_model; + uint8_t version; + uint8_t micro_version; + uint8_t force_pcm; + uint8_t key_frame; + uint8_t components; + uint8_t planes; + uint8_t codec_planes; + uint8_t planar_rgb; + uint8_t transparency; + uint8_t colorspace; + uint8_t pic_mode; + uint8_t ec; + uint8_t ppi; + uint8_t chunks; + uint8_t rct_search; + uint8_t padding[3]; +} FFv1VkParameters; + +static void add_push_data(FFVulkanShader *shd) +{ + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLC(1, u8buf slice_state; ); + GLSLC(1, u8buf scratch_data; ); + GLSLC(1, u8buf out_data; ); + GLSLC(0, ); + GLSLC(1, ivec4 fmt_lut; ); + GLSLC(1, ivec2 sar; ); + GLSLC(1, uvec2 chroma_shift; ); + GLSLC(0, ); + GLSLC(1, uint plane_state_size; ); + GLSLC(1, uint context_count; ); + GLSLC(1, uint32_t crcref; ); + GLSLC(1, uint32_t slice_size_max; ); + GLSLC(1, int rct_offset; ); + GLSLC(0, ); + GLSLC(1, uint8_t extend_lookup[8]; ); + GLSLC(1, uint8_t bits_per_raw_sample; ); + GLSLC(1, uint8_t context_model; ); + GLSLC(1, uint8_t version; ); + GLSLC(1, uint8_t micro_version; ); + GLSLC(1, uint8_t force_pcm; ); + GLSLC(1, uint8_t key_frame; ); + GLSLC(1, uint8_t components; ); + GLSLC(1, uint8_t planes; ); + GLSLC(1, uint8_t codec_planes; ); + GLSLC(1, uint8_t planar_rgb; ); + GLSLC(1, uint8_t transparency; ); + GLSLC(1, uint8_t colorspace; ); + GLSLC(1, uint8_t pic_mode; ); + GLSLC(1, uint8_t ec; ); + GLSLC(1, uint8_t ppi; ); + GLSLC(1, uint8_t chunks; ); + GLSLC(1, uint8_t rct_search; ); + GLSLC(1, uint8_t padding[3]; ); + GLSLC(0, }; ); + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkParameters), + VK_SHADER_STAGE_COMPUTE_BIT); +} + +typedef struct FFv1VkRCTSearchParameters { + int fmt_lut[4]; + int rct_offset; + uint8_t planar_rgb; + uint8_t transparency; + uint8_t key_frame; + uint8_t force_pcm; + uint8_t version; + uint8_t micro_version; + uint8_t padding[2]; +} FFv1VkRCTSearchParameters; + +static int run_rct_search(AVCodecContext *avctx, FFVkExecContext *exec, + AVFrame *enc_in, VkImageView *enc_in_views, + FFVkBuffer *slice_data_buf, uint32_t slice_data_size) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + AVHWFramesContext *src_hwfc = (AVHWFramesContext *)enc_in->hw_frames_ctx->data; + FFv1VkRCTSearchParameters pd; + + /* Update descriptors */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->rct_search, + 0, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&fv->s, exec, &fv->rct_search, + enc_in, enc_in_views, + 0, 1, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->rct_search); + + pd = (FFv1VkRCTSearchParameters) { + .rct_offset = 1 << f->bits_per_raw_sample, + .planar_rgb = ff_vk_mt_is_np_rgb(src_hwfc->sw_format) && + (ff_vk_count_images((AVVkFrame *)enc_in->data[0]) > 1), + .transparency = f->transparency, + .key_frame = f->key_frame, + .force_pcm = fv->force_pcm, + .version = f->version, + .micro_version = f->micro_version, + }; + + if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14) + memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int)); + else + ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1); + + ff_vk_shader_update_push_const(&fv->s, exec, &fv->rct_search, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + return 0; +} + +static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, + FFVkExecContext *exec, + const AVFrame *pict) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + + VulkanEncodeFFv1FrameData *fd = exec->opaque; + FFv1VkParameters pd; + + /* Slice data */ + AVBufferRef *slice_data_ref; + FFVkBuffer *slice_data_buf; + uint32_t plane_state_size; + uint32_t slice_state_size; + uint32_t slice_data_size; + + /* Output data */ + size_t maxsize; + FFVkBuffer *out_data_buf; + + /* Results data */ + FFVkBuffer *results_data_buf; + + int has_inter = avctx->gop_size > 1; + uint32_t context_count = f->context_count[f->context_model]; + const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + + AVFrame *src = (AVFrame *)pict; + VkImageView src_views[AV_NUM_DATA_POINTERS]; + + AVFrame *tmp = NULL; + VkImageView tmp_views[AV_NUM_DATA_POINTERS]; + + VkImageMemoryBarrier2 img_bar[37]; + int nb_img_bar = 0; + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + /* Start recording */ + ff_vk_exec_start(&fv->s, exec); + + /* Frame state */ + f->cur_enc_frame = pict; + if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) { + av_buffer_unref(&fv->keyframe_slice_data_ref); + f->key_frame = fd->key_frame = 1; + f->gob_count++; + } else { + f->key_frame = fd->key_frame = 0; + } + + f->slice_count = f->max_slice_count; + + /* Allocate slice buffer data */ + if (f->ac == AC_GOLOMB_RICE) + plane_state_size = 8; + else + plane_state_size = CONTEXT_SIZE; + + plane_state_size *= context_count; + slice_state_size = plane_state_size*f->plane_count; + + slice_data_size = 256; /* Overestimation for the SliceContext struct */ + slice_state_size += slice_data_size; + slice_state_size = FFALIGN(slice_state_size, 8); + + /* Allocate slice data buffer */ + slice_data_ref = fv->keyframe_slice_data_ref; + if (!slice_data_ref) { + RET(ff_vk_get_pooled_buffer(&fv->s, &fv->slice_data_pool, + &slice_data_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, slice_state_size*f->slice_count, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + + /* Only save it if we're going to use it again */ + if (has_inter) + fv->keyframe_slice_data_ref = slice_data_ref; + } + slice_data_buf = (FFVkBuffer *)slice_data_ref->data; + ff_vk_exec_add_dep_buf(&fv->s, exec, &slice_data_ref, 1, has_inter); + + /* Allocate results buffer */ + RET(ff_vk_get_pooled_buffer(&fv->s, &fv->results_data_pool, + &fd->results_data_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, 2*f->slice_count*sizeof(uint64_t), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + results_data_buf = (FFVkBuffer *)fd->results_data_ref->data; + ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->results_data_ref, 1, 1); + + /* Output buffer size */ + maxsize = ff_ffv1_encode_buffer_size(avctx); + maxsize = FFMIN(maxsize, fv->s.props_11.maxMemoryAllocationSize); + + /* Allocate output buffer */ + RET(ff_vk_get_pooled_buffer(&fv->s, &fv->out_data_pool, + &fd->out_data_ref, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, maxsize, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + (maxsize < fv->max_heap_size ? + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0) | + (!(fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) ? + VK_MEMORY_PROPERTY_HOST_CACHED_BIT : 0x0))); + out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 1); + + /* Prepare input frame */ + RET(ff_vk_exec_add_dep_frame(&fv->s, exec, src, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + RET(ff_vk_create_imageviews(&fv->s, exec, src_views, src, + fv->rep_fmt)); + ff_vk_frame_barrier(&fv->s, exec, src, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + if (fv->is_rgb) { + /* Create a temporaty frame */ + tmp = av_frame_alloc(); + if (!(tmp)) + return AVERROR(ENOMEM); + + RET(av_hwframe_get_buffer(fv->intermediate_frames_ref, + tmp, 0)); + + RET(ff_vk_exec_add_dep_frame(&fv->s, exec, tmp, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + RET(ff_vk_create_imageviews(&fv->s, exec, tmp_views, + tmp, + fv->rep_fmt)); + } + + /* Setup shader */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->setup, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&fv->s, exec, &fv->setup, + src, src_views, + 1, 1, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + /* Add a buffer barrier between previous and current frame */ + if (!f->key_frame) { + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_data_buf->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_data_buf->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_data_buf->buf, + .size = VK_WHOLE_SIZE, + .offset = 0, + }; + } + + if (fv->optimize_rct) { + RET(run_rct_search(avctx, exec, + src, src_views, + slice_data_buf, slice_data_size)); + + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_data_buf->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_data_buf->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_data_buf->buf, + .size = slice_data_size*f->slice_count, + .offset = 0, + }; + } + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_img_bar = 0; + if (nb_buf_bar) { + slice_data_buf->stage = buf_bar[0].dstStageMask; + slice_data_buf->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + } + + /* Run setup shader */ + ff_vk_exec_bind_shader(&fv->s, exec, &fv->setup); + pd = (FFv1VkParameters) { + .slice_state = slice_data_buf->address + f->slice_count*256, + .out_data = out_data_buf->address, + .bits_per_raw_sample = f->bits_per_raw_sample, + .sar[0] = pict->sample_aspect_ratio.num, + .sar[1] = pict->sample_aspect_ratio.den, + .chroma_shift[0] = f->chroma_h_shift, + .chroma_shift[1] = f->chroma_v_shift, + .plane_state_size = plane_state_size, + .context_count = context_count, + .crcref = f->crcref, + .rct_offset = 1 << f->bits_per_raw_sample, + .slice_size_max = out_data_buf->size / f->slice_count, + .context_model = fv->ctx.context_model, + .version = f->version, + .micro_version = f->micro_version, + .force_pcm = fv->force_pcm, + .key_frame = f->key_frame, + .components = fmt_desc->nb_components, + .planes = av_pix_fmt_count_planes(avctx->sw_pix_fmt), + .codec_planes = f->plane_count, + .planar_rgb = ff_vk_mt_is_np_rgb(avctx->sw_pix_fmt) && + (ff_vk_count_images((AVVkFrame *)src->data[0]) > 1), + .transparency = f->transparency, + .colorspace = f->colorspace, + .pic_mode = !(pict->flags & AV_FRAME_FLAG_INTERLACED) ? 3 : + !(pict->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 2 : 1, + .ec = f->ec, + .ppi = fv->ppi, + .chunks = fv->chunks, + .rct_search = fv->optimize_rct, + }; + + /* For some reason the C FFv1 encoder/decoder treats these differently */ + if (avctx->sw_pix_fmt == AV_PIX_FMT_GBRP10 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP12 || + avctx->sw_pix_fmt == AV_PIX_FMT_GBRP14) + memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int)); + else + ff_vk_set_perm(avctx->sw_pix_fmt, pd.fmt_lut, 1); + + for (int i = 0; i < f->quant_table_count; i++) + pd.extend_lookup[i] = (f->quant_tables[i][3][127] != 0) || + (f->quant_tables[i][4][127] != 0); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->setup, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + /* Clean up temporary image */ + if (fv->is_rgb) { + AVVkFrame *vkf = (AVVkFrame *)tmp->data[0]; + vk->CmdClearColorImage(exec->buf, vkf->img[0], VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + } + + /* Setup shader modified the slice data buffer */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_data_buf->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_data_buf->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_data_buf->buf, + .size = slice_data_size*f->slice_count, + .offset = 0, + }; + + if (f->key_frame || f->version > 3) { + FFv1VkResetParameters pd_reset; + + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->reset, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + + /* Run setup shader */ + ff_vk_exec_bind_shader(&fv->s, exec, &fv->reset); + pd_reset = (FFv1VkResetParameters) { + .slice_state = slice_data_buf->address + f->slice_count*256, + .plane_state_size = plane_state_size, + .codec_planes = f->plane_count, + .key_frame = f->key_frame, + }; + for (int i = 0; i < f->quant_table_count; i++) + pd_reset.context_count[i] = f->context_count[i]; + + ff_vk_shader_update_push_const(&fv->s, exec, &fv->reset, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd_reset), &pd_reset); + + /* Sync between setup and reset shaders */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + slice_data_buf->stage = buf_bar[0].dstStageMask; + slice_data_buf->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, + f->plane_count); + } + + /* If the reset shader ran, insert a barrier now. */ + if (f->key_frame || f->version > 3) { + /* Reset shader modified the slice data buffer */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_data_buf->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_data_buf->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_data_buf->buf, + .size = slice_data_buf->size - slice_data_size*f->slice_count, + .offset = slice_data_size*f->slice_count, + }; + } + + if (fv->is_rgb) { + ff_vk_frame_barrier(&fv->s, exec, tmp, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + } + + /* Final barrier before encoding */ + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + nb_img_bar = 0; + if (nb_buf_bar) { + slice_data_buf->stage = buf_bar[0].dstStageMask; + slice_data_buf->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + } + + /* Main encode shader */ + ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc, + 1, 0, 0, + slice_data_buf, + 0, slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&fv->s, exec, &fv->enc, + src, src_views, + 1, 1, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + ff_vk_shader_update_desc_buffer(&fv->s, exec, + &fv->enc, 1, 2, 0, + results_data_buf, + 0, results_data_buf->size, + VK_FORMAT_UNDEFINED); + if (fv->is_rgb) + ff_vk_shader_update_img_array(&fv->s, exec, &fv->enc, + tmp, tmp_views, + 1, 3, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&fv->s, exec, &fv->enc); + ff_vk_shader_update_push_const(&fv->s, exec, &fv->enc, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1); + + /* Submit */ + err = ff_vk_exec_submit(&fv->s, exec); + if (err < 0) + return err; + + f->picture_number++; + + /* This, if needed, was referenced by the execution context + * as it was declared as a dependency. */ + av_frame_free(&tmp); + return 0; + +fail: + av_frame_free(&tmp); + ff_vk_exec_discard_deps(&fv->s, exec); + + return err; +} + +static int transfer_slices(AVCodecContext *avctx, + VkBufferCopy *buf_regions, int nb_regions, + VulkanEncodeFFv1FrameData *fd, + uint8_t *dst, AVBufferRef *dst_ref) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFVulkanFunctions *vk = &fv->s.vkfn; + FFVkExecContext *exec; + + FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + + AVBufferRef *mapped_ref; + FFVkBuffer *mapped_buf; + + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + err = ff_vk_host_map_buffer(&fv->s, &mapped_ref, dst, dst_ref, + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + if (err < 0) + return err; + + mapped_buf = (FFVkBuffer *)mapped_ref->data; + + /* Transfer the slices */ + exec = ff_vk_exec_get(&fv->s, &fv->transfer_exec_pool); + ff_vk_exec_start(&fv->s, exec); + + ff_vk_exec_add_dep_buf(&fv->s, exec, &fd->out_data_ref, 1, 0); + fd->out_data_ref = NULL; /* Ownership passed */ + + ff_vk_exec_add_dep_buf(&fv->s, exec, &mapped_ref, 1, 0); + mapped_ref = NULL; /* Ownership passed */ + + /* Ensure the output buffer is finished */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = out_data_buf->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = out_data_buf->access, + .dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = out_data_buf->buf, + .size = VK_WHOLE_SIZE, + .offset = 0, + }; + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + out_data_buf->stage = buf_bar[0].dstStageMask; + out_data_buf->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + + for (int i = 0; i < nb_regions; i++) + buf_regions[i].dstOffset += mapped_buf->virtual_offset; + + vk->CmdCopyBuffer(exec->buf, + out_data_buf->buf, mapped_buf->buf, + nb_regions, buf_regions); + + /* Submit */ + err = ff_vk_exec_submit(&fv->s, exec); + if (err < 0) + return err; + + /* We need the encoded data immediately */ + ff_vk_exec_wait(&fv->s, exec); + + return 0; +} + +static int get_packet(AVCodecContext *avctx, FFVkExecContext *exec, + AVPacket *pkt) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanFunctions *vk = &fv->s.vkfn; + VulkanEncodeFFv1FrameData *fd = exec->opaque; + + FFVkBuffer *out_data_buf = (FFVkBuffer *)fd->out_data_ref->data; + FFVkBuffer *results_data_buf = (FFVkBuffer *)fd->results_data_ref->data; + uint64_t *sc; + + /* Make sure encoding's done */ + ff_vk_exec_wait(&fv->s, exec); + + /* Invalidate slice/output data if needed */ + if (!(results_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = results_data_buf->mem, + .offset = 0, + .size = VK_WHOLE_SIZE, + }; + vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev, + 1, &invalidate_data); + } + + /* Calculate final size */ + pkt->size = 0; + for (int i = 0; i < f->slice_count; i++) { + sc = &((uint64_t *)results_data_buf->mapped_mem)[i*2]; + av_log(avctx, AV_LOG_DEBUG, "Slice %i size = %"PRIu64", " + "src offset = %"PRIu64"\n", + i, sc[0], sc[1]); + + fv->buf_regions[i] = (VkBufferCopy) { + .srcOffset = sc[1], + .dstOffset = pkt->size, + .size = sc[0], + }; + pkt->size += sc[0]; + } + av_log(avctx, AV_LOG_VERBOSE, "Encoded data: %iMiB\n", pkt->size / (1024*1024)); + av_buffer_unref(&fd->results_data_ref); /* No need for this buffer anymore */ + + /* Allocate packet */ + if ((err = ff_get_encode_buffer(avctx, pkt, pkt->size, 0)) < 0) + return err; + + pkt->pts = fd->pts; + pkt->dts = fd->pts; + pkt->duration = fd->duration; + pkt->flags |= AV_PKT_FLAG_KEY * fd->key_frame; + + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + pkt->opaque = fd->frame_opaque; + pkt->opaque_ref = fd->frame_opaque_ref; + fd->frame_opaque_ref = NULL; + } + + /* Try using host mapped memory transfers first */ + if (fv->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) { + err = transfer_slices(avctx, fv->buf_regions, f->slice_count, fd, + pkt->data, pkt->buf); + if (err >= 0) + return err; + } + + /* Invalidate slice/output data if needed */ + if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = out_data_buf->mem, + .offset = 0, + .size = VK_WHOLE_SIZE, + }; + vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev, + 1, &invalidate_data); + } + + /* Copy each slice */ + for (int i = 0; i < f->slice_count; i++) { + VkBufferCopy *region = &fv->buf_regions[i]; + memcpy(pkt->data + region->dstOffset, + out_data_buf->mapped_mem + region->srcOffset, + region->size); + } + + av_buffer_unref(&fd->out_data_ref); + + return 0; +} + +static int vulkan_encode_ffv1_receive_packet(AVCodecContext *avctx, + AVPacket *pkt) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + VulkanEncodeFFv1FrameData *fd; + FFVkExecContext *exec; + AVFrame *frame; + + while (1) { + /* Roll an execution context */ + exec = ff_vk_exec_get(&fv->s, &fv->exec_pool); + + /* If it had a frame, immediately output it */ + if (exec->had_submission) { + exec->had_submission = 0; + fv->in_flight--; + return get_packet(avctx, exec, pkt); + } + + /* Get next frame to encode */ + frame = fv->frame; + err = ff_encode_get_frame(avctx, frame); + if (err < 0 && err != AVERROR_EOF) { + return err; + } else if (err == AVERROR_EOF) { + if (!fv->in_flight) + return err; + continue; + } + + /* Encode frame */ + fd = exec->opaque; + fd->pts = frame->pts; + fd->duration = frame->duration; + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + fd->frame_opaque = frame->opaque; + fd->frame_opaque_ref = frame->opaque_ref; + frame->opaque_ref = NULL; + } + + err = vulkan_encode_ffv1_submit_frame(avctx, exec, frame); + av_frame_unref(frame); + if (err < 0) + return err; + + fv->in_flight++; + if (fv->in_flight < fv->async_depth) + return AVERROR(EAGAIN); + } + + return 0; +} + +static int init_indirect(AVCodecContext *avctx, enum AVPixelFormat sw_format) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + AVHWFramesContext *frames_ctx; + AVVulkanFramesContext *vk_frames; + + fv->intermediate_frames_ref = av_hwframe_ctx_alloc(fv->s.device_ref); + if (!fv->intermediate_frames_ref) + return AVERROR(ENOMEM); + + frames_ctx = (AVHWFramesContext *)fv->intermediate_frames_ref->data; + frames_ctx->format = AV_PIX_FMT_VULKAN; + frames_ctx->sw_format = sw_format; + frames_ctx->width = fv->s.frames->width; + frames_ctx->height = f->num_v_slices*RGB_LINECACHE; + + vk_frames = frames_ctx->hwctx; + vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; + vk_frames->usage = VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + vk_frames->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + err = av_hwframe_ctx_init(fv->intermediate_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize frame pool with format %s: %s\n", + av_get_pix_fmt_name(sw_format), av_err2str(err)); + av_buffer_unref(&fv->intermediate_frames_ref); + return err; + } + + return 0; +} + +static int check_support(AVHWFramesConstraints *constraints, + enum AVPixelFormat fmt) +{ + for (int i = 0; constraints->valid_sw_formats[i]; i++) { + if (constraints->valid_sw_formats[i] == fmt) + return 1; + } + return 0; +} + +static enum AVPixelFormat get_supported_rgb_buffer_fmt(AVCodecContext *avctx) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + + enum AVPixelFormat fmt; + AVHWFramesConstraints *constraints; + constraints = av_hwdevice_get_hwframe_constraints(fv->s.device_ref, + NULL); + + /* What we'd like to optimally have */ + fmt = fv->ctx.use32bit ? + (fv->ctx.transparency ? AV_PIX_FMT_RGBA128 : AV_PIX_FMT_RGB96) : + (fv->ctx.transparency ? AV_PIX_FMT_RGBA64 : AV_PIX_FMT_RGB48); + if (check_support(constraints, fmt)) + goto end; + + if (fv->ctx.use32bit) { + if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA128))) + goto end; + } else { + if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA64))) + goto end; + + if (!fv->ctx.transparency && + check_support(constraints, (fmt = AV_PIX_FMT_RGB96))) + goto end; + + if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA128))) + goto end; + } + + fmt = AV_PIX_FMT_NONE; + +end: + av_hwframe_constraints_free(&constraints); + return fmt; +} + +static void define_shared_code(AVCodecContext *avctx, FFVulkanShader *shd) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + int smp_bits = fv->ctx.use32bit ? 32 : 16; + + av_bprintf(&shd->src, "#define RGB_LINECACHE %i\n" ,RGB_LINECACHE); + av_bprintf(&shd->src, "#define CONTEXT_SIZE %i\n" ,CONTEXT_SIZE); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_MASK 0x%x\n" ,MAX_QUANT_TABLE_MASK); + + if (f->ac == AC_GOLOMB_RICE) { + av_bprintf(&shd->src, "#define PB_UNALIGNED\n" ); + av_bprintf(&shd->src, "#define GOLOMB\n" ); + } + + if (fv->is_rgb) + av_bprintf(&shd->src, "#define RGB\n"); + + GLSLF(0, #define TYPE int%i_t ,smp_bits); + GLSLF(0, #define VTYPE2 i%ivec2 ,smp_bits); + GLSLF(0, #define VTYPE3 i%ivec3 ,smp_bits); + GLSLD(ff_source_rangecoder_comp); + + if (f->ac == AC_GOLOMB_RICE) + GLSLD(ff_source_ffv1_vlc_comp); + + GLSLD(ff_source_ffv1_common_comp); +} + +static int init_rct_search_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanShader *shd = &fv->rct_search; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + + RET(ff_vk_shader_init(&fv->s, shd, "ffv1_rct_search", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2", + "GL_EXT_null_initializer" }, 3, + 32, 32, 1, + 0)); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLC(1, ivec4 fmt_lut; ); + GLSLC(1, int rct_offset; ); + GLSLC(1, uint8_t planar_rgb; ); + GLSLC(1, uint8_t transparency; ); + GLSLC(1, uint8_t key_frame; ); + GLSLC(1, uint8_t force_pcm; ); + GLSLC(1, uint8_t version; ); + GLSLC(1, uint8_t micro_version; ); + GLSLC(1, uint8_t padding[3]; ); + GLSLC(0, }; ); + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkResetParameters), + VK_SHADER_STAGE_COMPUTE_BIT); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + /* Never used */ + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 1)); + + define_shared_code(avctx, shd); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + { + .name = "src", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, + fv->rep_fmt), + .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), + .mem_quali = "readonly", + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0)); + + GLSLD(ff_source_ffv1_rct_search_comp); + + RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_setup_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanShader *shd = &fv->setup; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + + RET(ff_vk_shader_init(&fv->s, shd, "ffv1_setup", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + 1, 1, 1, + 0)); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + add_push_data(shd); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + av_bprintf(&shd->src, "#define FULL_RENORM\n"); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { /* This descriptor is never used */ + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 0)); + + define_shared_code(avctx, shd); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + { + .name = "src", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, + fv->rep_fmt), + .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), + .mem_quali = "readonly", + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0)); + + GLSLD(ff_source_ffv1_enc_setup_comp); + + RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_reset_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanShader *shd = &fv->reset; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + int wg_dim = FFMIN(fv->s.props.properties.limits.maxComputeWorkGroupSize[0], 1024); + + RET(ff_vk_shader_init(&fv->s, shd, "ffv1_reset", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + wg_dim, 1, 1, + 0)); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLF(1, uint context_count[%i]; ,MAX_QUANT_TABLES); + GLSLC(1, u8buf slice_state; ); + GLSLC(1, uint plane_state_size; ); + GLSLC(1, uint8_t codec_planes; ); + GLSLC(1, uint8_t key_frame; ); + GLSLC(1, uint8_t version; ); + GLSLC(1, uint8_t micro_version; ); + GLSLC(1, uint8_t padding[1]; ); + GLSLC(0, }; ); + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkResetParameters), + VK_SHADER_STAGE_COMPUTE_BIT); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 0)); + + define_shared_code(avctx, shd); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .mem_quali = "readonly", + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + }; + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 1, 0, 0)); + + GLSLD(ff_source_ffv1_reset_comp); + + RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_encode_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) +{ + int err; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVulkanShader *shd = &fv->enc; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + int use_cached_reader = fv->ctx.ac != AC_GOLOMB_RICE; + + RET(ff_vk_shader_init(&fv->s, shd, "ffv1_enc", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + use_cached_reader ? CONTEXT_SIZE : 1, 1, 1, + 0)); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + add_push_data(shd); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + if (use_cached_reader) + av_bprintf(&shd->src, "#define CACHED_SYMBOL_READER 1\n"); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + { + .name = "crc_ieee_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint32_t crc_ieee[256];", + }, + }; + + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 3, 1, 0)); + + define_shared_code(avctx, shd); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + { + .name = "src", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, + fv->rep_fmt), + .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), + .mem_quali = "readonly", + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "results_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_quali = "writeonly", + .buf_content = "uint64_t slice_results[2048];", + }, + { /* place holder for desc_set[3] */ + }, + }; + if (fv->is_rgb) { + AVHWFramesContext *intermediate_frames_ctx; + intermediate_frames_ctx = (AVHWFramesContext *)fv->intermediate_frames_ref->data; + desc_set[3] = (FFVulkanDescriptorSetBinding) { + .name = "tmp", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(intermediate_frames_ctx->sw_format, + FF_VK_REP_NATIVE), + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }; + } + RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 3 + fv->is_rgb, 0, 0)); + + GLSLD(ff_source_ffv1_enc_comp); + + RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) +{ + int err; + size_t maxsize, max_heap_size, max_host_size; + VulkanEncodeFFv1Context *fv = avctx->priv_data; + FFV1Context *f = &fv->ctx; + FFVkSPIRVCompiler *spv; + + if ((err = ff_ffv1_common_init(avctx, f)) < 0) + return err; + + if (f->ac == 1) + f->ac = AC_RANGE_CUSTOM_TAB; + + err = ff_ffv1_encode_setup_plane_info(avctx, avctx->sw_pix_fmt); + if (err < 0) + return err; + + /* Target version 3 by default */ + f->version = 3; + + err = ff_ffv1_encode_init(avctx); + if (err < 0) + return err; + + /* Rice coding did not support high bit depths */ + if (f->bits_per_raw_sample > (f->version > 3 ? 16 : 8)) { + if (f->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_WARNING, "bits_per_raw_sample > 8, " + "forcing range coder\n"); + f->ac = AC_RANGE_CUSTOM_TAB; + } + } + + if (f->version < 4 && avctx->gop_size > 1) { + av_log(avctx, AV_LOG_ERROR, "Using inter frames requires version 4 (-level 4)\n"); + return AVERROR_INVALIDDATA; + } + + if (f->version == 4 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, "Version 4 is experimental and requires -strict -2\n"); + return AVERROR_INVALIDDATA; + } + + /* We target version 4.3 */ + if (f->version == 4 && f->micro_version > 4) + f->micro_version = 3; + + //if (fv->ctx.ac == AC_GOLOMB_RICE) { + if (0) { + int w_a = FFALIGN(avctx->width, LG_ALIGN_W); + int h_a = FFALIGN(avctx->height, LG_ALIGN_H); + int w_sl, h_sl; + + /* Pixels per line an invocation handles */ + int ppi = 0; + /* Chunk size */ + int chunks = 0; + + do { + if (ppi < 2) + ppi++; + chunks++; + w_sl = w_a / (LG_ALIGN_W*ppi); + h_sl = h_a / (LG_ALIGN_H*chunks); + } while (w_sl > MAX_SLICES / h_sl); + + av_log(avctx, AV_LOG_VERBOSE, "Slice config: %ix%i, %i total\n", + LG_ALIGN_W*ppi, LG_ALIGN_H*chunks, w_sl*h_sl); + av_log(avctx, AV_LOG_VERBOSE, "Horizontal slices: %i (%i pixels per invoc)\n", + w_sl, ppi); + av_log(avctx, AV_LOG_VERBOSE, "Vertical slices: %i (%i chunks)\n", + h_sl, chunks); + + f->num_h_slices = w_sl; + f->num_v_slices = h_sl; + + fv->ppi = ppi; + fv->chunks = chunks; + } else { + f->num_h_slices = fv->num_h_slices; + f->num_v_slices = fv->num_v_slices; + + if (f->num_h_slices <= 0 && f->num_v_slices <= 0) { + if (avctx->slices) { + err = ff_ffv1_encode_determine_slices(avctx); + if (err < 0) + return err; + } else { + f->num_h_slices = 32; + f->num_v_slices = 32; + } + } else if (f->num_h_slices && f->num_v_slices <= 0) { + f->num_v_slices = MAX_SLICES / f->num_h_slices; + } else if (f->num_v_slices && f->num_h_slices <= 0) { + f->num_h_slices = MAX_SLICES / f->num_v_slices; + } + + f->num_h_slices = FFMIN(f->num_h_slices, avctx->width); + f->num_v_slices = FFMIN(f->num_v_slices, avctx->height); + + if (f->num_h_slices * f->num_v_slices > MAX_SLICES) { + av_log(avctx, AV_LOG_ERROR, "Too many slices (%i), maximum supported " + "by the standard is %i\n", + f->num_h_slices * f->num_v_slices, MAX_SLICES); + return AVERROR_PATCHWELCOME; + } + } + + f->max_slice_count = f->num_h_slices * f->num_v_slices; + + if ((err = ff_ffv1_write_extradata(avctx)) < 0) + return err; + + if (f->version < 4) { + if (((f->chroma_h_shift > 0) && (avctx->width % (64 << f->chroma_h_shift))) || + ((f->chroma_v_shift > 0) && (avctx->height % (64 << f->chroma_v_shift)))) { + av_log(avctx, AV_LOG_ERROR, "Encoding frames with subsampling and unaligned " + "dimensions is only supported in version 4 (-level 4)\n"); + return AVERROR_PATCHWELCOME; + } + } + + if (fv->force_pcm) { + if (f->version < 4) { + av_log(avctx, AV_LOG_ERROR, "PCM coding only supported by version 4 (-level 4)\n"); + return AVERROR_INVALIDDATA; + } else if (f->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_ERROR, "PCM coding requires range coding\n"); + return AVERROR_INVALIDDATA; + } + } + + /* Init Vulkan */ + err = ff_vk_init(&fv->s, avctx, NULL, avctx->hw_frames_ctx); + if (err < 0) + return err; + + fv->qf = ff_vk_qf_find(&fv->s, VK_QUEUE_COMPUTE_BIT, 0); + if (!fv->qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no compute queues!\n"); + return err; + } + + /* Try to measure VRAM size */ + max_heap_size = 0; + max_host_size = 0; + for (int i = 0; i < fv->s.mprops.memoryHeapCount; i++) { + if (fv->s.mprops.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + max_heap_size = FFMAX(fv->max_heap_size, + fv->s.mprops.memoryHeaps[i].size); + if (!(fv->s.mprops.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)) + max_host_size = FFMAX(max_host_size, + fv->s.mprops.memoryHeaps[i].size); + } + fv->max_heap_size = max_heap_size; + + maxsize = ff_ffv1_encode_buffer_size(avctx); + if (maxsize > fv->s.props_11.maxMemoryAllocationSize) { + av_log(avctx, AV_LOG_WARNING, "Encoding buffer size (%zu) larger " + "than maximum device allocation (%zu), clipping\n", + maxsize, fv->s.props_11.maxMemoryAllocationSize); + maxsize = fv->s.props_11.maxMemoryAllocationSize; + } + + if (max_heap_size < maxsize) { + av_log(avctx, AV_LOG_WARNING, "Encoding buffer (%zu) larger than VRAM (%zu), " + "using host memory (slower)\n", + maxsize, fv->max_heap_size); + + /* Keep 1/2th of RAM as headroom */ + max_heap_size = max_host_size - (max_host_size >> 1); + } else { + /* Keep 1/8th of VRAM as headroom */ + max_heap_size = max_heap_size - (max_heap_size >> 3); + } + + av_log(avctx, AV_LOG_INFO, "Async buffers: %zuMiB per context, %zuMiB total, depth: %i\n", + maxsize / (1024*1024), + (fv->async_depth * maxsize) / (1024*1024), + fv->async_depth); + + err = ff_vk_exec_pool_init(&fv->s, fv->qf, &fv->exec_pool, + fv->async_depth, + 0, 0, 0, NULL); + if (err < 0) + return err; + + fv->transfer_qf = ff_vk_qf_find(&fv->s, VK_QUEUE_TRANSFER_BIT, 0); + if (!fv->transfer_qf) { + av_log(avctx, AV_LOG_ERROR, "Device has no transfer queues!\n"); + return err; + } + + err = ff_vk_exec_pool_init(&fv->s, fv->transfer_qf, &fv->transfer_exec_pool, + 1, + 0, 0, 0, NULL); + if (err < 0) + return err; + + spv = ff_vk_spirv_init(); + if (!spv) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n"); + return AVERROR_EXTERNAL; + } + + /* Detect the special RGB coding mode */ + fv->is_rgb = !(f->colorspace == 0 && avctx->sw_pix_fmt != AV_PIX_FMT_YA8) && + !(avctx->sw_pix_fmt == AV_PIX_FMT_YA8); + + /* bits_per_raw_sample use regular unsigned representation, + * but in higher bit depths, the data is casted to int16_t */ + fv->rep_fmt = FF_VK_REP_UINT; + if (!fv->is_rgb && f->bits_per_raw_sample > 8) + fv->rep_fmt = FF_VK_REP_INT; + + /* Init rct search shader */ + fv->optimize_rct = fv->is_rgb && f->version >= 4 && + !fv->force_pcm && fv->optimize_rct; + if (fv->optimize_rct) { + err = init_rct_search_shader(avctx, spv); + if (err < 0) { + spv->uninit(&spv); + return err; + } + } + + /* Init setup shader */ + err = init_setup_shader(avctx, spv); + if (err < 0) { + spv->uninit(&spv); + return err; + } + + /* Init reset shader */ + err = init_reset_shader(avctx, spv); + if (err < 0) { + spv->uninit(&spv); + return err; + } + + if (fv->is_rgb) { + enum AVPixelFormat intermediate_fmt = get_supported_rgb_buffer_fmt(avctx); + if (intermediate_fmt == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Unable to find a supported compatible " + "pixel format for RCT buffer!\n"); + return AVERROR(ENOTSUP); + } + + RET(init_indirect(avctx, intermediate_fmt)); + } + + /* Encode shader */ + err = init_encode_shader(avctx, spv); + if (err < 0) { + spv->uninit(&spv); + return err; + } + + spv->uninit(&spv); + + /* Range coder data */ + err = ff_ffv1_vk_init_state_transition_data(&fv->s, + &fv->rangecoder_static_buf, + f); + if (err < 0) + return err; + + /* Quantization table data */ + err = ff_ffv1_vk_init_quant_table_data(&fv->s, + &fv->quant_buf, + f); + if (err < 0) + return err; + + /* CRC table buffer */ + err = ff_ffv1_vk_init_crc_table_data(&fv->s, + &fv->crc_tab_buf, + f); + if (err < 0) + return err; + + /* Update setup global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->setup, 0, 0, 0, + &fv->rangecoder_static_buf, + 0, fv->rangecoder_static_buf.size, + VK_FORMAT_UNDEFINED)); + + /* Update encode global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 0, 0, + &fv->rangecoder_static_buf, + 0, fv->rangecoder_static_buf.size, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 1, 0, + &fv->quant_buf, + 0, fv->quant_buf.size, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0], + &fv->enc, 0, 2, 0, + &fv->crc_tab_buf, + 0, fv->crc_tab_buf.size, + VK_FORMAT_UNDEFINED)); + + /* Temporary frame */ + fv->frame = av_frame_alloc(); + if (!fv->frame) + return AVERROR(ENOMEM); + + /* Async data pool */ + fv->async_depth = fv->exec_pool.pool_size; + fv->exec_ctx_info = av_calloc(fv->async_depth, sizeof(*fv->exec_ctx_info)); + if (!fv->exec_ctx_info) + return AVERROR(ENOMEM); + for (int i = 0; i < fv->async_depth; i++) + fv->exec_pool.contexts[i].opaque = &fv->exec_ctx_info[i]; + + fv->buf_regions = av_malloc_array(f->max_slice_count, sizeof(*fv->buf_regions)); + if (!fv->buf_regions) + return AVERROR(ENOMEM); + +fail: + return err; +} + +static av_cold int vulkan_encode_ffv1_close(AVCodecContext *avctx) +{ + VulkanEncodeFFv1Context *fv = avctx->priv_data; + + ff_vk_exec_pool_free(&fv->s, &fv->exec_pool); + ff_vk_exec_pool_free(&fv->s, &fv->transfer_exec_pool); + + ff_vk_shader_free(&fv->s, &fv->enc); + ff_vk_shader_free(&fv->s, &fv->reset); + ff_vk_shader_free(&fv->s, &fv->setup); + ff_vk_shader_free(&fv->s, &fv->rct_search); + + if (fv->exec_ctx_info) { + for (int i = 0; i < fv->async_depth; i++) { + VulkanEncodeFFv1FrameData *fd = &fv->exec_ctx_info[i]; + av_buffer_unref(&fd->out_data_ref); + av_buffer_unref(&fd->results_data_ref); + av_buffer_unref(&fd->frame_opaque_ref); + } + } + av_free(fv->exec_ctx_info); + + av_buffer_unref(&fv->intermediate_frames_ref); + + av_buffer_pool_uninit(&fv->results_data_pool); + + av_buffer_pool_uninit(&fv->out_data_pool); + + av_buffer_unref(&fv->keyframe_slice_data_ref); + av_buffer_pool_uninit(&fv->slice_data_pool); + + ff_vk_free_buf(&fv->s, &fv->quant_buf); + ff_vk_free_buf(&fv->s, &fv->rangecoder_static_buf); + ff_vk_free_buf(&fv->s, &fv->crc_tab_buf); + + av_free(fv->buf_regions); + av_frame_free(&fv->frame); + ff_vk_uninit(&fv->s); + + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeFFv1Context, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption vulkan_encode_ffv1_options[] = { + { "slicecrc", "Protect slices with CRCs", OFFSET(ctx.ec), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE }, + { "context", "Context model", OFFSET(ctx.context_model), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, VE }, + { "coder", "Coder type", OFFSET(ctx.ac), AV_OPT_TYPE_INT, + { .i64 = AC_RANGE_CUSTOM_TAB }, -2, 2, VE, .unit = "coder" }, + { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_GOLOMB_RICE }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "range_def", "Range with default table", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_RANGE_DEFAULT_TAB_FORCE }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "range_tab", "Range with custom table", 0, AV_OPT_TYPE_CONST, + { .i64 = AC_RANGE_CUSTOM_TAB }, INT_MIN, INT_MAX, VE, .unit = "coder" }, + { "qtable", "Quantization table", OFFSET(ctx.qtable), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 2, VE , .unit = "qtable"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + { "greater8bit", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = QTABLE_GT8BIT }, INT_MIN, INT_MAX, VE, .unit = "qtable" }, + + { "slices_h", "Number of horizontal slices", OFFSET(num_h_slices), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, MAX_SLICES, VE }, + { "slices_v", "Number of vertical slices", OFFSET(num_v_slices), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, MAX_SLICES, VE }, + + { "force_pcm", "Code all slices with no prediction", OFFSET(force_pcm), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE }, + + { "rct_search", "Run a search for RCT parameters (level 4 only)", OFFSET(optimize_rct), AV_OPT_TYPE_BOOL, + { .i64 = 1 }, 0, 1, VE }, + + { "async_depth", "Internal parallelization depth", OFFSET(async_depth), AV_OPT_TYPE_INT, + { .i64 = 1 }, 1, INT_MAX, VE }, + + { NULL } +}; + +static const FFCodecDefault vulkan_encode_ffv1_defaults[] = { + { "g", "1" }, + { NULL }, +}; + +static const AVClass vulkan_encode_ffv1_class = { + .class_name = "ffv1_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_ffv1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVCodecHWConfigInternal *const vulkan_encode_ffv1_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(VULKAN, VULKAN), + NULL, +}; + +const FFCodec ff_ffv1_vulkan_encoder = { + .p.name = "ffv1_vulkan", + CODEC_LONG_NAME("FFmpeg video codec #1 (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_FFV1, + .priv_data_size = sizeof(VulkanEncodeFFv1Context), + .init = &vulkan_encode_ffv1_init, + FF_CODEC_RECEIVE_PACKET_CB(&vulkan_encode_ffv1_receive_packet), + .close = &vulkan_encode_ffv1_close, + .p.priv_class = &vulkan_encode_ffv1_class, + .p.capabilities = AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_FLUSH | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, + .defaults = vulkan_encode_ffv1_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), + .hw_configs = vulkan_encode_ffv1_hw_configs, + .p.wrapper_name = "vulkan", +}; diff --git a/libavcodec/fic.c b/libavcodec/fic.c index ec26e3154d..b3468d751b 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -56,7 +56,6 @@ typedef struct FICContext { int aligned_width, aligned_height; int num_slices, slice_h; - uint8_t cursor_buf[4096]; int skip_cursor; } FICContext; @@ -86,6 +85,7 @@ static const uint8_t fic_header[7] = { 0, 0, 1, 'F', 'I', 'C', 'V' }; #define FIC_HEADER_SIZE 27 #define CURSOR_OFFSET 59 +#define CURSOR_SIZE 4096 static av_always_inline void fic_idct(int16_t *blk, int step, int shift, int rnd) { @@ -214,10 +214,11 @@ static av_always_inline void fic_alpha_blend(uint8_t *dst, uint8_t *src, dst[i] += ((src[i] - dst[i]) * alpha[i]) >> 8; } -static void fic_draw_cursor(AVCodecContext *avctx, int cur_x, int cur_y) +static void fic_draw_cursor(AVCodecContext *avctx, const uint8_t cursor_buf[CURSOR_SIZE], + int cur_x, int cur_y) { FICContext *ctx = avctx->priv_data; - uint8_t *ptr = ctx->cursor_buf; + const uint8_t *ptr = cursor_buf; uint8_t *dstptr[3]; uint8_t planes[4][1024]; uint8_t chroma[3][256]; @@ -281,9 +282,6 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int skip_cursor = ctx->skip_cursor; const uint8_t *sdata; - if ((ret = ff_reget_buffer(avctx, ctx->frame, 0)) < 0) - return ret; - /* Header + at least one slice (4) */ if (avpkt->size < FIC_HEADER_SIZE + 4) { av_log(avctx, AV_LOG_ERROR, "Frame data is too small.\n"); @@ -296,10 +294,14 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* Is it a skip frame? */ if (src[17]) { - if (!ctx->final_frame) { + if (!ctx->final_frame->data[0]) { av_log(avctx, AV_LOG_WARNING, "Initial frame is skipped\n"); return AVERROR_INVALIDDATA; } + ret = ff_reget_buffer(avctx, ctx->final_frame, + FF_REGET_BUFFER_FLAG_READONLY); + if (ret < 0) + return ret; goto skip; } @@ -346,9 +348,8 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, skip_cursor = 1; } - if (!skip_cursor && avpkt->size < CURSOR_OFFSET + sizeof(ctx->cursor_buf)) { + if (!skip_cursor && avpkt->size < CURSOR_OFFSET + CURSOR_SIZE) skip_cursor = 1; - } /* Slice height for all but the last slice. */ ctx->slice_h = 16 * (ctx->aligned_height >> 4) / nslices; @@ -403,6 +404,9 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, ctx->slice_data[slice].y_off = y_off; } + if ((ret = ff_reget_buffer(avctx, ctx->frame, 0)) < 0) + return ret; + if ((ret = avctx->execute(avctx, fic_decode_slice, ctx->slice_data, NULL, nslices, sizeof(ctx->slice_data[0]))) < 0) return ret; @@ -416,29 +420,24 @@ static int fic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, break; } } - av_frame_free(&ctx->final_frame); - ctx->final_frame = av_frame_clone(ctx->frame); - if (!ctx->final_frame) { - av_log(avctx, AV_LOG_ERROR, "Could not clone frame buffer.\n"); - return AVERROR(ENOMEM); - } - - /* Make sure we use a user-supplied buffer. */ - if ((ret = ff_reget_buffer(avctx, ctx->final_frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not make frame writable.\n"); + ret = av_frame_replace(ctx->final_frame, ctx->frame); + if (ret < 0) return ret; - } - /* Draw cursor. */ + /* Draw cursor if needed. */ if (!skip_cursor) { - memcpy(ctx->cursor_buf, src + CURSOR_OFFSET, sizeof(ctx->cursor_buf)); - fic_draw_cursor(avctx, cur_x, cur_y); + /* Make frame writable. */ + ret = ff_reget_buffer(avctx, ctx->final_frame, 0); + if (ret < 0) + return ret; + + fic_draw_cursor(avctx, src + CURSOR_OFFSET, cur_x, cur_y); } skip: - *got_frame = 1; if ((ret = av_frame_ref(rframe, ctx->final_frame)) < 0) return ret; + *got_frame = 1; return avpkt->size; } @@ -469,6 +468,9 @@ static av_cold int fic_decode_init(AVCodecContext *avctx) ctx->frame = av_frame_alloc(); if (!ctx->frame) return AVERROR(ENOMEM); + ctx->final_frame = av_frame_alloc(); + if (!ctx->final_frame) + return AVERROR(ENOMEM); return 0; } @@ -496,4 +498,5 @@ const FFCodec ff_fic_decoder = { .close = fic_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, .p.priv_class = &fic_decoder_class, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/fits.c b/libavcodec/fits.c index 5f364960e0..0fc2d895b7 100644 --- a/libavcodec/fits.c +++ b/libavcodec/fits.c @@ -32,6 +32,8 @@ int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state) { header->state = state; header->naxis_index = 0; + header->naxis = 0; + memset(header->naxisn, 0, sizeof(header->naxisn)); header->blank_found = 0; header->pcount = 0; header->gcount = 1; diff --git a/libavcodec/fitsenc.c b/libavcodec/fitsenc.c index 86ea11f0c0..2a31514068 100644 --- a/libavcodec/fitsenc.c +++ b/libavcodec/fitsenc.c @@ -117,11 +117,6 @@ const FFCodec ff_fits_encoder = { .p.id = AV_CODEC_ID_FITS, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(fits_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRAP16BE, - AV_PIX_FMT_GBRP16BE, - AV_PIX_FMT_GBRP, - AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GRAY16BE, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRAP16BE, AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/flac_parse.h b/libavcodec/flac_parse.h index b0cbad825e..78485b3320 100644 --- a/libavcodec/flac_parse.h +++ b/libavcodec/flac_parse.h @@ -58,7 +58,7 @@ typedef struct FLACFrameInfo { * @param[out] s where parsed information is stored * @param[in] buffer pointer to start of 34-byte streaminfo data * - * @return negative error code on faiure or >= 0 on success + * @return negative error code on failure or >= 0 on success */ int ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, const uint8_t *buffer); diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index ad921a1bd1..0c88f577a1 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -827,10 +827,7 @@ const FFCodec ff_flac_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P), .p.priv_class = &flac_decoder_class, }; diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c index f5362bf66f..b5b0609716 100644 --- a/libavcodec/flacdsp.c +++ b/libavcodec/flacdsp.c @@ -94,7 +94,7 @@ static void flac_lpc_33_c(int64_t *decoded, const int32_t *residual, int64_t sum = 0; for (j = 0; j < pred_order; j++) sum += (int64_t)coeffs[j] * (uint64_t)decoded[j]; - decoded[j] = residual[i] + (sum >> qlevel); + decoded[j] = (uint64_t)residual[i] + (uint64_t)(sum >> qlevel); } } diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h index 3b7b35a112..fb76c55aee 100644 --- a/libavcodec/flacdsp.h +++ b/libavcodec/flacdsp.h @@ -35,10 +35,6 @@ typedef struct FLACDSPContext { void (*wasted32)(int32_t *decoded, int wasted, int len); void (*wasted33)(int64_t *decoded, const int32_t *residual, int wasted, int len); - void (*lpc16_encode)(int32_t *res, const int32_t *smp, int len, int order, - const int32_t coefs[32], int shift); - void (*lpc32_encode)(int32_t *res, const int32_t *smp, int len, int order, - const int32_t coefs[32], int shift); } FLACDSPContext; void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels); diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c index 3a9578f5cd..c6b9eb437a 100644 --- a/libavcodec/flacenc.c +++ b/libavcodec/flacenc.c @@ -1760,9 +1760,7 @@ const FFCodec ff_flac_encoder = { .init = flac_encode_init, FF_CODEC_ENCODE_CB(flac_encode_frame), .close = flac_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), .p.priv_class = &flac_encoder_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, }; diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c index 6156d00d0d..17e0bc1b3c 100644 --- a/libavcodec/flashsv2enc.c +++ b/libavcodec/flashsv2enc.c @@ -786,7 +786,7 @@ static int optimum_block_height(FlashSV2Context * s) static int optimum_use15_7(FlashSV2Context * s) { #ifndef FLASHSV2_DUMB - double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den * s->avctx->ticks_per_frame)) / + double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den)) / ((double) s->avctx->time_base.num) * s->avctx->frame_num; if (ideal + use15_7_threshold < s->total_bits) { return 1; @@ -802,8 +802,7 @@ static int optimum_dist(FlashSV2Context * s) { #ifndef FLASHSV2_DUMB double ideal = - s->avctx->bit_rate * s->avctx->time_base.den * - s->avctx->ticks_per_frame; + s->avctx->bit_rate * s->avctx->time_base.den; int dist = pow((s->total_bits / ideal) * color15_7_factor, 3); av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist); return dist; @@ -920,6 +919,6 @@ const FFCodec ff_flashsv2_encoder = { .init = flashsv2_encode_init, FF_CODEC_ENCODE_CB(flashsv2_encode_frame), .close = flashsv2_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/flashsvenc.c b/libavcodec/flashsvenc.c index 5cf0602f5d..bd4c8651e2 100644 --- a/libavcodec/flashsvenc.c +++ b/libavcodec/flashsvenc.c @@ -67,6 +67,7 @@ typedef struct FlashSVContext { unsigned packet_size; int64_t last_key_frame; uint8_t tmpblock[3 * 256 * 256]; + int compression_level; } FlashSVContext; static int copy_region_enc(const uint8_t *sptr, uint8_t *dptr, int dx, int dy, @@ -121,6 +122,10 @@ static av_cold int flashsv_encode_init(AVCodecContext *avctx) nb_blocks = h_blocks * v_blocks; s->packet_size = 4 + nb_blocks * (2 + 3 * BLOCK_WIDTH * BLOCK_HEIGHT); + s->compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT + ? Z_DEFAULT_COMPRESSION + : av_clip(avctx->compression_level, 0, 9); + return 0; } @@ -170,9 +175,10 @@ static int encode_bitstream(FlashSVContext *s, const AVFrame *p, uint8_t *buf, p->linesize[0], previous_frame); if (res || *I_frame) { - unsigned long zsize = 3 * block_width * block_height; + unsigned long zsize = 3 * block_width * block_height + 12; ret = compress2(ptr + 2, &zsize, s->tmpblock, - 3 * cur_blk_width * cur_blk_height, 9); + 3 * cur_blk_width * cur_blk_height, + s->compression_level); if (ret != Z_OK) av_log(s->avctx, AV_LOG_ERROR, @@ -256,5 +262,5 @@ const FFCodec ff_flashsv_encoder = { .init = flashsv_encode_init, FF_CODEC_ENCODE_CB(flashsv_encode_frame), .close = flashsv_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), }; diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c index 43f3f83bf6..f17e61a9f2 100644 --- a/libavcodec/flicvideo.c +++ b/libavcodec/flicvideo.c @@ -682,11 +682,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, /* make the palette available on the way out */ memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); if (s->new_palette) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->new_palette = 0; } diff --git a/libavcodec/vulkan.h b/libavcodec/float_scalarproduct.c similarity index 87% rename from libavcodec/vulkan.h rename to libavcodec/float_scalarproduct.c index b15efd4add..647f0ec72d 100644 --- a/libavcodec/vulkan.h +++ b/libavcodec/float_scalarproduct.c @@ -16,9 +16,4 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VULKAN_H -#define AVCODEC_VULKAN_H - -#include "libavutil/vulkan.h" - -#endif /* AVCODEC_VULKAN_H */ +#include "libavutil/float_scalarproduct.c" diff --git a/libavcodec/flvdec.c b/libavcodec/flvdec.c index f4bfd99417..0f6eaad5c6 100644 --- a/libavcodec/flvdec.c +++ b/libavcodec/flvdec.c @@ -26,31 +26,31 @@ #include "mpegvideo.h" #include "mpegvideodec.h" -int ff_flv_decode_picture_header(MpegEncContext *s) +int ff_flv_decode_picture_header(H263DecContext *const h) { int format, width, height; /* picture header */ - if (get_bits(&s->gb, 17) != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + if (get_bits(&h->gb, 17) != 1) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return AVERROR_INVALIDDATA; } - format = get_bits(&s->gb, 5); + format = get_bits(&h->gb, 5); if (format != 0 && format != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture format\n"); return AVERROR_INVALIDDATA; } - s->h263_flv = format + 1; - s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */ - format = get_bits(&s->gb, 3); + h->flv = format; + h->picture_number = get_bits(&h->gb, 8); /* picture timestamp */ + format = get_bits(&h->gb, 3); switch (format) { case 0: - width = get_bits(&s->gb, 8); - height = get_bits(&s->gb, 8); + width = get_bits(&h->gb, 8); + height = get_bits(&h->gb, 8); break; case 1: - width = get_bits(&s->gb, 16); - height = get_bits(&s->gb, 16); + width = get_bits(&h->gb, 16); + height = get_bits(&h->gb, 16); break; case 2: width = 352; @@ -76,36 +76,32 @@ int ff_flv_decode_picture_header(MpegEncContext *s) width = height = 0; break; } - if (av_image_check_size(width, height, 0, s->avctx)) + if (av_image_check_size(width, height, 0, h->c.avctx)) return AVERROR(EINVAL); - s->width = width; - s->height = height; + h->c.width = width; + h->c.height = height; - s->pict_type = AV_PICTURE_TYPE_I + get_bits(&s->gb, 2); - s->droppable = s->pict_type > AV_PICTURE_TYPE_P; - if (s->droppable) - s->pict_type = AV_PICTURE_TYPE_P; + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits(&h->gb, 2); + h->c.droppable = h->c.pict_type > AV_PICTURE_TYPE_P; + if (h->c.droppable) + h->c.pict_type = AV_PICTURE_TYPE_P; - skip_bits1(&s->gb); /* deblocking flag */ - s->chroma_qscale = s->qscale = get_bits(&s->gb, 5); + skip_bits1(&h->gb); /* deblocking flag */ + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); - s->h263_plus = 0; - - s->h263_long_vectors = 0; + h->h263_long_vectors = 0; /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - s->f_code = 1; + if (h->ehc_mode) + h->c.avctx->sample_aspect_ratio= (AVRational){1,2}; - if (s->ehc_mode) - s->avctx->sample_aspect_ratio= (AVRational){1,2}; - - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "%c esc_type:%d, qp:%d num:%d\n", - s->droppable ? 'D' : av_get_picture_type_char(s->pict_type), - s->h263_flv - 1, s->qscale, s->picture_number); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "%c esc_type:%d, qp:%d num:%d\n", + h->c.droppable ? 'D' : av_get_picture_type_char(h->c.pict_type), + h->flv, h->c.qscale, h->picture_number); } return 0; @@ -116,7 +112,7 @@ const FFCodec ff_flv_decoder = { CODEC_LONG_NAME("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_FLV1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/flvdec.h b/libavcodec/flvdec.h index d5aff74a98..e0f6d299ca 100644 --- a/libavcodec/flvdec.h +++ b/libavcodec/flvdec.h @@ -21,8 +21,8 @@ #ifndef AVCODEC_FLVDEC_H #define AVCODEC_FLVDEC_H -#include "mpegvideo.h" +struct H263DecContext; -int ff_flv_decode_picture_header(MpegEncContext *s); +int ff_flv_decode_picture_header(struct H263DecContext *const h); #endif /* AVCODEC_FLVDEC_H */ diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c index 40eec07b3e..0b6e73b11e 100644 --- a/libavcodec/flvenc.c +++ b/libavcodec/flvenc.c @@ -20,76 +20,51 @@ #include "codec_internal.h" #include "flvenc.h" -#include "h263data.h" #include "mpegvideo.h" -#include "mpegvideodata.h" #include "mpegvideoenc.h" +#include "put_bits.h" -void ff_flv_encode_picture_header(MpegEncContext *s) +int ff_flv_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int format; - align_put_bits(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 17, 1); /* 0: H.263 escape codes 1: 11-bit escape codes */ - put_bits(&s->pb, 5, (s->h263_flv - 1)); + put_bits(&s->pb, 5, 1); put_bits(&s->pb, 8, - (((int64_t) s->picture_number * 30 * s->avctx->time_base.num) / // FIXME use timestamp - s->avctx->time_base.den) & 0xff); /* TemporalReference */ - if (s->width == 352 && s->height == 288) + (((int64_t) s->picture_number * 30 * s->c.avctx->time_base.num) / // FIXME use timestamp + s->c.avctx->time_base.den) & 0xff); /* TemporalReference */ + if (s->c.width == 352 && s->c.height == 288) format = 2; - else if (s->width == 176 && s->height == 144) + else if (s->c.width == 176 && s->c.height == 144) format = 3; - else if (s->width == 128 && s->height == 96) + else if (s->c.width == 128 && s->c.height == 96) format = 4; - else if (s->width == 320 && s->height == 240) + else if (s->c.width == 320 && s->c.height == 240) format = 5; - else if (s->width == 160 && s->height == 120) + else if (s->c.width == 160 && s->c.height == 120) format = 6; - else if (s->width <= 255 && s->height <= 255) + else if (s->c.width <= 255 && s->c.height <= 255) format = 0; /* use 1 byte width & height */ else format = 1; /* use 2 bytes width & height */ put_bits(&s->pb, 3, format); /* PictureSize */ if (format == 0) { - put_bits(&s->pb, 8, s->width); - put_bits(&s->pb, 8, s->height); + put_bits(&s->pb, 8, s->c.width); + put_bits(&s->pb, 8, s->c.height); } else if (format == 1) { - put_bits(&s->pb, 16, s->width); - put_bits(&s->pb, 16, s->height); + put_bits(&s->pb, 16, s->c.width); + put_bits(&s->pb, 16, s->c.height); } - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_P); /* PictureType */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_P); /* PictureType */ put_bits(&s->pb, 1, 1); /* DeblockingFlag: on */ - put_bits(&s->pb, 5, s->qscale); /* Quantizer */ + put_bits(&s->pb, 5, s->c.qscale); /* Quantizer */ put_bits(&s->pb, 1, 0); /* ExtraInformation */ - if (s->h263_aic) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_aic_dc_scale_table; - } else { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; - } -} - -void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, - int run, int last) -{ - if (level < 64) { // 7-bit level - put_bits(pb, 1, 0); - put_bits(pb, 1, last); - put_bits(pb, 6, run); - - put_sbits(pb, 7, slevel); - } else { - /* 11-bit level */ - put_bits(pb, 1, 1); - put_bits(pb, 1, last); - put_bits(pb, 6, run); - - put_sbits(pb, 11, slevel); - } + return 0; } const FFCodec ff_flv_encoder = { @@ -98,13 +73,12 @@ const FFCodec ff_flv_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_FLV1, .p.priv_class = &ff_mpv_enc_class, - .priv_data_size = sizeof(MpegEncContext), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/flvenc.h b/libavcodec/flvenc.h index 1ecbb46b17..a244145e42 100644 --- a/libavcodec/flvenc.h +++ b/libavcodec/flvenc.h @@ -21,11 +21,8 @@ #ifndef AVCODEC_FLVENC_H #define AVCODEC_FLVENC_H -#include "mpegvideo.h" -#include "put_bits.h" +typedef struct MPVMainEncContext MPVMainEncContext; -void ff_flv_encode_picture_header(MpegEncContext *s); -void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, int run, - int last); +int ff_flv_encode_picture_header(MPVMainEncContext *const m); #endif /* AVCODEC_FLV_H */ diff --git a/libavcodec/ftr.c b/libavcodec/ftr.c index 7cf1b1586f..06241fdca3 100644 --- a/libavcodec/ftr.c +++ b/libavcodec/ftr.c @@ -51,7 +51,7 @@ static av_cold int ftr_init(AVCodecContext *avctx) codec = avcodec_find_decoder(AV_CODEC_ID_AAC); if (!codec) - return AVERROR_BUG; + return AVERROR_DECODER_NOT_FOUND; for (int i = 0; i < s->nb_context; i++) { s->aac_avctx[i] = avcodec_alloc_context3(codec); @@ -203,10 +203,6 @@ const FFCodec ff_ftr_decoder = { .close = ftr_close, .flush = ftr_flush, .priv_data_size = sizeof(FTRContext), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/g722dec.c b/libavcodec/g722dec.c index 231f1d32eb..cc89737b31 100644 --- a/libavcodec/g722dec.c +++ b/libavcodec/g722dec.c @@ -63,6 +63,8 @@ static av_cold int g722_decode_init(AVCodecContext * avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (!avctx->sample_rate) + avctx->sample_rate = 16000; c->band[0].scale_factor = 8; c->band[1].scale_factor = 2; diff --git a/libavcodec/g722enc.c b/libavcodec/g722enc.c index 19ab0f8b55..fc3db7cc8b 100644 --- a/libavcodec/g722enc.c +++ b/libavcodec/g722enc.c @@ -382,9 +382,7 @@ const FFCodec ff_adpcm_g722_encoder = { .init = g722_encode_init, .close = g722_encode_close, FF_CODEC_ENCODE_CB(g722_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/g723_1dec.c b/libavcodec/g723_1dec.c index 5fe4a21d9b..67a5df55ff 100644 --- a/libavcodec/g723_1dec.c +++ b/libavcodec/g723_1dec.c @@ -1118,10 +1118,6 @@ const FFCodec ff_g723_1_decoder = { .priv_data_size = sizeof(G723_1_Context), .init = g723_1_decode_init, FF_CODEC_DECODE_CB(g723_1_decode_frame), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .p.priv_class = &g723_1dec_class, }; diff --git a/libavcodec/g723_1enc.c b/libavcodec/g723_1enc.c index be80153130..ee5b0fe251 100644 --- a/libavcodec/g723_1enc.c +++ b/libavcodec/g723_1enc.c @@ -1246,10 +1246,6 @@ const FFCodec ff_g723_1_encoder = { .init = g723_1_encode_init, FF_CODEC_ENCODE_CB(g723_1_encode_frame), .defaults = defaults, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE - }, - .p.ch_layouts = (const AVChannelLayout[]){ - AV_CHANNEL_LAYOUT_MONO, { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), }; diff --git a/libavcodec/g726.c b/libavcodec/g726.c index e048cd973e..f41df3073f 100644 --- a/libavcodec/g726.c +++ b/libavcodec/g726.c @@ -410,8 +410,7 @@ const FFCodec ff_adpcm_g726_encoder = { .priv_data_size = sizeof(G726Context), .init = g726_encode_init, FF_CODEC_ENCODE_CB(g726_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &g726_class, .defaults = defaults, }; @@ -428,8 +427,7 @@ const FFCodec ff_adpcm_g726le_encoder = { .priv_data_size = sizeof(G726Context), .init = g726_encode_init, FF_CODEC_ENCODE_CB(g726_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &g726_class, .defaults = defaults, }; @@ -457,6 +455,8 @@ static av_cold int g726_decode_init(AVCodecContext *avctx) g726_reset(c); avctx->sample_fmt = AV_SAMPLE_FMT_S16; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; return 0; } diff --git a/libavcodec/g728_template.c b/libavcodec/g728_template.c new file mode 100644 index 0000000000..dd1b1a4415 --- /dev/null +++ b/libavcodec/g728_template.c @@ -0,0 +1,65 @@ +/* + * G.728 / RealAudio 2.0 (28.8K) decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static void convolve(float *tgt, const float *src, int len, int n) +{ + for (; n >= 0; n--) + tgt[n] = ff_scalarproduct_float_c(src, src - n, len); + +} + +/** + * Hybrid window filtering, see blocks 36 and 49 of the G.728 specification. + * + * @param order filter order + * @param n input length + * @param non_rec number of non-recursive samples + * @param out filter output + * @param hist pointer to the input history of the filter + * @param out pointer to the non-recursive part of the output + * @param out2 pointer to the recursive part of the output + * @param window pointer to the windowing function table + */ +static void do_hybrid_window(void (*vector_fmul)(float *dst, const float *src0, const float *src1, int len), + int order, int n, int non_rec, float *out, + const float *hist, float *out2, const float *window) +{ + int i; + float buffer1[MAX_BACKWARD_FILTER_ORDER + 1]; + float buffer2[MAX_BACKWARD_FILTER_ORDER + 1]; + LOCAL_ALIGNED(32, float, work, [FFALIGN(MAX_BACKWARD_FILTER_ORDER + + MAX_BACKWARD_FILTER_LEN + + MAX_BACKWARD_FILTER_NONREC, 16)]); + + av_assert2(order>=0); + + vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16)); + + convolve(buffer1, work + order , n , order); + convolve(buffer2, work + order + n, non_rec, order); + + for (i=0; i <= order; i++) { + out2[i] = out2[i] * ATTEN + buffer1[i]; + out [i] = out2[i] + buffer2[i]; + } + + /* Multiply by the white noise correcting factor (WNCF). */ + *out *= 257.0 / 256.0; +} diff --git a/libavcodec/g728data.h b/libavcodec/g728data.h new file mode 100644 index 0000000000..a2ddf5682d --- /dev/null +++ b/libavcodec/g728data.h @@ -0,0 +1,70 @@ +/* + * G.728 decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_G728DATA_H +#define AVCODEC_G728DATA_H + +#include +#include "libavutil/macros.h" + +#define IDIM 5 /* Vector dimension (excitation block size) */ +#define LPC 50 /* Synthesis filter order */ +#define LPCLG 10 /* Log-gain predictor order */ +#define NFRSZ 20 /* Frame size (adaptation cycle size in samples */ +#define NONR 35 /* Number of non-recursive window samples for synthesis filter */ +#define NONRLG 20 /* Number of non-recursive window samples for log-gain predictor */ +#define NUPDATE 4 /* Predictor update period (in terms of vectors) */ + +#define NSBSZ (LPC + NONR + NFRSZ) +#define NSBGSZ (LPCLG + NONRLG + NUPDATE) + +// Hybrid window for the synthesis filter +static const uint16_t g728_wnr[NSBSZ] = { + 1565, 3127, 4681, 6225, 7755, 9266, 10757, 12223, 13661, 15068, + 16441, 17776, 19071, 20322, 21526, 22682, 23786, 24835, 25828, 26761, + 27634, 28444, 29188, 29866, 30476, 31016, 31486, 31884, 32208, 32460, + 32637, 32739, 32767, 32721, 32599, 32403, 32171, 31940, 31711, 31484, + 31259, 31034, 30812, 30591, 30372, 30154, 29938, 29724, 29511, 29299, + 29089, 28881, 28674, 28468, 28264, 28062, 27861, 27661, 27463, 27266, + 27071, 26877, 26684, 26493, 26303, 26114, 25927, 25742, 25557, 25374, + 25192, 25012, 24832, 24654, 24478, 24302, 24128, 23955, 23784, 23613, + 23444, 23276, 23109, 22943, 22779, 22616, 22454, 22293, 22133, 21974, + 21817, 21661, 21505, 21351, 21198, 21046, 20896, 20746, 20597, 20450, + 20303, 20157, 20013, 19870, 19727 +}; + +// Hybrid window for the log-gain predictor +static const uint16_t g728_wnrg[NSBGSZ] = { + 3026, 6025, 8973, 11845, 14615, 17261, 19759, 22088, 24228, 26162, + 27872, 29344, 30565, 31525, 32216, 32631, 32767, 32625, 32203, 31506, + 30540, 29461, 28420, 27416, 26448, 25514, 24613, 23743, 22905, 22096, + 21315, 20562, 19836, 19135 +}; + +// Values for bandwidth broadcasting +static const uint16_t g728_facv[LPC] = { + 16192, 16002, 15815, 15629, 15446, 15265, 15086, 14910, 14735, 14562, + 14391, 14223, 14056, 13891, 13729, 13568, 13409, 13252, 13096, 12943, + 12791, 12641, 12493, 12347, 12202, 12059, 11918, 11778, 11640, 11504, + 11369, 11236, 11104, 10974, 10845, 10718, 10593, 10468, 10346, 10225, + 10105, 9986, 9869, 9754, 9639, 9526, 9415, 9304, 9195, 9088 +}; + +#endif /* AVCODEC_G728DATA_H */ diff --git a/libavcodec/g728dec.c b/libavcodec/g728dec.c new file mode 100644 index 0000000000..6403bcae46 --- /dev/null +++ b/libavcodec/g728dec.c @@ -0,0 +1,220 @@ +/* + * G.728 decoder + * Copyright (c) 2025 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 + */ + +#include "avcodec.h" +#include "celp_filters.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "g728data.h" +#include "lpc_functions.h" +#include "ra288.h" +#include "libavutil/float_dsp.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +#define MAX_BACKWARD_FILTER_ORDER LPC +#define MAX_BACKWARD_FILTER_LEN NFRSZ +#define MAX_BACKWARD_FILTER_NONREC NONR +#define ATTEN 0.75f +#include "g728_template.c" + +#define LPCW 10 /* Perceptual weighting filter order */ +#define GOFF 32.0f /* Log-gain offset value */ + +static float g728_gq_db[8]; +static float g728_y_db[128]; +static DECLARE_ALIGNED(32, float, g728_wnr_r)[FFALIGN(NSBSZ,16)]; +static DECLARE_ALIGNED(32, float, g728_wnrg_r)[FFALIGN(NSBGSZ, 16)]; +static DECLARE_ALIGNED(32, float, g728_facv_f)[FFALIGN(LPC, 16)]; + +static av_cold void g728_init_static_data(void) +{ + for(int i = 0; i < FF_ARRAY_ELEMS(amptable); i++) + g728_gq_db[i] = 10.0f*log10f(amptable[i] * amptable[i]); + + for (int i = 0; i < FF_ARRAY_ELEMS(codetable); i++) { + float cby[IDIM]; + for (int j = 0; j < IDIM; j++) + cby[j] = codetable[i][j] * (1.0f/(1<<11)); + g728_y_db[i] = 10.0f*log10f(ff_scalarproduct_float_c(cby, cby, IDIM) / IDIM); + } + + for (int i = 0; i < NSBSZ; i++) + g728_wnr_r[i] = g728_wnr[NSBSZ - 1 - i] * (1.0f/(1<<15)); + for (int i = 0; i < NSBGSZ; i++) + g728_wnrg_r[i] = g728_wnrg[NSBGSZ - 1 - i] * (1.0f/(1<<15)); + for (int i = 0; i < LPC; i++) + g728_facv_f[i] = g728_facv[i] * (1.0f/(1<<14)); +} + +typedef struct { + AVFloatDSPContext *fdsp; + int valid; + float a[LPC]; + DECLARE_ALIGNED(32, float, sb)[NSBSZ]; + DECLARE_ALIGNED(32, float, sbg)[NSBGSZ]; + DECLARE_ALIGNED(32, float, gp)[FFALIGN(LPCLG, 16)]; + DECLARE_ALIGNED(32, float, atmp)[FFALIGN(LPC, 16)]; + float rexp[LPC + 1]; + float rexpg[LPCLG + 1]; + float r[LPC + 1]; + float alpha; +} G728Context; + +static av_cold int g728_decode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + G728Context *s = avctx->priv_data; + + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->fdsp) + return AVERROR(ENOMEM); + + s->gp[0] = -1.0f; + for (int i = 0; i < NUPDATE; i++) + s->sbg[NSBGSZ - 1 -i] = -GOFF; + + avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; + + av_channel_layout_uninit(&avctx->ch_layout); + avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; + + ff_thread_once(&init_static_once, g728_init_static_data); + return 0; +} + +static av_cold int g728_decode_close(AVCodecContext *avctx) +{ + G728Context *s = avctx->priv_data; + av_freep(&s->fdsp); + return 0; +} + +static int hybrid_window(AVFloatDSPContext *fdsp, + int order, int n, int non_rec, float *out, + const float *hist, float *out2, const float *window) +{ + do_hybrid_window(fdsp->vector_fmul, order, n, non_rec, out, hist, out2, window); + return out[order] != 0.0f; +} + +static void decode_frame(G728Context *s, GetBitContext *gb, float *dst) +{ + float *gstate = s->sbg + NSBGSZ - 2; + + for (int idx = 0; idx < NUPDATE; idx++) { + DECLARE_ALIGNED(32, float, et)[IDIM]; + float *statelpc = s->sb + NSBSZ - NFRSZ + idx*IDIM; + float gain, gain_db; + int is, ig; + + gain_db = 0.0f; + for (int i = 0; i < LPCLG; i++) + gain_db -= s->gp[i] * gstate[-i]; + gain_db = av_clipf(gain_db, -GOFF, 28.0f); + + is = get_bits(gb, 7); // shape index + ig = get_bits(gb, 3); // gain index + + gain = powf(10.0f, (gain_db + GOFF) * .05f) * amptable[ig] * (1.0f/(1<<11)); + for (int i = 0; i < IDIM; i++) + et[i] = codetable[is][i] * gain; + + ff_celp_lp_synthesis_filterf(statelpc, s->a, et, IDIM, LPC); + + for (int i = 0; i < IDIM; i++) { + statelpc[i] = av_clipf(statelpc[i], -4095.0f, 4095.0f); + dst[idx*IDIM + i] = statelpc[i] * (1.0f/(1<<12)); + } + + gstate++; + *gstate = FFMAX(-GOFF, g728_gq_db[ig] + g728_y_db[is] + gain_db); + + if (idx == 0) { + DECLARE_ALIGNED(32, float, gptmp)[FFALIGN(LPCLG, 16)]; + if (s->valid && (s->valid = !compute_lpc_coefs(s->r + 1, LPCW, LPC, s->atmp, 0, 0, 1, &s->alpha))) { + s->fdsp->vector_fmul(s->atmp, s->atmp, g728_facv_f, FFALIGN(LPC, 16)); + } + if (hybrid_window(s->fdsp, LPCLG, NUPDATE, NONRLG, s->r, s->sbg, s->rexpg, g728_wnrg_r) && + !compute_lpc_coefs(s->r, 0, LPCLG, gptmp, 0, 0, 1, &s->alpha)) { + s->fdsp->vector_fmul(s->gp, gptmp, gain_bw_tab, FFALIGN(LPCLG, 16)); + } + memmove(s->sbg, s->sbg + NUPDATE, sizeof(float)*(LPCLG + NONRLG)); + gstate = s->sbg + NSBGSZ - 1 - NUPDATE; + } else if (idx == 1) { + if (s->valid) + memcpy(s->a, s->atmp, sizeof(float)*LPC); + } + } + + s->valid = 0; + if (hybrid_window(s->fdsp, LPC, NFRSZ, NONR, s->r, s->sb, s->rexp, g728_wnr_r)) { + s->valid = !compute_lpc_coefs(s->r, 0, LPCW, s->atmp, 0, 0, 1, &s->alpha); + } + + memmove(s->sb, s->sb + NFRSZ, sizeof(float)*(LPC + NONR)); +} + +static int g728_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + G728Context *s = avctx->priv_data; + GetBitContext gb; + int ret; + int nb_frames = avpkt->size / 5; + + if (!nb_frames) + return AVERROR_INVALIDDATA; + + if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) + return ret; + +#define SAMPLES_PER_FRAME 20 + + frame->nb_samples = nb_frames * SAMPLES_PER_FRAME; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (int i = 0; i < nb_frames; i++) + decode_frame(s, &gb, (float *)frame->data[0] + i * 20); + + *got_frame_ptr = 1; + + return nb_frames * 5; +} + +const FFCodec ff_g728_decoder = { + .p.name = "g728", + CODEC_LONG_NAME("G.728)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_G728, + .priv_data_size = sizeof(G728Context), + .init = g728_decode_init, + .close = g728_decode_close, + FF_CODEC_DECODE_CB(g728_decode_frame), + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | + AV_CODEC_CAP_DR1, +}; diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index bf10a6dd33..7499ed7444 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -761,11 +761,7 @@ const FFCodec ff_g729_decoder = { .init = decoder_init, FF_CODEC_DECODE_CB(decode_frame), .close = decode_close, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, }; const FFCodec ff_acelp_kelvin_decoder = { @@ -777,9 +773,5 @@ const FFCodec ff_acelp_kelvin_decoder = { .init = decoder_init, FF_CODEC_DECODE_CB(decode_frame), .close = decode_close, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c index b1880b2fe1..824253477f 100644 --- a/libavcodec/g729postfilter.c +++ b/libavcodec/g729postfilter.c @@ -211,8 +211,8 @@ static int16_t long_term_filter(AudioDSPContext *adsp, int pitch_delay_int, /* Compute signals with non-integer delay k (with 1/8 precision), where k is in [0;6] range. Entire delay is qual to best_delay+(k+1)/8 - This is archieved by applying an interpolation filter of - legth 33 to source signal. */ + This is achieved by applying an interpolation filter of + length 33 to source signal. */ for (k = 0; k < ANALYZED_FRAC_DELAYS; k++) { ff_acelp_interpolate(&delayed_signal[k][0], &sig_scaled[RES_PREV_DATA_SIZE - best_delay_int], diff --git a/libavcodec/gemdec.c b/libavcodec/gemdec.c index 5ece2e2ee3..07f01a24a1 100644 --- a/libavcodec/gemdec.c +++ b/libavcodec/gemdec.c @@ -182,11 +182,6 @@ static int gem_decode_frame(AVCodecContext *avctx, AVFrame *p, p->pict_type = AV_PICTURE_TYPE_I; p->flags |= AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif palette = (uint32_t *)p->data[1]; if (tag == AV_RB32("STTT")) { diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h index fe2f6378b4..80a77f0ae3 100644 --- a/libavcodec/get_bits.h +++ b/libavcodec/get_bits.h @@ -76,6 +76,7 @@ typedef BitstreamContext GetBitContext; #define get_bits_count bits_tell +#define get_bits_bytesize bits_bytesize #define get_bits_left bits_left #define skip_bits_long bits_skip #define skip_bits bits_skip @@ -106,7 +107,7 @@ typedef BitstreamContext GetBitContext; #else // CACHED_BITSTREAM_READER typedef struct GetBitContext { - const uint8_t *buffer, *buffer_end; + const uint8_t *buffer; int index; int size_in_bits; int size_in_bits_plus8; @@ -163,11 +164,7 @@ static inline unsigned int show_bits(GetBitContext *s, int n); * For examples see get_bits, show_bits, skip_bits, get_vlc. */ -#if defined LONG_BITSTREAM_READER -# define MIN_CACHE_BITS 32 -#else -# define MIN_CACHE_BITS 25 -#endif +#define MIN_CACHE_BITS 25 #define OPEN_READER_NOSIZE(name, gb) \ unsigned int name ## _index = (gb)->index; \ @@ -195,24 +192,11 @@ static inline unsigned int show_bits(GetBitContext *s, int n); /* Using these two macros ensures that 32 bits are available. */ # define UPDATE_CACHE_LE_32(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 64, 32) - # define UPDATE_CACHE_BE_32(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 64, 32) -# ifdef LONG_BITSTREAM_READER - -# define UPDATE_CACHE_LE(name, gb) UPDATE_CACHE_LE_32(name, (gb)) - -# define UPDATE_CACHE_BE(name, gb) UPDATE_CACHE_BE_32(name, (gb)) - -#else - # define UPDATE_CACHE_LE(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 32, 32) - # define UPDATE_CACHE_BE(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 32, 32) -#endif - - #ifdef BITSTREAM_READER_LE # define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) @@ -268,6 +252,20 @@ static inline int get_bits_count(const GetBitContext *s) return s->index; } +/** + * Get the size of the GetBitContext's buffer in bytes. + * + * @param s the GetBitContext + * @param round_up If set, the number of bits will be rounded up to full bytes; + * this does not matter if the number of bits is known to be + * a multiple of eight, e.g. if the GetBitContext has been + * initialized with init_get_bits8. + */ +static inline int get_bits_bytesize(const GetBitContext *s, int round_up) +{ + return (s->size_in_bits + (round_up ? 7 : 0)) >> 3; +} + /** * Skips the specified number of bits. * @param n the number of bits to skip, @@ -514,7 +512,6 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n) static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, int bit_size) { - int buffer_size; int ret = 0; if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { @@ -523,12 +520,9 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, ret = AVERROR_INVALIDDATA; } - buffer_size = (bit_size + 7) >> 3; - s->buffer = buffer; s->size_in_bits = bit_size; s->size_in_bits_plus8 = bit_size + 8; - s->buffer_end = buffer + buffer_size; s->index = 0; return ret; @@ -611,7 +605,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, bits); \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ \ if (max_depth > 1 && n < 0) { \ SKIP_BITS(name, gb, bits); \ @@ -623,7 +617,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, nb_bits) + level; \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ if (max_depth > 2 && n < 0) { \ LAST_SKIP_BITS(name, gb, nb_bits); \ if (need_update) { \ @@ -633,7 +627,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) \ index = SHOW_UBITS(name, gb, nb_bits) + level; \ level = table[index].level; \ - n = table[index].len; \ + n = table[index].len8; \ } \ } \ run = table[index].run; \ diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c index ff19f61e86..b391adf24f 100644 --- a/libavcodec/get_buffer.c +++ b/libavcodec/get_buffer.c @@ -32,7 +32,7 @@ #include "avcodec.h" #include "internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" typedef struct FramePool { /** @@ -53,7 +53,7 @@ typedef struct FramePool { int samples; } FramePool; -static void frame_pool_free(FFRefStructOpaque unused, void *obj) +static void frame_pool_free(AVRefStructOpaque unused, void *obj) { FramePool *pool = obj; int i; @@ -77,7 +77,7 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) return 0; } - pool = ff_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free); + pool = av_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free); if (!pool) return AVERROR(ENOMEM); @@ -142,7 +142,10 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) if (ret < 0) goto fail; - pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL); + pool->pools[0] = av_buffer_pool_init(pool->linesize[0], + CONFIG_MEMORY_POISONING ? + NULL : + av_buffer_allocz); if (!pool->pools[0]) { ret = AVERROR(ENOMEM); goto fail; @@ -157,12 +160,12 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) default: av_assert0(0); } - ff_refstruct_unref(&avctx->internal->pool); + av_refstruct_unref(&avctx->internal->pool); avctx->internal->pool = pool; return 0; fail: - ff_refstruct_unref(&pool); + av_refstruct_unref(&pool); return ret; } diff --git a/libavcodec/gif.c b/libavcodec/gif.c index c36fa66737..04f5341ea7 100644 --- a/libavcodec/gif.c +++ b/libavcodec/gif.c @@ -559,10 +559,8 @@ const FFCodec ff_gif_encoder = { .init = gif_encode_init, FF_CODEC_ENCODE_CB(gif_encode_frame), .close = gif_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, + AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8), .p.priv_class = &gif_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/h261.h b/libavcodec/h261.h index 4279a12677..fb5fc6f940 100644 --- a/libavcodec/h261.h +++ b/libavcodec/h261.h @@ -29,7 +29,6 @@ #define AVCODEC_H261_H #include "mpegutils.h" -#include "mpegvideo.h" #include "rl.h" /** @@ -54,6 +53,7 @@ extern const uint16_t ff_h261_tcoeff_vlc[65][2]; extern const int8_t ff_h261_tcoeff_level[64]; extern const int8_t ff_h261_tcoeff_run[64]; -void ff_h261_loop_filter(MpegEncContext *s); +struct MpegEncContext; +void ff_h261_loop_filter(struct MpegEncContext *s); #endif /* AVCODEC_H261_H */ diff --git a/libavcodec/h261dec.c b/libavcodec/h261dec.c index cabca33c8d..32d41903e7 100644 --- a/libavcodec/h261dec.c +++ b/libavcodec/h261dec.c @@ -25,17 +25,22 @@ * H.261 decoder. */ -#include "libavutil/avassert.h" +#include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "get_bits.h" #include "mpeg_er.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "h261.h" +#define SLICE_OK 0 +#define SLICE_ERROR -1 +#define SLICE_END -2 ///framerate = (AVRational) { 30000, 1001 }; + /* The H.261 analog of intra/key frames is setting the freeze picture release flag, + * but this does not guarantee that the frame uses intra-only encoding, + * so we still need to allocate dummy frames. So set pict_type to P here + * for all frames and override it after having decoded the frame. */ + s->pict_type = AV_PICTURE_TYPE_P; + s->private_ctx = &h->common; // set defaults ret = ff_mpv_decode_init(s, avctx); @@ -124,18 +139,18 @@ static int h261_decode_gob_header(H261DecContext *h) if (!h->gob_start_code_skipped) { /* Check for GOB Start Code */ - val = show_bits(&s->gb, 15); + val = show_bits(&h->gb, 15); if (val) return -1; /* We have a GBSC */ - skip_bits(&s->gb, 16); + skip_bits(&h->gb, 16); } h->gob_start_code_skipped = 0; - h->gob_number = get_bits(&s->gb, 4); /* GN */ - s->qscale = get_bits(&s->gb, 5); /* GQUANT */ + h->gob_number = get_bits(&h->gb, 4); /* GN */ + s->qscale = get_bits(&h->gb, 5); /* GQUANT */ /* Check if gob_number is valid */ if (s->mb_height == 18) { // CIF @@ -148,13 +163,14 @@ static int h261_decode_gob_header(H261DecContext *h) } /* GEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; if (s->qscale == 0) { av_log(s->avctx, AV_LOG_ERROR, "qscale has forbidden 0 value\n"); if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return -1; + s->qscale = 1; } /* For the first transmitted macroblock in a GOB, MBA is the absolute @@ -204,7 +220,7 @@ static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) s->cur_pic.motion_val[0][b_xy][1] = s->mv[0][0][1]; } - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, h->block); } return 0; @@ -251,7 +267,7 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded scan_table = s->intra_scantable.permutated; if (s->mb_intra) { /* DC coef */ - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); // 0 (00000000b) and -128 (10000000b) are FORBIDDEN if ((level & 0x7F) == 0) { av_log(s->avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", @@ -262,17 +278,17 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded * being coded as 1111 1111. */ if (level == 255) level = 128; - block[0] = level * s->y_dc_scale; + block[0] = level * 8; i = 1; } else if (coded) { // Run Level Code // EOB Not possible for first level when cbp is available (that's why the table is different) // 0 1 1s // * * 0* - int check = show_bits(&s->gb, 2); + int check = show_bits(&h->gb, 2); i = 0; if (check & 0x2) { - skip_bits(&s->gb, 2); + skip_bits(&h->gb, 2); block[0] = qmul + qadd; block[0] *= (check & 0x1) ? -1 : 1; i = 1; @@ -285,14 +301,14 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded return 0; } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); i--; // offset by -1 to allow direct indexing of scan_table for (;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TCOEFF_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl->rl_vlc[0], TCOEFF_VLC_BITS, 2, 0); if (run == 66) { if (level) { - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y); return -1; @@ -301,25 +317,25 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded /* The remaining combinations of (run, level) are encoded with a * 20-bit word consisting of 6 bits escape, 6 bits run and 8 bits * level. */ - run = SHOW_UBITS(re, &s->gb, 6) + 1; - SKIP_CACHE(re, &s->gb, 6); - level = SHOW_SBITS(re, &s->gb, 8); + run = SHOW_UBITS(re, &h->gb, 6) + 1; + SKIP_CACHE(re, &h->gb, 6); + level = SHOW_SBITS(re, &h->gb, 8); if (level > 0) level = level * qmul + qadd; else if (level < 0) level = level * qmul - qadd; - SKIP_COUNTER(re, &s->gb, 6 + 8); + SKIP_COUNTER(re, &h->gb, 6 + 8); } else if (level == 0) { break; } else { level = level * qmul + qadd; - if (SHOW_UBITS(re, &s->gb, 1)) + if (SHOW_UBITS(re, &h->gb, 1)) level = -level; - SKIP_COUNTER(re, &s->gb, 1); + SKIP_COUNTER(re, &h->gb, 1); } i += run; if (i >= 64) { - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); av_log(s->avctx, AV_LOG_ERROR, "run overflow at %dx%d\n", s->mb_x, s->mb_y); return -1; @@ -327,7 +343,7 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded j = scan_table[i]; block[j] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } s->block_last_index[n] = i; return 0; @@ -342,7 +358,7 @@ static int h261_decode_mb(H261DecContext *h) cbp = 63; // Read mba do { - h->mba_diff = get_vlc2(&s->gb, h261_mba_vlc, + h->mba_diff = get_vlc2(&h->gb, h261_mba_vlc, H261_MBA_VLC_BITS, 2); /* Check for slice end */ @@ -354,7 +370,7 @@ static int h261_decode_mb(H261DecContext *h) } while (h->mba_diff == MBA_STUFFING); // stuffing if (h->mba_diff < 0) { - if (get_bits_left(&s->gb) <= 7) + if (get_bits_left(&h->gb) <= 7) return SLICE_END; av_log(s->avctx, AV_LOG_ERROR, "illegal mba at %d %d\n", s->mb_x, s->mb_y); @@ -373,15 +389,18 @@ static int h261_decode_mb(H261DecContext *h) h261_init_dest(s); // Read mtype - com->mtype = get_vlc2(&s->gb, h261_mtype_vlc, H261_MTYPE_VLC_BITS, 2); + com->mtype = get_vlc2(&h->gb, h261_mtype_vlc, H261_MTYPE_VLC_BITS, 2); if (com->mtype < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid mtype index\n"); return SLICE_ERROR; } // Read mquant - if (IS_QUANT(com->mtype)) - ff_set_qscale(s, get_bits(&s->gb, 5)); + if (IS_QUANT(com->mtype)) { + s->qscale = get_bits(&h->gb, 5); + if (!s->qscale) + s->qscale = 1; + } s->mb_intra = IS_INTRA4x4(com->mtype); @@ -401,8 +420,8 @@ static int h261_decode_mb(H261DecContext *h) h->current_mv_y = 0; } - h->current_mv_x = decode_mv_component(&s->gb, h->current_mv_x); - h->current_mv_y = decode_mv_component(&s->gb, h->current_mv_y); + h->current_mv_x = decode_mv_component(&h->gb, h->current_mv_x); + h->current_mv_y = decode_mv_component(&h->gb, h->current_mv_y); } else { h->current_mv_x = 0; h->current_mv_y = 0; @@ -410,7 +429,7 @@ static int h261_decode_mb(H261DecContext *h) // Read cbp if (HAS_CBP(com->mtype)) - cbp = get_vlc2(&s->gb, h261_cbp_vlc, H261_CBP_VLC_BITS, 1) + 1; + cbp = get_vlc2(&h->gb, h261_cbp_vlc, H261_CBP_VLC_BITS, 1) + 1; if (s->mb_intra) { s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; @@ -434,9 +453,9 @@ static int h261_decode_mb(H261DecContext *h) intra: /* decode each block */ if (s->mb_intra || HAS_CBP(com->mtype)) { - s->bdsp.clear_blocks(s->block[0]); + s->bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (h261_decode_block(h, s->block[i], i, cbp & 32) < 0) + if (h261_decode_block(h, h->block[i], i, cbp & 32) < 0) return SLICE_ERROR; cbp += cbp; } @@ -445,7 +464,7 @@ intra: s->block_last_index[i] = -1; } - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, h->block); return SLICE_OK; } @@ -454,14 +473,13 @@ intra: * Decode the H.261 picture header. * @return <0 if no startcode found */ -static int h261_decode_picture_header(H261DecContext *h) +static int h261_decode_picture_header(H261DecContext *h, int *is_key) { MpegEncContext *const s = &h->s; - int format, i; uint32_t startcode = 0; - for (i = get_bits_left(&s->gb); i > 24; i -= 1) { - startcode = ((startcode << 1) | get_bits(&s->gb, 1)) & 0x000FFFFF; + for (int i = get_bits_left(&h->gb); i > 24; i -= 1) { + startcode = ((startcode << 1) | get_bits(&h->gb, 1)) & 0x000FFFFF; if (startcode == 0x10) break; @@ -473,14 +491,14 @@ static int h261_decode_picture_header(H261DecContext *h) } /* temporal reference */ - skip_bits(&s->gb, 5); /* picture timestamp */ + skip_bits(&h->gb, 5); /* picture timestamp */ /* PTYPE starts here */ - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + *is_key = get_bits1(&h->gb); /* freeze picture release off */ - format = get_bits1(&s->gb); + int format = get_bits1(&h->gb); // only 2 formats possible if (format == 0) { // QCIF @@ -491,18 +509,13 @@ static int h261_decode_picture_header(H261DecContext *h) s->height = 288; } - skip_bits1(&s->gb); /* still image mode off */ - skip_bits1(&s->gb); /* Reserved */ + skip_bits1(&h->gb); /* still image mode off */ + skip_bits1(&h->gb); /* Reserved */ /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - /* H.261 has no I-frames, but if we pass AV_PICTURE_TYPE_I for the first - * frame, the codec crashes if it does not contain all I-blocks - * (e.g. when a packet is lost). */ - s->pict_type = AV_PICTURE_TYPE_P; - h->gob_number = 0; return 0; } @@ -511,8 +524,6 @@ static int h261_decode_gob(H261DecContext *h) { MpegEncContext *const s = &h->s; - ff_set_qscale(s, s->qscale); - /* decode mb's */ while (h->current_mba <= MBA_STUFFING) { int ret; @@ -536,20 +547,6 @@ static int h261_decode_gob(H261DecContext *h) return -1; } -/** - * returns the number of bytes consumed for building the current frame - */ -static int get_consumed_bytes(MpegEncContext *s, int buf_size) -{ - int pos = get_bits_count(&s->gb) >> 3; - if (pos == 0) - pos = 1; // avoid infinite loops (i doubt that is needed but ...) - if (pos + 10 > buf_size) - pos = buf_size; // oops ;) - - return pos; -} - static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, int *got_frame, AVPacket *avpkt) { @@ -557,16 +554,16 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; MpegEncContext *s = &h->s; - int ret; + int ret, is_key; ff_dlog(avctx, "*****frame %"PRId64" size=%d\n", avctx->frame_num, buf_size); ff_dlog(avctx, "bytes=%x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]); h->gob_start_code_skipped = 0; - init_get_bits(&s->gb, buf, buf_size * 8); + init_get_bits(&h->gb, buf, buf_size * 8); - ret = h261_decode_picture_header(h); + ret = h261_decode_picture_header(h, &is_key); /* skip if the header was thrashed */ if (ret < 0) { @@ -587,8 +584,7 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, return ret; } - if ((avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) || - (avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) || + if ((avctx->skip_frame >= AVDISCARD_NONINTRA && !is_key) || avctx->skip_frame >= AVDISCARD_ALL) return buf_size; @@ -608,7 +604,10 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, } ff_mpv_frame_end(s); - av_assert0(s->pict_type == s->cur_pic.ptr->f->pict_type); + if (is_key) { + s->cur_pic.ptr->f->pict_type = AV_PICTURE_TYPE_I; + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; + } if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; @@ -616,7 +615,7 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, *got_frame = 1; - return get_consumed_bytes(s, buf_size); + return buf_size; } const FFCodec ff_h261_decoder = { @@ -630,4 +629,5 @@ const FFCodec ff_h261_decoder = { .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .p.max_lowres = 3, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, }; diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c index f417366e75..c75e029d68 100644 --- a/libavcodec/h261enc.c +++ b/libavcodec/h261enc.c @@ -35,21 +35,28 @@ #include "h261.h" #include "h261enc.h" #include "mpegvideoenc.h" +#include "put_bits.h" #define H261_MAX_RUN 26 #define H261_MAX_LEVEL 15 #define H261_ESC_LEN (6 + 6 + 8) +#define MV_TAB_OFFSET 32 static struct VLCLUT { uint8_t len; uint16_t code; } vlc_lut[H261_MAX_RUN + 1][32 /* 0..2 * H261_MAX_LEN are used */]; +// Not const despite never being initialized because doing so would +// put it into .rodata instead of .bss and bloat the binary. +// mv_penalty exists so that the motion estimation code can avoid branches. +static uint8_t mv_penalty[MAX_FCODE + 1][MAX_DMV * 2 + 1]; static uint8_t uni_h261_rl_len [64 * 128]; static uint8_t uni_h261_rl_len_last[64 * 128]; +static uint8_t h261_mv_codes[64][2]; typedef struct H261EncContext { - MpegEncContext s; + MPVMainEncContext s; H261Context common; @@ -60,25 +67,23 @@ typedef struct H261EncContext { } format; } H261EncContext; -void ff_h261_encode_picture_header(MpegEncContext *s) +static int h261_encode_picture_header(MPVMainEncContext *const m) { - H261EncContext *const h = (H261EncContext *)s; + H261EncContext *const h = (H261EncContext *)m; + MPVEncContext *const s = &h->s.s; int temp_ref; - align_put_bits(&s->pb); - - /* Update the pointer to last GOB */ - s->ptr_lastgob = put_bits_ptr(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 20, 0x10); /* PSC */ - temp_ref = s->picture_number * 30000LL * s->avctx->time_base.num / - (1001LL * s->avctx->time_base.den); // FIXME maybe this should use a timestamp + temp_ref = s->picture_number * 30000LL * s->c.avctx->time_base.num / + (1001LL * s->c.avctx->time_base.den); // FIXME maybe this should use a timestamp put_sbits(&s->pb, 5, temp_ref); /* TemporalReference */ put_bits(&s->pb, 1, 0); /* split screen off */ put_bits(&s->pb, 1, 0); /* camera off */ - put_bits(&s->pb, 1, s->pict_type == AV_PICTURE_TYPE_I); /* freeze picture release on/off */ + put_bits(&s->pb, 1, s->c.pict_type == AV_PICTURE_TYPE_I); /* freeze picture release on/off */ put_bits(&s->pb, 1, h->format); /* 0 == QCIF, 1 == CIF */ @@ -88,12 +93,14 @@ void ff_h261_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); /* no PEI */ h->gob_number = h->format - 1; s->mb_skip_run = 0; + + return 0; } /** * Encode a group of blocks header. */ -static void h261_encode_gob_header(MpegEncContext *s, int mb_line) +static void h261_encode_gob_header(MPVEncContext *const s, int mb_line) { H261EncContext *const h = (H261EncContext *)s; if (h->format == H261_QCIF) { @@ -103,65 +110,53 @@ static void h261_encode_gob_header(MpegEncContext *s, int mb_line) } put_bits(&s->pb, 16, 1); /* GBSC */ put_bits(&s->pb, 4, h->gob_number); /* GN */ - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ put_bits(&s->pb, 1, 0); /* no GEI */ s->mb_skip_run = 0; - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } -void ff_h261_reorder_mb_index(MpegEncContext *s) +void ff_h261_reorder_mb_index(MPVEncContext *const s) { const H261EncContext *const h = (H261EncContext*)s; - int index = s->mb_x + s->mb_y * s->mb_width; + int index = s->c.mb_x + s->c.mb_y * s->c.mb_width; if (index % 11 == 0) { if (index % 33 == 0) h261_encode_gob_header(s, 0); - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } /* for CIF the GOB's are fragmented in the middle of a scanline * that's why we need to adjust the x and y index of the macroblocks */ if (h->format == H261_CIF) { - s->mb_x = index % 11; + s->c.mb_x = index % 11; index /= 11; - s->mb_y = index % 3; + s->c.mb_y = index % 3; index /= 3; - s->mb_x += 11 * (index % 2); + s->c.mb_x += 11 * (index % 2); index /= 2; - s->mb_y += 3 * index; + s->c.mb_y += 3 * index; - ff_init_block_index(s); - ff_update_block_index(s, 8, 0, 1); + ff_init_block_index(&s->c); + ff_update_block_index(&s->c, 8, 0, 1); } } static void h261_encode_motion(PutBitContext *pb, int val) { - int sign, code; - if (val == 0) { - // Corresponds to ff_h261_mv_tab[0] - put_bits(pb, 1, 1); - } else { - if (val > 15) - val -= 32; - if (val < -16) - val += 32; - sign = val < 0; - code = sign ? -val : val; - put_bits(pb, ff_h261_mv_tab[code][1], ff_h261_mv_tab[code][0]); - put_bits(pb, 1, sign); - } + put_bits(pb, h261_mv_codes[MV_TAB_OFFSET + val][1], + h261_mv_codes[MV_TAB_OFFSET + val][0]); } -static inline int get_cbp(MpegEncContext *s, int16_t block[6][64]) +static inline int get_cbp(const int block_last_index[6]) { int i, cbp; cbp = 0; for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 0) + if (block_last_index[i] >= 0) cbp |= 1 << (5 - i); return cbp; } @@ -173,10 +168,10 @@ static inline int get_cbp(MpegEncContext *s, int16_t block[6][64]) */ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) { - MpegEncContext *const s = &h->s; + MPVEncContext *const s = &h->s.s; int level, run, i, j, last_index, last_non_zero; - if (s->mb_intra) { + if (s->c.mb_intra) { /* DC coef */ level = block[0]; /* 255 cannot be represented, so we clamp */ @@ -195,7 +190,7 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) put_bits(&s->pb, 8, level); i = 1; } else if ((block[0] == 1 || block[0] == -1) && - (s->block_last_index[n] > -1)) { + (s->c.block_last_index[n] > -1)) { // special case put_bits(&s->pb, 2, block[0] > 0 ? 2 : 3); i = 1; @@ -204,10 +199,10 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) } /* AC coefs */ - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -231,8 +226,8 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) put_bits(&s->pb, 2, 0x2); // EOB } -void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) +static void h261_encode_mb(MPVEncContext *const s, int16_t block[6][64], + int motion_x, int motion_y) { /* The following is only allowed because this encoder * does not use slice threading. */ @@ -244,9 +239,9 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], com->mtype = 0; - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ - cbp = get_cbp(s, block); + cbp = get_cbp(s->c.block_last_index); /* mvd indicates if this block is motion compensated */ mvd = motion_x | motion_y; @@ -254,9 +249,9 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], if ((cbp | mvd) == 0) { /* skip macroblock */ s->mb_skip_run++; - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; - s->qscale -= s->dquant; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; + s->c.qscale -= s->dquant; return; } } @@ -268,7 +263,7 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], s->mb_skip_run = 0; /* calculate MTYPE */ - if (!s->mb_intra) { + if (!s->c.mb_intra) { com->mtype++; if (mvd || s->loop_filter) @@ -283,7 +278,7 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], if (s->dquant && cbp) { com->mtype++; } else - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; put_bits(&s->pb, ff_h261_mtype_bits[com->mtype], @@ -292,15 +287,15 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], com->mtype = ff_h261_mtype_map[com->mtype]; if (IS_QUANT(com->mtype)) { - ff_set_qscale(s, s->qscale + s->dquant); - put_bits(&s->pb, 5, s->qscale); + ff_set_qscale(&s->c, s->c.qscale + s->dquant); + put_bits(&s->pb, 5, s->c.qscale); } if (IS_16X16(com->mtype)) { - mv_diff_x = (motion_x >> 1) - s->last_mv[0][0][0]; - mv_diff_y = (motion_y >> 1) - s->last_mv[0][0][1]; - s->last_mv[0][0][0] = (motion_x >> 1); - s->last_mv[0][0][1] = (motion_y >> 1); + mv_diff_x = (motion_x >> 1) - s->c.last_mv[0][0][0]; + mv_diff_y = (motion_y >> 1) - s->c.last_mv[0][0][1]; + s->c.last_mv[0][0][0] = (motion_x >> 1); + s->c.last_mv[0][0][1] = (motion_y >> 1); h261_encode_motion(&s->pb, mv_diff_x); h261_encode_motion(&s->pb, mv_diff_y); } @@ -316,13 +311,14 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], h261_encode_block(h, block[i], i); if (!IS_16X16(com->mtype)) { - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; } } static av_cold void h261_encode_init_static(void) { + uint8_t (*const mv_codes)[2] = h261_mv_codes + MV_TAB_OFFSET; memset(uni_h261_rl_len, H261_ESC_LEN, sizeof(uni_h261_rl_len)); memset(uni_h261_rl_len_last, H261_ESC_LEN + 2 /* EOB */, sizeof(uni_h261_rl_len_last)); @@ -341,35 +337,54 @@ static av_cold void h261_encode_init_static(void) uni_h261_rl_len_last[UNI_AC_ENC_INDEX(run, 64 + level)] = len + 2; uni_h261_rl_len_last[UNI_AC_ENC_INDEX(run, 64 - level)] = len + 2; } + + for (ptrdiff_t i = 1;; i++) { + // sign-one MV codes; diff -16..-1, 16..31 + mv_codes[32 - i][0] = mv_codes[-i][0] = (ff_h261_mv_tab[i][0] << 1) | 1 /* sign */; + mv_codes[32 - i][1] = mv_codes[-i][1] = ff_h261_mv_tab[i][1] + 1; + if (i == 16) + break; + // sign-zero MV codes: diff -31..-17, 1..15 + mv_codes[i][0] = mv_codes[i - 32][0] = ff_h261_mv_tab[i][0] << 1; + mv_codes[i][1] = mv_codes[i - 32][1] = ff_h261_mv_tab[i][1] + 1; + } + // MV code for difference zero; has no sign + mv_codes[0][0] = 1; + mv_codes[0][1] = 1; } -av_cold int ff_h261_encode_init(MpegEncContext *s) +static av_cold int h261_encode_init(AVCodecContext *avctx) { - H261EncContext *const h = (H261EncContext*)s; static AVOnce init_static_once = AV_ONCE_INIT; + H261EncContext *const h = avctx->priv_data; + MPVEncContext *const s = &h->s.s; - if (s->width == 176 && s->height == 144) { + if (avctx->width == 176 && avctx->height == 144) { h->format = H261_QCIF; - } else if (s->width == 352 && s->height == 288) { + } else if (avctx->width == 352 && avctx->height == 288) { h->format = H261_CIF; } else { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "The specified picture size of %dx%d is not valid for the " "H.261 codec.\nValid sizes are 176x144, 352x288\n", - s->width, s->height); + avctx->width, avctx->height); return AVERROR(EINVAL); } - s->private_ctx = &h->common; + s->c.private_ctx = &h->common; + h->s.encode_picture_header = h261_encode_picture_header; + s->encode_mb = h261_encode_mb; s->min_qcoeff = -127; s->max_qcoeff = 127; s->ac_esc_length = H261_ESC_LEN; + s->me.mv_penalty = mv_penalty; + s->intra_ac_vlc_length = s->inter_ac_vlc_length = uni_h261_rl_len; s->intra_ac_vlc_last_length = s->inter_ac_vlc_last_length = uni_h261_rl_len_last; ff_thread_once(&init_static_once, h261_encode_init_static); - return 0; + return ff_mpv_encode_init(avctx); } const FFCodec ff_h261_encoder = { @@ -378,13 +393,12 @@ const FFCodec ff_h261_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H261, .p.priv_class = &ff_mpv_enc_class, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(H261EncContext), - .init = ff_mpv_encode_init, + .init = h261_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/h261enc.h b/libavcodec/h261enc.h index d8fdcad7aa..77f072a5e7 100644 --- a/libavcodec/h261enc.h +++ b/libavcodec/h261enc.h @@ -28,12 +28,8 @@ #ifndef AVCODEC_H261ENC_H #define AVCODEC_H261ENC_H -#include "mpegvideo.h" +typedef struct MPVEncContext MPVEncContext; -void ff_h261_reorder_mb_index(MpegEncContext *s); -void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y); -void ff_h261_encode_picture_header(MpegEncContext *s); -int ff_h261_encode_init(MpegEncContext *s); +void ff_h261_reorder_mb_index(MPVEncContext *s); #endif diff --git a/libavcodec/h263.c b/libavcodec/h263.c index 19eb3ba52f..6d2de715ab 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -27,17 +27,19 @@ * H.263/MPEG-4 codec. */ +#include "config.h" + #include "libavutil/thread.h" #include "mpegvideo.h" #include "h263.h" #include "h263data.h" #include "h263dsp.h" -#include "idctdsp.h" #include "mathops.h" #include "mpegpicture.h" #include "mpegutils.h" #include "rl.h" +#if CONFIG_MPEGVIDEO static av_cold void h263_init_rl_inter(void) { static uint8_t h263_rl_inter_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; @@ -49,6 +51,7 @@ av_cold void ff_h263_init_rl_inter(void) static AVOnce init_static_once = AV_ONCE_INIT; ff_thread_once(&init_static_once, h263_init_rl_inter); } +#endif void ff_h263_update_motion_val(MpegEncContext * s){ const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; diff --git a/libavcodec/h263.h b/libavcodec/h263.h index 27a5f31c59..2fee0df4cd 100644 --- a/libavcodec/h263.h +++ b/libavcodec/h263.h @@ -27,6 +27,16 @@ #define H263_GOB_HEIGHT(h) ((h) <= 400 ? 1 : (h) <= 800 ? 2 : 4) +static inline int ff_h263_round_chroma(int x) +{ + //FIXME static or not? + static const uint8_t h263_chroma_roundtab[16] = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + }; + return h263_chroma_roundtab[x & 0xf] + (x >> 3); +} + av_const int ff_h263_aspect_to_info(AVRational aspect); int16_t *ff_h263_pred_motion(MpegEncContext * s, int block, int dir, int *px, int *py); @@ -34,4 +44,12 @@ void ff_h263_init_rl_inter(void); void ff_h263_update_motion_val(MpegEncContext * s); void ff_h263_loop_filter(MpegEncContext * s); +static inline void ff_h263_clean_intra_table_entries(MpegEncContext *s, int xy) +{ + if (s->mbintra_table[xy]) { + s->mbintra_table[xy] = 0; + ff_clean_intra_table_entries(s); + } +} + #endif /* AVCODEC_H263_H */ diff --git a/libavcodec/h263data.h b/libavcodec/h263data.h index 06554bdf0d..e733089e83 100644 --- a/libavcodec/h263data.h +++ b/libavcodec/h263data.h @@ -59,6 +59,10 @@ extern const uint16_t ff_inter_vlc[103][2]; extern const int8_t ff_inter_level[102]; extern const int8_t ff_inter_run[102]; +/* the following defines are valid for both ff_h263_rl_inter and ff_rl_intra_aic */ +#define H263_RL_NB_ELEMS 102 // does not include escape +#define H263_RL_NON_LAST_CODES 58 +#define H263_ESCAPE_CODE_LENGTH 7 extern RLTable ff_h263_rl_inter; extern RLTable ff_rl_intra_aic; diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 0c23012584..3821472e91 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -41,9 +41,10 @@ #include "mpeg_er.h" #include "mpeg4video.h" #include "mpeg4videodec.h" -#include "mpeg4videodefs.h" #include "mpegvideo.h" +#include "mpegvideodata.h" #include "mpegvideodec.h" +#include "mpegvideo_unquantize.h" #include "msmpeg4dec.h" #include "thread.h" #include "wmv2dec.h" @@ -89,7 +90,9 @@ static enum AVPixelFormat h263_get_format(AVCodecContext *avctx) av_cold int ff_h263_decode_init(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + H263DecContext *const h = avctx->priv_data; + MPVContext *const s = &h->c; + MPVUnquantDSPContext unquant_dsp_ctx; int ret; s->out_format = FMT_H263; @@ -99,24 +102,28 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) if (ret < 0) return ret; - s->decode_mb = ff_h263_decode_mb; + h->decode_mb = ff_h263_decode_mb; s->low_delay = 1; + s->y_dc_scale_table = + s->c_dc_scale_table = ff_mpeg1_dc_scale_table; + + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, 0); // dct_unquantize defaults for H.263; - // they might change on a per-frame basis for MPEG-4. - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - s->dct_unquantize_inter = s->dct_unquantize_h263_inter; + // they might change on a per-frame basis for MPEG-4; + // dct_unquantize_inter will be unset for MSMPEG4 codecs later. + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_h263_inter; /* select sub codec */ switch (avctx->codec->id) { case AV_CODEC_ID_H263: case AV_CODEC_ID_H263P: avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; + h->decode_header = ff_h263_decode_picture_header; break; case AV_CODEC_ID_MPEG4: - // dct_unquantize_inter is only used with MPEG-2 quantizers, - // so we can already set dct_unquantize_inter here once and for all. - s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter; break; case AV_CODEC_ID_MSMPEG4V1: s->h263_pred = 1; @@ -138,22 +145,26 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) s->h263_pred = 1; s->msmpeg4_version = MSMP4_WMV2; break; - case AV_CODEC_ID_H263I: case AV_CODEC_ID_RV10: case AV_CODEC_ID_RV20: break; - case AV_CODEC_ID_FLV1: - s->h263_flv = 1; +#if CONFIG_H263I_DECODER + case AV_CODEC_ID_H263I: + h->decode_header = ff_intel_h263_decode_picture_header; break; +#endif +#if CONFIG_FLV_DECODER + case AV_CODEC_ID_FLV1: + h->decode_header = ff_flv_decode_picture_header; + break; +#endif default: - av_log(avctx, AV_LOG_ERROR, "Unsupported codec %d\n", - avctx->codec->id); - return AVERROR(ENOSYS); + av_unreachable("Switch contains a case for every codec using ff_h263_decode_init()"); } if (avctx->codec_tag == AV_RL32("L263") || avctx->codec_tag == AV_RL32("S263")) if (avctx->extradata_size == 56 && avctx->extradata[0] == 1) - s->ehc_mode = 1; + h->ehc_mode = 1; /* for H.263, we allocate the images after having read the header */ if (avctx->codec->id != AV_CODEC_ID_H263 && @@ -170,254 +181,246 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) return 0; } -/** - * Return the number of bytes consumed for building the current frame. - */ -static int get_consumed_bytes(MpegEncContext *s, int buf_size) +static void report_decode_progress(H263DecContext *const h) { - int pos = (get_bits_count(&s->gb) + 7) >> 3; - - if (s->divx_packed || s->avctx->hwaccel) { - /* We would have to scan through the whole buf to handle the weird - * reordering ... */ - return buf_size; - } else { - // avoid infinite loops (maybe not needed...) - if (pos == 0) - pos = 1; - // oops ;) - if (pos + 10 > buf_size) - pos = buf_size; - - return pos; - } + if (h->c.pict_type != AV_PICTURE_TYPE_B && !h->partitioned_frame && !h->c.er.error_occurred) + ff_thread_progress_report(&h->c.cur_pic.ptr->progress, h->c.mb_y); } -static int decode_slice(MpegEncContext *s) +static int decode_slice(H263DecContext *const h) { - const int part_mask = s->partitioned_frame + const int part_mask = h->partitioned_frame ? (ER_AC_END | ER_AC_ERROR) : 0x7F; - const int mb_size = 16 >> s->avctx->lowres; + const int mb_size = 16 >> h->c.avctx->lowres; int ret; - s->last_resync_gb = s->gb; - s->first_slice_line = 1; - s->resync_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y; + h->last_resync_gb = h->gb; + h->c.first_slice_line = 1; + h->c.resync_mb_x = h->c.mb_x; + h->c.resync_mb_y = h->c.mb_y; - ff_set_qscale(s, s->qscale); + ff_set_qscale(&h->c, h->c.qscale); - if (s->studio_profile) { - if ((ret = ff_mpeg4_decode_studio_slice_header(s->avctx->priv_data)) < 0) + if (h->c.studio_profile) { + if ((ret = ff_mpeg4_decode_studio_slice_header(h)) < 0) return ret; } - if (s->avctx->hwaccel) { - const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8; - ret = FF_HW_CALL(s->avctx, decode_slice, start, s->gb.buffer_end - start); + if (h->c.avctx->hwaccel) { + const uint8_t *start = h->gb.buffer + get_bits_count(&h->gb) / 8; + ret = FF_HW_CALL(h->c.avctx, decode_slice, start, + get_bits_bytesize(&h->gb, 0) - get_bits_count(&h->gb) / 8); // ensure we exit decode loop - s->mb_y = s->mb_height; + h->c.mb_y = h->c.mb_height; return ret; } - if (s->partitioned_frame) { - const int qscale = s->qscale; + if (h->partitioned_frame) { + const int qscale = h->c.qscale; - if (CONFIG_MPEG4_DECODER && s->codec_id == AV_CODEC_ID_MPEG4) - if ((ret = ff_mpeg4_decode_partitions(s->avctx->priv_data)) < 0) + if (CONFIG_MPEG4_DECODER && h->c.codec_id == AV_CODEC_ID_MPEG4) + if ((ret = ff_mpeg4_decode_partitions(h)) < 0) return ret; /* restore variables which were modified */ - s->first_slice_line = 1; - s->mb_x = s->resync_mb_x; - s->mb_y = s->resync_mb_y; - ff_set_qscale(s, qscale); + h->c.first_slice_line = 1; + h->c.mb_x = h->c.resync_mb_x; + h->c.mb_y = h->c.resync_mb_y; + ff_set_qscale(&h->c, qscale); } - for (; s->mb_y < s->mb_height; s->mb_y++) { + for (; h->c.mb_y < h->c.mb_height; h->c.mb_y++) { /* per-row end of slice checks */ - if (s->msmpeg4_version != MSMP4_UNUSED) { - if (s->resync_mb_y + s->slice_height == s->mb_y) { - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, ER_MB_END); + if (h->c.msmpeg4_version != MSMP4_UNUSED) { + if (h->c.resync_mb_y + h->slice_height == h->c.mb_y) { + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return 0; } } - if (s->msmpeg4_version == MSMP4_V1) { - s->last_dc[0] = - s->last_dc[1] = - s->last_dc[2] = 128; + if (h->c.msmpeg4_version == MSMP4_V1) { + h->c.last_dc[0] = + h->c.last_dc[1] = + h->c.last_dc[2] = 128; } - ff_init_block_index(s); - for (; s->mb_x < s->mb_width; s->mb_x++) { + ff_init_block_index(&h->c); + for (; h->c.mb_x < h->c.mb_width; h->c.mb_x++) { int ret; - ff_update_block_index(s, s->avctx->bits_per_raw_sample, - s->avctx->lowres, s->chroma_x_shift); + ff_update_block_index(&h->c, h->c.avctx->bits_per_raw_sample, + h->c.avctx->lowres, h->c.chroma_x_shift); - if (s->resync_mb_x == s->mb_x && s->resync_mb_y + 1 == s->mb_y) - s->first_slice_line = 0; + if (h->c.resync_mb_x == h->c.mb_x && h->c.resync_mb_y + 1 == h->c.mb_y) + h->c.first_slice_line = 0; /* DCT & quantize */ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - ff_dlog(s, "%d %06X\n", - get_bits_count(&s->gb), show_bits(&s->gb, 24)); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + ff_dlog(h->c.avctx, "%d %06X\n", + get_bits_count(&h->gb), show_bits(&h->gb, 24)); - ff_tlog(NULL, "Decoding MB at %dx%d\n", s->mb_x, s->mb_y); - ret = s->decode_mb(s, s->block); + ff_tlog(NULL, "Decoding MB at %dx%d\n", h->c.mb_x, h->c.mb_y); + ret = h->decode_mb(h); - if (s->pict_type != AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); + if (h->c.h263_pred || h->c.h263_aic) { + int mb_xy = h->c.mb_y * h->c.mb_stride + h->c.mb_x; + if (!h->c.mb_intra) { + ff_h263_clean_intra_table_entries(&h->c, mb_xy); + } else + h->c.mbintra_table[mb_xy] = 1; + } + + if (h->c.pict_type != AV_PICTURE_TYPE_B) + ff_h263_update_motion_val(&h->c); if (ret < 0) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; if (ret == SLICE_END) { - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, ER_MB_END & part_mask); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_MB_END & part_mask); - s->padding_bug_score--; + h->padding_bug_score--; - if (++s->mb_x >= s->mb_width) { - s->mb_x = 0; - ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size); - ff_mpv_report_decode_progress(s); - s->mb_y++; + if (++h->c.mb_x >= h->c.mb_width) { + h->c.mb_x = 0; + report_decode_progress(h); + ff_mpeg_draw_horiz_band(&h->c, h->c.mb_y * mb_size, mb_size); + h->c.mb_y++; } return 0; } else if (ret == SLICE_NOEND) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Slice mismatch at MB: %d\n", xy); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x + 1, s->mb_y, + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x + 1, h->c.mb_y, ER_MB_END & part_mask); return AVERROR_INVALIDDATA; } - av_log(s->avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, ER_MB_ERROR & part_mask); + av_log(h->c.avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_MB_ERROR & part_mask); - if ((s->avctx->err_recognition & AV_EF_IGNORE_ERR) && get_bits_left(&s->gb) > 0) + if ((h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) && get_bits_left(&h->gb) > 0) continue; return AVERROR_INVALIDDATA; } - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); } - ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size); - ff_mpv_report_decode_progress(s); + report_decode_progress(h); + ff_mpeg_draw_horiz_band(&h->c, h->c.mb_y * mb_size, mb_size); - s->mb_x = 0; + h->c.mb_x = 0; } - av_assert1(s->mb_x == 0 && s->mb_y == s->mb_height); + av_assert1(h->c.mb_x == 0 && h->c.mb_y == h->c.mb_height); // Detect incorrect padding with wrong stuffing codes used by NEC N-02B - if (s->codec_id == AV_CODEC_ID_MPEG4 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 48 && - show_bits(&s->gb, 24) == 0x4010 && - !s->data_partitioning) - s->padding_bug_score += 32; + if (h->c.codec_id == AV_CODEC_ID_MPEG4 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 48 && + show_bits(&h->gb, 24) == 0x4010 && + !h->data_partitioning) + h->padding_bug_score += 32; /* try to detect the padding bug */ - if (s->codec_id == AV_CODEC_ID_MPEG4 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 0 && - get_bits_left(&s->gb) < 137 && - !s->data_partitioning) { - const int bits_count = get_bits_count(&s->gb); - const int bits_left = s->gb.size_in_bits - bits_count; + if (h->c.codec_id == AV_CODEC_ID_MPEG4 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 0 && + get_bits_left(&h->gb) < 137 && + !h->data_partitioning) { + const int bits_count = get_bits_count(&h->gb); + const int bits_left = h->gb.size_in_bits - bits_count; if (bits_left == 0) { - s->padding_bug_score += 16; + h->padding_bug_score += 16; } else if (bits_left != 1) { - int v = show_bits(&s->gb, 8); + int v = show_bits(&h->gb, 8); v |= 0x7F >> (7 - (bits_count & 7)); if (v == 0x7F && bits_left <= 8) - s->padding_bug_score--; - else if (v == 0x7F && ((get_bits_count(&s->gb) + 8) & 8) && + h->padding_bug_score--; + else if (v == 0x7F && ((get_bits_count(&h->gb) + 8) & 8) && bits_left <= 16) - s->padding_bug_score += 4; + h->padding_bug_score += 4; else - s->padding_bug_score++; + h->padding_bug_score++; } } - if (s->codec_id == AV_CODEC_ID_H263 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 8 && - get_bits_left(&s->gb) < 300 && - s->pict_type == AV_PICTURE_TYPE_I && - show_bits(&s->gb, 8) == 0 && - !s->data_partitioning) { + if (h->c.codec_id == AV_CODEC_ID_H263 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 8 && + get_bits_left(&h->gb) < 300 && + h->c.pict_type == AV_PICTURE_TYPE_I && + show_bits(&h->gb, 8) == 0 && + !h->data_partitioning) { - s->padding_bug_score += 32; + h->padding_bug_score += 32; } - if (s->codec_id == AV_CODEC_ID_H263 && - (s->workaround_bugs & FF_BUG_AUTODETECT) && - get_bits_left(&s->gb) >= 64 && - AV_RB64(s->gb.buffer_end - 8) == 0xCDCDCDCDFC7F0000) { + if (h->c.codec_id == AV_CODEC_ID_H263 && + (h->c.workaround_bugs & FF_BUG_AUTODETECT) && + get_bits_left(&h->gb) >= 64 && + AV_RB64(h->gb.buffer + (get_bits_bytesize(&h->gb, 0) - 8)) == 0xCDCDCDCDFC7F0000) { - s->padding_bug_score += 32; + h->padding_bug_score += 32; } - if (s->workaround_bugs & FF_BUG_AUTODETECT) { + if (h->c.workaround_bugs & FF_BUG_AUTODETECT) { if ( - (s->padding_bug_score > -2 && !s->data_partitioning)) - s->workaround_bugs |= FF_BUG_NO_PADDING; + (h->padding_bug_score > -2 && !h->data_partitioning)) + h->c.workaround_bugs |= FF_BUG_NO_PADDING; else - s->workaround_bugs &= ~FF_BUG_NO_PADDING; + h->c.workaround_bugs &= ~FF_BUG_NO_PADDING; } // handle formats which don't have unique end markers - if (s->msmpeg4_version != MSMP4_UNUSED || (s->workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly - int left = get_bits_left(&s->gb); + if (h->c.msmpeg4_version != MSMP4_UNUSED || (h->c.workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly + int left = get_bits_left(&h->gb); int max_extra = 7; /* no markers in M$ crap */ - if (s->msmpeg4_version != MSMP4_UNUSED && s->pict_type == AV_PICTURE_TYPE_I) + if (h->c.msmpeg4_version != MSMP4_UNUSED && h->c.pict_type == AV_PICTURE_TYPE_I) max_extra += 17; /* buggy padding but the frame should still end approximately at * the bitstream end */ - if ((s->workaround_bugs & FF_BUG_NO_PADDING) && - (s->avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE))) + if ((h->c.workaround_bugs & FF_BUG_NO_PADDING) && + (h->c.avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE))) max_extra += 48; - else if ((s->workaround_bugs & FF_BUG_NO_PADDING)) + else if ((h->c.workaround_bugs & FF_BUG_NO_PADDING)) max_extra += 256 * 256 * 256 * 64; if (left > max_extra) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "discarding %d junk bits at end, next would be %X\n", - left, show_bits(&s->gb, 24)); + left, show_bits(&h->gb, 24)); else if (left < 0) - av_log(s->avctx, AV_LOG_ERROR, "overreading %d bits\n", -left); + av_log(h->c.avctx, AV_LOG_ERROR, "overreading %d bits\n", -left); else - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, ER_MB_END); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return 0; } - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "slice end not reached but screenspace end (%d left %06X, score= %d)\n", - get_bits_left(&s->gb), show_bits(&s->gb, 24), s->padding_bug_score); + get_bits_left(&h->gb), show_bits(&h->gb, 24), h->padding_bug_score); - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, h->c.mb_x, h->c.mb_y, ER_MB_END & part_mask); return AVERROR_INVALIDDATA; @@ -426,31 +429,30 @@ static int decode_slice(MpegEncContext *s) int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, int *got_frame, AVPacket *avpkt) { + H263DecContext *const h = avctx->priv_data; + MPVContext *const s = &h->c; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - MpegEncContext *s = avctx->priv_data; int ret; int slice_ret = 0; + int bak_width, bak_height; /* no supplementary picture */ if (buf_size == 0) { /* special case for last picture */ - if (s->low_delay == 0 && s->next_pic.ptr) { - if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) + if ((!h->c.low_delay || h->skipped_last_frame) && h->c.next_pic.ptr) { + if ((ret = av_frame_ref(pict, h->c.next_pic.ptr->f)) < 0) return ret; - ff_mpv_unref_picture(&s->next_pic); + if (h->skipped_last_frame) { + /* If the stream ended with an NVOP, we output the last frame + * in display order, but with the props from the last input + * packet so that the stream's end time is correct. */ + ret = ff_decode_frame_props(avctx, pict); + if (ret < 0) + return ret; + } - *got_frame = 1; - } else if (s->skipped_last_frame && s->cur_pic.ptr) { - /* Output the last picture we decoded again if the stream ended with - * an NVOP */ - if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) - return ret; - /* Copy props from the last input packet. Otherwise, props from the last - * returned picture would be reused */ - if ((ret = ff_decode_frame_props(avctx, pict)) < 0) - return ret; - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&h->c.next_pic); *got_frame = 1; } @@ -458,98 +460,59 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, return 0; } -retry: - if (s->divx_packed && s->bitstream_buffer_size) { - int i; - for(i=0; i < buf_size-3; i++) { - if (buf[i]==0 && buf[i+1]==0 && buf[i+2]==1) { - if (buf[i+3]==0xB0) { - av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); - s->bitstream_buffer_size = 0; - } - break; - } - } - } - - if (s->bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) // divx 5.01+/xvid frame reorder - ret = init_get_bits8(&s->gb, s->bitstream_buffer, - s->bitstream_buffer_size); - else - ret = init_get_bits8(&s->gb, buf, buf_size); - - s->bitstream_buffer_size = 0; + // h->gb might be overridden in ff_mpeg4_decode_picture_header() below. + ret = init_get_bits8(&h->gb, buf, buf_size); if (ret < 0) return ret; - /* let's go :-) */ - if (CONFIG_WMV2_DECODER && s->msmpeg4_version == MSMP4_WMV2) { - ret = ff_wmv2_decode_picture_header(s); -#if CONFIG_MSMPEG4DEC - } else if (s->msmpeg4_version != MSMP4_UNUSED) { - ret = ff_msmpeg4_decode_picture_header(s); -#endif - } else if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) { - ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb, 0, 0); - s->skipped_last_frame = (ret == FRAME_SKIPPED); - } else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) { - ret = ff_intel_h263_decode_picture_header(s); - } else if (CONFIG_FLV_DECODER && s->h263_flv) { - ret = ff_flv_decode_picture_header(s); - } else { - ret = ff_h263_decode_picture_header(s); - } + bak_width = h->c.width; + bak_height = h->c.height; + /* let's go :-) */ + ret = h->decode_header(h); if (ret < 0 || ret == FRAME_SKIPPED) { - if ( s->width != avctx->coded_width - || s->height != avctx->coded_height) { - av_log(s->avctx, AV_LOG_WARNING, "Reverting picture dimensions change due to header decoding failure\n"); - s->width = avctx->coded_width; - s->height= avctx->coded_height; + if ( h->c.width != bak_width + || h->c.height != bak_height) { + av_log(h->c.avctx, AV_LOG_WARNING, "Reverting picture dimensions change due to header decoding failure\n"); + h->c.width = bak_width; + h->c.height= bak_height; + } } if (ret == FRAME_SKIPPED) - return get_consumed_bytes(s, buf_size); + return buf_size; /* skip if the header was thrashed */ if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "header damaged\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "header damaged\n"); return ret; } - if (!s->context_initialized) { + if (!h->c.context_initialized) { avctx->pix_fmt = h263_get_format(avctx); if ((ret = ff_mpv_common_init(s)) < 0) return ret; } - avctx->has_b_frames = !s->low_delay; + avctx->has_b_frames = !h->c.low_delay; if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) { - if (s->pict_type != AV_PICTURE_TYPE_B && s->mb_num/2 > get_bits_left(&s->gb)) + if (h->c.pict_type != AV_PICTURE_TYPE_B && h->c.mb_num/2 > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; - if (ff_mpeg4_workaround_bugs(avctx) == 1) - goto retry; - if (s->studio_profile != (s->idsp.idct == NULL)) + ff_mpeg4_workaround_bugs(avctx); + if (h->c.studio_profile != (h->c.idsp.idct == NULL)) ff_mpv_idct_init(s); - if (s->mpeg_quant) { - s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra; - } else { - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - } } /* After H.263 & MPEG-4 header decode we have the height, width, - * and other parameters. So then we could init the picture. - * FIXME: By the way H.263 decoder is evolving it should have - * an H263EncContext */ - if (s->width != avctx->coded_width || - s->height != avctx->coded_height || - s->context_reinit) { + * and other parameters. So then we could init the picture. */ + if (h->c.width != avctx->coded_width || + h->c.height != avctx->coded_height || + h->c.context_reinit) { /* H.263 could change picture size any time */ - s->context_reinit = 0; + h->c.context_reinit = 0; - ret = ff_set_dimensions(avctx, s->width, s->height); + ret = ff_set_dimensions(avctx, h->c.width, h->c.height); if (ret < 0) return ret; @@ -565,43 +528,39 @@ retry: } } - if (s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P || - s->codec_id == AV_CODEC_ID_H263I) - s->gob_index = H263_GOB_HEIGHT(s->height); - /* skip B-frames if we don't have reference frames */ - if (!s->last_pic.ptr && - (s->pict_type == AV_PICTURE_TYPE_B || s->droppable)) - return get_consumed_bytes(s, buf_size); + if (!h->c.last_pic.ptr && + (h->c.pict_type == AV_PICTURE_TYPE_B || h->c.droppable)) + return buf_size; if ((avctx->skip_frame >= AVDISCARD_NONREF && - s->pict_type == AV_PICTURE_TYPE_B) || + h->c.pict_type == AV_PICTURE_TYPE_B) || (avctx->skip_frame >= AVDISCARD_NONKEY && - s->pict_type != AV_PICTURE_TYPE_I) || + h->c.pict_type != AV_PICTURE_TYPE_I) || avctx->skip_frame >= AVDISCARD_ALL) - return get_consumed_bytes(s, buf_size); + return buf_size; if ((ret = ff_mpv_frame_start(s, avctx)) < 0) return ret; - if (!s->divx_packed && !avctx->hwaccel) + if (!h->divx_packed) ff_thread_finish_setup(avctx); if (avctx->hwaccel) { - ret = FF_HW_CALL(avctx, start_frame, - s->gb.buffer, s->gb.buffer_end - s->gb.buffer); + ret = FF_HW_CALL(avctx, start_frame, NULL, + h->gb.buffer, get_bits_bytesize(&h->gb, 0)); if (ret < 0 ) return ret; } - ff_mpeg_er_frame_start(s); + ff_mpv_er_frame_start_ext(s, h->partitioned_frame, + s->pp_time, s->pb_time); /* the second part of the wmv2 header contains the MB skip bits which * are stored in current_picture->mb_type which is not available before * ff_mpv_frame_start() */ #if CONFIG_WMV2_DECODER - if (s->msmpeg4_version == MSMP4_WMV2) { - ret = ff_wmv2_decode_secondary_picture_header(s); + if (h->c.msmpeg4_version == MSMP4_WMV2) { + ret = ff_wmv2_decode_secondary_picture_header(h); if (ret < 0) return ret; if (ret == 1) @@ -610,40 +569,39 @@ retry: #endif /* decode each macroblock */ - s->mb_x = 0; - s->mb_y = 0; + h->c.mb_x = 0; + h->c.mb_y = 0; - slice_ret = decode_slice(s); - while (s->mb_y < s->mb_height) { - if (s->msmpeg4_version != MSMP4_UNUSED) { - if (s->slice_height == 0 || s->mb_x != 0 || slice_ret < 0 || - (s->mb_y % s->slice_height) != 0 || get_bits_left(&s->gb) < 0) + slice_ret = decode_slice(h); + while (h->c.mb_y < h->c.mb_height) { + if (h->c.msmpeg4_version != MSMP4_UNUSED) { + if (h->slice_height == 0 || h->c.mb_x != 0 || slice_ret < 0 || + (h->c.mb_y % h->slice_height) != 0 || get_bits_left(&h->gb) < 0) break; } else { - int prev_x = s->mb_x, prev_y = s->mb_y; - if (ff_h263_resync(s) < 0) + int prev_x = h->c.mb_x, prev_y = h->c.mb_y; + if (ff_h263_resync(h) < 0) break; - if (prev_y * s->mb_width + prev_x < s->mb_y * s->mb_width + s->mb_x) - s->er.error_occurred = 1; + if (prev_y * h->c.mb_width + prev_x < h->c.mb_y * h->c.mb_width + h->c.mb_x) + h->c.er.error_occurred = 1; } - if (s->msmpeg4_version < MSMP4_WMV1 && s->h263_pred) + if (h->c.msmpeg4_version < MSMP4_WMV1 && h->c.h263_pred) ff_mpeg4_clean_buffers(s); - if (decode_slice(s) < 0) + if (decode_slice(h) < 0) slice_ret = AVERROR_INVALIDDATA; } - if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && - s->pict_type == AV_PICTURE_TYPE_I) + if (h->c.msmpeg4_version != MSMP4_UNUSED && h->c.msmpeg4_version < MSMP4_WMV1 && + h->c.pict_type == AV_PICTURE_TYPE_I) if (!CONFIG_MSMPEG4DEC || - ff_msmpeg4_decode_ext_header(s, buf_size) < 0) - s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR; + ff_msmpeg4_decode_ext_header(h, buf_size) < 0) + h->c.er.error_status_table[h->c.mb_num - 1] = ER_MB_ERROR; - av_assert1(s->bitstream_buffer_size == 0); frame_end: - if (!s->studio_profile) - ff_er_frame_end(&s->er, NULL); + if (!h->c.studio_profile) + ff_er_frame_end(&h->c.er, NULL); if (avctx->hwaccel) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); @@ -654,27 +612,24 @@ frame_end: ff_mpv_frame_end(s); if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) - ff_mpeg4_frame_end(avctx, buf, buf_size); + ff_mpeg4_frame_end(avctx, avpkt); - if (!s->divx_packed && avctx->hwaccel) - ff_thread_finish_setup(avctx); - - av_assert1(s->pict_type == s->cur_pic.ptr->f->pict_type); - if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) + av_assert1(h->c.pict_type == h->c.cur_pic.ptr->f->pict_type); + if (h->c.pict_type == AV_PICTURE_TYPE_B || h->c.low_delay) { + if ((ret = av_frame_ref(pict, h->c.cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->cur_pic.ptr, pict); - ff_mpv_export_qp_table(s, pict, s->cur_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); - } else if (s->last_pic.ptr) { - if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0) + ff_print_debug_info(s, h->c.cur_pic.ptr, pict); + ff_mpv_export_qp_table(s, pict, h->c.cur_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); + } else if (h->c.last_pic.ptr) { + if ((ret = av_frame_ref(pict, h->c.last_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->last_pic.ptr, pict); - ff_mpv_export_qp_table(s, pict, s->last_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); + ff_print_debug_info(s, h->c.last_pic.ptr, pict); + ff_mpv_export_qp_table(s, pict, h->c.last_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1); } - if (s->last_pic.ptr || s->low_delay) { + if (h->c.last_pic.ptr || h->c.low_delay) { if ( pict->format == AV_PIX_FMT_YUV420P - && (s->codec_tag == AV_RL32("GEOV") || s->codec_tag == AV_RL32("GEOX"))) { + && (h->c.codec_tag == AV_RL32("GEOV") || h->c.codec_tag == AV_RL32("GEOX"))) { for (int p = 0; p < 3; p++) { int h = AV_CEIL_RSHIFT(pict->height, !!p); @@ -688,7 +643,7 @@ frame_end: if (slice_ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return slice_ret; else - return get_consumed_bytes(s, buf_size); + return buf_size; } static const AVCodecHWConfigInternal *const h263_hw_config_list[] = { @@ -712,7 +667,7 @@ const FFCodec ff_h263_decoder = { CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -730,7 +685,7 @@ const FFCodec ff_h263p_decoder = { CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263P, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/h263dec.h b/libavcodec/h263dec.h index 633d4aa577..ace210b036 100644 --- a/libavcodec/h263dec.h +++ b/libavcodec/h263dec.h @@ -20,13 +20,10 @@ #ifndef AVCODEC_H263DEC_H #define AVCODEC_H263DEC_H +#include "get_bits.h" #include "mpegvideo.h" #include "vlc.h" - -/** - * Return value for header parsers if frame is not coded. - * */ -#define FRAME_SKIPPED 100 +#include "libavutil/mem_internal.h" // The defines below define the number of bits that are read at once for // reading vlc values. Changing these may improve speed and data cache needs @@ -43,24 +40,80 @@ extern VLCElem ff_h263_inter_MCBPC_vlc[]; extern VLCElem ff_h263_cbpy_vlc[]; extern VLCElem ff_h263_mv_vlc[]; -int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code); +typedef struct H263DecContext { + MPVContext c; + + GetBitContext gb; + + int mb_num_left; ///< number of MBs left in this video packet (for partitioned slices only) + + int picture_number; + + int pb_frame; ///< PB-frame mode (0 = none, 1 = base, 2 = improved) + + /* motion compensation */ + int h263_long_vectors; ///< use horrible H.263v1 long vector mode + + /* FLV specific */ + int flv; ///< use flv H.263 header + + /* H.263 specific */ + int ehc_mode; + int gob_index; + + /* H.263+ specific */ + int custom_pcf; + int umvplus; ///< == H.263+ && unrestricted_mv + int h263_slice_structured; + int alt_inter_vlc; ///< alternative inter vlc + int loop_filter; + int modified_quant; + + /* MPEG-4 specific */ + int padding_bug_score; ///< used to detect the VERY common padding bug in MPEG-4 + int skipped_last_frame; + int divx_packed; ///< divx specific, used to workaround (many) bugs in divx5 + int data_partitioning; ///< data partitioning flag from header + int partitioned_frame; ///< is current frame partitioned + + /* MSMPEG4 specific */ + int slice_height; ///< in macroblocks + + /* RV10 specific */ + int rv10_version; ///< RV10 version: 0 or 3 + int rv10_first_dc_coded[3]; + + int (*decode_header)(struct H263DecContext *const h); +#define FRAME_SKIPPED 100 ///< Frame is not coded + + int (*decode_mb)(struct H263DecContext *h); +#define SLICE_OK 0 +#define SLICE_ERROR -1 +#define SLICE_END -2 ///pb, x, f_code); ff_h263_encode_motion(&s->pb, y, f_code); } -static inline int get_p_cbp(MpegEncContext * s, +static inline int get_p_cbp(MPVEncContext *const s, int16_t block[6][64], int motion_x, int motion_y){ int cbp; @@ -53,7 +52,7 @@ static inline int get_p_cbp(MpegEncContext * s, int best_cbpy_score = INT_MAX; int best_cbpc_score = INT_MAX; int cbpc = (-1), cbpy = (-1); - const int offset = (s->mv_type == MV_TYPE_16X16 ? 0 : 16) + (s->dquant ? 8 : 0); + const int offset = (s->c.mv_type == MV_TYPE_16X16 ? 0 : 16) + (s->dquant ? 8 : 0); const int lambda = s->lambda2 >> (FF_LAMBDA_SHIFT - 6); for (int i = 0; i < 4; i++) { @@ -80,21 +79,21 @@ static inline int get_p_cbp(MpegEncContext * s, } } cbp = cbpc + 4 * cbpy; - if (!(motion_x | motion_y | s->dquant) && s->mv_type == MV_TYPE_16X16) { + if (!(motion_x | motion_y | s->dquant) && s->c.mv_type == MV_TYPE_16X16) { if (best_cbpy_score + best_cbpc_score + 2 * lambda >= 0) cbp= 0; } for (int i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0 && !((cbp >> (5 - i)) & 1)) { - s->block_last_index[i] = -1; - s->bdsp.clear_block(s->block[i]); + if (s->c.block_last_index[i] >= 0 && !((cbp >> (5 - i)) & 1)) { + s->c.block_last_index[i] = -1; + s->c.bdsp.clear_block(s->block[i]); } } } else { cbp = 0; for (int i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } } diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index 7b48fcae17..fa57911c08 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -22,6 +22,7 @@ #include "config.h" +#include "libavutil/error.h" #include "libavutil/intmath.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -581,13 +582,16 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, if (codec_id == AV_CODEC_ID_VVC) ret = vvc_parse_nal_header(nal, logctx); - else if (codec_id == AV_CODEC_ID_HEVC) + else if (codec_id == AV_CODEC_ID_HEVC) { ret = hevc_parse_nal_header(nal, logctx); - else + if (nal->nuh_layer_id == 63) + continue; + } else ret = h264_parse_nal_header(nal, logctx); if (ret < 0) { - av_log(logctx, AV_LOG_WARNING, "Invalid NAL unit %d, skipping.\n", - nal->type); + av_log(logctx, AV_LOG_WARNING, + "Failed to parse header of NALU (type %d): \"%s\". Skipping NALU.\n", + nal->type, av_err2str(ret)); continue; } diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c index c46a563308..04432b6a8d 100644 --- a/libavcodec/h2645_sei.c +++ b/libavcodec/h2645_sei.c @@ -26,11 +26,13 @@ #include "config_components.h" #include "libavutil/ambient_viewing_environment.h" +#include "libavutil/buffer.h" #include "libavutil/display.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" #include "libavutil/stereo3d.h" #include "atsc_a53.h" @@ -42,8 +44,9 @@ #include "h2645_sei.h" #include "itut35.h" -#define IS_H264(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_H264 : CONFIG_H264_SEI) -#define IS_HEVC(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_HEVC : CONFIG_HEVC_SEI) +#define IS_H264(codec_id) (CONFIG_H264_SEI && (CONFIG_HEVC_SEI || CONFIG_VVC_SEI ) ? codec_id == AV_CODEC_ID_H264 : CONFIG_H264_SEI) +#define IS_HEVC(codec_id) (CONFIG_HEVC_SEI && (CONFIG_H264_SEI || CONFIG_VVC_SEI ) ? codec_id == AV_CODEC_ID_HEVC : CONFIG_HEVC_SEI) +#define IS_VVC(codec_id) (CONFIG_VVC_SEI && (CONFIG_H264_SEI || CONFIG_HEVC_SEI) ? codec_id == AV_CODEC_ID_VVC : CONFIG_VVC_SEI ) #if CONFIG_HEVC_SEI static int decode_registered_user_data_dynamic_hdr_plus(HEVCSEIDynamicHDRPlus *s, @@ -155,20 +158,10 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, bytestream2_skipu(gb, 1); // itu_t_t35_country_code_extension_byte } - if (country_code != ITU_T_T35_COUNTRY_CODE_US && - country_code != ITU_T_T35_COUNTRY_CODE_UK && - country_code != ITU_T_T35_COUNTRY_CODE_CN) { - av_log(logctx, AV_LOG_VERBOSE, - "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d)\n", - country_code); - return 0; - } - /* itu_t_t35_payload_byte follows */ provider_code = bytestream2_get_be16u(gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { + if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_ATSC) { uint32_t user_identifier; if (bytestream2_get_bytes_left(gb) < 4) @@ -186,9 +179,7 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, user_identifier); break; } - break; - } - case ITU_T_T35_PROVIDER_CODE_LCEVC: { + } else if (country_code == ITU_T_T35_COUNTRY_CODE_UK && provider_code == ITU_T_T35_PROVIDER_CODE_VNOVA) { if (bytestream2_get_bytes_left(gb) < 2) return AVERROR_INVALIDDATA; @@ -196,7 +187,7 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, return decode_registered_user_data_lcevc(&h->lcevc, gb); } #if CONFIG_HEVC_SEI - case ITU_T_T35_PROVIDER_CODE_CUVA: { + else if (country_code == ITU_T_T35_COUNTRY_CODE_CN && provider_code == ITU_T_T35_PROVIDER_CODE_HDR_VIVID) { const uint16_t cuva_provider_oriented_code = 0x0005; uint16_t provider_oriented_code; @@ -210,9 +201,7 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, if (provider_oriented_code == cuva_provider_oriented_code) { return decode_registered_user_data_dynamic_hdr_vivid(&h->dynamic_hdr_vivid, gb); } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { + } else if(country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG) { // A/341 Amendment - 2094-40 const uint16_t smpte2094_40_provider_oriented_code = 0x0001; const uint8_t smpte2094_40_application_identifier = 0x04; @@ -231,9 +220,7 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, application_identifier == smpte2094_40_application_identifier) { return decode_registered_user_data_dynamic_hdr_plus(&h->dynamic_hdr_plus, gb); } - break; - } - case 0x5890: { // aom_provider_code + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_AOM) { const uint16_t aom_grain_provider_oriented_code = 0x0001; uint16_t provider_oriented_code; @@ -249,15 +236,13 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, gb->buffer, bytestream2_get_bytes_left(gb)); } - break; } - unsupported_provider_code: #endif - default: + else { + unsupported_provider_code: av_log(logctx, AV_LOG_VERBOSE, - "Unsupported User Data Registered ITU-T T35 SEI message (provider_code = %d)\n", - provider_code); - break; + "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d, provider_code = %d)\n", + country_code, provider_code); } return 0; @@ -425,7 +410,7 @@ static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h } } } - if (IS_HEVC(codec_id)) + if (!IS_H264(codec_id)) h->persistence_flag = get_bits1(gb); else h->repetition_period = get_ue_golomb_long(gb); @@ -494,7 +479,11 @@ int ff_h2645_sei_message_decode(H2645SEI *h, enum SEIType type, case SEI_TYPE_DISPLAY_ORIENTATION: return decode_display_orientation(&h->display_orientation, gb); case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: - return decode_film_grain_characteristics(&h->film_grain_characteristics, codec_id, gb); + av_refstruct_unref(&h->film_grain_characteristics); + h->film_grain_characteristics = av_refstruct_allocz(sizeof(*h->film_grain_characteristics)); + if (!h->film_grain_characteristics) + return AVERROR(ENOMEM); + return decode_film_grain_characteristics(h->film_grain_characteristics, codec_id, gb); case SEI_TYPE_FRAME_PACKING_ARRANGEMENT: return decode_frame_packing_arrangement(&h->frame_packing, gb, codec_id); case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: @@ -542,6 +531,20 @@ int ff_h2645_sei_ctx_replace(H2645SEI *dst, const H2645SEI *src) } } + for (unsigned i = 0; i < FF_ARRAY_ELEMS(dst->aom_film_grain.sets); i++) { + ret = av_buffer_replace(&dst->aom_film_grain.sets[i], + src->aom_film_grain.sets[i]); + if (ret < 0) + return ret; + } + dst->aom_film_grain.enable = src->aom_film_grain.enable; + + dst->mastering_display = src->mastering_display; + dst->content_light = src->content_light; + + av_refstruct_replace(&dst->film_grain_characteristics, + src->film_grain_characteristics); + return 0; } @@ -787,7 +790,11 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, if (!sd) av_buffer_unref(&a53->buf_ref); a53->buf_ref = NULL; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } ret = h2645_sei_to_side_data(avctx, sei, &frame->side_data, &frame->nb_side_data); @@ -811,8 +818,8 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, return ret; } - if (sei->film_grain_characteristics.present) { - H2645SEIFilmGrainCharacteristics *fgc = &sei->film_grain_characteristics; + if (sei->film_grain_characteristics && sei->film_grain_characteristics->present) { + H2645SEIFilmGrainCharacteristics *fgc = sei->film_grain_characteristics; AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(frame); AVFilmGrainH274Params *h274; @@ -830,7 +837,7 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, fgp->subsampling_x = fgp->subsampling_y = 0; h274->model_id = fgc->model_id; - if (fgc->separate_colour_description_present_flag) { + if (IS_VVC(codec_id) || fgc->separate_colour_description_present_flag) { fgp->bit_depth_luma = fgc->bit_depth_luma; fgp->bit_depth_chroma = fgc->bit_depth_chroma; fgp->color_range = fgc->full_range + 1; @@ -851,17 +858,6 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, h274->blending_mode_id = fgc->blending_mode_id; h274->log2_scale_factor = fgc->log2_scale_factor; -#if FF_API_H274_FILM_GRAIN_VCS -FF_DISABLE_DEPRECATION_WARNINGS - h274->bit_depth_luma = fgp->bit_depth_luma; - h274->bit_depth_chroma = fgp->bit_depth_chroma; - h274->color_range = fgp->color_range; - h274->color_primaries = fgp->color_primaries; - h274->color_trc = fgp->color_trc; - h274->color_space = fgp->color_space; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - memcpy(&h274->component_model_present, &fgc->comp_model_present_flag, sizeof(h274->component_model_present)); memcpy(&h274->num_intensity_intervals, &fgc->num_intensity_intervals, @@ -880,7 +876,11 @@ FF_ENABLE_DEPRECATION_WARNINGS else fgc->present = fgc->persistence_flag; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } #if CONFIG_HEVC_SEI @@ -913,5 +913,7 @@ void ff_h2645_sei_reset(H2645SEI *s) s->ambient_viewing_environment.present = 0; s->mastering_display.present = 0; s->content_light.present = 0; - s->aom_film_grain.enable = 0; + + av_refstruct_unref(&s->film_grain_characteristics); + ff_aom_uninit_film_grain_params(&s->aom_film_grain); } diff --git a/libavcodec/h2645_sei.h b/libavcodec/h2645_sei.h index 598f78b585..f2ad7147c6 100644 --- a/libavcodec/h2645_sei.h +++ b/libavcodec/h2645_sei.h @@ -108,7 +108,7 @@ typedef struct H2645SEIFilmGrainCharacteristics { uint8_t intensity_interval_upper_bound[3][256]; int16_t comp_model_value[3][256][6]; int repetition_period; //< H.264 only - int persistence_flag; //< HEVC only + int persistence_flag; //< HEVC/VVC } H2645SEIFilmGrainCharacteristics; typedef struct H2645SEIMasteringDisplay { @@ -135,11 +135,13 @@ typedef struct H2645SEI { H2645SEIFramePacking frame_packing; H2645SEIDisplayOrientation display_orientation; H2645SEIAlternativeTransfer alternative_transfer; - H2645SEIFilmGrainCharacteristics film_grain_characteristics; H2645SEIAmbientViewingEnvironment ambient_viewing_environment; H2645SEIMasteringDisplay mastering_display; H2645SEIContentLight content_light; AVFilmGrainAFGS1Params aom_film_grain; + + // Dynamic allocations due to large size. + H2645SEIFilmGrainCharacteristics *film_grain_characteristics; } H2645SEI; enum { diff --git a/libavcodec/h2645_vui.c b/libavcodec/h2645_vui.c index e5c7bf46f9..0e576c1563 100644 --- a/libavcodec/h2645_vui.c +++ b/libavcodec/h2645_vui.c @@ -67,11 +67,16 @@ void ff_h2645_decode_common_vui_params(GetBitContext *gb, H2645VUI *vui, void *l vui->matrix_coeffs = get_bits(gb, 8); // Set invalid values to "unspecified" - if (!av_color_primaries_name(vui->colour_primaries)) + if (vui->colour_primaries == AVCOL_PRI_RESERVED0 || + vui->colour_primaries == AVCOL_PRI_RESERVED || + !av_color_primaries_name(vui->colour_primaries)) vui->colour_primaries = AVCOL_PRI_UNSPECIFIED; - if (!av_color_transfer_name(vui->transfer_characteristics)) + if (vui->transfer_characteristics == AVCOL_TRC_RESERVED0 || + vui->transfer_characteristics == AVCOL_TRC_RESERVED || + !av_color_transfer_name(vui->transfer_characteristics)) vui->transfer_characteristics = AVCOL_TRC_UNSPECIFIED; - if (!av_color_space_name(vui->matrix_coeffs)) + if (vui->matrix_coeffs == AVCOL_SPC_RESERVED || + !av_color_space_name(vui->matrix_coeffs)) vui->matrix_coeffs = AVCOL_SPC_UNSPECIFIED; } } diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c index 4e94136313..0d6562b583 100644 --- a/libavcodec/h264_mb.c +++ b/libavcodec/h264_mb.c @@ -407,7 +407,7 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon /* don't optimize for luma-only case, since B-frames usually * use implicit weights => chroma too. */ uint8_t *tmp_cb = sl->bipred_scratchpad; - uint8_t *tmp_cr = sl->bipred_scratchpad + (16 << pixel_shift); + uint8_t *tmp_cr = sl->bipred_scratchpad + (8 << pixel_shift + (chroma_idc == 3)); uint8_t *tmp_y = sl->bipred_scratchpad + 16 * sl->mb_uvlinesize; int refn0 = sl->ref_cache[0][scan8[n]]; int refn1 = sl->ref_cache[1][scan8[n]]; @@ -529,7 +529,7 @@ static av_always_inline void xchg_mb_border(const H264Context *h, H264SliceConte } if (sl->deblocking_filter == 2) { - deblock_topleft = h->slice_table[sl->mb_xy - 1 - h->mb_stride] == sl->slice_num; + deblock_topleft = h->slice_table[sl->mb_xy - 1 - (h->mb_stride << MB_FIELD(sl))] == sl->slice_num; deblock_top = sl->top_type; } else { deblock_topleft = (sl->mb_x > 0); diff --git a/libavcodec/h264_mc_template.c b/libavcodec/h264_mc_template.c index d02e2bf580..d24b0a0edc 100644 --- a/libavcodec/h264_mc_template.c +++ b/libavcodec/h264_mc_template.c @@ -162,4 +162,3 @@ static void MCFUNC(hl_motion)(const H264Context *h, H264SliceContext *sl, if (USES_LIST(mb_type, 1)) prefetch_motion(h, sl, 1, PIXEL_SHIFT, CHROMA_IDC); } - diff --git a/libavcodec/h264_parse.h b/libavcodec/h264_parse.h index 3481451c10..ad5099edb5 100644 --- a/libavcodec/h264_parse.h +++ b/libavcodec/h264_parse.h @@ -36,7 +36,7 @@ #define MB_TYPE_REF0 MB_TYPE_CODEC_SPECIFIC #define MB_TYPE_8x8DCT 0x01000000 -// This table must be here because scan8[constant] must be known at compiletime +// This table must be here because scan8[constant] must be known at compile time static const uint8_t scan8[16 * 3 + 3] = { 4 + 1 * 8, 5 + 1 * 8, 4 + 2 * 8, 5 + 2 * 8, 6 + 1 * 8, 7 + 1 * 8, 6 + 2 * 8, 7 + 2 * 8, diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index 94cfbc481e..006f4059e8 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -47,7 +47,7 @@ #include "h264data.h" #include "mpegutils.h" #include "parser.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "startcode.h" typedef struct H264ParseContext { @@ -374,7 +374,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, goto fail; } - ff_refstruct_replace(&p->ps.pps, p->ps.pps_list[pps_id]); + av_refstruct_replace(&p->ps.pps, p->ps.pps_list[pps_id]); p->ps.sps = p->ps.pps->sps; sps = p->ps.sps; diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index 3234141dbd..f5d2b31cd6 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -32,7 +32,7 @@ #include "h264dec.h" #include "hwaccel_internal.h" #include "mpegutils.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" @@ -46,35 +46,35 @@ void ff_h264_unref_picture(H264Picture *pic) ff_thread_release_ext_buffer(&pic->tf); av_frame_unref(pic->f_grain); - ff_refstruct_unref(&pic->hwaccel_picture_private); + av_refstruct_unref(&pic->hwaccel_picture_private); - ff_refstruct_unref(&pic->qscale_table_base); - ff_refstruct_unref(&pic->mb_type_base); - ff_refstruct_unref(&pic->pps); + av_refstruct_unref(&pic->qscale_table_base); + av_refstruct_unref(&pic->mb_type_base); + av_refstruct_unref(&pic->pps); for (i = 0; i < 2; i++) { - ff_refstruct_unref(&pic->motion_val_base[i]); - ff_refstruct_unref(&pic->ref_index[i]); + av_refstruct_unref(&pic->motion_val_base[i]); + av_refstruct_unref(&pic->ref_index[i]); } - ff_refstruct_unref(&pic->decode_error_flags); + av_refstruct_unref(&pic->decode_error_flags); memset((uint8_t*)pic + off, 0, sizeof(*pic) - off); } static void h264_copy_picture_params(H264Picture *dst, const H264Picture *src) { - ff_refstruct_replace(&dst->qscale_table_base, src->qscale_table_base); - ff_refstruct_replace(&dst->mb_type_base, src->mb_type_base); - ff_refstruct_replace(&dst->pps, src->pps); + av_refstruct_replace(&dst->qscale_table_base, src->qscale_table_base); + av_refstruct_replace(&dst->mb_type_base, src->mb_type_base); + av_refstruct_replace(&dst->pps, src->pps); for (int i = 0; i < 2; i++) { - ff_refstruct_replace(&dst->motion_val_base[i], src->motion_val_base[i]); - ff_refstruct_replace(&dst->ref_index[i], src->ref_index[i]); + av_refstruct_replace(&dst->motion_val_base[i], src->motion_val_base[i]); + av_refstruct_replace(&dst->ref_index[i], src->ref_index[i]); } - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); - ff_refstruct_replace(&dst->decode_error_flags, src->decode_error_flags); + av_refstruct_replace(&dst->decode_error_flags, src->decode_error_flags); dst->qscale_table = src->qscale_table; dst->mb_type = src->mb_type; diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 3c8fc33c7f..3a3cad7de7 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -34,7 +34,7 @@ #include "h2645_vui.h" #include "h264_ps.h" #include "golomb.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define MIN_LOG2_MAX_FRAME_NUM 4 @@ -86,7 +86,7 @@ static const int level_max_dpb_mbs[][2] = { static void remove_pps(H264ParamSets *s, int id) { - ff_refstruct_unref(&s->pps_list[id]); + av_refstruct_unref(&s->pps_list[id]); } static void remove_sps(H264ParamSets *s, int id) @@ -100,7 +100,7 @@ static void remove_sps(H264ParamSets *s, int id) remove_pps(s, i); } #endif - ff_refstruct_unref(&s->sps_list[id]); + av_refstruct_unref(&s->sps_list[id]); } static inline int decode_hrd_parameters(GetBitContext *gb, void *logctx, @@ -272,12 +272,12 @@ void ff_h264_ps_uninit(H264ParamSets *ps) int i; for (i = 0; i < MAX_SPS_COUNT; i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (i = 0; i < MAX_PPS_COUNT; i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); - ff_refstruct_unref(&ps->pps); + av_refstruct_unref(&ps->pps); ps->sps = NULL; } @@ -290,11 +290,11 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, SPS *sps; int ret; - sps = ff_refstruct_allocz(sizeof(*sps)); + sps = av_refstruct_allocz(sizeof(*sps)); if (!sps) return AVERROR(ENOMEM); - sps->data_size = gb->buffer_end - gb->buffer; + sps->data_size = get_bits_bytesize(gb, 1); if (sps->data_size > sizeof(sps->data)) { av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized SPS\n"); sps->data_size = sizeof(sps->data); @@ -578,7 +578,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, * otherwise drop all PPSes that depend on it */ if (ps->sps_list[sps_id] && !memcmp(ps->sps_list[sps_id], sps, sizeof(*sps))) { - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); } else { remove_sps(ps, sps_id); ps->sps_list[sps_id] = sps; @@ -587,7 +587,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, return 0; fail: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return AVERROR_INVALIDDATA; } @@ -686,11 +686,11 @@ static int more_rbsp_data_in_pps(const SPS *sps, void *logctx) return 1; } -static void pps_free(FFRefStructOpaque unused, void *obj) +static void pps_free(AVRefStructOpaque unused, void *obj) { PPS *pps = obj; - ff_refstruct_unref(&pps->sps); + av_refstruct_unref(&pps->sps); } int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx, @@ -708,11 +708,11 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct return AVERROR_INVALIDDATA; } - pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); + pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); if (!pps) return AVERROR(ENOMEM); - pps->data_size = gb->buffer_end - gb->buffer; + pps->data_size = get_bits_bytesize(gb, 1); if (pps->data_size > sizeof(pps->data)) { av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized PPS " "(%"SIZE_SPECIFIER" > %"SIZE_SPECIFIER")\n", @@ -733,7 +733,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct ret = AVERROR_INVALIDDATA; goto fail; } - pps->sps = ff_refstruct_ref_c(ps->sps_list[pps->sps_id]); + pps->sps = av_refstruct_ref_c(ps->sps_list[pps->sps_id]); sps = pps->sps; if (sps->bit_depth_luma > 14) { @@ -840,6 +840,6 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct return 0; fail: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return ret; } diff --git a/libavcodec/h264_ps.h b/libavcodec/h264_ps.h index 80af4832fe..f216e4989f 100644 --- a/libavcodec/h264_ps.h +++ b/libavcodec/h264_ps.h @@ -57,7 +57,7 @@ typedef struct SPS { int ref_frame_count; ///< num_ref_frames int gaps_in_frame_num_allowed_flag; int mb_width; ///< pic_width_in_mbs_minus1 + 1 - ///< (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) + /// (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) int mb_height; int frame_mbs_only_flag; int mb_aff; ///< mb_adaptive_frame_field_flag diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 5eb2855065..608e13d7d5 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -337,7 +337,7 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) break; } if (i >= 0) - ref->pic_id = pred; + pic_id = pred; break; } case 2: { @@ -354,7 +354,6 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) ref = h->long_ref[long_idx]; assert(!(ref && !ref->reference)); if (ref && (ref->reference & pic_structure)) { - ref->pic_id = pic_id; assert(ref->long_ref); i = 0; } else { @@ -371,12 +370,15 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) i < 0 ? "reference picture missing during reorder\n" : "mismatching reference\n" ); + if (h->avctx->err_recognition & AV_EF_EXPLODE) { + return AVERROR_INVALIDDATA; + } memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME } else { for (i = index; i + 1 < sl->ref_count[list]; i++) { if (sl->ref_list[list][i].parent && ref->long_ref == sl->ref_list[list][i].parent->long_ref && - ref->pic_id == sl->ref_list[list][i].pic_id) + pic_id == sl->ref_list[list][i].pic_id) break; } for (; i > index; i--) { @@ -393,6 +395,10 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) for (int index = 0; index < sl->ref_count[list]; index++) { if ( !sl->ref_list[list][index].parent || (!FIELD_PICTURE(h) && (sl->ref_list[list][index].reference&3) != 3)) { + if (h->avctx->err_recognition & AV_EF_EXPLODE) { + av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture\n"); + return AVERROR_INVALIDDATA; + } av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture, default is %d\n", h->default_ref[list].poc); for (int i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++) @@ -409,7 +415,7 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) if (h->default_ref[list2].parent && !h->default_ref[list2].parent->gray && !(!FIELD_PICTURE(h) && (h->default_ref[list2].reference&3) != 3)) { sl->ref_list[list][index] = h->default_ref[list2]; - av_log(h, AV_LOG_DEBUG, "replacement of gray gap frame\n"); + av_log(h->avctx, AV_LOG_DEBUG, "replacement of gray gap frame\n"); break; } } diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 8d6dc77943..15a5232209 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -55,7 +55,6 @@ void ff_h264_sei_uninit(H264SEIContext *h) h->picture_timing.present = 0; h->buffering_period.present = 0; h->common.frame_packing.present = 0; - h->common.film_grain_characteristics.present = 0; h->common.display_orientation.present = 0; h->common.afd.present = 0; diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index bb9275e569..8c8f6e6c73 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -129,12 +129,6 @@ struct H264ParamSets; int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, const struct H264ParamSets *ps, void *logctx); -static inline int ff_h264_sei_ctx_replace(H264SEIContext *dst, - const H264SEIContext *src) -{ - return ff_h2645_sei_ctx_replace(&dst->common, &src->common); -} - /** * Reset SEI values at the beginning of the frame. */ diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index a66b75ca80..7e53e38cca 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -45,7 +45,7 @@ #include "mathops.h" #include "mpegutils.h" #include "rectangle.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" @@ -166,19 +166,19 @@ static int init_table_pools(H264Context *h) const int b4_stride = h->mb_width * 4 + 1; const int b4_array_size = b4_stride * h->mb_height * 4; - h->qscale_table_pool = ff_refstruct_pool_alloc(big_mb_num + h->mb_stride, 0); - h->mb_type_pool = ff_refstruct_pool_alloc((big_mb_num + h->mb_stride) * + h->qscale_table_pool = av_refstruct_pool_alloc(big_mb_num + h->mb_stride, 0); + h->mb_type_pool = av_refstruct_pool_alloc((big_mb_num + h->mb_stride) * sizeof(uint32_t), 0); - h->motion_val_pool = ff_refstruct_pool_alloc(2 * (b4_array_size + 4) * + h->motion_val_pool = av_refstruct_pool_alloc(2 * (b4_array_size + 4) * sizeof(int16_t), 0); - h->ref_index_pool = ff_refstruct_pool_alloc(4 * mb_array_size, 0); + h->ref_index_pool = av_refstruct_pool_alloc(4 * mb_array_size, 0); if (!h->qscale_table_pool || !h->mb_type_pool || !h->motion_val_pool || !h->ref_index_pool) { - ff_refstruct_pool_uninit(&h->qscale_table_pool); - ff_refstruct_pool_uninit(&h->mb_type_pool); - ff_refstruct_pool_uninit(&h->motion_val_pool); - ff_refstruct_pool_uninit(&h->ref_index_pool); + av_refstruct_pool_uninit(&h->qscale_table_pool); + av_refstruct_pool_uninit(&h->mb_type_pool); + av_refstruct_pool_uninit(&h->motion_val_pool); + av_refstruct_pool_uninit(&h->ref_index_pool); return AVERROR(ENOMEM); } @@ -191,6 +191,13 @@ static int alloc_picture(H264Context *h, H264Picture *pic) av_assert0(!pic->f->data[0]); + if (h->sei.common.lcevc.info) { + HEVCSEILCEVC *lcevc = &h->sei.common.lcevc; + ret = ff_frame_new_side_data_from_buf(h->avctx, pic->f, AV_FRAME_DATA_LCEVC, &lcevc->info); + if (ret < 0) + return ret; + } + pic->tf.f = pic->f; ret = ff_thread_get_ext_buffer(h->avctx, &pic->tf, pic->reference ? AV_GET_BUFFER_FLAG_REF : 0); @@ -211,7 +218,7 @@ static int alloc_picture(H264Context *h, H264Picture *pic) goto fail; if (h->decode_error_flags_pool) { - pic->decode_error_flags = ff_refstruct_pool_get(h->decode_error_flags_pool); + pic->decode_error_flags = av_refstruct_pool_get(h->decode_error_flags_pool); if (!pic->decode_error_flags) goto fail; atomic_init(pic->decode_error_flags, 0); @@ -236,8 +243,8 @@ static int alloc_picture(H264Context *h, H264Picture *pic) goto fail; } - pic->qscale_table_base = ff_refstruct_pool_get(h->qscale_table_pool); - pic->mb_type_base = ff_refstruct_pool_get(h->mb_type_pool); + pic->qscale_table_base = av_refstruct_pool_get(h->qscale_table_pool); + pic->mb_type_base = av_refstruct_pool_get(h->mb_type_pool); if (!pic->qscale_table_base || !pic->mb_type_base) goto fail; @@ -245,15 +252,15 @@ static int alloc_picture(H264Context *h, H264Picture *pic) pic->qscale_table = pic->qscale_table_base + 2 * h->mb_stride + 1; for (i = 0; i < 2; i++) { - pic->motion_val_base[i] = ff_refstruct_pool_get(h->motion_val_pool); - pic->ref_index[i] = ff_refstruct_pool_get(h->ref_index_pool); + pic->motion_val_base[i] = av_refstruct_pool_get(h->motion_val_pool); + pic->ref_index[i] = av_refstruct_pool_get(h->ref_index_pool); if (!pic->motion_val_base[i] || !pic->ref_index[i]) goto fail; pic->motion_val[i] = pic->motion_val_base[i] + 4; } - pic->pps = ff_refstruct_ref_c(h->ps.pps); + pic->pps = av_refstruct_ref_c(h->ps.pps); pic->mb_width = h->mb_width; pic->mb_height = h->mb_height; @@ -358,11 +365,11 @@ int ff_h264_update_thread_context(AVCodecContext *dst, // SPS/PPS for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) - ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]); + av_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) - ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]); + av_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]); - ff_refstruct_replace(&h->ps.pps, h1->ps.pps); + av_refstruct_replace(&h->ps.pps, h1->ps.pps); h->ps.sps = h1->ps.sps; if (need_reinit || !inited) { @@ -437,13 +444,11 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->frame_recovered = h1->frame_recovered; - ret = ff_h264_sei_ctx_replace(&h->sei, &h1->sei); + ret = ff_h2645_sei_ctx_replace(&h->sei.common, &h1->sei.common); if (ret < 0) return ret; h->sei.common.unregistered.x264_build = h1->sei.common.unregistered.x264_build; - h->sei.common.mastering_display = h1->sei.common.mastering_display; - h->sei.common.content_light = h1->sei.common.content_light; if (!h->cur_pic_ptr) return 0; @@ -516,7 +521,10 @@ static int h264_frame_start(H264Context *h) pic->f->crop_top = h->crop_top; pic->f->crop_bottom = h->crop_bottom; - pic->needs_fg = h->sei.common.film_grain_characteristics.present && !h->avctx->hwaccel && + pic->needs_fg = + h->sei.common.film_grain_characteristics && + h->sei.common.film_grain_characteristics->present && + !h->avctx->hwaccel && !(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN); if ((ret = alloc_picture(h, pic)) < 0) @@ -806,6 +814,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #endif #if CONFIG_H264_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_H264_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) { @@ -1049,7 +1060,7 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl int needs_reinit = 0, must_reinit, ret; if (first_slice) - ff_refstruct_replace(&h->ps.pps, h->ps.pps_list[sl->pps_id]); + av_refstruct_replace(&h->ps.pps, h->ps.pps_list[sl->pps_id]); if (h->ps.sps != h->ps.pps->sps) { h->ps.sps = h->ps.pps->sps; @@ -2096,7 +2107,7 @@ int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal) if (ret < 0) return ret; } else if (h->cur_pic_ptr && !FIELD_PICTURE(h) && !h->first_field && h->nal_unit_type == H264_NAL_IDR_SLICE) { - av_log(h, AV_LOG_WARNING, "Broken frame packetizing\n"); + av_log(h->avctx, AV_LOG_WARNING, "Broken frame packetizing\n"); ret = ff_h264_field_end(h, h->slice_ctx, 1); ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0); ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1); diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 0154fe17b6..b1cf0f81b3 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -52,7 +52,7 @@ #include "mpegutils.h" #include "profiles.h" #include "rectangle.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" @@ -156,10 +156,10 @@ void ff_h264_free_tables(H264Context *h) av_freep(&h->mb2b_xy); av_freep(&h->mb2br_xy); - ff_refstruct_pool_uninit(&h->qscale_table_pool); - ff_refstruct_pool_uninit(&h->mb_type_pool); - ff_refstruct_pool_uninit(&h->motion_val_pool); - ff_refstruct_pool_uninit(&h->ref_index_pool); + av_refstruct_pool_uninit(&h->qscale_table_pool); + av_refstruct_pool_uninit(&h->mb_type_pool); + av_refstruct_pool_uninit(&h->motion_val_pool); + av_refstruct_pool_uninit(&h->ref_index_pool); #if CONFIG_ERROR_RESILIENCE av_freep(&h->er.mb_index2xy); @@ -313,7 +313,7 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h) ff_h264_sei_uninit(&h->sei); if (avctx->active_thread_type & FF_THREAD_FRAME) { - h->decode_error_flags_pool = ff_refstruct_pool_alloc(sizeof(atomic_int), 0); + h->decode_error_flags_pool = av_refstruct_pool_alloc(sizeof(atomic_int), 0); if (!h->decode_error_flags_pool) return AVERROR(ENOMEM); } @@ -364,7 +364,7 @@ static av_cold int h264_decode_end(AVCodecContext *avctx) h->cur_pic_ptr = NULL; - ff_refstruct_pool_uninit(&h->decode_error_flags_pool); + av_refstruct_pool_uninit(&h->decode_error_flags_pool); av_freep(&h->slice_ctx); h->nb_slice_ctx = 0; @@ -397,12 +397,6 @@ static av_cold int h264_decode_init(AVCodecContext *avctx) return AVERROR_UNKNOWN; } -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (!avctx->internal->is_copy) { if (avctx->extradata_size > 0 && avctx->extradata) { ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, @@ -587,7 +581,8 @@ static void debug_green_metadata(const H264SEIGreenMetaData *gm, void *logctx) } } -static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) +static int decode_nal_units(H264Context *h, AVBufferRef *buf_ref, + const uint8_t *buf, int buf_size) { AVCodecContext *const avctx = h->avctx; int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts @@ -668,7 +663,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) } if (h->avctx->hwaccel && - (ret = FF_HW_CALL(h->avctx, start_frame, buf, buf_size)) < 0) + (ret = FF_HW_CALL(h->avctx, start_frame, buf_ref, + buf, buf_size)) < 0) goto end; } @@ -742,8 +738,10 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) nal->type, nal->size_bits); } - if (err < 0) { + if (err < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) { av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n"); + ret = err; + goto end; } } @@ -756,7 +754,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (h->cur_pic_ptr->decode_error_flags) { /* Frame-threading in use */ atomic_int *decode_error = h->cur_pic_ptr->decode_error_flags; - /* Using atomics here is not supposed to provide syncronisation; + /* Using atomics here is not supposed to provide synchronisation; * they are merely used to allow to set decode_error from both * decoding threads in case of coded slices. */ atomic_fetch_or_explicit(decode_error, FF_DECODE_ERROR_DECODE_SLICES, @@ -825,19 +823,6 @@ end: return (ret < 0) ? ret : buf_size; } -/** - * Return the number of bytes consumed for building the current frame. - */ -static int get_consumed_bytes(int pos, int buf_size) -{ - if (pos == 0) - pos = 1; // avoid infinite loops (I doubt that is needed but...) - if (pos + 10 > buf_size) - pos = buf_size; // oops ;) - - return pos; -} - static int h264_export_enc_params(AVFrame *f, const H264Picture *p) { AVVideoEncParams *par; @@ -1064,7 +1049,7 @@ static int h264_decode_frame(AVCodecContext *avctx, AVFrame *pict, avctx->err_recognition, avctx); } - buf_index = decode_nal_units(h, buf, buf_size); + buf_index = decode_nal_units(h, avpkt->buf, buf, buf_size); if (buf_index < 0) return AVERROR_INVALIDDATA; @@ -1098,7 +1083,7 @@ static int h264_decode_frame(AVCodecContext *avctx, AVFrame *pict, ff_h264_unref_picture(&h->last_pic_for_ec); - return get_consumed_bytes(buf_index, buf_size); + return buf_size; } #define OFFSET(x) offsetof(H264Context, x) diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index ccd7583bf4..1df99015cc 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -305,11 +305,11 @@ typedef struct H264SliceContext { DECLARE_ALIGNED(8, uint16_t, sub_mb_type)[4]; - ///< as a DCT coefficient is int32_t in high depth, we need to reserve twice the space. + /// as a DCT coefficient is int32_t in high depth, we need to reserve twice the space. DECLARE_ALIGNED(16, int16_t, mb)[16 * 48 * 2]; DECLARE_ALIGNED(16, int16_t, mb_luma_dc)[3][16 * 2]; - ///< as mb is addressed by scantable[i] and scantable is uint8_t we can either - ///< check that i is not too large or ensure that there is some unused stuff after mb + /// as mb is addressed by scantable[i] and scantable is uint8_t we can either + /// check that i is not too large or ensure that there is some unused stuff after mb int16_t mb_padding[256 * 2]; uint8_t (*mvd_table[2])[2]; @@ -541,7 +541,7 @@ typedef struct H264Context { * all subsequently output fraames are also marked as recovered * * In effect, if you want all subsequent DECODED frames marked as recovered, set frame_recovered - * If you want all subsequent DISPAYED frames marked as recovered, set the frame->recovered + * If you want all subsequent DISPLAYED frames marked as recovered, set the frame->recovered */ int frame_recovered; @@ -570,11 +570,11 @@ typedef struct H264Context { H264SEIContext sei; - struct FFRefStructPool *qscale_table_pool; - struct FFRefStructPool *mb_type_pool; - struct FFRefStructPool *motion_val_pool; - struct FFRefStructPool *ref_index_pool; - struct FFRefStructPool *decode_error_flags_pool; + struct AVRefStructPool *qscale_table_pool; + struct AVRefStructPool *mb_type_pool; + struct AVRefStructPool *motion_val_pool; + struct AVRefStructPool *ref_index_pool; + struct AVRefStructPool *decode_error_flags_pool; int ref2frm[MAX_SLICES][2][64]; ///< reference to frame number lists, used in the loop filter, the first 2 are for -2,-1 int non_gray; ///< Did we encounter a intra frame after a gray gap frame diff --git a/libavcodec/h264pred_template.c b/libavcodec/h264pred_template.c index b5bc942a5e..98b28d0afb 100644 --- a/libavcodec/h264pred_template.c +++ b/libavcodec/h264pred_template.c @@ -414,7 +414,6 @@ static inline void FUNCC(pred16x16_plane_compat)(uint8_t *_src, { int i, j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +7-stride; @@ -748,7 +747,6 @@ static void FUNCC(pred8x8_plane)(uint8_t *_src, ptrdiff_t _stride) { int j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +3-stride; @@ -784,7 +782,6 @@ static void FUNCC(pred8x16_plane)(uint8_t *_src, ptrdiff_t _stride) { int j, k; int a; - INIT_CLIP pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); const pixel * const src0 = src +3-stride; diff --git a/libavcodec/h264qpel.c b/libavcodec/h264qpel.c index 65fef03304..faca1e8953 100644 --- a/libavcodec/h264qpel.c +++ b/libavcodec/h264qpel.c @@ -102,6 +102,8 @@ av_cold void ff_h264qpel_init(H264QpelContext *c, int bit_depth) ff_h264qpel_init_arm(c, bit_depth); #elif ARCH_PPC ff_h264qpel_init_ppc(c, bit_depth); +#elif ARCH_RISCV + ff_h264qpel_init_riscv(c, bit_depth); #elif ARCH_X86 ff_h264qpel_init_x86(c, bit_depth); #elif ARCH_MIPS diff --git a/libavcodec/h264qpel.h b/libavcodec/h264qpel.h index 0259e8de23..24baf826f9 100644 --- a/libavcodec/h264qpel.h +++ b/libavcodec/h264qpel.h @@ -34,6 +34,7 @@ void ff_h264qpel_init(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_aarch64(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_arm(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_ppc(H264QpelContext *c, int bit_depth); +void ff_h264qpel_init_riscv(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_mips(H264QpelContext *c, int bit_depth); void ff_h264qpel_init_loongarch(H264QpelContext *c, int bit_depth); diff --git a/libavcodec/h264qpel_template.c b/libavcodec/h264qpel_template.c index f7fabe4aaa..324a0889e9 100644 --- a/libavcodec/h264qpel_template.c +++ b/libavcodec/h264qpel_template.c @@ -78,7 +78,6 @@ static inline void FUNC(copy_block16)(uint8_t *dst, const uint8_t *restrict src, static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *p_dst, const uint8_t *restrict p_src, int dstStride, int srcStride)\ {\ const int h=2;\ - INIT_CLIP\ int i;\ pixel *dst = (pixel*)p_dst;\ const pixel *restrict src = (const pixel*)p_src;\ @@ -96,7 +95,6 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *p_dst, const static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *_dst, const uint8_t *restrict _src, int dstStride, int srcStride)\ {\ const int w=2;\ - INIT_CLIP\ int i;\ pixel *dst = (pixel*)_dst;\ const pixel *restrict src = (const pixel*)_src;\ @@ -123,7 +121,6 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *_dst, pixel const int h=2;\ const int w=2;\ const int pad = (BIT_DEPTH == 10) ? (-10 * ((1<> 7; @@ -235,7 +240,7 @@ int ff_h274_apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, uint8_t * const out = out_frame->data[c]; const int out_stride = out_frame->linesize[c]; - int8_t * const grain = out_frame->data[c]; // re-use output buffer for grain + int8_t * const grain = out_frame->data[c]; // reuse output buffer for grain const int grain_stride = out_stride; const uint8_t * const in = in_frame->data[c]; const int in_stride = in_frame->linesize[c]; @@ -790,3 +795,195 @@ static const int8_t R64T[64][64] = { 17, -16, 15, -14, 13, -12, 11, -10, 9, -8, 7, -6, 4, -3, 2, -1, } }; + +struct H274HashContext { + int type; + struct AVMD5 *ctx; + +#if HAVE_BIGENDIAN + BswapDSPContext bdsp; + uint8_t *buf; + int buf_size; +#endif +}; + +static av_always_inline void bswap16_buf_if_be(H274HashContext *s, const int ps, const uint8_t **src, const int w) +{ +#if HAVE_BIGENDIAN + if (ps) { + s->bdsp.bswap16_buf((uint16_t *)s->buf, + (const uint16_t *)*src, w); + *src = s->buf; + } +#endif +} + +static int verify_plane_md5(H274HashContext *s, + const uint8_t *_src, const int w, const int h, const int stride, + const int ps, const uint8_t *expected) +{ +#define MD5_SIZE 16 + struct AVMD5 *ctx = s->ctx; + uint8_t md5[MD5_SIZE]; + + av_md5_init(ctx); + for (int j = 0; j < h; j++) { + const uint8_t *src = &_src[j * stride]; + bswap16_buf_if_be(s, ps, &src, w); + av_md5_update(ctx, src, w << ps); + src += stride; + } + av_md5_final(ctx, md5); + + if (memcmp(md5, expected, MD5_SIZE)) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int verify_plane_crc(H274HashContext *s, const uint8_t *_src, const int w, const int h, const int stride, + const int ps, uint16_t expected) +{ + uint32_t crc = 0x0F1D; // CRC-16-CCITT-AUG + const AVCRC *ctx = av_crc_get_table(AV_CRC_16_CCITT); + + for (int j = 0; j < h; j++) { + const uint8_t *src = &_src[j * stride]; + bswap16_buf_if_be(s, ps, &src, w); + crc = av_crc(ctx, crc, src, w << ps); + src += stride; + } + crc = av_bswap16(crc); + + if (crc != expected) + return AVERROR_INVALIDDATA; + + return 0; +} + +#define CAL_CHECKSUM(pixel) ((pixel) ^ xor_mask) +static int verify_plane_checksum(const uint8_t *src, const int w, const int h, const int stride, const int ps, + uint32_t expected) +{ + uint32_t checksum = 0; + expected = av_le2ne32(expected); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + const int xor_mask = (x & 0xFF) ^ (y & 0xFF) ^ (x >> 8) ^ (y >> 8); + checksum += CAL_CHECKSUM(src[x << ps]); + if (ps) + checksum += CAL_CHECKSUM(src[(x << ps) + 1]); + } + src += stride; + } + + if (checksum != expected) + return AVERROR_INVALIDDATA; + + return 0; +} + +enum { + HASH_MD5SUM, + HASH_CRC, + HASH_CHECKSUM, + HASH_LAST = HASH_CHECKSUM, +}; + +void ff_h274_hash_freep(H274HashContext **ctx) +{ + if (*ctx) { + H274HashContext *c = *ctx; + if (c->ctx) + av_free(c->ctx); + av_freep(ctx); +#if HAVE_BIGENDIAN + av_freep(&c->buf); +#endif + } +} + +int ff_h274_hash_init(H274HashContext **ctx, const int type) +{ + H274HashContext *c; + + if (type > HASH_LAST || !ctx) + return AVERROR(EINVAL); + + c = *ctx; + if (c) { + if (c->type != type) { + if (c->type == HASH_MD5SUM) + av_freep(&c->ctx); + c->type = type; + } + } else { + c = av_mallocz(sizeof(H274HashContext)); + if (!c) + return AVERROR(ENOMEM); + c->type = type; + *ctx = c; + } + + if (type == HASH_MD5SUM && !c->ctx) { + c->ctx = av_md5_alloc(); + if (!c->ctx) + return AVERROR(ENOMEM); + } + +#if HAVE_BIGENDIAN + ff_bswapdsp_init(&c->bdsp); +#endif + + return 0; +} + +int ff_h274_hash_verify(H274HashContext *c, const H274SEIPictureHash *hash, + const AVFrame *frame, const int coded_width, const int coded_height) +{ + const AVPixFmtDescriptor *desc; + int err = 0; + + if (!c || !hash || !frame) + return AVERROR(EINVAL); + + if (c->type != hash->hash_type) + return AVERROR(EINVAL); + + desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR(EINVAL); + + for (int i = 0; i < desc->nb_components; i++) { + const int w = i ? (coded_width >> desc->log2_chroma_w) : coded_width; + const int h = i ? (coded_height >> desc->log2_chroma_h) : coded_height; + const int ps = desc->comp[i].step - 1; + const uint8_t *src = frame->data[i]; + const int stride = frame->linesize[i]; + +#if HAVE_BIGENDIAN + if (c->type != HASH_CHECKSUM) { + if (ps) { + av_fast_malloc(&c->buf, &c->buf_size, + FFMAX3(frame->linesize[0], frame->linesize[1], + frame->linesize[2])); + if (!c->buf) + return AVERROR(ENOMEM); + } + } +#endif + + if (c->type == HASH_MD5SUM) + err = verify_plane_md5(c, src, w, h, stride, ps, hash->md5[i]); + else if (c->type == HASH_CRC) + err = verify_plane_crc(c, src, w, h, stride, ps, hash->crc[i]); + else if (c->type == HASH_CHECKSUM) + err = verify_plane_checksum(src, w, h, stride, ps, hash->checksum[i]); + if (err < 0) + goto fail; + } + +fail: + return err; +} diff --git a/libavcodec/h274.h b/libavcodec/h274.h index cebc8becb3..055dd591d2 100644 --- a/libavcodec/h274.h +++ b/libavcodec/h274.h @@ -64,4 +64,29 @@ int ff_h274_apply_film_grain(AVFrame *out, const AVFrame *in, H274FilmGrainDatabase *db, const AVFilmGrainParams *params); +typedef struct H274HashContext H274HashContext; + +typedef struct H274SEIPictureHash { + int present; + union { + uint8_t md5[3][16]; + uint16_t crc[3]; + uint32_t checksum[3]; + }; + uint8_t hash_type; +} H274SEIPictureHash; + +int ff_h274_hash_init(H274HashContext **c, int type); +int ff_h274_hash_verify(H274HashContext *c, const H274SEIPictureHash *hash, + const AVFrame *frame, int coded_width, int coded_height); +void ff_h274_hash_freep(H274HashContext **c); + +typedef struct H274SEIFrameFieldInfo { + int present; + int picture_struct; + uint8_t display_elemental_periods; + uint8_t source_scan_type; + uint8_t duplicate_flag; +} H274SEIFrameFieldInfo; + #endif /* AVCODEC_H274_H */ diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c index 918eff7876..70bf592f2a 100644 --- a/libavcodec/hapdec.c +++ b/libavcodec/hapdec.c @@ -310,6 +310,7 @@ static int hap_decode(AVCodecContext *avctx, AVFrame *frame, ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); if (ret < 0) return ret; + memset(ctx->tex_buf, 0, ctx->tex_size); avctx->execute2(avctx, decompress_chunks_thread, NULL, ctx->chunk_results, ctx->chunk_count); diff --git a/libavcodec/hapenc.c b/libavcodec/hapenc.c index 8dc12a851c..a0b199906d 100644 --- a/libavcodec/hapenc.c +++ b/libavcodec/hapenc.c @@ -305,7 +305,7 @@ static av_cold int hap_init(AVCodecContext *avctx) } break; default: - av_log(avctx, AV_LOG_ERROR, "Invalid compresor %02X\n", ctx->opt_compressor); + av_log(avctx, AV_LOG_ERROR, "Invalid compressor %02X\n", ctx->opt_compressor); return AVERROR_INVALIDDATA; } if (corrected_chunk_count != ctx->opt_chunk_count) { @@ -361,8 +361,6 @@ const FFCodec ff_hap_encoder = { .init = hap_init, FF_CODEC_ENCODE_CB(hap_encode), .close = hap_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c new file mode 100644 index 0000000000..d18e872f4f --- /dev/null +++ b/libavcodec/hashtable.c @@ -0,0 +1,212 @@ +/* + * Generic hashtable + * Copyright (C) 2025 Emma Worley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/attributes.h" +#include "libavutil/crc.h" +#include "libavutil/error.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" +#include "hashtable.h" + +#define ALIGN _Alignof(size_t) + +struct FFHashtableContext { + size_t key_size; + size_t val_size; + size_t entry_size; + size_t max_entries; + size_t nb_entries; + const AVCRC *crc; + uint8_t *table; + uint8_t swapbuf[]; +}; + +/* + * Hash table entries are comprised of a probe sequence length (PSL), key, and + * value. When the PSL of an entry is zero, it means it is not occupied by a + * key/value pair. When the PSL is non-zero, it represents the "distance" of + * the entry from its "home" location plus one, where the "home" location is + * hash(key) % max_entries. + */ + +#define ENTRY_PSL_VAL(entry) (*(size_t*)(entry)) +#define ENTRY_KEY_PTR(entry) ((entry) + sizeof(size_t)) +#define ENTRY_VAL_PTR(entry) (ENTRY_KEY_PTR(entry) + ctx->key_size) + +#define KEYS_EQUAL(k1, k2) (!memcmp((k1), (k2), ctx->key_size)) + +av_cold int ff_hashtable_alloc(FFHashtableContext **ctx, size_t key_size, + size_t val_size, size_t max_entries) +{ + const size_t keyval_size = key_size + val_size; + + if (keyval_size < key_size || // did (unsigned,defined) wraparound happen? + keyval_size > FFMIN(SIZE_MAX - sizeof(size_t) - (ALIGN - 1), + (SIZE_MAX - sizeof(FFHashtableContext)) / 2)) + return AVERROR(ERANGE); + + FFHashtableContext *res = av_mallocz(sizeof(*res) + 2 * keyval_size); + if (!res) + return AVERROR(ENOMEM); + res->key_size = key_size; + res->val_size = val_size; + res->entry_size = FFALIGN(sizeof(size_t) + keyval_size, ALIGN); + res->max_entries = max_entries; + res->nb_entries = 0; + res->crc = av_crc_get_table(AV_CRC_32_IEEE); + if (!res->crc) { + ff_hashtable_freep(&res); + return AVERROR_BUG; + } + res->table = av_calloc(res->max_entries, res->entry_size); + if (!res->table) { + ff_hashtable_freep(&res); + return AVERROR(ENOMEM); + } + + *ctx = res; + return 0; +} + +static size_t hash_key(const struct FFHashtableContext *ctx, const void *key) +{ + return av_crc(ctx->crc, 0, key, ctx->key_size) % ctx->max_entries; +} + +int ff_hashtable_get(const struct FFHashtableContext *ctx, const void *key, void *val) +{ + if (!ctx->nb_entries) + return 0; + + size_t hash = hash_key(ctx, key); + + for (size_t psl = 1; psl <= ctx->max_entries; psl++) { + size_t wrapped_index = (hash + psl) % ctx->max_entries; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(entry) < psl) + // When PSL stops increasing it means there are no further entries + // with the same key hash. + return 0; + if (KEYS_EQUAL(ENTRY_KEY_PTR(entry), key)) { + memcpy(val, ENTRY_VAL_PTR(entry), ctx->val_size); + return 1; + } + } + return 0; +} + +int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void *val) +{ + int swapping = 0; + size_t psl = 1; + size_t hash = hash_key(ctx, key); + size_t wrapped_index = hash % ctx->max_entries; + uint8_t *set = ctx->swapbuf; + uint8_t *tmp = ctx->swapbuf + ctx->key_size + ctx->val_size; + + memcpy(set, key, ctx->key_size); + memcpy(set + ctx->key_size, val, ctx->val_size); + + for (size_t i = 0; i < ctx->max_entries; i++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (!ENTRY_PSL_VAL(entry) || (!swapping && KEYS_EQUAL(ENTRY_KEY_PTR(entry), set))) { + if (!ENTRY_PSL_VAL(entry)) + ctx->nb_entries++; + ENTRY_PSL_VAL(entry) = psl; + memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size); + return 1; + } + if (ENTRY_PSL_VAL(entry) < psl) { + // When PSL stops increasing it means there are no further entries + // with the same key hash. We can only hope to find an unoccupied + // entry. + if (ctx->nb_entries == ctx->max_entries) + // The table is full so inserts are impossible. + return 0; + // Robin Hood hash tables "steal from the rich" by minimizing the + // PSL of the inserted entry. + swapping = 1; + // set needs to swap with entry + memcpy(tmp, ENTRY_KEY_PTR(entry), ctx->key_size + ctx->val_size); + memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size); + FFSWAP(uint8_t*, set, tmp); + FFSWAP(size_t, psl, ENTRY_PSL_VAL(entry)); + } + psl++; + } + return 0; +} + +int ff_hashtable_delete(struct FFHashtableContext *ctx, const void *key) +{ + if (!ctx->nb_entries) + return 0; + + uint8_t *next_entry; + size_t hash = hash_key(ctx, key); + size_t wrapped_index = hash % ctx->max_entries; + + for (size_t psl = 1; psl <= ctx->max_entries; psl++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + uint8_t *entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(entry) < psl) + // When PSL stops increasing it means there are no further entries + // with the same key hash. + return 0; + if (KEYS_EQUAL(ENTRY_KEY_PTR(entry), key)) { + ENTRY_PSL_VAL(entry) = 0; + // Shift each following entry that will benefit from a reduced PSL. + for (psl++; psl <= ctx->max_entries; psl++) { + if (++wrapped_index == ctx->max_entries) + wrapped_index = 0; + next_entry = ctx->table + wrapped_index * ctx->entry_size; + if (ENTRY_PSL_VAL(next_entry) <= 1) { + ctx->nb_entries--; + return 1; + } + memcpy(entry, next_entry, ctx->entry_size); + ENTRY_PSL_VAL(entry)--; + ENTRY_PSL_VAL(next_entry) = 0; + entry = next_entry; + } + } + } + return 0; +} + +void ff_hashtable_clear(struct FFHashtableContext *ctx) +{ + memset(ctx->table, 0, ctx->entry_size * ctx->max_entries); +} + +av_cold void ff_hashtable_freep(FFHashtableContext **ctx) +{ + if (*ctx) { + av_freep(&(*ctx)->table); + av_freep(ctx); + } +} diff --git a/libavcodec/hashtable.h b/libavcodec/hashtable.h new file mode 100644 index 0000000000..f81b4bb93f --- /dev/null +++ b/libavcodec/hashtable.h @@ -0,0 +1,94 @@ +/* + * Generic hashtable + * Copyright (C) 2024 Emma Worley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_HASHTABLE_H +#define AVCODEC_HASHTABLE_H + +#include + +/* Implements a hash table using Robin Hood open addressing. + * See: https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf + * + * Keys are placed in the table based on their CRC value and are considered + * equal when they are bytewise-identical. + */ + +typedef struct FFHashtableContext FFHashtableContext; + +/** + * Create a fixed-sized Robin Hood hash table. + * + * @param ctx context to allocate and initialize + * @param key_size size of key type in bytes + * @param val_size size of value type in bytes + * @param max_entries maximum number of key-value pairs to store + * + * @return zero on success, nonzero on error + */ +int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t val_size, size_t max_entries); + +/** + * Look up a value from a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * @param val destination pointer for value data + * + * @return 1 if the key is found, zero if the key is not found + */ +int ff_hashtable_get(const struct FFHashtableContext *ctx, const void *key, void *val); + +/** + * Store a value in a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * @param val pointer for value data + * + * @return 1 if the key is written, zero if the key is not written due to the hash table reaching max capacity + */ +int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void *val); + +/** + * Delete a value from a hash table given a key. + * + * @param ctx hash table context + * @param key pointer to key data + * + * @return 1 if the key is deleted, zero if the key is not deleted due to not being found + */ +int ff_hashtable_delete(struct FFHashtableContext *ctx, const void *key); + +/** + * Delete all values from a hash table. + * + * @param ctx hash table context + */ +void ff_hashtable_clear(struct FFHashtableContext *ctx); + +/** + * Free a hash table. + * + * @param ctx hash table context + */ +void ff_hashtable_freep(struct FFHashtableContext **ctx); + +#endif diff --git a/libavcodec/hcadec.c b/libavcodec/hcadec.c index e8f877c3cf..7780372cf3 100644 --- a/libavcodec/hcadec.c +++ b/libavcodec/hcadec.c @@ -245,6 +245,7 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata, c->base_band_count = bytestream2_get_byteu(gb); c->stereo_band_count = bytestream2_get_byte (gb); c->bands_per_hfr_group = bytestream2_get_byte (gb); + bytestream2_skipu(gb, 2); } else if (chunk == MKBETAG('d', 'e', 'c', 0)) { bytestream2_skipu(gb, 2); bytestream2_skipu(gb, 1); @@ -634,6 +635,5 @@ const FFCodec ff_hca_decoder = { .close = decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/hdrenc.c b/libavcodec/hdrenc.c index a7bf36946d..71478475e0 100644 --- a/libavcodec/hdrenc.c +++ b/libavcodec/hdrenc.c @@ -182,9 +182,6 @@ const FFCodec ff_hdr_encoder = { .init = hdr_encode_init, FF_CODEC_ENCODE_CB(hdr_encode_frame), .close = hdr_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/hevc/cabac.c b/libavcodec/hevc/cabac.c index 892dd1c215..55d5741f87 100644 --- a/libavcodec/hevc/cabac.c +++ b/libavcodec/hevc/cabac.c @@ -1512,4 +1512,3 @@ void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_si case 0: lc->pu.mvd.y = 0; break; } } - diff --git a/libavcodec/hevc/dsp.c b/libavcodec/hevc/dsp.c index 60f059292c..a154fab2bf 100644 --- a/libavcodec/hevc/dsp.c +++ b/libavcodec/hevc/dsp.c @@ -265,6 +265,10 @@ int i = 0; ff_hevc_dsp_init_arm(hevcdsp, bit_depth); #elif ARCH_PPC ff_hevc_dsp_init_ppc(hevcdsp, bit_depth); +#elif ARCH_RISCV + ff_hevc_dsp_init_riscv(hevcdsp, bit_depth); +#elif ARCH_WASM + ff_hevc_dsp_init_wasm(hevcdsp, bit_depth); #elif ARCH_X86 ff_hevc_dsp_init_x86(hevcdsp, bit_depth); #elif ARCH_MIPS diff --git a/libavcodec/hevc/dsp.h b/libavcodec/hevc/dsp.h index 02b8e0e8e2..a63586c3a2 100644 --- a/libavcodec/hevc/dsp.h +++ b/libavcodec/hevc/dsp.h @@ -133,6 +133,8 @@ extern const int8_t ff_hevc_qpel_filters[4][16]; void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth); 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_riscv(HEVCDSPContext *c, const int bit_depth); +void ff_hevc_dsp_init_wasm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_loongarch(HEVCDSPContext *c, const int bit_depth); diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h index 8bd59142db..710786a89d 100644 --- a/libavcodec/hevc/hevc.h +++ b/libavcodec/hevc/hevc.h @@ -162,5 +162,17 @@ enum { HEVC_MAX_PALETTE_PREDICTOR_SIZE = 128, }; +enum HEVCScalabilityMask { + HEVC_SCALABILITY_DEPTH = 1 << (15 - 0), + HEVC_SCALABILITY_MULTIVIEW = 1 << (15 - 1), + HEVC_SCALABILITY_SPATIAL = 1 << (15 - 2), + HEVC_SCALABILITY_AUXILIARY = 1 << (15 - 3), + HEVC_SCALABILITY_MASK_MAX = 0xFFFF, +}; + +enum HEVCAuxId { + HEVC_AUX_ALPHA = 1, + HEVC_AUX_DEPTH = 2, +}; #endif /* AVCODEC_HEVC_HEVC_H */ diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index 0dc24f82f8..f44bda8a92 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -28,6 +28,7 @@ #include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavutil/common.h" +#include "libavutil/container_fifo.h" #include "libavutil/film_grain_params.h" #include "libavutil/internal.h" #include "libavutil/md5.h" @@ -35,13 +36,13 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/stereo3d.h" +#include "libavutil/tdrdi.h" #include "libavutil/timecode.h" #include "aom_film_grain.h" #include "bswapdsp.h" #include "cabac_functions.h" #include "codec_internal.h" -#include "container_fifo.h" #include "decode.h" #include "golomb.h" #include "hevc.h" @@ -52,8 +53,9 @@ #include "internal.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" +#include "threadprogress.h" static const uint8_t hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 }; @@ -91,8 +93,8 @@ static void pic_arrays_free(HEVCLayerContext *l) av_freep(&l->sao_pixel_buffer_v[i]); } - ff_refstruct_pool_uninit(&l->tab_mvf_pool); - ff_refstruct_pool_uninit(&l->rpl_tab_pool); + av_refstruct_pool_uninit(&l->tab_mvf_pool); + av_refstruct_pool_uninit(&l->rpl_tab_pool); } /* allocate arrays that depend on frame dimensions */ @@ -128,7 +130,7 @@ static int pic_arrays_init(HEVCLayerContext *l, const HEVCSPS *sps) l->filter_slice_edges = av_mallocz(ctb_count); l->tab_slice_address = av_malloc_array(pic_size_in_ctb, sizeof(*l->tab_slice_address)); - l->qp_y_tab = av_malloc_array(pic_size_in_ctb, + l->qp_y_tab = av_calloc(pic_size_in_ctb, sizeof(*l->qp_y_tab)); if (!l->qp_y_tab || !l->filter_slice_edges || !l->tab_slice_address) goto fail; @@ -138,8 +140,8 @@ static int pic_arrays_init(HEVCLayerContext *l, const HEVCSPS *sps) if (!l->horizontal_bs || !l->vertical_bs) goto fail; - l->tab_mvf_pool = ff_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 0); - l->rpl_tab_pool = ff_refstruct_pool_alloc(ctb_count * sizeof(RefPicListTab), 0); + l->tab_mvf_pool = av_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 0); + l->rpl_tab_pool = av_refstruct_pool_alloc(ctb_count * sizeof(RefPicListTab), 0); if (!l->tab_mvf_pool || !l->rpl_tab_pool) goto fail; @@ -150,10 +152,10 @@ static int pic_arrays_init(HEVCLayerContext *l, const HEVCSPS *sps) int w = sps->width >> sps->hshift[c_idx]; int h = sps->height >> sps->vshift[c_idx]; l->sao_pixel_buffer_h[c_idx] = - av_malloc((w * 2 * sps->ctb_height) << + av_mallocz((w * 2 * sps->ctb_height) << sps->pixel_shift); l->sao_pixel_buffer_v[c_idx] = - av_malloc((h * 2 * sps->ctb_width) << + av_mallocz((h * 2 * sps->ctb_width) << sps->pixel_shift); if (!l->sao_pixel_buffer_h[c_idx] || !l->sao_pixel_buffer_v[c_idx]) @@ -173,11 +175,8 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, { int i = 0; int j = 0; - uint8_t luma_weight_l0_flag[16]; - uint8_t chroma_weight_l0_flag[16]; - uint8_t luma_weight_l1_flag[16]; - uint8_t chroma_weight_l1_flag[16]; int luma_log2_weight_denom; + unsigned luma_weight_flags, chroma_weight_flags; luma_log2_weight_denom = get_ue_golomb_long(gb); if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7) { @@ -194,29 +193,22 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, sh->chroma_log2_weight_denom = chroma_log2_weight_denom; } + luma_weight_flags = get_bits(gb, sh->nb_refs[L0]); + chroma_weight_flags = sps->chroma_format_idc != 0 ? get_bits(gb, sh->nb_refs[L0]) : 0; for (i = 0; i < sh->nb_refs[L0]; i++) { - luma_weight_l0_flag[i] = get_bits1(gb); - if (!luma_weight_l0_flag[i]) { - sh->luma_weight_l0[i] = 1 << sh->luma_log2_weight_denom; - sh->luma_offset_l0[i] = 0; - } - } - if (sps->chroma_format_idc != 0) { - for (i = 0; i < sh->nb_refs[L0]; i++) - chroma_weight_l0_flag[i] = get_bits1(gb); - } else { - for (i = 0; i < sh->nb_refs[L0]; i++) - chroma_weight_l0_flag[i] = 0; - } - for (i = 0; i < sh->nb_refs[L0]; i++) { - if (luma_weight_l0_flag[i]) { + unsigned flag_bit = 1 << (sh->nb_refs[L0] - 1 - i); + + if (luma_weight_flags & flag_bit) { int delta_luma_weight_l0 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l0 != delta_luma_weight_l0) return AVERROR_INVALIDDATA; sh->luma_weight_l0[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l0; sh->luma_offset_l0[i] = get_se_golomb(gb); + } else { + sh->luma_weight_l0[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l0[i] = 0; } - if (chroma_weight_l0_flag[i]) { + if (chroma_weight_flags & flag_bit) { for (j = 0; j < 2; j++) { int delta_chroma_weight_l0 = get_se_golomb(gb); int delta_chroma_offset_l0 = get_se_golomb(gb); @@ -238,29 +230,22 @@ static int pred_weight_table(SliceHeader *sh, void *logctx, } } if (sh->slice_type == HEVC_SLICE_B) { + luma_weight_flags = get_bits(gb, sh->nb_refs[L1]); + chroma_weight_flags = sps->chroma_format_idc != 0 ? get_bits(gb, sh->nb_refs[L1]) : 0; for (i = 0; i < sh->nb_refs[L1]; i++) { - luma_weight_l1_flag[i] = get_bits1(gb); - if (!luma_weight_l1_flag[i]) { - sh->luma_weight_l1[i] = 1 << sh->luma_log2_weight_denom; - sh->luma_offset_l1[i] = 0; - } - } - if (sps->chroma_format_idc != 0) { - for (i = 0; i < sh->nb_refs[L1]; i++) - chroma_weight_l1_flag[i] = get_bits1(gb); - } else { - for (i = 0; i < sh->nb_refs[L1]; i++) - chroma_weight_l1_flag[i] = 0; - } - for (i = 0; i < sh->nb_refs[L1]; i++) { - if (luma_weight_l1_flag[i]) { + unsigned flag_bit = 1 << (sh->nb_refs[L1] - 1 - i); + + if (luma_weight_flags & flag_bit) { int delta_luma_weight_l1 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l1 != delta_luma_weight_l1) return AVERROR_INVALIDDATA; sh->luma_weight_l1[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l1; sh->luma_offset_l1[i] = get_se_golomb(gb); + } else { + sh->luma_weight_l1[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l1[i] = 0; } - if (chroma_weight_l1_flag[i]) { + if (chroma_weight_flags & flag_bit) { for (j = 0; j < 2; j++) { int delta_chroma_weight_l1 = get_se_golomb(gb); int delta_chroma_offset_l1 = get_se_golomb(gb); @@ -402,8 +387,12 @@ static int export_stream_params_from_sei(HEVCContext *s) { AVCodecContext *avctx = s->avctx; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (s->sei.common.a53_caption.buf_ref) s->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (s->sei.common.alternative_transfer.present && av_color_transfer_name(s->sei.common.alternative_transfer.preferred_transfer_characteristics) && @@ -411,9 +400,13 @@ static int export_stream_params_from_sei(HEVCContext *s) avctx->color_trc = s->sei.common.alternative_transfer.preferred_transfer_characteristics; } - if (s->sei.common.film_grain_characteristics.present || +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS + if ((s->sei.common.film_grain_characteristics && s->sei.common.film_grain_characteristics->present) || s->sei.common.aom_film_grain.enable) avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif return 0; } @@ -457,6 +450,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps) return 0; } +int ff_hevc_is_alpha_video(const HEVCContext *s) +{ + const HEVCVPS *vps = s->vps; + int ret = 0; + + if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1]) + return 0; + + /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other + * than alpha cannot reach here. + */ + ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY); + + av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n", + ret ? "is" : "not"); + + return ret; +} + static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) { unsigned layers_active_output = 0, highest_layer; @@ -464,6 +476,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) s->layers_active_output = 1; s->layers_active_decode = 1; + if (ff_hevc_is_alpha_video(s)) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt); + + if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) + return 0; + + s->layers_active_decode = (1 << vps->nb_layers) - 1; + s->layers_active_output = 1; + + return 0; + } + // nothing requested - decode base layer only if (!s->nb_view_ids) return 0; @@ -521,6 +545,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) return 0; } +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s, + enum AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + return AV_PIX_FMT_YUVA420P; + case AV_PIX_FMT_YUV420P10: + return AV_PIX_FMT_YUVA420P10; + case AV_PIX_FMT_YUV444P: + return AV_PIX_FMT_YUVA444P; + case AV_PIX_FMT_YUV422P: + return AV_PIX_FMT_YUVA422P; + case AV_PIX_FMT_YUV422P10LE: + return AV_PIX_FMT_YUVA422P10LE; + case AV_PIX_FMT_YUV444P10: + return AV_PIX_FMT_YUVA444P10; + case AV_PIX_FMT_YUV444P12: + return AV_PIX_FMT_YUVA444P12; + case AV_PIX_FMT_YUV422P12: + return AV_PIX_FMT_YUVA422P12; + default: + av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n", + av_get_pix_fmt_name(pix_fmt)); + return AV_PIX_FMT_NONE; + } +} + static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ @@ -531,9 +583,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL + \ CONFIG_HEVC_VULKAN_HWACCEL) - enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; + enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts; + enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE; int ret; + if (ff_hevc_is_alpha_video(s)) + alpha_fmt = map_to_alpha_format(s, sps->pix_fmt); + switch (sps->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: @@ -617,6 +673,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; case AV_PIX_FMT_YUV444P10: @@ -645,10 +704,15 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; } + if (alpha_fmt != AV_PIX_FMT_NONE) + *fmt++ = alpha_fmt; *fmt++ = sps->pix_fmt; *fmt = AV_PIX_FMT_NONE; @@ -676,8 +740,8 @@ static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) int ret; pic_arrays_free(l); - ff_refstruct_unref(&l->sps); - ff_refstruct_unref(&s->vps); + av_refstruct_unref(&l->sps); + av_refstruct_unref(&s->vps); if (!sps) return 0; @@ -690,14 +754,14 @@ static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth); ff_videodsp_init (&s->vdsp, sps->bit_depth); - l->sps = ff_refstruct_ref_c(sps); - s->vps = ff_refstruct_ref_c(sps->vps); + l->sps = av_refstruct_ref_c(sps); + s->vps = av_refstruct_ref_c(sps->vps); return 0; fail: pic_arrays_free(l); - ff_refstruct_unref(&l->sps); + av_refstruct_unref(&l->sps); return ret; } @@ -1047,7 +1111,7 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) { unsigned num_entry_point_offsets = get_ue_golomb_long(gb); // It would be possible to bound this tighter but this here is simpler - if (num_entry_point_offsets > get_bits_left(gb)) { + if (num_entry_point_offsets > get_bits_left(gb) || num_entry_point_offsets > UINT16_MAX) { av_log(s->avctx, AV_LOG_ERROR, "num_entry_point_offsets %d is invalid\n", num_entry_point_offsets); return AVERROR_INVALIDDATA; } @@ -1091,12 +1155,18 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext } ret = get_bits1(gb); - if (!ret) { + if (!ret && get_bits_left(gb) >= 0) { av_log(s->avctx, AV_LOG_ERROR, "alignment_bit_equal_to_one=0\n"); return AVERROR_INVALIDDATA; } sh->data_offset = align_get_bits(gb) - gb->buffer; + if (get_bits_left(gb) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Overread slice header by %d bits\n", -get_bits_left(gb)); + return AVERROR_INVALIDDATA; + } + // Inferred parameters sh->slice_qp = 26U + pps->pic_init_qp_minus26 + sh->slice_qp_delta; if (sh->slice_qp > 51 || @@ -1117,12 +1187,6 @@ static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext return AVERROR_INVALIDDATA; } - if (get_bits_left(gb) < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Overread slice header by %d bits\n", -get_bits_left(gb)); - return AVERROR_INVALIDDATA; - } - return 0; } @@ -2031,9 +2095,10 @@ static void hls_prediction_unit(HEVCLocalContext *lc, int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int partIdx, int idx) { -#define POS(c_idx, x, y) \ +#define POS(c_idx, x, y) \ + &s->cur_frame->f->data[c_idx] ? \ &s->cur_frame->f->data[c_idx][((y) >> sps->vshift[c_idx]) * linesize[c_idx] + \ - (((x) >> sps->hshift[c_idx]) << sps->pixel_shift)] + (((x) >> sps->hshift[c_idx]) << sps->pixel_shift)] : NULL const HEVCContext *const s = lc->parent; int merge_idx = 0; struct MvField current_mv = {{{ 0 }}}; @@ -2044,7 +2109,7 @@ static void hls_prediction_unit(HEVCLocalContext *lc, const RefPicList *refPicList = s->cur_frame->refPicList; const HEVCFrame *ref0 = NULL, *ref1 = NULL; const int *linesize = s->cur_frame->f->linesize; - uint8_t *dst0 = POS(0, x0, y0); + uint8_t *dst0 = s->cur_frame->f->data[0] + y0 * linesize[0] + (x0 << sps->pixel_shift); uint8_t *dst1 = POS(1, x0, y0); uint8_t *dst2 = POS(2, x0, y0); int log2_min_cb_size = sps->log2_min_cb_size; @@ -2687,7 +2752,7 @@ static int hls_decode_entry(HEVCContext *s, GetBitContext *gb) const HEVCPPS *const pps = s->pps; const HEVCSPS *const sps = pps->sps; const uint8_t *slice_data = gb->buffer + s->sh.data_offset; - const size_t slice_size = gb->buffer_end - gb->buffer - s->sh.data_offset; + const size_t slice_size = get_bits_bytesize(gb, 1) - s->sh.data_offset; int ctb_size = 1 << sps->log2_ctb_size; int more_data = 1; int x_ctb = 0; @@ -2751,6 +2816,8 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, const uint8_t *data = s->data + s->sh.offset[ctb_row]; const size_t data_size = s->sh.size[ctb_row]; + int progress = 0; + int ret; if (ctb_row) @@ -2762,13 +2829,15 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, hls_decode_neighbour(lc, l, pps, sps, x_ctb, y_ctb, ctb_addr_ts); - ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP); + if (ctb_row) + ff_thread_progress_await(&s->wpp_progress[ctb_row - 1], + progress + SHIFT_CTB_WPP + 1); /* atomic_load's prototype requires a pointer to non-const atomic variable * (due to implementations via mutexes, where reads involve writes). * Of course, casting const away here is nevertheless safe. */ if (atomic_load((atomic_int*)&s->wpp_err)) { - ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; } @@ -2792,19 +2861,19 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, ctb_addr_ts++; ff_hevc_save_states(lc, pps, ctb_addr_ts); - ff_thread_report_progress2(s->avctx, ctb_row, thread, 1); + ff_thread_progress_report(&s->wpp_progress[ctb_row], ++progress); ff_hevc_hls_filters(lc, l, pps, x_ctb, y_ctb, ctb_size); if (!more_data && (x_ctb+ctb_size) < sps->width && ctb_row != s->sh.num_entry_point_offsets) { /* Casting const away here is safe, because it is an atomic operation. */ atomic_store((atomic_int*)&s->wpp_err, 1); - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; } if ((x_ctb+ctb_size) >= sps->width && (y_ctb+ctb_size) >= sps->height ) { ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb, ctb_size); - ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return ctb_addr_ts; } ctb_addr_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts]; @@ -2814,17 +2883,43 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, break; } } - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; error: l->tab_slice_address[ctb_addr_rs] = -1; /* Casting const away here is safe, because it is an atomic operation. */ atomic_store((atomic_int*)&s->wpp_err, 1); - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return ret; } +static int wpp_progress_init(HEVCContext *s, unsigned count) +{ + if (s->nb_wpp_progress < count) { + void *tmp = av_realloc_array(s->wpp_progress, count, + sizeof(*s->wpp_progress)); + if (!tmp) + return AVERROR(ENOMEM); + + s->wpp_progress = tmp; + memset(s->wpp_progress + s->nb_wpp_progress, 0, + (count - s->nb_wpp_progress) * sizeof(*s->wpp_progress)); + + for (int i = s->nb_wpp_progress; i < count; i++) { + int ret = ff_thread_progress_init(&s->wpp_progress[i], 1); + if (ret < 0) + return ret; + s->nb_wpp_progress = i + 1; + } + } + + for (int i = 0; i < count; i++) + ff_thread_progress_reset(&s->wpp_progress[i]); + + return 0; +} + static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) { const HEVCPPS *const pps = s->pps; @@ -2909,7 +3004,7 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) } atomic_store(&s->wpp_err, 0); - res = ff_slice_thread_allocz_entries(s->avctx, s->sh.num_entry_point_offsets + 1); + res = wpp_progress_init(s, s->sh.num_entry_point_offsets + 1); if (res < 0) return res; @@ -3056,14 +3151,11 @@ static int set_side_data(HEVCContext *s) return ret; if (s->sei.common.dynamic_hdr_vivid.info) { - AVBufferRef *info_ref = av_buffer_ref(s->sei.common.dynamic_hdr_vivid.info); - if (!info_ref) + if (!av_frame_side_data_add(&out->side_data, &out->nb_side_data, + AV_FRAME_DATA_DYNAMIC_HDR_VIVID, + &s->sei.common.dynamic_hdr_vivid.info, + AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) return AVERROR(ENOMEM); - - if (!av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DYNAMIC_HDR_VIVID, info_ref)) { - av_buffer_unref(&info_ref); - return AVERROR(ENOMEM); - } } return 0; @@ -3131,7 +3223,7 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, return AVERROR_INVALIDDATA; } - ff_refstruct_replace(&s->pps, pps); + av_refstruct_replace(&s->pps, pps); if (l->sps != sps) { const HEVCSPS *sps_base = s->layers[0].sps; enum AVPixelFormat pix_fmt = sps->pix_fmt; @@ -3151,6 +3243,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, !sps->vui.common.video_signal_type_present_flag) pix_fmt = sps_base->pix_fmt; + // Ignore range mismatch between base layer and alpha layer + if (ff_hevc_is_alpha_video(s) && + sps_base->pix_fmt == AV_PIX_FMT_YUV420P && + pix_fmt == AV_PIX_FMT_YUVJ420P) + pix_fmt = sps_base->pix_fmt; + if (pix_fmt != sps_base->pix_fmt || sps->width != sps_base->width || sps->height != sps_base->height) { @@ -3192,9 +3290,19 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, s->first_nal_type = s->nal_unit_type; s->poc = s->sh.poc; - if (IS_IRAP(s)) + if (IS_IRAP(s)) { s->no_rasl_output_flag = IS_IDR(s) || IS_BLA(s) || (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos); + s->recovery_poc = HEVC_RECOVERY_END; + } + + if (s->recovery_poc != HEVC_RECOVERY_END && + s->sei.recovery_point.has_recovery_poc) { + if (s->recovery_poc == HEVC_RECOVERY_UNSPECIFIED) + s->recovery_poc = s->poc + s->sei.recovery_point.recovery_poc_cnt; + else if (s->poc >= s->recovery_poc) + s->recovery_poc = HEVC_RECOVERY_END; + } /* 8.3.1 */ if (s->temporal_id == 0 && @@ -3236,7 +3344,8 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, else s->cur_frame->f->flags &= ~AV_FRAME_FLAG_KEY; - s->cur_frame->needs_fg = (s->sei.common.film_grain_characteristics.present || + s->cur_frame->needs_fg = ((s->sei.common.film_grain_characteristics && + s->sei.common.film_grain_characteristics->present) || s->sei.common.aom_film_grain.enable) && !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && !s->avctx->hwaccel; @@ -3246,8 +3355,8 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, goto fail; if (s->cur_frame->needs_fg && - (s->sei.common.film_grain_characteristics.present && - !ff_h274_film_grain_params_supported(s->sei.common.film_grain_characteristics.model_id, + (s->sei.common.film_grain_characteristics && s->sei.common.film_grain_characteristics->present && + !ff_h274_film_grain_params_supported(s->sei.common.film_grain_characteristics->model_id, s->cur_frame->f->format) || !av_film_grain_params_select(s->cur_frame->f))) { av_log_once(s->avctx, AV_LOG_WARNING, AV_LOG_DEBUG, &s->film_grain_warning_shown, @@ -3276,7 +3385,10 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, goto fail; if (s->avctx->hwaccel) { - ret = FF_HW_CALL(s->avctx, start_frame, NULL, 0); + AVCodecInternal *avci = s->avctx->internal; + AVPacket *avpkt = avci->in_pkt; + ret = FF_HW_CALL(s->avctx, start_frame, + avpkt->buf, NULL, 0); if (ret < 0) goto fail; } @@ -3432,7 +3544,7 @@ static int decode_slice(HEVCContext *s, unsigned nal_idx, GetBitContext *gb) ret = hls_slice_header(&s->sh, s, gb); if (ret < 0) { - // hls_slice_header() does not cleanup on failure thus the state now is inconsistant so we cannot use it on depandant slices + // hls_slice_header() does not cleanup on failure thus the state now is inconsistent so we cannot use it on dependent slices s->slice_initialized = 0; return ret; } @@ -3569,6 +3681,12 @@ fail: return ret; } +static void decode_reset_recovery_point(HEVCContext *s) +{ + s->recovery_poc = HEVC_RECOVERY_UNSPECIFIED; + s->sei.recovery_point.has_recovery_poc = 0; +} + static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) { int i, ret = 0; @@ -3579,6 +3697,8 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->last_eos = s->eos; s->eos = 0; s->slice_initialized = 0; + if (s->last_eos) + decode_reset_recovery_point(s); for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { HEVCLayerContext *l = &s->layers[i]; @@ -3600,6 +3720,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->pkt.nals[i].type == HEVC_NAL_EOS_NUT) { if (eos_at_start) { s->last_eos = 1; + decode_reset_recovery_point(s); } else { s->eos = 1; } @@ -3626,8 +3747,10 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) } s->rpu_buf = av_buffer_alloc(nal->raw_size - 2); - if (!s->rpu_buf) - return AVERROR(ENOMEM); + if (!s->rpu_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } memcpy(s->rpu_buf->data, nal->raw_data + 2, nal->raw_size - 2); ret = ff_dovi_rpu_parse(&s->dovi_ctx, nal->data + 2, nal->size - 2, @@ -3716,7 +3839,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) s->pkt_dts = AV_NOPTS_VALUE; - if (ff_container_fifo_can_read(s->output_fifo)) + if (av_container_fifo_can_read(s->output_fifo)) goto do_output; av_packet_unref(avpkt); @@ -3754,7 +3877,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) return ret; do_output: - if (ff_container_fifo_read(s->output_fifo, frame) >= 0) { + if (av_container_fifo_read(s->output_fifo, frame, 0) >= 0) { if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) av_frame_remove_side_data(frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS); @@ -3779,10 +3902,10 @@ static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) dst->needs_fg = 1; } - dst->pps = ff_refstruct_ref_c(src->pps); - dst->tab_mvf = ff_refstruct_ref(src->tab_mvf); - dst->rpl_tab = ff_refstruct_ref(src->rpl_tab); - dst->rpl = ff_refstruct_ref(src->rpl); + dst->pps = av_refstruct_ref_c(src->pps); + dst->tab_mvf = av_refstruct_ref(src->tab_mvf); + dst->rpl_tab = av_refstruct_ref(src->rpl_tab); + dst->rpl = av_refstruct_ref(src->rpl); dst->nb_rpl_elems = src->nb_rpl_elems; dst->poc = src->poc; @@ -3791,7 +3914,7 @@ static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) dst->base_layer_frame = src->base_layer_frame; - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); return 0; @@ -3803,18 +3926,18 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { pic_arrays_free(&s->layers[i]); - ff_refstruct_unref(&s->layers[i].sps); + av_refstruct_unref(&s->layers[i].sps); } - ff_refstruct_unref(&s->vps); - ff_refstruct_unref(&s->pps); + av_refstruct_unref(&s->vps); + av_refstruct_unref(&s->pps); ff_dovi_ctx_unref(&s->dovi_ctx); av_buffer_unref(&s->rpu_buf); av_freep(&s->md5_ctx); - ff_container_fifo_free(&s->output_fifo); + av_container_fifo_free(&s->output_fifo); for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { HEVCLayerContext *l = &s->layers[layer]; @@ -3826,6 +3949,10 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) ff_hevc_ps_uninit(&s->ps); + for (int i = 0; i < s->nb_wpp_progress; i++) + ff_thread_progress_destroy(&s->wpp_progress[i]); + av_freep(&s->wpp_progress); + av_freep(&s->sh.entry_point_offset); av_freep(&s->sh.offset); av_freep(&s->sh.size); @@ -3854,7 +3981,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx) s->local_ctx[0].logctx = avctx; s->local_ctx[0].common_cabac_state = &s->cabac; - s->output_fifo = ff_container_fifo_alloc_avframe(0); + s->output_fifo = av_container_fifo_alloc_avframe(0); if (!s->output_fifo) return AVERROR(ENOMEM); @@ -3909,16 +4036,16 @@ static int hevc_update_thread_context(AVCodecContext *dst, } for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++) - ff_refstruct_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]); + av_refstruct_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) - ff_refstruct_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]); + av_refstruct_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++) - ff_refstruct_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]); + av_refstruct_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]); // PPS do not persist between frames - ff_refstruct_unref(&s->pps); + av_refstruct_unref(&s->pps); s->poc_tid0 = s0->poc_tid0; s->eos = s0->eos; @@ -3967,26 +4094,68 @@ static int hevc_update_thread_context(AVCodecContext *dst, s->sei.common.frame_packing = s0->sei.common.frame_packing; s->sei.common.display_orientation = s0->sei.common.display_orientation; s->sei.common.alternative_transfer = s0->sei.common.alternative_transfer; - s->sei.common.mastering_display = s0->sei.common.mastering_display; - s->sei.common.content_light = s0->sei.common.content_light; - s->sei.common.aom_film_grain = s0->sei.common.aom_film_grain; s->sei.tdrdi = s0->sei.tdrdi; + s->sei.recovery_point = s0->sei.recovery_point; + s->recovery_poc = s0->recovery_poc; return 0; } #endif +static int hevc_sei_to_context(AVCodecContext *avctx, HEVCSEI *sei) +{ + int ret; + + if (sei->tdrdi.num_ref_displays) { + AVBufferRef *buf; + size_t size; + AV3DReferenceDisplaysInfo *tdrdi = av_tdrdi_alloc(sei->tdrdi.num_ref_displays, &size); + + if (!tdrdi) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *)tdrdi, size, NULL, NULL, 0); + if (!buf) { + av_free(tdrdi); + return AVERROR(ENOMEM); + } + + tdrdi->prec_ref_display_width = sei->tdrdi.prec_ref_display_width; + tdrdi->ref_viewing_distance_flag = sei->tdrdi.ref_viewing_distance_flag; + tdrdi->prec_ref_viewing_dist = sei->tdrdi.prec_ref_viewing_dist; + tdrdi->num_ref_displays = sei->tdrdi.num_ref_displays; + for (int i = 0; i < sei->tdrdi.num_ref_displays; i++) { + AV3DReferenceDisplay *display = av_tdrdi_get_display(tdrdi, i); + + display->left_view_id = sei->tdrdi.left_view_id[i]; + display->right_view_id = sei->tdrdi.right_view_id[i]; + display->exponent_ref_display_width = sei->tdrdi.exponent_ref_display_width[i]; + display->mantissa_ref_display_width = sei->tdrdi.mantissa_ref_display_width[i]; + display->exponent_ref_viewing_distance = sei->tdrdi.exponent_ref_viewing_distance[i]; + display->mantissa_ref_viewing_distance = sei->tdrdi.mantissa_ref_viewing_distance[i]; + display->additional_shift_present_flag = sei->tdrdi.additional_shift_present_flag[i]; + display->num_sample_shift = sei->tdrdi.num_sample_shift[i]; + } + ret = ff_frame_new_side_data_from_buf_ext(avctx, &avctx->decoded_side_data, &avctx->nb_decoded_side_data, + AV_FRAME_DATA_3D_REFERENCE_DISPLAYS, &buf); + if (ret < 0) { + av_buffer_unref(&buf); + return ret; + } + } + + ret = ff_h2645_sei_to_context(avctx, &sei->common); + if (ret < 0) + return ret; + + return 0; +} + static av_cold int hevc_decode_init(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; int ret; - if (avctx->active_thread_type & FF_THREAD_SLICE) { - ret = ff_slice_thread_init_progress(avctx); - if (ret < 0) - return ret; - } - ret = hevc_init_context(avctx); if (ret < 0) return ret; @@ -4005,7 +4174,7 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) return ret; } - ret = ff_h2645_sei_to_context(avctx, &s->sei.common); + ret = hevc_sei_to_context(avctx, &s->sei); if (ret < 0) return ret; } @@ -4037,7 +4206,7 @@ static void hevc_decode_flush(AVCodecContext *avctx) static const AVOption options[] = { { "apply_defdispwin", "Apply default display window from VUI", OFFSET(apply_defdispwin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, - { "strict-displaywin", "stricly apply default display window size", OFFSET(apply_defdispwin), + { "strict-displaywin", "strictly apply default display window size", OFFSET(apply_defdispwin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, { "view_ids", "Array of view IDs that should be decoded and output; a single -1 to decode all views", .offset = OFFSET(view_ids), .type = AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h index 6ba2ca3887..911d5c3ae3 100644 --- a/libavcodec/hevc/hevcdec.h +++ b/libavcodec/hevc/hevcdec.h @@ -78,6 +78,10 @@ (s)->nal_unit_type == HEVC_NAL_BLA_N_LP) #define IS_IRAP(s) ((s)->nal_unit_type >= HEVC_NAL_BLA_W_LP && (s)->nal_unit_type <= HEVC_NAL_RSV_IRAP_VCL23) +#define HEVC_RECOVERY_UNSPECIFIED INT_MAX +#define HEVC_RECOVERY_END INT_MIN +#define HEVC_IS_RECOVERING(s) ((s)->recovery_poc != HEVC_RECOVERY_UNSPECIFIED && (s)->recovery_poc != HEVC_RECOVERY_END) + enum RPSType { ST_CURR_BEF = 0, ST_CURR_AFT, @@ -203,9 +207,9 @@ typedef struct RefPicListTab { typedef struct SliceHeader { unsigned int pps_id; - ///< address (in raster order) of the first block in the current slice segment + /// address (in raster order) of the first block in the current slice segment unsigned int slice_segment_addr; - ///< address (in raster order) of the first block in the current slice + /// address (in raster order) of the first block in the current slice unsigned int slice_addr; enum HEVCSliceType slice_type; @@ -219,7 +223,7 @@ typedef struct SliceHeader { uint8_t colour_plane_id; uint8_t inter_layer_pred; - ///< RPS coded in the slice header itself is stored here + /// RPS coded in the slice header itself is stored here int short_term_ref_pic_set_sps_flag; int short_term_ref_pic_set_size; ShortTermRPS slice_rps; @@ -353,6 +357,7 @@ typedef struct DBParams { #define HEVC_FRAME_FLAG_SHORT_REF (1 << 1) #define HEVC_FRAME_FLAG_LONG_REF (1 << 2) #define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3) +#define HEVC_FRAME_FLAG_CORRUPT (1 << 4) typedef struct HEVCFrame { union { @@ -480,8 +485,8 @@ typedef struct HEVCLayerContext { uint8_t *sao_pixel_buffer_h[3]; uint8_t *sao_pixel_buffer_v[3]; - struct FFRefStructPool *tab_mvf_pool; - struct FFRefStructPool *rpl_tab_pool; + struct AVRefStructPool *tab_mvf_pool; + struct AVRefStructPool *rpl_tab_pool; } HEVCLayerContext; typedef struct HEVCContext { @@ -502,13 +507,13 @@ typedef struct HEVCContext { /** 1 if the independent slice segment header was successfully parsed */ uint8_t slice_initialized; - struct ContainerFifo *output_fifo; + struct AVContainerFifo *output_fifo; HEVCParamSets ps; HEVCSEI sei; struct AVMD5 *md5_ctx; - ///< candidate references for the current frame + /// candidate references for the current frame RefPicList rps[NB_RPS_TYPE]; const HEVCVPS *vps; ///< RefStruct reference @@ -523,6 +528,7 @@ typedef struct HEVCContext { int slice_idx; ///< number of the slice being currently decoded int eos; ///< current packet contains an EOS/EOB NAL int last_eos; ///< last packet contains an EOS/EOB NAL + int recovery_poc; // NoRaslOutputFlag associated with the last IRAP frame int no_rasl_output_flag; @@ -540,6 +546,9 @@ typedef struct HEVCContext { /** The target for the common_cabac_state of the local contexts. */ HEVCCABACState cabac; + struct ThreadProgress *wpp_progress; + unsigned nb_wpp_progress; + atomic_int wpp_err; const uint8_t *data; @@ -711,6 +720,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps, void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size); +int ff_hevc_is_alpha_video(const HEVCContext *s); + extern const uint8_t ff_hevc_qpel_extra_before[4]; extern const uint8_t ff_hevc_qpel_extra_after[4]; extern const uint8_t ff_hevc_qpel_extra[4]; diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c index f18b88489b..57125d59c1 100644 --- a/libavcodec/hevc/ps.c +++ b/libavcodec/hevc/ps.c @@ -30,7 +30,7 @@ #include "data.h" #include "ps.h" #include "profiles.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" static const uint8_t default_scaling_list_intra[] = { 16, 16, 16, 16, 17, 18, 21, 24, @@ -69,9 +69,9 @@ static void remove_sps(HEVCParamSets *s, int id) /* drop all PPS that depend on this SPS */ for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++) if (s->pps_list[i] && s->pps_list[i]->sps_id == id) - ff_refstruct_unref(&s->pps_list[i]); + av_refstruct_unref(&s->pps_list[i]); - ff_refstruct_unref(&s->sps_list[id]); + av_refstruct_unref(&s->sps_list[id]); } } @@ -82,7 +82,7 @@ static void remove_vps(HEVCParamSets *s, int id) for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) if (s->sps_list[i] && s->sps_list[i]->vps_id == id) remove_sps(s, i); - ff_refstruct_unref(&s->vps_list[id]); + av_refstruct_unref(&s->vps_list[id]); } } @@ -442,7 +442,7 @@ static int decode_hrd(GetBitContext *gb, int common_inf_present, return 0; } -static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) +static void hevc_vps_free(AVRefStructOpaque opaque, void *obj) { HEVCVPS *vps = obj; @@ -450,14 +450,6 @@ static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) av_freep(&vps->data); } -enum ScalabilityMask { - HEVC_SCALABILITY_DEPTH = 0, - HEVC_SCALABILITY_MULTIVIEW = 1, - HEVC_SCALABILITY_SPATIAL = 2, - HEVC_SCALABILITY_AUXILIARY = 3, - HEVC_SCALABILITY_MASK_MAX = 15, -}; - enum DependencyType { HEVC_DEP_TYPE_SAMPLE = 0, HEVC_DEP_TYPE_MV = 1, @@ -468,14 +460,17 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps uint64_t layer1_id_included) { PTL ptl_dummy; - uint8_t max_sub_layers[HEVC_MAX_LAYERS]; + uint8_t max_sub_layers[HEVC_MAX_LAYERS] = {1, 1}; + uint8_t dimension_id_len[16] = {0}; + uint8_t dimension_id[16] = {0}; + unsigned n; - int splitting_flag, dimension_id_len, view_id_len, num_add_olss, + int splitting_flag, view_id_len, num_add_olss, num_scalability_types, default_output_layer_idc, direct_dep_type_len, direct_dep_type, sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl; unsigned non_vui_extension_length; - if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) { + if (vps->vps_max_layers == 1) { av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n"); return 0; } @@ -528,20 +523,35 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps */ vps->nb_layers = 2; + /* vps_base_layer_internal_flag is true has been checked before */ if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0) return AVERROR_INVALIDDATA; splitting_flag = get_bits1(gb); - for (int i = 0; i <= HEVC_SCALABILITY_MASK_MAX; i++) { - int scalability_mask_flag = get_bits1(gb); - if (scalability_mask_flag != (i == HEVC_SCALABILITY_MULTIVIEW)) { - av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n", i); - return AVERROR_PATCHWELCOME; - } + vps->scalability_mask_flag = get_bits(gb, 16); + num_scalability_types = av_popcount(vps->scalability_mask_flag); + if (!num_scalability_types) { + av_log(avctx, AV_LOG_ERROR, "Missing scalability mask\n"); + return AVERROR_INVALIDDATA; } - if (!splitting_flag) - dimension_id_len = get_bits(gb, 3) + 1; + if (!(vps->scalability_mask_flag & + (HEVC_SCALABILITY_MULTIVIEW | HEVC_SCALABILITY_AUXILIARY))) { + av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n", + 15 - ff_ctz(vps->scalability_mask_flag)); + return AVERROR_PATCHWELCOME; + } + // x265 specify MULTIVIEW when the stream really is alpha video only. + if (num_scalability_types > 1) + av_log(avctx, AV_LOG_WARNING, "Multiple scalability types presented\n"); + + n = 0; + for (int i = 0; i < num_scalability_types - splitting_flag; i++) { + dimension_id_len[i] = get_bits(gb, 3) + 1; + n += dimension_id_len[i]; + } + if (splitting_flag) + dimension_id_len[num_scalability_types - 1] = 5 - n; if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */ int layer_id_in_nuh = get_bits(gb, 6); @@ -558,28 +568,57 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps } if (!splitting_flag) { - int view_idx = get_bits(gb, dimension_id_len); - if (view_idx != 1) { - av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx); + int index = 0; + + for (int i = 0; i < num_scalability_types; i++) + dimension_id[i] = get_bits(gb, dimension_id_len[i]); + + if (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) + index++; + + /* AuxId 1 is alpha, 2 is depth. Only support alpha */ + if (vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY && + dimension_id[index] != HEVC_AUX_ALPHA) { + av_log(avctx, AV_LOG_WARNING, + "Unsupported dimension_id %d for HEVC_SCALABILITY_AUXILIARY\n", + dimension_id[index]); return AVERROR_PATCHWELCOME; } } view_id_len = get_bits(gb, 4); - if (view_id_len) - for (int i = 0; i < 2 /* NumViews */; i++) + if (view_id_len) { + n = (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) ? 2 : 1; + for (int i = 0; i < n; i++) vps->view_id[i] = get_bits(gb, view_id_len); - - if (!get_bits1(gb) /* direct_dependency_flag */) { - av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n"); - return AVERROR_PATCHWELCOME; } - vps->num_direct_ref_layers[1] = 1; + + /* direct_dependency_flag */ + vps->num_direct_ref_layers[1] = get_bits1(gb); + if (!vps->num_direct_ref_layers[1]) { + vps->num_add_layer_sets = get_ue_golomb(gb); + if (vps->num_add_layer_sets > 1) { + av_log(avctx, AV_LOG_WARNING, + "Unsupported num_add_layer_sets: %d\n", vps->num_add_layer_sets); + return AVERROR_PATCHWELCOME; + } + + if (vps->num_add_layer_sets) { + /* highest_layer_idx_plus1 */ + if (!get_bits1(gb)) + return AVERROR_PATCHWELCOME; + } + } + vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets; + if (vps->num_output_layer_sets != 2) + return AVERROR_INVALIDDATA; sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag - for (int i = 0; i < vps->vps_max_layers; i++) - max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 : - vps->vps_max_sub_layers; + if (sub_layers_max_present) { + for (int i = 0; i < vps->vps_max_layers; i++) + max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 : + vps->vps_max_sub_layers; + } if (get_bits1(gb) /* max_tid_ref_present_flag */) skip_bits(gb, 3); // max_tid_il_ref_pics_plus1 @@ -612,18 +651,24 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps } /* Consequence of established layer dependencies */ - if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) | - (1 << vps->layer_id_in_nuh[1]))) { - av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n"); - return AVERROR_PATCHWELCOME; + if (layer1_id_included && + layer1_id_included != ((1ULL << vps->layer_id_in_nuh[0]) | + (1ULL << vps->layer_id_in_nuh[1]))) { + av_log(avctx, AV_LOG_ERROR, + "Dependent layer not included in layer ID?\n"); + return AVERROR_PATCHWELCOME; } + if (!layer1_id_included) + vps->ols[1] = 2; + else + vps->ols[1] = 3; - vps->num_output_layer_sets = 2; - vps->ols[1] = 3; + if (vps->vps_num_layer_sets == 1 || default_output_layer_idc == 2) + skip_bits1(gb); for (int j = 0; j < av_popcount64(vps->ols[1]); j++) { int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl)); - if (ptl_idx < 1 || ptl_idx >= nb_ptl) { + if (ptl_idx >= nb_ptl) { av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx); return AVERROR_INVALIDDATA; } @@ -666,6 +711,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps vps->max_one_active_ref_layer = get_bits1(gb); vps->poc_lsb_aligned = get_bits1(gb); + if (!vps->num_direct_ref_layers[1]) + vps->poc_lsb_not_present = get_bits1(gb) << 1; sub_layer_flag_info_present_flag = get_bits1(gb); for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) { @@ -687,12 +734,14 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps return AVERROR_INVALIDDATA; } - skip_bits1(gb); /* direct_depenency_all_layers_flag */ - direct_dep_type = get_bits_long(gb, direct_dep_type_len); - if (direct_dep_type > HEVC_DEP_TYPE_BOTH) { - av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n", - direct_dep_type); - return AVERROR_PATCHWELCOME; + /* direct_depenency_all_layers_flag */ + if (get_bits1(gb)) { + direct_dep_type = get_bits_long(gb, direct_dep_type_len); + if (direct_dep_type > HEVC_DEP_TYPE_BOTH) { + av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n", + direct_dep_type); + return AVERROR_PATCHWELCOME; + } } non_vui_extension_length = get_ue_golomb(gb); @@ -714,9 +763,10 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, { int i; int vps_id = get_bits(gb, 4); - ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + ptrdiff_t nal_size = get_bits_bytesize(gb, 1); int ret = AVERROR_INVALIDDATA; uint64_t layer1_id_included = 0; + unsigned vps_base_layer_internal_flag, vps_base_layer_available_flag; HEVCVPS *vps; if (ps->vps_list[vps_id]) { @@ -726,7 +776,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, return 0; } - vps = ff_refstruct_alloc_ext(sizeof(*vps), 0, NULL, hevc_vps_free); + vps = av_refstruct_alloc_ext(sizeof(*vps), 0, NULL, hevc_vps_free); if (!vps) return AVERROR(ENOMEM); @@ -740,8 +790,12 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, } vps->vps_id = vps_id; - if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits - av_log(avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n"); + vps_base_layer_internal_flag = get_bits1(gb); + vps_base_layer_available_flag = get_bits1(gb); + if (!vps_base_layer_internal_flag || !vps_base_layer_available_flag) { + av_log(avctx, AV_LOG_ERROR, + "vps_base_layer_internal_flag or vps_base_layer_available_flag not set\n"); + ret = AVERROR_PATCHWELCOME; goto err; } @@ -860,7 +914,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, return 0; err: - ff_refstruct_unref(&vps); + av_refstruct_unref(&vps); return ret; } @@ -1154,6 +1208,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, HEVCWindow *ow; int ret = 0; int bit_depth_chroma, num_comps, multi_layer_ext; + int vps_max_sub_layers; int i; // Coded parameters @@ -1166,7 +1221,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->vps_id); return AVERROR_INVALIDDATA; } - sps->vps = ff_refstruct_ref_c(vps_list[sps->vps_id]); + sps->vps = av_refstruct_ref_c(vps_list[sps->vps_id]); } sps->max_sub_layers = get_bits(gb, 3) + 1; @@ -1178,7 +1233,10 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->max_sub_layers = sps->vps->vps_max_sub_layers; } - if (sps->max_sub_layers > HEVC_MAX_SUB_LAYERS) { + vps_max_sub_layers = sps->vps ? sps->vps->vps_max_sub_layers + : FFMIN(sps->max_sub_layers, HEVC_MAX_SUB_LAYERS); + + if (sps->max_sub_layers > vps_max_sub_layers) { av_log(avctx, AV_LOG_ERROR, "sps_max_sub_layers out of range: %d\n", sps->max_sub_layers); return AVERROR_INVALIDDATA; @@ -1203,6 +1261,12 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, if (multi_layer_ext) { const RepFormat *rf = &sps->vps->rep_format; + if (sps->vps->nb_layers == 1) { + av_log(avctx, AV_LOG_WARNING, "SPS %d references an unsupported VPS extension. Ignoring\n", + *sps_id); + return AVERROR(ENOSYS); + } + if (get_bits1(gb) && // update_rep_format_flag get_bits(gb, 8)) { // sps_rep_format_idx av_log(avctx, AV_LOG_ERROR, "sps_rep_format_idx!=0\n"); @@ -1618,11 +1682,11 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return 0; } -static void hevc_sps_free(FFRefStructOpaque opaque, void *obj) +static void hevc_sps_free(AVRefStructOpaque opaque, void *obj) { HEVCSPS *sps = obj; - ff_refstruct_unref(&sps->vps); + av_refstruct_unref(&sps->vps); av_freep(&sps->data); } @@ -1637,7 +1701,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps, unsigned nuh_layer_id, int apply_defdispwin) { - HEVCSPS *sps = ff_refstruct_alloc_ext(sizeof(*sps), 0, NULL, hevc_sps_free); + HEVCSPS *sps = av_refstruct_alloc_ext(sizeof(*sps), 0, NULL, hevc_sps_free); unsigned int sps_id; int ret; @@ -1646,7 +1710,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "Decoding SPS\n"); - sps->data_size = gb->buffer_end - gb->buffer; + sps->data_size = get_bits_bytesize(gb, 1); sps->data = av_memdup(gb->buffer, sps->data_size); if (!sps->data) { ret = AVERROR(ENOMEM); @@ -1674,7 +1738,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, * otherwise drop all PPSes that depend on it */ if (ps->sps_list[sps_id] && compare_sps(ps->sps_list[sps_id], sps)) { - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); } else { remove_sps(ps, sps_id); ps->sps_list[sps_id] = sps; @@ -1682,15 +1746,15 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, return 0; err: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return ret; } -static void hevc_pps_free(FFRefStructOpaque unused, void *obj) +static void hevc_pps_free(AVRefStructOpaque unused, void *obj) { HEVCPPS *pps = obj; - ff_refstruct_unref(&pps->sps); + av_refstruct_unref(&pps->sps); av_freep(&pps->column_width); av_freep(&pps->row_height); @@ -2101,7 +2165,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, const HEVCSPS *sps = NULL; const HEVCVPS *vps = NULL; int i, ret = 0; - ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + ptrdiff_t nal_size = get_bits_bytesize(gb, 1); unsigned int pps_id = get_ue_golomb_long(gb); unsigned log2_parallel_merge_level_minus2; HEVCPPS *pps; @@ -2120,7 +2184,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, return 0; } - pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); + pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); if (!pps) return AVERROR(ENOMEM); @@ -2157,7 +2221,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, sps = ps->sps_list[pps->sps_id]; vps = ps->vps_list[sps->vps_id]; - pps->sps = ff_refstruct_ref_c(sps); + pps->sps = av_refstruct_ref_c(sps); pps->dependent_slice_segments_enabled_flag = get_bits1(gb); pps->output_flag_present_flag = get_bits1(gb); @@ -2357,13 +2421,13 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, "Overread PPS by %d bits\n", -get_bits_left(gb)); } - ff_refstruct_unref(&ps->pps_list[pps_id]); + av_refstruct_unref(&ps->pps_list[pps_id]); ps->pps_list[pps_id] = pps; return 0; err: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return ret; } @@ -2372,11 +2436,11 @@ void ff_hevc_ps_uninit(HEVCParamSets *ps) int i; for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++) - ff_refstruct_unref(&ps->vps_list[i]); + av_refstruct_unref(&ps->vps_list[i]); for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); } int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type) diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h index 6f5b1f8755..25475b5593 100644 --- a/libavcodec/hevc/ps.h +++ b/libavcodec/hevc/ps.h @@ -205,6 +205,8 @@ typedef struct HEVCVPS { */ int nb_layers; + uint16_t scalability_mask_flag; + // LayerIdxInVps[nuh_layer_id], i.e. a mapping of nuh_layer_id to VPS layer // indices. Valid values are between 0 and HEVC_VPS_MAX_LAYERS. Entries for // unmapped values of nuh_layer_id are set to -1. @@ -235,6 +237,7 @@ typedef struct HEVCVPS { // NumDirectRefLayers[layer_idx] uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS]; + uint8_t num_add_layer_sets; RepFormat rep_format; @@ -343,7 +346,7 @@ typedef struct HEVCSPS { int sps_palette_predictor_initializer[3][HEVC_MAX_PALETTE_PREDICTOR_SIZE]; int motion_vector_resolution_control_idc; - ///< coded frame dimension in various units + /// coded frame dimension in various units int width; int height; int ctb_width; diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c index 6ba667e9f5..ab2e075af0 100644 --- a/libavcodec/hevc/refs.c +++ b/libavcodec/hevc/refs.c @@ -21,33 +21,36 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/container_fifo.h" #include "libavutil/mem.h" #include "libavutil/stereo3d.h" -#include "container_fifo.h" #include "decode.h" #include "hevc.h" #include "hevcdec.h" #include "progressframe.h" -#include "refstruct.h" +#include "thread.h" +#include "libavutil/refstruct.h" void ff_hevc_unref_frame(HEVCFrame *frame, int flags) { frame->flags &= ~flags; + if (!(frame->flags & ~HEVC_FRAME_FLAG_CORRUPT)) + frame->flags = 0; if (!frame->flags) { ff_progress_frame_unref(&frame->tf); av_frame_unref(frame->frame_grain); frame->needs_fg = 0; - ff_refstruct_unref(&frame->pps); - ff_refstruct_unref(&frame->tab_mvf); + av_refstruct_unref(&frame->pps); + av_refstruct_unref(&frame->tab_mvf); - ff_refstruct_unref(&frame->rpl); + av_refstruct_unref(&frame->rpl); frame->nb_rpl_elems = 0; - ff_refstruct_unref(&frame->rpl_tab); + av_refstruct_unref(&frame->rpl_tab); frame->refPicList = NULL; - ff_refstruct_unref(&frame->hwaccel_picture_private); + av_refstruct_unref(&frame->hwaccel_picture_private); } } @@ -79,6 +82,31 @@ void ff_hevc_flush_dpb(HEVCContext *s) } } +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base) +{ + AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3); + uintptr_t data = (uintptr_t)alpha->data[0]; + int ret; + + for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) { + AVBufferRef *buf = alpha->buf[i]; + uintptr_t buf_begin = (uintptr_t)buf->data; + + if (data >= buf_begin && data < buf_begin + buf->size) { + ret = av_buffer_replace(&alpha->buf[i], base_a); + if (ret < 0) + return ret; + + alpha->linesize[0] = base->linesize[3]; + alpha->data[0] = base->data[3]; + + return 0; + } + } + + return AVERROR_BUG; +} + static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) { const HEVCVPS *vps = l->sps->vps; @@ -103,7 +131,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) } // add view ID side data if it's nontrivial - if (vps->nb_layers > 1 || view_id) { + if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) { HEVCSEITDRDI *tdrdi = &s->sei.tdrdi; AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data, &frame->f->nb_side_data, @@ -130,21 +158,20 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) } } - ret = ff_progress_frame_get_buffer(s->avctx, &frame->tf, - AV_GET_BUFFER_FLAG_REF); + ret = ff_thread_get_buffer(s->avctx, frame->f, AV_GET_BUFFER_FLAG_REF); if (ret < 0) - return NULL; + goto fail; - frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl)); + frame->rpl = av_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl)); if (!frame->rpl) goto fail; frame->nb_rpl_elems = s->pkt.nb_nals; - frame->tab_mvf = ff_refstruct_pool_get(l->tab_mvf_pool); + frame->tab_mvf = av_refstruct_pool_get(l->tab_mvf_pool); if (!frame->tab_mvf) goto fail; - frame->rpl_tab = ff_refstruct_pool_get(l->rpl_tab_pool); + frame->rpl_tab = av_refstruct_pool_get(l->rpl_tab_pool); if (!frame->rpl_tab) goto fail; frame->ctb_count = l->sps->ctb_width * l->sps->ctb_height; @@ -161,7 +188,14 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) if (ret < 0) goto fail; - frame->pps = ff_refstruct_ref_c(s->pps); + frame->pps = av_refstruct_ref_c(s->pps); + if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) { + AVFrame *alpha = frame->f; + AVFrame *base = s->layers[0].cur_frame->f; + ret = replace_alpha_plane(alpha, base); + if (ret < 0) + goto fail; + } return frame; fail: @@ -176,6 +210,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) { HEVCFrame *ref; int i; + int no_output; /* check that this POC doesn't already exist */ for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { @@ -199,7 +234,10 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) ref->base_layer_frame = (l != &s->layers[0] && s->layers[0].cur_frame) ? s->layers[0].cur_frame - s->layers[0].DPB : -1; - if (s->sh.pic_output_flag) + no_output = !IS_IRAP(s) && (s->poc < s->recovery_poc) && + !(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL); + if (s->sh.pic_output_flag && !no_output) ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; else ref->flags = HEVC_FRAME_FLAG_SHORT_REF; @@ -266,8 +304,10 @@ int ff_hevc_output_frames(HEVCContext *s, int output = !discard && (layers_active_output & (1 << min_layer)); if (output) { + if (frame->flags & HEVC_FRAME_FLAG_CORRUPT) + f->flags |= AV_FRAME_FLAG_CORRUPT; f->pkt_dts = s->pkt_dts; - ret = ff_container_fifo_write(s->output_fifo, f); + ret = av_container_fifo_write(s->output_fifo, f, AV_CONTAINER_FIFO_FLAG_REF); } ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT); if (ret < 0) @@ -462,6 +502,20 @@ static int add_candidate_ref(HEVCContext *s, HEVCLayerContext *l, if (ref == s->cur_frame || list->nb_refs >= HEVC_MAX_REFS) return AVERROR_INVALIDDATA; + if (!IS_IRAP(s)) { + int ref_corrupt = !ref || ref->flags & (HEVC_FRAME_FLAG_CORRUPT | + HEVC_FRAME_FLAG_UNAVAILABLE); + int recovering = HEVC_IS_RECOVERING(s); + + if (ref_corrupt && !recovering) { + if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) + return AVERROR_INVALIDDATA; + + s->cur_frame->flags |= HEVC_FRAME_FLAG_CORRUPT; + } + } + if (!ref) { ref = generate_missing_ref(s, l, poc); if (!ref) diff --git a/libavcodec/hevc/sei.c b/libavcodec/hevc/sei.c index e11a33773c..b8e98cde89 100644 --- a/libavcodec/hevc/sei.c +++ b/libavcodec/hevc/sei.c @@ -79,6 +79,21 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, return 0; } +static int decode_nal_sei_recovery_point(HEVCSEI *s, GetBitContext *gb) +{ + HEVCSEIRecoveryPoint *rec = &s->recovery_point; + int recovery_poc_cnt = get_se_golomb(gb); + + if (recovery_poc_cnt > INT16_MAX || recovery_poc_cnt < INT16_MIN) + return AVERROR_INVALIDDATA; + rec->recovery_poc_cnt = recovery_poc_cnt; + rec->exact_match_flag = get_bits1(gb); + rec->broken_link_flag = get_bits1(gb); + rec->has_recovery_poc = 1; + + return 0; +} + static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx) { int num_sps_ids_minus1; @@ -212,6 +227,8 @@ static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte, return decode_nal_sei_decoded_picture_hash(&s->picture_hash, gbyte); case SEI_TYPE_PIC_TIMING: return decode_nal_sei_pic_timing(s, gb, ps, logctx); + case SEI_TYPE_RECOVERY_POINT: + return decode_nal_sei_recovery_point(s, gb); case SEI_TYPE_ACTIVE_PARAMETER_SETS: return decode_nal_sei_active_parameter_sets(s, gb, logctx); case SEI_TYPE_TIME_CODE: diff --git a/libavcodec/hevc/sei.h b/libavcodec/hevc/sei.h index a9d6a52080..c4714bb7c5 100644 --- a/libavcodec/hevc/sei.h +++ b/libavcodec/hevc/sei.h @@ -84,17 +84,24 @@ typedef struct HEVCSEITDRDI { uint8_t ref_viewing_distance_flag; uint8_t prec_ref_viewing_dist; uint8_t num_ref_displays; - uint16_t left_view_id[31]; - uint16_t right_view_id[31]; - uint8_t exponent_ref_display_width[31]; - uint8_t mantissa_ref_display_width[31]; - uint8_t exponent_ref_viewing_distance[31]; - uint8_t mantissa_ref_viewing_distance[31]; - uint8_t additional_shift_present_flag[31]; - int16_t num_sample_shift[31]; + uint16_t left_view_id[32]; + uint16_t right_view_id[32]; + uint8_t exponent_ref_display_width[32]; + uint8_t mantissa_ref_display_width[32]; + uint8_t exponent_ref_viewing_distance[32]; + uint8_t mantissa_ref_viewing_distance[32]; + uint8_t additional_shift_present_flag[32]; + int16_t num_sample_shift[32]; uint8_t three_dimensional_reference_displays_extension_flag; } HEVCSEITDRDI; +typedef struct HEVCSEIRecoveryPoint { + int16_t recovery_poc_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; + uint8_t has_recovery_poc; +} HEVCSEIRecoveryPoint; + typedef struct HEVCSEI { H2645SEI common; HEVCSEIPictureHash picture_hash; @@ -102,6 +109,7 @@ typedef struct HEVCSEI { int active_seq_parameter_set_id; HEVCSEITimeCode timecode; HEVCSEITDRDI tdrdi; + HEVCSEIRecoveryPoint recovery_point; } HEVCSEI; struct HEVCParamSets; @@ -109,11 +117,6 @@ struct HEVCParamSets; int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const struct HEVCParamSets *ps, enum HEVCNALUnitType type); -static inline int ff_hevc_sei_ctx_replace(HEVCSEI *dst, const HEVCSEI *src) -{ - return ff_h2645_sei_ctx_replace(&dst->common, &src->common); -} - /** * Reset SEI values that are stored on the Context. * e.g. Caption data that was extracted during NAL diff --git a/libavcodec/hpeldsp.c b/libavcodec/hpeldsp.c index 80494c9749..db0e02ee93 100644 --- a/libavcodec/hpeldsp.c +++ b/libavcodec/hpeldsp.c @@ -314,9 +314,6 @@ CALL_2X_PIXELS(OPNAME ## _pixels16_y2_8_c, \ CALL_2X_PIXELS(OPNAME ## _pixels16_xy2_8_c, \ OPNAME ## _pixels8_xy2_8_c, \ 8) \ -CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_8_c, \ - OPNAME ## _pixels8_8_c, \ - 8) \ CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_x2_8_c, \ OPNAME ## _no_rnd_pixels8_x2_8_c, \ 8) \ @@ -330,6 +327,8 @@ CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_xy2_8_c, \ #define op_avg(a, b) a = rnd_avg32(a, b) #define op_put(a, b) a = b #define put_no_rnd_pixels8_8_c put_pixels8_8_c +#define put_no_rnd_pixels16_8_c put_pixels16_8_c +#define avg_no_rnd_pixels16_8_c avg_pixels16_8_c PIXOP2(avg, op_avg) PIXOP2(put, op_put) #undef op_avg diff --git a/libavcodec/hpeldsp.h b/libavcodec/hpeldsp.h index 45e81b10a5..41a46f0760 100644 --- a/libavcodec/hpeldsp.h +++ b/libavcodec/hpeldsp.h @@ -97,7 +97,6 @@ typedef struct HpelDSPContext { void ff_hpeldsp_init(HpelDSPContext *c, int flags); void ff_hpeldsp_init_aarch64(HpelDSPContext *c, int flags); -void ff_hpeldsp_init_alpha(HpelDSPContext *c, int flags); void ff_hpeldsp_init_arm(HpelDSPContext *c, int flags); void ff_hpeldsp_init_ppc(HpelDSPContext *c, int flags); void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags); diff --git a/libavcodec/hq_common.c b/libavcodec/hq_common.c new file mode 100644 index 0000000000..9f56c819f3 --- /dev/null +++ b/libavcodec/hq_common.c @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hq_common.h" + +#define REPEAT(x) x x +#define ELEM(_sym, _len) {.sym = _sym << 4 | _sym, .len = _len }, +#define LEN5(sym) ELEM(sym, 5) +#define LEN4(sym) REPEAT(ELEM(sym, 4)) +#define LEN2(sym) REPEAT(REPEAT(REPEAT(ELEM(sym, 2)))) + +const VLCElem ff_hq_cbp_vlc[1 << HQ_CBP_VLC_BITS] = { + LEN2(0xF) + LEN4(0x0) + LEN4(0xE) + LEN4(0xD) + LEN4(0xB) + LEN4(0x7) + LEN4(0x3) + LEN4(0xC) + LEN4(0x5) + LEN4(0xA) + LEN5(0x9) + LEN5(0x6) + LEN5(0x1) + LEN5(0x2) + LEN5(0x4) + LEN5(0x8) +}; diff --git a/libavcodec/hq_common.h b/libavcodec/hq_common.h new file mode 100644 index 0000000000..e438ac7d07 --- /dev/null +++ b/libavcodec/hq_common.h @@ -0,0 +1,29 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HQ_COMMON_H +#define AVCODEC_HQ_COMMON_H + +#include "vlc.h" +#include "libavutil/attributes_internal.h" + +#define HQ_CBP_VLC_BITS 5 + +EXTERN const VLCElem ff_hq_cbp_vlc[1 << HQ_CBP_VLC_BITS]; + +#endif /* AVCODEC_HQ_COMMON_H */ diff --git a/libavcodec/hq_hqa.c b/libavcodec/hq_hqa.c index 738ed9868d..c813b923b6 100644 --- a/libavcodec/hq_hqa.c +++ b/libavcodec/hq_hqa.c @@ -30,6 +30,7 @@ #include "codec_internal.h" #include "decode.h" #include "get_bits.h" +#include "hq_common.h" #include "hq_hqadata.h" #include "hq_hqadsp.h" #include "vlc.h" @@ -57,8 +58,9 @@ typedef struct HQContext { DECLARE_ALIGNED(16, int16_t, block)[12][64]; } HQContext; -static VLCElem hq_ac_vlc[1184]; -static VLCElem hqa_cbp_vlc[32]; +static const int32_t *hq_quants[NUM_HQ_QUANTS][2][4]; + +static RL_VLC_ELEM hq_ac_rvlc[1184]; static inline void put_blocks(HQContext *c, AVFrame *pic, int plane, int x, int y, int ilace, @@ -76,9 +78,6 @@ static int hq_decode_block(HQContext *c, GetBitContext *gb, int16_t block[64], int qsel, int is_chroma, int is_hqa) { const int32_t *q; - int val, pos = 1; - - memset(block, 0, 64 * sizeof(*block)); if (!is_hqa) { block[0] = get_sbits(gb, 9) * 64; @@ -88,17 +87,22 @@ static int hq_decode_block(HQContext *c, GetBitContext *gb, int16_t block[64], block[0] = get_sbits(gb, 9) * 64; } - for (;;) { - val = get_vlc2(gb, hq_ac_vlc, 9, 2); - if (val < 0) + OPEN_READER(re, gb); + for (int pos = 0;;) { + int level, run; + UPDATE_CACHE(re, gb); + GET_RL_VLC(level, run, re, gb, hq_ac_rvlc, 9, 2, 0); + if (run == HQ_AC_INVALID_RUN) { + CLOSE_READER(re, gb); return AVERROR_INVALIDDATA; + } - pos += hq_ac_skips[val]; + pos += run; if (pos >= 64) break; - block[ff_zigzag_direct[pos]] = (int)(hq_ac_syms[val] * (unsigned)q[pos]) >> 12; - pos++; + block[ff_zigzag_direct[pos]] = (int)(level * (unsigned)q[pos]) >> 12; } + CLOSE_READER(re, gb); return 0; } @@ -109,6 +113,8 @@ static int hq_decode_mb(HQContext *c, AVFrame *pic, int qgroup, flag; int i, ret; + memset(c->block, 0, 8 * sizeof(c->block[0])); + qgroup = get_bits(gb, 4); flag = get_bits1(gb); @@ -143,6 +149,9 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, av_log(ctx->avctx, AV_LOG_VERBOSE, "HQ Profile %d\n", prof_num); } + if (bytestream2_get_bytes_left(gbc) < 3 * (profile->num_slices + 1)) + return AVERROR_INVALIDDATA; + ctx->avctx->coded_width = FFALIGN(profile->width, 16); ctx->avctx->coded_height = FFALIGN(profile->height, 16); ctx->avctx->width = profile->width; @@ -156,7 +165,7 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, /* Offsets are stored from CUV position, so adjust them accordingly. */ for (i = 0; i < profile->num_slices + 1; i++) - slice_off[i] = bytestream2_get_be24(gbc) - 4; + slice_off[i] = bytestream2_get_be24u(gbc) - 4; next_off = 0; for (slice = 0; slice < profile->num_slices; slice++) { @@ -192,22 +201,19 @@ static int hqa_decode_mb(HQContext *c, AVFrame *pic, int qgroup, GetBitContext *gb, int x, int y) { int flag = 0; - int i, ret, cbp; + int i, ret; if (get_bits_left(gb) < 1) return AVERROR_INVALIDDATA; - cbp = get_vlc2(gb, hqa_cbp_vlc, 5, 1); - - for (i = 0; i < 12; i++) - memset(c->block[i], 0, sizeof(*c->block)); + memset(c->block, 0, 12 * sizeof(c->block[0])); for (i = 0; i < 12; i++) c->block[i][0] = -128 * (1 << 6); + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { flag = get_bits1(gb); - cbp |= cbp << 4; if (cbp & 0x3) cbp |= 0x500; if (cbp & 0xC) @@ -258,14 +264,13 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s const int num_slices = 8; uint32_t slice_off[9]; int i, slice, ret; - int width, height, quant; const uint8_t *src = gbc->buffer; if (bytestream2_get_bytes_left(gbc) < 8 + 4*(num_slices + 1)) return AVERROR_INVALIDDATA; - width = bytestream2_get_be16(gbc); - height = bytestream2_get_be16(gbc); + int width = bytestream2_get_be16u(gbc); + int height = bytestream2_get_be16u(gbc); ret = ff_set_dimensions(ctx->avctx, width, height); if (ret < 0) @@ -278,8 +283,8 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s av_log(ctx->avctx, AV_LOG_VERBOSE, "HQA Profile\n"); - quant = bytestream2_get_byte(gbc); - bytestream2_skip(gbc, 3); + int quant = bytestream2_get_byteu(gbc); + bytestream2_skipu(gbc, 3); if (quant >= NUM_HQ_QUANTS) { av_log(ctx->avctx, AV_LOG_ERROR, "Invalid quantization matrix %d.\n", quant); @@ -292,7 +297,7 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, GetByteContext *gbc, s /* Offsets are stored from HQA1 position, so adjust them accordingly. */ for (i = 0; i < num_slices + 1; i++) - slice_off[i] = bytestream2_get_be32(gbc) - 4; + slice_off[i] = bytestream2_get_be32u(gbc) - 4; for (slice = 0; slice < num_slices; slice++) { if (slice_off[slice] < (num_slices + 1) * 3 || @@ -318,29 +323,26 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, { HQContext *ctx = avctx->priv_data; GetByteContext gbc0, *const gbc = &gbc0; - uint32_t info_tag; unsigned int data_size; int ret; - unsigned tag; - bytestream2_init(gbc, avpkt->data, avpkt->size); - if (bytestream2_get_bytes_left(gbc) < 4 + 4) { + if (avpkt->size < 4 + 4) { av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n", avpkt->size); return AVERROR_INVALIDDATA; } + bytestream2_init(gbc, avpkt->data, avpkt->size); - info_tag = bytestream2_peek_le32(gbc); + uint32_t info_tag = bytestream2_peek_le32u(gbc); if (info_tag == MKTAG('I', 'N', 'F', 'O')) { - int info_size; - bytestream2_skip(gbc, 4); - info_size = bytestream2_get_le32(gbc); + bytestream2_skipu(gbc, 4); + int info_size = bytestream2_get_le32u(gbc); if (info_size < 0 || bytestream2_get_bytes_left(gbc) < info_size) { av_log(avctx, AV_LOG_ERROR, "Invalid INFO size (%d).\n", info_size); return AVERROR_INVALIDDATA; } ff_canopus_parse_info_tag(avctx, gbc->buffer, info_size); - bytestream2_skip(gbc, info_size); + bytestream2_skipu(gbc, info_size); } data_size = bytestream2_get_bytes_left(gbc); @@ -352,7 +354,7 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, /* HQ defines dimensions and number of slices, and thus slice traversal * order. HQA has no size constraint and a fixed number of slices, so it * needs a separate scheme for it. */ - tag = bytestream2_get_le32(gbc); + unsigned tag = bytestream2_get_le32u(gbc); if ((tag & 0x00FFFFFF) == (MKTAG('U', 'V', 'C', ' ') & 0x00FFFFFF)) { ret = hq_decode_frame(ctx, pic, gbc, tag >> 24, data_size); } else if (tag == MKTAG('H', 'Q', 'A', '1')) { @@ -371,13 +373,33 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, return avpkt->size; } -static av_cold void hq_init_vlcs(void) +static av_cold void hq_init_static(void) { - VLC_INIT_STATIC_TABLE(hqa_cbp_vlc, 5, FF_ARRAY_ELEMS(cbp_vlc_lens), - cbp_vlc_lens, 1, 1, cbp_vlc_bits, 1, 1, 0); + VLC_INIT_STATIC_TABLE_FROM_LENGTHS(hq_ac_rvlc, 9, NUM_HQ_AC_ENTRIES, + hq_ac_lens, 1, hq_ac_sym, 2, 2, 0, 0); - VLC_INIT_STATIC_TABLE(hq_ac_vlc, 9, NUM_HQ_AC_ENTRIES, - hq_ac_bits, 1, 1, hq_ac_codes, 2, 2, 0); + for (size_t i = 0; i < FF_ARRAY_ELEMS(hq_ac_rvlc); ++i) { + int len = hq_ac_rvlc[i].len; + int sym = (int16_t)hq_ac_rvlc[i].sym, level = sym; + + // The invalid code has been remapped to HQ_AC_INVALID_RUN, + // so the VLC is complete. + av_assert1(len != 0); + + if (len > 0) { + level = sym >> 7; + hq_ac_rvlc[i].run = sym & 0x7F; + } + hq_ac_rvlc[i].len8 = len; + hq_ac_rvlc[i].level = level; + } + + for (size_t i = 0; i < FF_ARRAY_ELEMS(hq_quants); ++i) { + for (size_t j = 0; j < FF_ARRAY_ELEMS(hq_quants[0]); ++j) { + for (size_t k = 0; k < FF_ARRAY_ELEMS(hq_quants[0][0]); ++k) + hq_quants[i][j][k] = qmats[hq_quant_map[i][j][k]]; + } + } } static av_cold int hq_hqa_decode_init(AVCodecContext *avctx) @@ -388,7 +410,7 @@ static av_cold int hq_hqa_decode_init(AVCodecContext *avctx) ff_hqdsp_init(&ctx->hqhqadsp); - ff_thread_once(&init_static_once, hq_init_vlcs); + ff_thread_once(&init_static_once, hq_init_static); return 0; } diff --git a/libavcodec/hq_hqadata.h b/libavcodec/hq_hqadata.h index 2faf47f003..10120ee94f 100644 --- a/libavcodec/hq_hqadata.h +++ b/libavcodec/hq_hqadata.h @@ -23,7 +23,7 @@ #include -#define NUM_HQ_AC_ENTRIES 746 +#define NUM_HQ_AC_ENTRIES 747 // includes one invalid entry #define NUM_HQ_PROFILES 22 #define NUM_HQ_QUANTS 16 @@ -34,18 +34,92 @@ typedef struct HQProfile { int tab_w, tab_h; } HQProfile; +enum { + QMAT00, + QMAT01, + QMAT02, + QMAT03, + QMAT04, + QMAT05, + QMAT06, + QMAT07, + QMAT08, + QMAT09, + QMAT0A, + QMAT0B, + QMAT0C, + QMAT0D, + QMAT0E, + QMAT0F, + QMAT10, + QMAT11, + QMAT12, + QMAT13, + QMAT14, + QMAT15, + QMAT16, + QMAT17, + QMAT18, + QMAT19, + QMAT1A, + QMAT1B, + QMAT1C, + QMAT1D, + QMAT1E, + QMAT1F, + QMAT20, + QMAT21, + QMAT22, + QMAT23, + QMAT24, + QMAT25, + QMAT26, + QMAT27, + QMAT28, + QMAT29, + QMAT2A, + QMAT2B, + QMAT2C, + QMAT2D, + QMAT2E, + QMAT2F, + QMAT30, + QMAT31, + QMAT32, + QMAT33, + QMAT34, + QMAT35, + QMAT36, + QMAT37, + QMAT38, + QMAT39, + QMAT3A, + QMAT3B, + QMAT3C, + QMAT3D, + QMAT3E, + QMAT3F, + QMAT40, + QMAT41, + QMAT42, + QMAT43, + QMAT44, + QMAT45, + QMAT46, + QMAT47, + QMAT48, + QMAT49, + QMAT4A, + QMAT4B, + QMAT4C, + QMAT4D, + NUM_QMATS +}; + #define MAT_SIZE 64 -static const uint8_t cbp_vlc_bits[16] = { - 0x04, 0x1C, 0x1D, 0x09, 0x1E, 0x0B, 0x1B, 0x08, - 0x1F, 0x1A, 0x0C, 0x07, 0x0A, 0x06, 0x05, 0x00, -}; - -static const uint8_t cbp_vlc_lens[16] = { - 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 4, 4, 4, 2, -}; - -static const int32_t qmat00[MAT_SIZE] = { +static const int32_t qmats[NUM_QMATS][MAT_SIZE] = { +[QMAT00] = { 0x0040000, 0x000B18B, 0x00058C5, 0x000B1B1, 0x00082D3, 0x000B1B1, 0x000A953, 0x000827B, 0x00104F7, 0x000A953, 0x0009000, 0x000EADD, 0x001037B, 0x000756E, 0x0009000, 0x000776D, 0x000696A, 0x000E987, @@ -57,9 +131,8 @@ static const int32_t qmat00[MAT_SIZE] = { 0x00229B2, 0x001FCB2, 0x0019FA3, 0x000D94C, 0x000CFD2, 0x0007F2D, 0x000DEED, 0x0014D5E, 0x0029ABD, 0x0037BB5, 0x002D16B, 0x001FECE, 0x000B45B, 0x0011521, 0x0022A42, 0x0012B9C, -}; - -static const int32_t qmat01[MAT_SIZE] = { +}, +[QMAT01] = { 0x0040000, 0x000B18B, 0x00058C5, 0x000B1B1, 0x00082D3, 0x000B1B1, 0x000EB2D, 0x000B53A, 0x0016A73, 0x000EB2D, 0x000D000, 0x0014632, 0x0016314, 0x000A319, 0x000D000, 0x000A36D, 0x0009041, 0x0014BDA, @@ -71,9 +144,8 @@ static const int32_t qmat01[MAT_SIZE] = { 0x0045365, 0x007FD2A, 0x00675E5, 0x0036A1F, 0x0033AF3, 0x001FF4B, 0x001C010, 0x0029E24, 0x0053C47, 0x007003E, 0x005A9C7, 0x004024C, 0x0016A72, 0x0022A42, 0x0045485, 0x0025738, -}; - -static const int32_t qmat02[MAT_SIZE] = { +}, +[QMAT02] = { 0x0040000, 0x0016315, 0x000B18B, 0x0016363, 0x00105A6, 0x0016363, 0x00152A7, 0x00104F7, 0x00209EE, 0x00152A7, 0x0012000, 0x001D5B9, 0x00206F6, 0x000EADD, 0x0012000, 0x000EEDA, 0x000D2D4, 0x001D30D, @@ -85,9 +157,8 @@ static const int32_t qmat02[MAT_SIZE] = { 0x0045365, 0x003F964, 0x0033F47, 0x001B297, 0x0019FA3, 0x000FE59, 0x001BDDA, 0x0029ABD, 0x0053579, 0x006F76A, 0x005A2D7, 0x003FD9D, 0x00168B6, 0x0022A42, 0x0045485, 0x0025738, -}; - -static const int32_t qmat03[MAT_SIZE] = { +}, +[QMAT03] = { 0x0040000, 0x0016315, 0x000B18B, 0x0016363, 0x00105A6, 0x0016363, 0x001D65A, 0x0016A73, 0x002D4E7, 0x001D65A, 0x001A000, 0x0028C65, 0x002C628, 0x0014632, 0x001A000, 0x00146D9, 0x0012081, 0x00297B5, @@ -99,9 +170,8 @@ static const int32_t qmat03[MAT_SIZE] = { 0x008A6CA, 0x00FFA54, 0x00CEBCA, 0x006D43E, 0x00675E5, 0x003FE95, 0x003801F, 0x0053C47, 0x00A788E, 0x00E007C, 0x00B538D, 0x0080498, 0x002D4E3, 0x0045485, 0x008A90A, 0x004AE71, -}; - -static const int32_t qmat04[MAT_SIZE] = { +}, +[QMAT04] = { 0x0040000, 0x00214A0, 0x0010A50, 0x0021514, 0x0018879, 0x0021514, 0x001FBFA, 0x0018772, 0x0030EE5, 0x001FBFA, 0x001B000, 0x002C096, 0x0030A71, 0x001604B, 0x001B000, 0x0016647, 0x0013C3F, 0x002BC94, @@ -113,9 +183,8 @@ static const int32_t qmat04[MAT_SIZE] = { 0x0067D17, 0x005F616, 0x004DEEA, 0x0028BE3, 0x0026F75, 0x0017D86, 0x0029CC8, 0x003E81B, 0x007D036, 0x00A731F, 0x0087442, 0x005FC6B, 0x0021D11, 0x0033F64, 0x0067EC7, 0x00382D5, -}; - -static const int32_t qmat05[MAT_SIZE] = { +}, +[QMAT05] = { 0x0040000, 0x00214A0, 0x0010A50, 0x0021514, 0x0018879, 0x0021514, 0x002C186, 0x0021FAD, 0x0043F5A, 0x002C186, 0x0027000, 0x003D297, 0x004293C, 0x001E94C, 0x0027000, 0x001EA46, 0x001B0C2, 0x003E38F, @@ -127,9 +196,8 @@ static const int32_t qmat05[MAT_SIZE] = { 0x00CFA2F, 0x017F77F, 0x01361B0, 0x00A3E5C, 0x009B0D8, 0x005FDE0, 0x005402F, 0x007DA6B, 0x00FB4D5, 0x01500BA, 0x010FD54, 0x00C06E5, 0x0043F55, 0x0067EC7, 0x00CFD8F, 0x00705A9, -}; - -static const int32_t qmat06[MAT_SIZE] = { +}, +[QMAT06] = { 0x0040000, 0x002C62A, 0x0016315, 0x002C6C5, 0x0020B4C, 0x002C6C5, 0x002A54E, 0x00209EE, 0x00413DC, 0x002A54E, 0x0024000, 0x003AB73, 0x0040DEC, 0x001D5B9, 0x0024000, 0x001DDB4, 0x001A5A9, 0x003A61B, @@ -141,9 +209,8 @@ static const int32_t qmat06[MAT_SIZE] = { 0x008A6CA, 0x007F2C9, 0x0067E8E, 0x003652F, 0x0033F47, 0x001FCB2, 0x0037BB5, 0x0053579, 0x00A6AF3, 0x00DEED4, 0x00B45AE, 0x007FB39, 0x002D16B, 0x0045485, 0x008A90A, 0x004AE71, -}; - -static const int32_t qmat07[MAT_SIZE] = { +}, +[QMAT07] = { 0x0040000, 0x002C62A, 0x0016315, 0x002C6C5, 0x0020B4C, 0x002C6C5, 0x003ACB3, 0x002D4E7, 0x005A9CE, 0x003ACB3, 0x0034000, 0x00518CA, 0x0058C50, 0x0028C65, 0x0034000, 0x0028DB3, 0x0024102, 0x0052F69, @@ -155,9 +222,8 @@ static const int32_t qmat07[MAT_SIZE] = { 0x0114D94, 0x01FF4A9, 0x019D795, 0x00DA87B, 0x00CEBCA, 0x007FD2A, 0x007003E, 0x00A788E, 0x014F11C, 0x01C00F8, 0x016A71B, 0x0100931, 0x005A9C7, 0x008A90A, 0x0115214, 0x0095CE2, -}; - -static const int32_t qmat08[MAT_SIZE] = { +}, +[QMAT08] = { 0x0040000, 0x00377B5, 0x001BBDA, 0x0037876, 0x0028E1E, 0x0037876, 0x0034EA1, 0x0028C69, 0x00518D3, 0x0034EA1, 0x002D000, 0x004964F, 0x0051167, 0x0024B28, 0x002D000, 0x0025521, 0x0020F13, 0x0048FA1, @@ -169,9 +235,8 @@ static const int32_t qmat08[MAT_SIZE] = { 0x00AD07C, 0x009EF7B, 0x0081E31, 0x0043E7A, 0x0040F19, 0x0027BDF, 0x0045AA2, 0x00682D8, 0x00D05B0, 0x0116A89, 0x00E1719, 0x009FA07, 0x00385C6, 0x00569A6, 0x00AD34C, 0x005DA0D, -}; - -static const int32_t qmat09[MAT_SIZE] = { +}, +[QMAT09] = { 0x0040000, 0x00377B5, 0x001BBDA, 0x0037876, 0x0028E1E, 0x0037876, 0x00497E0, 0x0038A21, 0x0071441, 0x00497E0, 0x0041000, 0x0065EFC, 0x006EF64, 0x0032F7E, 0x0041000, 0x003311F, 0x002D143, 0x0067B44, @@ -183,9 +248,8 @@ static const int32_t qmat09[MAT_SIZE] = { 0x015A0F9, 0x027F1D3, 0x0204D7A, 0x011129A, 0x01026BD, 0x009FC75, 0x008C04E, 0x00D16B2, 0x01A2D64, 0x0230136, 0x01C50E1, 0x0140B7D, 0x0071438, 0x00AD34C, 0x015A699, 0x00BB41A, -}; - -static const int32_t qmat0A[MAT_SIZE] = { +}, +[QMAT0A] = { 0x0040000, 0x004293F, 0x00214A0, 0x0042A28, 0x00310F1, 0x0042A28, 0x003F7F5, 0x0030EE5, 0x0061DCA, 0x003F7F5, 0x0036000, 0x005812C, 0x00614E2, 0x002C096, 0x0036000, 0x002CC8E, 0x002787D, 0x0057928, @@ -197,9 +261,8 @@ static const int32_t qmat0A[MAT_SIZE] = { 0x00CFA2F, 0x00BEC2D, 0x009BDD5, 0x00517C6, 0x004DEEA, 0x002FB0B, 0x005398F, 0x007D036, 0x00FA06C, 0x014E63E, 0x010E885, 0x00BF8D6, 0x0043A21, 0x0067EC7, 0x00CFD8F, 0x00705A9, -}; - -static const int32_t qmat0B[MAT_SIZE] = { +}, +[QMAT0B] = { 0x0040000, 0x004293F, 0x00214A0, 0x0042A28, 0x00310F1, 0x0042A28, 0x005830D, 0x0043F5A, 0x0087EB5, 0x005830D, 0x004E000, 0x007A52F, 0x0085278, 0x003D297, 0x004E000, 0x003D48C, 0x0036183, 0x007C71E, @@ -211,9 +274,8 @@ static const int32_t qmat0B[MAT_SIZE] = { 0x019F45E, 0x02FEEFD, 0x026C35F, 0x0147CB9, 0x01361B0, 0x00BFBBF, 0x00A805D, 0x00FB4D5, 0x01F69AB, 0x02A0174, 0x021FAA8, 0x0180DC9, 0x0087EAA, 0x00CFD8F, 0x019FB1E, 0x00E0B52, -}; - -static const int32_t qmat0C[MAT_SIZE] = { +}, +[QMAT0C] = { 0x0040000, 0x004DACA, 0x0026D65, 0x004DBD9, 0x00393C4, 0x004DBD9, 0x004A148, 0x0039160, 0x00722C1, 0x004A148, 0x003F000, 0x0066C09, 0x007185D, 0x0033604, 0x003F000, 0x00343FB, 0x002E1E8, 0x00662AF, @@ -225,9 +287,8 @@ static const int32_t qmat0C[MAT_SIZE] = { 0x00F23E1, 0x00DE8DF, 0x00B5D78, 0x005F111, 0x005AEBC, 0x0037A38, 0x006187D, 0x0091D95, 0x0123B29, 0x01861F3, 0x013B9F0, 0x00DF7A4, 0x004EE7C, 0x00793E9, 0x00F27D1, 0x0083145, -}; - -static const int32_t qmat0D[MAT_SIZE] = { +}, +[QMAT0D] = { 0x0040000, 0x004DACA, 0x0026D65, 0x004DBD9, 0x00393C4, 0x004DBD9, 0x0066E3A, 0x004F494, 0x009E928, 0x0066E3A, 0x005B000, 0x008EB61, 0x009B58C, 0x00475B1, 0x005B000, 0x00477F9, 0x003F1C4, 0x00912F8, @@ -239,9 +300,8 @@ static const int32_t qmat0D[MAT_SIZE] = { 0x01E47C3, 0x037EC27, 0x02D3944, 0x017E6D8, 0x0169CA2, 0x00DFB0A, 0x00C406D, 0x01252F9, 0x024A5F2, 0x03101B2, 0x027A46F, 0x01C1016, 0x009E91C, 0x00F27D1, 0x01E4FA3, 0x010628B, -}; - -static const int32_t qmat0E[MAT_SIZE] = { +}, +[QMAT0E] = { 0x0040000, 0x0058C54, 0x002C62A, 0x0058D8A, 0x0041697, 0x0058D8A, 0x0054A9C, 0x00413DC, 0x00827B8, 0x0054A9C, 0x0048000, 0x00756E5, 0x0081BD8, 0x003AB73, 0x0048000, 0x003BB68, 0x0034B52, 0x0074C35, @@ -253,9 +313,8 @@ static const int32_t qmat0E[MAT_SIZE] = { 0x0114D94, 0x00FE591, 0x00CFD1C, 0x006CA5D, 0x0067E8E, 0x003F964, 0x006F76A, 0x00A6AF3, 0x014D5E6, 0x01BDDA8, 0x0168B5C, 0x00FF672, 0x005A2D7, 0x008A90A, 0x0115214, 0x0095CE2, -}; - -static const int32_t qmat0F[MAT_SIZE] = { +}, +[QMAT0F] = { 0x0040000, 0x0058C54, 0x002C62A, 0x0058D8A, 0x0041697, 0x0058D8A, 0x0075967, 0x005A9CE, 0x00B539C, 0x0075967, 0x0068000, 0x00A3194, 0x00B18A0, 0x00518CA, 0x0068000, 0x0051B65, 0x0048204, 0x00A5ED3, @@ -267,9 +326,8 @@ static const int32_t qmat0F[MAT_SIZE] = { 0x0229B27, 0x03FE951, 0x033AF2A, 0x01B50F6, 0x019D795, 0x00FFA54, 0x00E007C, 0x014F11C, 0x029E239, 0x03801F0, 0x02D4E36, 0x0201262, 0x00B538D, 0x0115214, 0x022A428, 0x012B9C3, -}; - -static const int32_t qmat10[MAT_SIZE] = { +}, +[QMAT10] = { 0x0040000, 0x006EF69, 0x00377B5, 0x006F0ED, 0x0051C3D, 0x006F0ED, 0x0069D43, 0x00518D3, 0x00A31A6, 0x0069D43, 0x005A000, 0x0092C9F, 0x00A22CD, 0x004964F, 0x005A000, 0x004AA42, 0x0041E26, 0x0091F43, @@ -281,9 +339,8 @@ static const int32_t qmat10[MAT_SIZE] = { 0x015A0F9, 0x013DEF5, 0x0103C63, 0x0087CF4, 0x0081E31, 0x004F7BD, 0x008B544, 0x00D05B0, 0x01A0B5F, 0x022D511, 0x01C2E32, 0x013F40F, 0x0070B8D, 0x00AD34C, 0x015A699, 0x00BB41A, -}; - -static const int32_t qmat11[MAT_SIZE] = { +}, +[QMAT11] = { 0x0040000, 0x006EF69, 0x00377B5, 0x006F0ED, 0x0051C3D, 0x006F0ED, 0x0092FC0, 0x0071441, 0x00E2883, 0x0092FC0, 0x0082000, 0x00CBDF9, 0x00DDEC8, 0x0065EFC, 0x0082000, 0x006623F, 0x005A285, 0x00CF687, @@ -295,9 +352,8 @@ static const int32_t qmat11[MAT_SIZE] = { 0x02B41F1, 0x04FE3A6, 0x0409AF4, 0x0222534, 0x0204D7A, 0x013F8E9, 0x011809B, 0x01A2D64, 0x0345AC7, 0x046026C, 0x038A1C3, 0x02816FA, 0x00E2871, 0x015A699, 0x02B4D32, 0x0176834, -}; - -static const int32_t qmat12[MAT_SIZE] = { +}, +[QMAT12] = { 0x0040000, 0x008527E, 0x004293F, 0x0085450, 0x00621E3, 0x0085450, 0x007EFEA, 0x0061DCA, 0x00C3B94, 0x007EFEA, 0x006C000, 0x00B0258, 0x00C29C3, 0x005812C, 0x006C000, 0x005991C, 0x004F0FB, 0x00AF250, @@ -309,9 +365,8 @@ static const int32_t qmat12[MAT_SIZE] = { 0x019F45E, 0x017D85A, 0x0137BAA, 0x00A2F8C, 0x009BDD5, 0x005F616, 0x00A731F, 0x00FA06C, 0x01F40D9, 0x029CC7B, 0x021D109, 0x017F1AB, 0x0087442, 0x00CFD8F, 0x019FB1E, 0x00E0B52, -}; - -static const int32_t qmat13[MAT_SIZE] = { +}, +[QMAT13] = { 0x0040000, 0x008527E, 0x004293F, 0x0085450, 0x00621E3, 0x0085450, 0x00B061A, 0x0087EB5, 0x010FD69, 0x00B061A, 0x009C000, 0x00F4A5E, 0x010A4F0, 0x007A52F, 0x009C000, 0x007A918, 0x006C307, 0x00F8E3C, @@ -323,9 +378,8 @@ static const int32_t qmat13[MAT_SIZE] = { 0x033E8BB, 0x05FDDFA, 0x04D86BE, 0x028F971, 0x026C35F, 0x017F77F, 0x01500BA, 0x01F69AB, 0x03ED355, 0x05402E9, 0x043F550, 0x0301B93, 0x010FD54, 0x019FB1E, 0x033F63C, 0x01C16A5, -}; - -static const int32_t qmat14[MAT_SIZE] = { +}, +[QMAT14] = { 0x0040000, 0x009B593, 0x004DACA, 0x009B7B2, 0x0072789, 0x009B7B2, 0x0094291, 0x00722C1, 0x00E4582, 0x0094291, 0x007E000, 0x00CD812, 0x00E30B9, 0x0066C09, 0x007E000, 0x00687F5, 0x005C3CF, 0x00CC55D, @@ -337,9 +391,8 @@ static const int32_t qmat14[MAT_SIZE] = { 0x01E47C3, 0x01BD1BE, 0x016BAF1, 0x00BE223, 0x00B5D78, 0x006F46F, 0x00C30F9, 0x0123B29, 0x0247652, 0x030C3E5, 0x02773E0, 0x01BEF48, 0x009DCF8, 0x00F27D1, 0x01E4FA3, 0x010628B, -}; - -static const int32_t qmat15[MAT_SIZE] = { +}, +[QMAT15] = { 0x0040000, 0x009B593, 0x004DACA, 0x009B7B2, 0x0072789, 0x009B7B2, 0x00CDC74, 0x009E928, 0x013D250, 0x00CDC74, 0x00B6000, 0x011D6C3, 0x0136B18, 0x008EB61, 0x00B6000, 0x008EFF2, 0x007E388, 0x01225F0, @@ -351,9 +404,8 @@ static const int32_t qmat15[MAT_SIZE] = { 0x03C8F85, 0x06FD84F, 0x05A7289, 0x02FCDAF, 0x02D3944, 0x01BF614, 0x01880D9, 0x024A5F2, 0x0494BE4, 0x0620365, 0x04F48DE, 0x038202B, 0x013D237, 0x01E4FA3, 0x03C9F46, 0x020C516, -}; - -static const int32_t qmat16[MAT_SIZE] = { +}, +[QMAT16] = { 0x0040000, 0x00B18A8, 0x0058C54, 0x00B1B15, 0x0082D2E, 0x00B1B15, 0x00A9538, 0x00827B8, 0x0104F6F, 0x00A9538, 0x0090000, 0x00EADCB, 0x01037AF, 0x00756E5, 0x0090000, 0x00776CF, 0x00696A4, 0x00E986B, @@ -365,9 +417,8 @@ static const int32_t qmat16[MAT_SIZE] = { 0x0229B27, 0x01FCB22, 0x019FA38, 0x00D94BA, 0x00CFD1C, 0x007F2C9, 0x00DEED4, 0x014D5E6, 0x029ABCC, 0x037BB4F, 0x02D16B7, 0x01FECE4, 0x00B45AE, 0x0115214, 0x022A428, 0x012B9C3, -}; - -static const int32_t qmat17[MAT_SIZE] = { +}, +[QMAT17] = { 0x0040000, 0x00B18A8, 0x0058C54, 0x00B1B15, 0x0082D2E, 0x00B1B15, 0x00EB2CD, 0x00B539C, 0x016A737, 0x00EB2CD, 0x00D0000, 0x0146328, 0x0163140, 0x00A3194, 0x00D0000, 0x00A36CB, 0x0090409, 0x014BDA5, @@ -379,9 +430,8 @@ static const int32_t qmat17[MAT_SIZE] = { 0x045364F, 0x07FD2A3, 0x0675E53, 0x036A1ED, 0x033AF2A, 0x01FF4A9, 0x01C00F8, 0x029E239, 0x053C472, 0x07003E1, 0x05A9C6B, 0x04024C4, 0x016A71B, 0x022A428, 0x0454850, 0x0257386, -}; - -static const int32_t qmat18[MAT_SIZE] = { +}, +[QMAT18] = { 0x0040000, 0x00C7BBD, 0x0063DDF, 0x00C7E77, 0x00932D4, 0x00C7E77, 0x00BE7DF, 0x0092CAF, 0x012595D, 0x00BE7DF, 0x00A2000, 0x0108384, 0x0123EA5, 0x00841C2, 0x00A2000, 0x00865A9, 0x0076978, 0x0106B78, @@ -393,9 +443,8 @@ static const int32_t qmat18[MAT_SIZE] = { 0x026EE8C, 0x023C486, 0x01D397F, 0x00F4751, 0x00E9CBF, 0x008F122, 0x00FACAE, 0x01770A2, 0x02EE145, 0x03EB2B9, 0x032B98E, 0x023EA81, 0x00CAE64, 0x0137C56, 0x026F8AD, 0x01510FC, -}; - -static const int32_t qmat19[MAT_SIZE] = { +}, +[QMAT19] = { 0x0040000, 0x00C7BBD, 0x0063DDF, 0x00C7E77, 0x00932D4, 0x00C7E77, 0x0108927, 0x00CBE0F, 0x0197C1E, 0x0108927, 0x00EA000, 0x016EF8D, 0x018F768, 0x00B77C6, 0x00EA000, 0x00B7DA4, 0x00A248A, 0x017555A, @@ -407,9 +456,8 @@ static const int32_t qmat19[MAT_SIZE] = { 0x04DDD19, 0x08FCCF7, 0x0744A1D, 0x03D762A, 0x03A250F, 0x023F33E, 0x01F8117, 0x02F1E80, 0x05E3D00, 0x07E045D, 0x065EFF9, 0x048295C, 0x0197BFE, 0x026F8AD, 0x04DF15A, 0x02A21F7, -}; - -static const int32_t qmat1A[MAT_SIZE] = { +}, +[QMAT1A] = { 0x0040000, 0x00DDED2, 0x006EF69, 0x00DE1DA, 0x00A387A, 0x00DE1DA, 0x00D3A86, 0x00A31A6, 0x014634B, 0x00D3A86, 0x00B4000, 0x012593E, 0x014459B, 0x0092C9F, 0x00B4000, 0x0095483, 0x0083C4D, 0x0123E85, @@ -421,9 +469,8 @@ static const int32_t qmat1A[MAT_SIZE] = { 0x02B41F1, 0x027BDEB, 0x02078C6, 0x010F9E9, 0x0103C63, 0x009EF7B, 0x0116A89, 0x01A0B5F, 0x03416BE, 0x045AA23, 0x0385C65, 0x027E81E, 0x00E1719, 0x015A699, 0x02B4D32, 0x0176834, -}; - -static const int32_t qmat1B[MAT_SIZE] = { +}, +[QMAT1B] = { 0x0040000, 0x00DDED2, 0x006EF69, 0x00DE1DA, 0x00A387A, 0x00DE1DA, 0x0125F81, 0x00E2883, 0x01C5105, 0x0125F81, 0x0104000, 0x0197BF2, 0x01BBD90, 0x00CBDF9, 0x0104000, 0x00CC47E, 0x00B450B, 0x019ED0E, @@ -435,9 +482,8 @@ static const int32_t qmat1B[MAT_SIZE] = { 0x05683E3, 0x09FC74C, 0x08135E8, 0x0444A68, 0x0409AF4, 0x027F1D3, 0x0230136, 0x0345AC7, 0x068B58E, 0x08C04D9, 0x0714386, 0x0502DF5, 0x01C50E1, 0x02B4D32, 0x0569A64, 0x02ED068, -}; - -static const int32_t qmat1C[MAT_SIZE] = { +}, +[QMAT1C] = { 0x0040000, 0x00F41E7, 0x007A0F4, 0x00F453D, 0x00B3E20, 0x00F453D, 0x00E8D2D, 0x00B369D, 0x0166D39, 0x00E8D2D, 0x00C6000, 0x0142EF7, 0x0164C91, 0x00A177B, 0x00C6000, 0x00A435D, 0x0090F21, 0x0141193, @@ -449,9 +495,8 @@ static const int32_t qmat1C[MAT_SIZE] = { 0x02F9556, 0x02BB74F, 0x023B80D, 0x012AC80, 0x011DC06, 0x00AEDD4, 0x0132863, 0x01CA61C, 0x0394C38, 0x04CA18D, 0x03DFF3C, 0x02BE5BA, 0x00F7FCF, 0x017D0DB, 0x02FA1B7, 0x019BF6C, -}; - -static const int32_t qmat1D[MAT_SIZE] = { +}, +[QMAT1D] = { 0x0040000, 0x00F41E7, 0x007A0F4, 0x00F453D, 0x00B3E20, 0x00F453D, 0x01435DA, 0x00F92F6, 0x01F25EC, 0x01435DA, 0x011E000, 0x01C0857, 0x01E83B8, 0x00E042B, 0x011E000, 0x00E0B57, 0x00C658C, 0x01C84C3, @@ -463,9 +508,8 @@ static const int32_t qmat1D[MAT_SIZE] = { 0x05F2AAD, 0x0AFC1A0, 0x08E21B2, 0x04B1EA5, 0x04710D9, 0x02BF068, 0x0268155, 0x039970E, 0x0732E1D, 0x09A0555, 0x07C9713, 0x058328D, 0x01F25C5, 0x02FA1B7, 0x05F436E, 0x0337ED9, -}; - -static const int32_t qmat1E[MAT_SIZE] = { +}, +[QMAT1E] = { 0x0040000, 0x010A4FD, 0x008527E, 0x010A89F, 0x00C43C5, 0x010A89F, 0x00FDFD3, 0x00C3B94, 0x0187727, 0x00FDFD3, 0x00D8000, 0x01604B0, 0x0185387, 0x00B0258, 0x00D8000, 0x00B3237, 0x009E1F6, 0x015E4A0, @@ -477,9 +521,8 @@ static const int32_t qmat1E[MAT_SIZE] = { 0x033E8BB, 0x02FB0B3, 0x026F754, 0x0145F17, 0x0137BAA, 0x00BEC2D, 0x014E63E, 0x01F40D9, 0x03E81B1, 0x05398F7, 0x043A213, 0x02FE357, 0x010E885, 0x019FB1E, 0x033F63C, 0x01C16A5, -}; - -static const int32_t qmat1F[MAT_SIZE] = { +}, +[QMAT1F] = { 0x0040000, 0x010A4FD, 0x008527E, 0x010A89F, 0x00C43C5, 0x010A89F, 0x0160C34, 0x010FD69, 0x021FAD3, 0x0160C34, 0x0138000, 0x01E94BC, 0x02149E1, 0x00F4A5E, 0x0138000, 0x00F5230, 0x00D860D, 0x01F1C78, @@ -491,9 +534,8 @@ static const int32_t qmat1F[MAT_SIZE] = { 0x067D176, 0x0BFBBF4, 0x09B0D7D, 0x051F2E3, 0x04D86BE, 0x02FEEFD, 0x02A0174, 0x03ED355, 0x07DA6AB, 0x0A805D1, 0x087EAA1, 0x0603726, 0x021FAA8, 0x033F63C, 0x067EC78, 0x0382D4A, -}; - -static const int32_t qmat20[MAT_SIZE] = { +}, +[QMAT20] = { 0x0040000, 0x0136B27, 0x009B593, 0x0136F64, 0x00E4F11, 0x0136F64, 0x0128521, 0x00E4582, 0x01C8B03, 0x0128521, 0x00FC000, 0x019B023, 0x01C6172, 0x00CD812, 0x00FC000, 0x00D0FEB, 0x00B879F, 0x0198ABB, @@ -505,9 +547,8 @@ static const int32_t qmat20[MAT_SIZE] = { 0x03C8F85, 0x037A37C, 0x02D75E2, 0x017C446, 0x016BAF1, 0x00DE8DF, 0x01861F3, 0x0247652, 0x048ECA4, 0x06187CA, 0x04EE7C1, 0x037DE90, 0x013B9F0, 0x01E4FA3, 0x03C9F46, 0x020C516, -}; - -static const int32_t qmat21[MAT_SIZE] = { +}, +[QMAT21] = { 0x0040000, 0x0136B27, 0x009B593, 0x0136F64, 0x00E4F11, 0x0136F64, 0x019B8E7, 0x013D250, 0x027A4A1, 0x019B8E7, 0x016C000, 0x023AD86, 0x026D631, 0x011D6C3, 0x016C000, 0x011DFE3, 0x00FC70F, 0x0244BE1, @@ -519,9 +560,8 @@ static const int32_t qmat21[MAT_SIZE] = { 0x0791F0A, 0x0DFB09D, 0x0B4E511, 0x05F9B5E, 0x05A7289, 0x037EC27, 0x03101B2, 0x0494BE4, 0x09297C7, 0x0C406C9, 0x09E91BC, 0x0704057, 0x027A46F, 0x03C9F46, 0x0793E8C, 0x0418A2B, -}; - -static const int32_t qmat22[MAT_SIZE] = { +}, +[QMAT22] = { 0x0040000, 0x0163151, 0x00B18A8, 0x0163629, 0x0105A5D, 0x0163629, 0x0152A6F, 0x0104F6F, 0x0209EDF, 0x0152A6F, 0x0120000, 0x01D5B96, 0x0206F5E, 0x00EADCB, 0x0120000, 0x00EED9F, 0x00D2D48, 0x01D30D5, @@ -533,9 +573,8 @@ static const int32_t qmat22[MAT_SIZE] = { 0x045364F, 0x03F9644, 0x033F46F, 0x01B2974, 0x019FA38, 0x00FE591, 0x01BDDA8, 0x029ABCC, 0x0535797, 0x06F769E, 0x05A2D6E, 0x03FD9C9, 0x0168B5C, 0x022A428, 0x0454850, 0x0257386, -}; - -static const int32_t qmat23[MAT_SIZE] = { +}, +[QMAT23] = { 0x0040000, 0x0163151, 0x00B18A8, 0x0163629, 0x0105A5D, 0x0163629, 0x01D659B, 0x016A737, 0x02D4E6E, 0x01D659B, 0x01A0000, 0x028C650, 0x02C6281, 0x0146328, 0x01A0000, 0x0146D96, 0x0120812, 0x0297B4A, @@ -547,9 +586,8 @@ static const int32_t qmat23[MAT_SIZE] = { 0x08A6C9E, 0x0FFA546, 0x0CEBCA6, 0x06D43D9, 0x0675E53, 0x03FE951, 0x03801F0, 0x053C472, 0x0A788E4, 0x0E007C1, 0x0B538D6, 0x0804988, 0x02D4E36, 0x0454850, 0x08A90A0, 0x04AE70D, -}; - -static const int32_t qmat24[MAT_SIZE] = { +}, +[QMAT24] = { 0x0040000, 0x018F77B, 0x00C7BBD, 0x018FCEF, 0x01265A8, 0x018FCEF, 0x017CFBD, 0x012595D, 0x024B2BB, 0x017CFBD, 0x0144000, 0x0210708, 0x0247D4A, 0x0108384, 0x0144000, 0x010CB53, 0x00ED2F1, 0x020D6F0, @@ -561,9 +599,8 @@ static const int32_t qmat24[MAT_SIZE] = { 0x04DDD19, 0x047890D, 0x03A72FD, 0x01E8EA3, 0x01D397F, 0x011E243, 0x01F595C, 0x02EE145, 0x05DC28A, 0x07D6572, 0x065731C, 0x047D502, 0x0195CC7, 0x026F8AD, 0x04DF15A, 0x02A21F7, -}; - -static const int32_t qmat25[MAT_SIZE] = { +}, +[QMAT25] = { 0x0040000, 0x018F77B, 0x00C7BBD, 0x018FCEF, 0x01265A8, 0x018FCEF, 0x021124E, 0x0197C1E, 0x032F83C, 0x021124E, 0x01D4000, 0x02DDF1A, 0x031EED1, 0x016EF8D, 0x01D4000, 0x016FB49, 0x0144914, 0x02EAAB3, @@ -575,9 +612,8 @@ static const int32_t qmat25[MAT_SIZE] = { 0x09BBA32, 0x11F99EF, 0x0E8943B, 0x07AEC54, 0x0744A1D, 0x047E67C, 0x03F022E, 0x05E3D00, 0x0BC7A00, 0x0FC08BA, 0x0CBDFF1, 0x09052B9, 0x032F7FC, 0x04DF15A, 0x09BE2B4, 0x05443EE, -}; - -static const int32_t qmat26[MAT_SIZE] = { +}, +[QMAT26] = { 0x0040000, 0x01BBDA5, 0x00DDED2, 0x01BC3B4, 0x01470F4, 0x01BC3B4, 0x01A750B, 0x014634B, 0x028C697, 0x01A750B, 0x0168000, 0x024B27B, 0x0288B36, 0x012593E, 0x0168000, 0x012A906, 0x010789A, 0x0247D0B, @@ -589,9 +625,8 @@ static const int32_t qmat26[MAT_SIZE] = { 0x05683E3, 0x04F7BD5, 0x040F18B, 0x021F3D1, 0x02078C6, 0x013DEF5, 0x022D511, 0x03416BE, 0x0682D7D, 0x08B5446, 0x070B8CA, 0x04FD03B, 0x01C2E32, 0x02B4D32, 0x0569A64, 0x02ED068, -}; - -static const int32_t qmat27[MAT_SIZE] = { +}, +[QMAT27] = { 0x0040000, 0x01BBDA5, 0x00DDED2, 0x01BC3B4, 0x01470F4, 0x01BC3B4, 0x024BF01, 0x01C5105, 0x038A20A, 0x024BF01, 0x0208000, 0x032F7E4, 0x0377B21, 0x0197BF2, 0x0208000, 0x01988FB, 0x0168A16, 0x033DA1D, @@ -603,9 +638,8 @@ static const int32_t qmat27[MAT_SIZE] = { 0x0AD07C5, 0x13F8E97, 0x1026BD0, 0x08894CF, 0x08135E8, 0x04FE3A6, 0x046026C, 0x068B58E, 0x0D16B1D, 0x11809B2, 0x0E2870C, 0x0A05BEA, 0x038A1C3, 0x0569A64, 0x0AD34C8, 0x05DA0D0, -}; - -static const int32_t qmat28[MAT_SIZE] = { +}, +[QMAT28] = { 0x0040000, 0x01E83CF, 0x00F41E7, 0x01E8A79, 0x0167C3F, 0x01E8A79, 0x01D1A59, 0x0166D39, 0x02CDA72, 0x01D1A59, 0x018C000, 0x0285DEE, 0x02C9921, 0x0142EF7, 0x018C000, 0x01486BA, 0x0121E43, 0x0282325, @@ -617,9 +651,8 @@ static const int32_t qmat28[MAT_SIZE] = { 0x05F2AAD, 0x0576E9E, 0x0477019, 0x0255900, 0x023B80D, 0x015DBA7, 0x02650C6, 0x0394C38, 0x0729870, 0x0994319, 0x07BFE78, 0x057CB74, 0x01EFF9E, 0x02FA1B7, 0x05F436E, 0x0337ED9, -}; - -static const int32_t qmat29[MAT_SIZE] = { +}, +[QMAT29] = { 0x0040000, 0x01E83CF, 0x00F41E7, 0x01E8A79, 0x0167C3F, 0x01E8A79, 0x0286BB5, 0x01F25EC, 0x03E4BD8, 0x0286BB5, 0x023C000, 0x03810AE, 0x03D0771, 0x01C0857, 0x023C000, 0x01C16AE, 0x018CB18, 0x0390986, @@ -631,9 +664,8 @@ static const int32_t qmat29[MAT_SIZE] = { 0x0BE5559, 0x15F8340, 0x11C4364, 0x0963D4B, 0x08E21B2, 0x057E0D0, 0x04D02AB, 0x0732E1D, 0x0E65C39, 0x1340AAA, 0x0F92E27, 0x0B0651B, 0x03E4B8A, 0x05F436E, 0x0BE86DC, 0x066FDB2, -}; - -static const int32_t qmat2A[MAT_SIZE] = { +}, +[QMAT2A] = { 0x0040000, 0x02149F9, 0x010A4FD, 0x021513E, 0x018878B, 0x021513E, 0x01FBFA7, 0x0187727, 0x030EE4E, 0x01FBFA7, 0x01B0000, 0x02C0961, 0x030A70D, 0x01604B0, 0x01B0000, 0x016646E, 0x013C3EC, 0x02BC940, @@ -645,9 +677,8 @@ static const int32_t qmat2A[MAT_SIZE] = { 0x067D176, 0x05F6166, 0x04DEEA7, 0x028BE2E, 0x026F754, 0x017D85A, 0x029CC7B, 0x03E81B1, 0x07D0363, 0x0A731ED, 0x0874425, 0x05FC6AD, 0x021D109, 0x033F63C, 0x067EC78, 0x0382D4A, -}; - -static const int32_t qmat2B[MAT_SIZE] = { +}, +[QMAT2B] = { 0x0040000, 0x02149F9, 0x010A4FD, 0x021513E, 0x018878B, 0x021513E, 0x02C1868, 0x021FAD3, 0x043F5A6, 0x02C1868, 0x0270000, 0x03D2978, 0x04293C1, 0x01E94BC, 0x0270000, 0x01EA461, 0x01B0C1A, 0x03E38EF, @@ -659,9 +690,8 @@ static const int32_t qmat2B[MAT_SIZE] = { 0x0CFA2ED, 0x17F77E9, 0x1361AF9, 0x0A3E5C6, 0x09B0D7D, 0x05FDDFA, 0x05402E9, 0x07DA6AB, 0x0FB4D56, 0x1500BA2, 0x10FD541, 0x0C06E4C, 0x043F550, 0x067EC78, 0x0CFD8F0, 0x0705A93, -}; - -static const int32_t qmat2C[MAT_SIZE] = { +}, +[QMAT2C] = { 0x0040000, 0x0241023, 0x0120812, 0x0241803, 0x01A92D7, 0x0241803, 0x02264F5, 0x01A8115, 0x035022A, 0x02264F5, 0x01D4000, 0x02FB4D3, 0x034B4F9, 0x017DA6A, 0x01D4000, 0x0184222, 0x0156995, 0x02F6F5B, @@ -673,9 +703,8 @@ static const int32_t qmat2C[MAT_SIZE] = { 0x0707840, 0x067542F, 0x0546D35, 0x02C235D, 0x02A369B, 0x019D50C, 0x02D4830, 0x043B72B, 0x0876E56, 0x0B520C1, 0x09289D3, 0x067C1E6, 0x024A275, 0x0384AC1, 0x0709582, 0x03CDBBA, -}; - -static const int32_t qmat2D[MAT_SIZE] = { +}, +[QMAT2D] = { 0x0040000, 0x0241023, 0x0120812, 0x0241803, 0x01A92D7, 0x0241803, 0x02FC51B, 0x024CFBA, 0x0499F73, 0x02FC51B, 0x02A4000, 0x0424242, 0x0482011, 0x0212121, 0x02A4000, 0x0213214, 0x01D4D1D, 0x0436858, @@ -687,9 +716,8 @@ static const int32_t qmat2D[MAT_SIZE] = { 0x0E0F081, 0x19F6C92, 0x14FF28E, 0x0B18E41, 0x0A7F947, 0x067DB24, 0x05B0327, 0x0881F39, 0x1103E72, 0x16C0C9A, 0x1267C5C, 0x0D0777D, 0x0499F17, 0x0709582, 0x0E12B04, 0x079B775, -}; - -static const int32_t qmat2E[MAT_SIZE] = { +}, +[QMAT2E] = { 0x0040000, 0x026D64D, 0x0136B27, 0x026DEC9, 0x01C9E22, 0x026DEC9, 0x0250A43, 0x01C8B03, 0x0391606, 0x0250A43, 0x01F8000, 0x0336046, 0x038C2E5, 0x019B023, 0x01F8000, 0x01A1FD6, 0x0170F3E, 0x0331575, @@ -701,9 +729,8 @@ static const int32_t qmat2E[MAT_SIZE] = { 0x0791F0A, 0x06F46F7, 0x05AEBC3, 0x02F888B, 0x02D75E2, 0x01BD1BE, 0x030C3E5, 0x048ECA4, 0x091D948, 0x0C30F95, 0x09DCF81, 0x06FBD20, 0x02773E0, 0x03C9F46, 0x0793E8C, 0x0418A2B, -}; - -static const int32_t qmat2F[MAT_SIZE] = { +}, +[QMAT2F] = { 0x0040000, 0x026D64D, 0x0136B27, 0x026DEC9, 0x01C9E22, 0x026DEC9, 0x03371CF, 0x027A4A1, 0x04F4941, 0x03371CF, 0x02D8000, 0x0475B0C, 0x04DAC61, 0x023AD86, 0x02D8000, 0x023BFC6, 0x01F8E1F, 0x04897C2, @@ -715,9 +742,8 @@ static const int32_t qmat2F[MAT_SIZE] = { 0x0F23E14, 0x1BF613A, 0x169CA23, 0x0BF36BC, 0x0B4E511, 0x06FD84F, 0x0620365, 0x09297C7, 0x1252F8F, 0x1880D93, 0x13D2377, 0x0E080AE, 0x04F48DE, 0x0793E8C, 0x0F27D18, 0x0831457, -}; - -static const int32_t qmat30[MAT_SIZE] = { +}, +[QMAT30] = { 0x0040000, 0x02C62A1, 0x0163151, 0x02C6C53, 0x020B4B9, 0x02C6C53, 0x02A54DF, 0x0209EDF, 0x0413DBE, 0x02A54DF, 0x0240000, 0x03AB72B, 0x040DEBC, 0x01D5B96, 0x0240000, 0x01DDB3E, 0x01A5A90, 0x03A61AB, @@ -729,9 +755,8 @@ static const int32_t qmat30[MAT_SIZE] = { 0x08A6C9E, 0x07F2C88, 0x067E8DF, 0x03652E8, 0x033F46F, 0x01FCB22, 0x037BB4F, 0x0535797, 0x0A6AF2E, 0x0DEED3C, 0x0B45ADD, 0x07FB392, 0x02D16B7, 0x0454850, 0x08A90A0, 0x04AE70D, -}; - -static const int32_t qmat31[MAT_SIZE] = { +}, +[QMAT31] = { 0x0040000, 0x02C62A1, 0x0163151, 0x02C6C53, 0x020B4B9, 0x02C6C53, 0x03ACB35, 0x02D4E6E, 0x05A9CDD, 0x03ACB35, 0x0340000, 0x0518CA0, 0x058C501, 0x028C650, 0x0340000, 0x028DB2C, 0x0241023, 0x052F694, @@ -743,9 +768,8 @@ static const int32_t qmat31[MAT_SIZE] = { 0x114D93C, 0x1FF4A8C, 0x19D794C, 0x0DA87B2, 0x0CEBCA6, 0x07FD2A3, 0x07003E1, 0x0A788E4, 0x14F11C8, 0x1C00F83, 0x16A71AD, 0x1009310, 0x05A9C6B, 0x08A90A0, 0x1152140, 0x095CE1A, -}; - -static const int32_t qmat32[MAT_SIZE] = { +}, +[QMAT32] = { 0x0040000, 0x031EEF6, 0x018F77B, 0x031F9DD, 0x024CB50, 0x031F9DD, 0x02F9F7A, 0x024B2BB, 0x0496575, 0x02F9F7A, 0x0288000, 0x0420E11, 0x048FA94, 0x0210708, 0x0288000, 0x02196A5, 0x01DA5E2, 0x041ADE0, @@ -757,9 +781,8 @@ static const int32_t qmat32[MAT_SIZE] = { 0x09BBA32, 0x08F1219, 0x074E5FB, 0x03D1D45, 0x03A72FD, 0x023C486, 0x03EB2B9, 0x05DC28A, 0x0BB8514, 0x0FACAE4, 0x0CAE638, 0x08FAA04, 0x032B98E, 0x04DF15A, 0x09BE2B4, 0x05443EE, -}; - -static const int32_t qmat33[MAT_SIZE] = { +}, +[QMAT33] = { 0x0040000, 0x031EEF6, 0x018F77B, 0x031F9DD, 0x024CB50, 0x031F9DD, 0x042249C, 0x032F83C, 0x065F078, 0x042249C, 0x03A8000, 0x05BBE34, 0x063DDA2, 0x02DDF1A, 0x03A8000, 0x02DF691, 0x0289228, 0x05D5567, @@ -771,9 +794,8 @@ static const int32_t qmat33[MAT_SIZE] = { 0x1377463, 0x23F33DD, 0x1D12876, 0x0F5D8A9, 0x0E8943B, 0x08FCCF7, 0x07E045D, 0x0BC7A00, 0x178F401, 0x1F81173, 0x197BFE2, 0x120A572, 0x065EFF9, 0x09BE2B4, 0x137C568, 0x0A887DD, -}; - -static const int32_t qmat34[MAT_SIZE] = { +}, +[QMAT34] = { 0x0040000, 0x0377B4A, 0x01BBDA5, 0x0378768, 0x028E1E8, 0x0378768, 0x034EA16, 0x028C697, 0x0518D2D, 0x034EA16, 0x02D0000, 0x04964F6, 0x051166B, 0x024B27B, 0x02D0000, 0x025520D, 0x020F134, 0x048FA15, @@ -785,9 +807,8 @@ static const int32_t qmat34[MAT_SIZE] = { 0x0AD07C5, 0x09EF7AA, 0x081E317, 0x043E7A2, 0x040F18B, 0x027BDEB, 0x045AA23, 0x0682D7D, 0x0D05AFA, 0x116A88B, 0x0E17194, 0x09FA076, 0x0385C65, 0x0569A64, 0x0AD34C8, 0x05DA0D0, -}; - -static const int32_t qmat35[MAT_SIZE] = { +}, +[QMAT35] = { 0x0040000, 0x0377B4A, 0x01BBDA5, 0x0378768, 0x028E1E8, 0x0378768, 0x0497E02, 0x038A20A, 0x0714414, 0x0497E02, 0x0410000, 0x065EFC8, 0x06EF642, 0x032F7E4, 0x0410000, 0x03311F7, 0x02D142C, 0x067B439, @@ -799,9 +820,8 @@ static const int32_t qmat35[MAT_SIZE] = { 0x15A0F8B, 0x27F1D2F, 0x204D79F, 0x111299F, 0x1026BD0, 0x09FC74C, 0x08C04D9, 0x0D16B1D, 0x1A2D63A, 0x2301364, 0x1C50E18, 0x140B7D4, 0x0714386, 0x0AD34C8, 0x15A6990, 0x0BB41A0, -}; - -static const int32_t qmat36[MAT_SIZE] = { +}, +[QMAT36] = { 0x0040000, 0x03D079E, 0x01E83CF, 0x03D14F2, 0x02CF87F, 0x03D14F2, 0x03A34B2, 0x02CDA72, 0x059B4E5, 0x03A34B2, 0x0318000, 0x050BBDC, 0x0593243, 0x0285DEE, 0x0318000, 0x0290D75, 0x0243C86, 0x050464B, @@ -813,9 +833,8 @@ static const int32_t qmat36[MAT_SIZE] = { 0x0BE5559, 0x0AEDD3B, 0x08EE032, 0x04AB1FF, 0x0477019, 0x02BB74F, 0x04CA18D, 0x0729870, 0x0E530E0, 0x1328633, 0x0F7FCEF, 0x0AF96E8, 0x03DFF3C, 0x05F436E, 0x0BE86DC, 0x066FDB2, -}; - -static const int32_t qmat37[MAT_SIZE] = { +}, +[QMAT37] = { 0x0040000, 0x03D079E, 0x01E83CF, 0x03D14F2, 0x02CF87F, 0x03D14F2, 0x050D769, 0x03E4BD8, 0x07C97B0, 0x050D769, 0x0478000, 0x070215C, 0x07A0EE2, 0x03810AE, 0x0478000, 0x0382D5C, 0x0319630, 0x072130C, @@ -827,9 +846,8 @@ static const int32_t qmat37[MAT_SIZE] = { 0x17CAAB2, 0x2BF0680, 0x23886C9, 0x12C7A95, 0x11C4364, 0x0AFC1A0, 0x09A0555, 0x0E65C39, 0x1CCB873, 0x2681554, 0x1F25C4D, 0x160CA36, 0x07C9713, 0x0BE86DC, 0x17D0DB8, 0x0CDFB63, -}; - -static const int32_t qmat38[MAT_SIZE] = { +}, +[QMAT38] = { 0x0040000, 0x04293F2, 0x02149F9, 0x042A27C, 0x0310F16, 0x042A27C, 0x03F7F4E, 0x030EE4E, 0x061DC9D, 0x03F7F4E, 0x0360000, 0x05812C1, 0x0614E1A, 0x02C0961, 0x0360000, 0x02CC8DC, 0x02787D8, 0x0579280, @@ -841,9 +859,8 @@ static const int32_t qmat38[MAT_SIZE] = { 0x0CFA2ED, 0x0BEC2CC, 0x09BDD4E, 0x0517C5D, 0x04DEEA7, 0x02FB0B3, 0x05398F7, 0x07D0363, 0x0FA06C5, 0x14E63DA, 0x10E884B, 0x0BF8D5B, 0x043A213, 0x067EC78, 0x0CFD8F0, 0x0705A93, -}; - -static const int32_t qmat39[MAT_SIZE] = { +}, +[QMAT39] = { 0x0040000, 0x04293F2, 0x02149F9, 0x042A27C, 0x0310F16, 0x042A27C, 0x05830D0, 0x043F5A6, 0x087EB4B, 0x05830D0, 0x04E0000, 0x07A52F0, 0x0852782, 0x03D2978, 0x04E0000, 0x03D48C2, 0x0361835, 0x07C71DE, @@ -855,9 +872,8 @@ static const int32_t qmat39[MAT_SIZE] = { 0x19F45DA, 0x2FEEFD2, 0x26C35F2, 0x147CB8C, 0x1361AF9, 0x0BFBBF4, 0x0A805D1, 0x0FB4D56, 0x1F69AAC, 0x2A01744, 0x21FAA83, 0x180DC98, 0x087EAA1, 0x0CFD8F0, 0x19FB1E0, 0x0E0B527, -}; - -static const int32_t qmat3A[MAT_SIZE] = { +}, +[QMAT3A] = { 0x0040000, 0x0482046, 0x0241023, 0x0483007, 0x03525AD, 0x0483007, 0x044C9EA, 0x035022A, 0x06A0454, 0x044C9EA, 0x03A8000, 0x05F69A7, 0x06969F2, 0x02FB4D3, 0x03A8000, 0x0308444, 0x02AD32A, 0x05EDEB5, @@ -869,9 +885,8 @@ static const int32_t qmat3A[MAT_SIZE] = { 0x0E0F081, 0x0CEA85D, 0x0A8DA6A, 0x05846BA, 0x0546D35, 0x033AA17, 0x05A9060, 0x0876E56, 0x10EDCAB, 0x16A4182, 0x12513A7, 0x0CF83CD, 0x04944EA, 0x0709582, 0x0E12B04, 0x079B775, -}; - -static const int32_t qmat3B[MAT_SIZE] = { +}, +[QMAT3B] = { 0x0040000, 0x0482046, 0x0241023, 0x0483007, 0x03525AD, 0x0483007, 0x05F8A36, 0x0499F73, 0x0933EE7, 0x05F8A36, 0x0548000, 0x0848484, 0x0904022, 0x0424242, 0x0548000, 0x0426427, 0x03A9A39, 0x086D0B1, @@ -883,9 +898,8 @@ static const int32_t qmat3B[MAT_SIZE] = { 0x1C1E101, 0x33ED923, 0x29FE51C, 0x1631C82, 0x14FF28E, 0x0CFB649, 0x0B6064D, 0x1103E72, 0x2207CE5, 0x2D81935, 0x24CF8B9, 0x1A0EEFA, 0x0933E2E, 0x0E12B04, 0x1C25608, 0x0F36EEA, -}; - -static const int32_t qmat3C[MAT_SIZE] = { +}, +[QMAT3C] = { 0x0040000, 0x04DAC9A, 0x026D64D, 0x04DBD91, 0x0393C44, 0x04DBD91, 0x04A1486, 0x0391606, 0x0722C0C, 0x04A1486, 0x03F0000, 0x066C08C, 0x07185C9, 0x0336046, 0x03F0000, 0x0343FAC, 0x02E1E7C, 0x0662AEB, @@ -897,9 +911,8 @@ static const int32_t qmat3C[MAT_SIZE] = { 0x0F23E14, 0x0DE8DEE, 0x0B5D786, 0x05F1117, 0x05AEBC3, 0x037A37C, 0x06187CA, 0x091D948, 0x123B291, 0x1861F29, 0x13B9F02, 0x0DF7A3F, 0x04EE7C1, 0x0793E8C, 0x0F27D18, 0x0831457, -}; - -static const int32_t qmat3D[MAT_SIZE] = { +}, +[QMAT3D] = { 0x0040000, 0x04DAC9A, 0x026D64D, 0x04DBD91, 0x0393C44, 0x04DBD91, 0x066E39D, 0x04F4941, 0x09E9282, 0x066E39D, 0x05B0000, 0x08EB618, 0x09B58C2, 0x0475B0C, 0x05B0000, 0x0477F8D, 0x03F1C3D, 0x0912F83, @@ -911,9 +924,8 @@ static const int32_t qmat3D[MAT_SIZE] = { 0x1E47C29, 0x37EC275, 0x2D39446, 0x17E6D78, 0x169CA23, 0x0DFB09D, 0x0C406C9, 0x1252F8F, 0x24A5F1E, 0x3101B25, 0x27A46EE, 0x1C1015C, 0x09E91BC, 0x0F27D18, 0x1E4FA30, 0x10628AD, -}; - -static const int32_t qmat3E[MAT_SIZE] = { +}, +[QMAT3E] = { 0x0040000, 0x058C543, 0x02C62A1, 0x058D8A6, 0x0416973, 0x058D8A6, 0x054A9BD, 0x0413DBE, 0x0827B7B, 0x054A9BD, 0x0480000, 0x0756E57, 0x081BD78, 0x03AB72B, 0x0480000, 0x03BB67B, 0x034B520, 0x074C355, @@ -925,9 +937,8 @@ static const int32_t qmat3E[MAT_SIZE] = { 0x114D93C, 0x0FE5910, 0x0CFD1BE, 0x06CA5D1, 0x067E8DF, 0x03F9644, 0x06F769E, 0x0A6AF2E, 0x14D5E5C, 0x1BDDA78, 0x168B5B9, 0x0FF6724, 0x05A2D6E, 0x08A90A0, 0x1152140, 0x095CE1A, -}; - -static const int32_t qmat3F[MAT_SIZE] = { +}, +[QMAT3F] = { 0x0040000, 0x058C543, 0x02C62A1, 0x058D8A6, 0x0416973, 0x058D8A6, 0x075966A, 0x05A9CDD, 0x0B539BA, 0x075966A, 0x0680000, 0x0A31940, 0x0B18A03, 0x0518CA0, 0x0680000, 0x051B658, 0x0482046, 0x0A5ED28, @@ -939,9 +950,8 @@ static const int32_t qmat3F[MAT_SIZE] = { 0x229B278, 0x3FE9518, 0x33AF299, 0x1B50F65, 0x19D794C, 0x0FFA546, 0x0E007C1, 0x14F11C8, 0x29E2390, 0x3801F06, 0x2D4E359, 0x2012620, 0x0B538D6, 0x1152140, 0x22A4280, 0x12B9C33, -}; - -static const int32_t qmat40[MAT_SIZE] = { +}, +[QMAT40] = { 0x0040000, 0x063DDEB, 0x031EEF6, 0x063F3BB, 0x04996A1, 0x063F3BB, 0x05F3EF5, 0x0496575, 0x092CAEB, 0x05F3EF5, 0x0510000, 0x0841C22, 0x091F527, 0x0420E11, 0x0510000, 0x0432D4B, 0x03B4BC4, 0x0835BC0, @@ -953,9 +963,8 @@ static const int32_t qmat40[MAT_SIZE] = { 0x1377463, 0x11E2432, 0x0E9CBF6, 0x07A3A8B, 0x074E5FB, 0x047890D, 0x07D6572, 0x0BB8514, 0x1770A28, 0x1F595C7, 0x195CC70, 0x11F5408, 0x065731C, 0x09BE2B4, 0x137C568, 0x0A887DD, -}; - -static const int32_t qmat41[MAT_SIZE] = { +}, +[QMAT41] = { 0x0040000, 0x063DDEB, 0x031EEF6, 0x063F3BB, 0x04996A1, 0x063F3BB, 0x0844938, 0x065F078, 0x0CBE0F1, 0x0844938, 0x0750000, 0x0B77C68, 0x0C7BB43, 0x05BBE34, 0x0750000, 0x05BED23, 0x051244F, 0x0BAAACD, @@ -967,9 +976,8 @@ static const int32_t qmat41[MAT_SIZE] = { 0x26EE8C7, 0x47E67BB, 0x3A250EC, 0x1EBB151, 0x1D12876, 0x11F99EF, 0x0FC08BA, 0x178F401, 0x2F1E802, 0x3F022E7, 0x32F7FC4, 0x2414AE4, 0x0CBDFF1, 0x137C568, 0x26F8AD0, 0x1510FBA, -}; - -static const int32_t qmat42[MAT_SIZE] = { +}, +[QMAT42] = { 0x0040000, 0x06EF693, 0x0377B4A, 0x06F0ECF, 0x051C3CF, 0x06F0ECF, 0x069D42D, 0x0518D2D, 0x0A31A5A, 0x069D42D, 0x05A0000, 0x092C9ED, 0x0A22CD6, 0x04964F6, 0x05A0000, 0x04AA41A, 0x041E268, 0x091F42B, @@ -981,9 +989,8 @@ static const int32_t qmat42[MAT_SIZE] = { 0x15A0F8B, 0x13DEF54, 0x103C62D, 0x087CF45, 0x081E317, 0x04F7BD5, 0x08B5446, 0x0D05AFA, 0x1A0B5F3, 0x22D5116, 0x1C2E328, 0x13F40EC, 0x070B8CA, 0x0AD34C8, 0x15A6990, 0x0BB41A0, -}; - -static const int32_t qmat43[MAT_SIZE] = { +}, +[QMAT43] = { 0x0040000, 0x06EF693, 0x0377B4A, 0x06F0ECF, 0x051C3CF, 0x06F0ECF, 0x092FC05, 0x0714414, 0x0E28828, 0x092FC05, 0x0820000, 0x0CBDF90, 0x0DDEC84, 0x065EFC8, 0x0820000, 0x06623EE, 0x05A2858, 0x0CF6872, @@ -995,9 +1002,8 @@ static const int32_t qmat43[MAT_SIZE] = { 0x2B41F16, 0x4FE3A5E, 0x409AF3F, 0x222533E, 0x204D79F, 0x13F8E97, 0x11809B2, 0x1A2D63A, 0x345AC74, 0x46026C7, 0x38A1C30, 0x2816FA7, 0x0E2870C, 0x15A6990, 0x2B4D320, 0x1768340, -}; - -static const int32_t qmat44[MAT_SIZE] = { +}, +[QMAT44] = { 0x0040000, 0x07A0F3C, 0x03D079E, 0x07A29E4, 0x059F0FE, 0x07A29E4, 0x0746964, 0x059B4E5, 0x0B369CA, 0x0746964, 0x0630000, 0x0A177B8, 0x0B26485, 0x050BBDC, 0x0630000, 0x0521AE9, 0x048790C, 0x0A08C95, @@ -1009,9 +1015,8 @@ static const int32_t qmat44[MAT_SIZE] = { 0x17CAAB2, 0x15DBA76, 0x11DC065, 0x09563FF, 0x08EE032, 0x0576E9E, 0x0994319, 0x0E530E0, 0x1CA61BF, 0x2650C65, 0x1EFF9DF, 0x15F2DD1, 0x07BFE78, 0x0BE86DC, 0x17D0DB8, 0x0CDFB63, -}; - -static const int32_t qmat45[MAT_SIZE] = { +}, +[QMAT45] = { 0x0040000, 0x07A0F3C, 0x03D079E, 0x07A29E4, 0x059F0FE, 0x07A29E4, 0x0A1AED2, 0x07C97B0, 0x0F92F5F, 0x0A1AED2, 0x08F0000, 0x0E042B8, 0x0F41DC4, 0x070215C, 0x08F0000, 0x0705AB9, 0x0632C61, 0x0E42617, @@ -1023,9 +1028,8 @@ static const int32_t qmat45[MAT_SIZE] = { 0x2F95565, 0x57E0D01, 0x4710D92, 0x258F52A, 0x23886C9, 0x15F8340, 0x1340AAA, 0x1CCB873, 0x39970E6, 0x4D02AA8, 0x3E4B89B, 0x2C1946B, 0x0F92E27, 0x17D0DB8, 0x2FA1B6F, 0x19BF6C7, -}; - -static const int32_t qmat46[MAT_SIZE] = { +}, +[QMAT46] = { 0x0040000, 0x08527E4, 0x04293F2, 0x08544F9, 0x0621E2C, 0x08544F9, 0x07EFE9C, 0x061DC9D, 0x0C3B939, 0x07EFE9C, 0x06C0000, 0x0B02582, 0x0C29C34, 0x05812C1, 0x06C0000, 0x05991B9, 0x04F0FAF, 0x0AF2500, @@ -1037,9 +1041,8 @@ static const int32_t qmat46[MAT_SIZE] = { 0x19F45DA, 0x17D8598, 0x137BA9D, 0x0A2F8B9, 0x09BDD4E, 0x05F6166, 0x0A731ED, 0x0FA06C5, 0x1F40D8B, 0x29CC7B4, 0x21D1096, 0x17F1AB5, 0x0874425, 0x0CFD8F0, 0x19FB1E0, 0x0E0B527, -}; - -static const int32_t qmat47[MAT_SIZE] = { +}, +[QMAT47] = { 0x0040000, 0x08527E4, 0x04293F2, 0x08544F9, 0x0621E2C, 0x08544F9, 0x0B061A0, 0x087EB4B, 0x10FD696, 0x0B061A0, 0x09C0000, 0x0F4A5E0, 0x10A4F04, 0x07A52F0, 0x09C0000, 0x07A9184, 0x06C3069, 0x0F8E3BC, @@ -1051,9 +1054,8 @@ static const int32_t qmat47[MAT_SIZE] = { 0x33E8BB4, 0x5FDDFA4, 0x4D86BE5, 0x28F9717, 0x26C35F2, 0x17F77E9, 0x1500BA2, 0x1F69AAC, 0x3ED3558, 0x5402E89, 0x43F5506, 0x301B92F, 0x10FD541, 0x19FB1E0, 0x33F63BF, 0x1C16A4D, -}; - -static const int32_t qmat48[MAT_SIZE] = { +}, +[QMAT48] = { 0x0040000, 0x090408D, 0x0482046, 0x090600E, 0x06A4B5A, 0x090600E, 0x08993D3, 0x06A0454, 0x0D408A9, 0x08993D3, 0x0750000, 0x0BED34D, 0x0D2D3E3, 0x05F69A7, 0x0750000, 0x0610888, 0x055A653, 0x0BDBD6A, @@ -1065,9 +1067,8 @@ static const int32_t qmat48[MAT_SIZE] = { 0x1C1E101, 0x19D50BB, 0x151B4D4, 0x0B08D73, 0x0A8DA6A, 0x067542F, 0x0B520C1, 0x10EDCAB, 0x21DB956, 0x2D48303, 0x24A274D, 0x19F079A, 0x09289D3, 0x0E12B04, 0x1C25608, 0x0F36EEA, -}; - -static const int32_t qmat49[MAT_SIZE] = { +}, +[QMAT49] = { 0x0040000, 0x090408D, 0x0482046, 0x090600E, 0x06A4B5A, 0x090600E, 0x0BF146D, 0x0933EE7, 0x1267DCE, 0x0BF146D, 0x0A90000, 0x1090908, 0x1208045, 0x0848484, 0x0A90000, 0x084C84F, 0x0753472, 0x10DA161, @@ -1079,9 +1080,8 @@ static const int32_t qmat49[MAT_SIZE] = { 0x383C203, 0x67DB247, 0x53FCA38, 0x2C63904, 0x29FE51C, 0x19F6C92, 0x16C0C9A, 0x2207CE5, 0x440F9CA, 0x5B0326A, 0x499F171, 0x341DDF3, 0x1267C5C, 0x1C25608, 0x384AC0F, 0x1E6DDD4, -}; - -static const int32_t qmat4A[MAT_SIZE] = { +}, +[QMAT4A] = { 0x0040000, 0x09B5935, 0x04DAC9A, 0x09B7B22, 0x0727888, 0x09B7B22, 0x094290B, 0x0722C0C, 0x0E45818, 0x094290B, 0x07E0000, 0x0CD8118, 0x0E30B92, 0x066C08C, 0x07E0000, 0x0687F58, 0x05C3CF7, 0x0CC55D5, @@ -1093,9 +1093,8 @@ static const int32_t qmat4A[MAT_SIZE] = { 0x1E47C29, 0x1BD1BDD, 0x16BAF0C, 0x0BE222D, 0x0B5D786, 0x06F46F7, 0x0C30F95, 0x123B291, 0x2476522, 0x30C3E52, 0x2773E04, 0x1BEF47E, 0x09DCF81, 0x0F27D18, 0x1E4FA30, 0x10628AD, -}; - -static const int32_t qmat4B[MAT_SIZE] = { +}, +[QMAT4B] = { 0x0040000, 0x09B5935, 0x04DAC9A, 0x09B7B22, 0x0727888, 0x09B7B22, 0x0CDC73A, 0x09E9282, 0x13D2505, 0x0CDC73A, 0x0B60000, 0x11D6C30, 0x136B185, 0x08EB618, 0x0B60000, 0x08EFF19, 0x07E387B, 0x1225F06, @@ -1107,9 +1106,8 @@ static const int32_t qmat4B[MAT_SIZE] = { 0x3C8F852, 0x6FD84EA, 0x5A7288B, 0x2FCDAF0, 0x2D39446, 0x1BF613A, 0x1880D93, 0x24A5F1E, 0x494BE3C, 0x620364A, 0x4F48DDC, 0x38202B7, 0x13D2377, 0x1E4FA30, 0x3C9F45F, 0x20C515A, -}; - -static const int32_t qmat4C[MAT_SIZE] = { +}, +[QMAT4C] = { 0x0040000, 0x1208119, 0x090408D, 0x120C01B, 0x0D496B4, 0x120C01B, 0x11327A7, 0x0D408A9, 0x1A81151, 0x11327A7, 0x0EA0000, 0x17DA69B, 0x1A5A7C7, 0x0BED34D, 0x0EA0000, 0x0C21110, 0x0AB4CA7, 0x17B7AD5, @@ -1121,9 +1119,8 @@ static const int32_t qmat4C[MAT_SIZE] = { 0x383C203, 0x33AA175, 0x2A369A9, 0x1611AE6, 0x151B4D4, 0x0CEA85D, 0x16A4182, 0x21DB956, 0x43B72AC, 0x5A90607, 0x4944E9A, 0x33E0F34, 0x12513A7, 0x1C25608, 0x384AC0F, 0x1E6DDD4, -}; - -static const int32_t qmat4D[MAT_SIZE] = { +}, +[QMAT4D] = { 0x0040000, 0x1208119, 0x090408D, 0x120C01B, 0x0D496B4, 0x120C01B, 0x17E28DA, 0x1267DCE, 0x24CFB9B, 0x17E28DA, 0x1520000, 0x2121210, 0x2410089, 0x1090908, 0x1520000, 0x109909D, 0x0EA68E4, 0x21B42C3, @@ -1135,319 +1132,240 @@ static const int32_t qmat4D[MAT_SIZE] = { 0x7078406, 0xCFB648E, 0xA7F9470, 0x58C7207, 0x53FCA38, 0x33ED923, 0x2D81935, 0x440F9CA, 0x881F394, 0xB6064D3, 0x933E2E2, 0x683BBE7, 0x24CF8B9, 0x384AC0F, 0x709581F, 0x3CDBBA7, +}, }; -static const int32_t *const hq_quants[NUM_HQ_QUANTS][2][4] = { - { { qmat00, qmat02, qmat06, qmat0E }, { qmat01, qmat03, qmat07, qmat0F } }, - { { qmat02, qmat06, qmat0E, qmat16 }, { qmat03, qmat07, qmat0F, qmat17 } }, - { { qmat04, qmat0A, qmat12, qmat1E }, { qmat05, qmat0B, qmat13, qmat1F } }, - { { qmat06, qmat0E, qmat16, qmat22 }, { qmat07, qmat0F, qmat17, qmat23 } }, - { { qmat08, qmat10, qmat1A, qmat26 }, { qmat09, qmat11, qmat1B, qmat27 } }, - { { qmat0A, qmat12, qmat1E, qmat2A }, { qmat0B, qmat13, qmat1F, qmat2B } }, - { { qmat0C, qmat14, qmat20, qmat2E }, { qmat0D, qmat15, qmat21, qmat2F } }, - { { qmat0E, qmat16, qmat22, qmat30 }, { qmat0F, qmat17, qmat23, qmat31 } }, - { { qmat16, qmat22, qmat30, qmat3E }, { qmat17, qmat23, qmat31, qmat3F } }, - { { qmat18, qmat24, qmat32, qmat40 }, { qmat19, qmat25, qmat33, qmat41 } }, - { { qmat1A, qmat26, qmat34, qmat42 }, { qmat1B, qmat27, qmat35, qmat43 } }, - { { qmat1C, qmat28, qmat36, qmat44 }, { qmat1D, qmat29, qmat37, qmat45 } }, - { { qmat1E, qmat2A, qmat38, qmat46 }, { qmat1F, qmat2B, qmat39, qmat47 } }, - { { qmat20, qmat2E, qmat3C, qmat4A }, { qmat21, qmat2F, qmat3D, qmat4B } }, - { { qmat2C, qmat3A, qmat48, qmat4C }, { qmat2D, qmat3B, qmat49, qmat4D } }, - { { qmat3A, qmat48, qmat4C, qmat4C }, { qmat3B, qmat49, qmat4D, qmat4D } }, +static const uint8_t hq_quant_map[NUM_HQ_QUANTS][2][4] = +{ + { { QMAT00, QMAT02, QMAT06, QMAT0E }, { QMAT01, QMAT03, QMAT07, QMAT0F } }, + { { QMAT02, QMAT06, QMAT0E, QMAT16 }, { QMAT03, QMAT07, QMAT0F, QMAT17 } }, + { { QMAT04, QMAT0A, QMAT12, QMAT1E }, { QMAT05, QMAT0B, QMAT13, QMAT1F } }, + { { QMAT06, QMAT0E, QMAT16, QMAT22 }, { QMAT07, QMAT0F, QMAT17, QMAT23 } }, + { { QMAT08, QMAT10, QMAT1A, QMAT26 }, { QMAT09, QMAT11, QMAT1B, QMAT27 } }, + { { QMAT0A, QMAT12, QMAT1E, QMAT2A }, { QMAT0B, QMAT13, QMAT1F, QMAT2B } }, + { { QMAT0C, QMAT14, QMAT20, QMAT2E }, { QMAT0D, QMAT15, QMAT21, QMAT2F } }, + { { QMAT0E, QMAT16, QMAT22, QMAT30 }, { QMAT0F, QMAT17, QMAT23, QMAT31 } }, + { { QMAT16, QMAT22, QMAT30, QMAT3E }, { QMAT17, QMAT23, QMAT31, QMAT3F } }, + { { QMAT18, QMAT24, QMAT32, QMAT40 }, { QMAT19, QMAT25, QMAT33, QMAT41 } }, + { { QMAT1A, QMAT26, QMAT34, QMAT42 }, { QMAT1B, QMAT27, QMAT35, QMAT43 } }, + { { QMAT1C, QMAT28, QMAT36, QMAT44 }, { QMAT1D, QMAT29, QMAT37, QMAT45 } }, + { { QMAT1E, QMAT2A, QMAT38, QMAT46 }, { QMAT1F, QMAT2B, QMAT39, QMAT47 } }, + { { QMAT20, QMAT2E, QMAT3C, QMAT4A }, { QMAT21, QMAT2F, QMAT3D, QMAT4B } }, + { { QMAT2C, QMAT3A, QMAT48, QMAT4C }, { QMAT2D, QMAT3B, QMAT49, QMAT4D } }, + { { QMAT3A, QMAT48, QMAT4C, QMAT4C }, { QMAT3B, QMAT49, QMAT4D, QMAT4D } }, }; -static const uint8_t hq_ac_bits[NUM_HQ_AC_ENTRIES] = { - 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 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, 8, 8, 8, 8, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 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, 10, 10, 10, 10, 10, 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, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +#define HQ_AC_INVALID_RUN 0 + +#define E(level, skip) ((level * (1 << 7)) | (skip + 1)) +// The invalid entry has length 16 and is mapped to an invalid run. +#define INVALID_ENT HQ_AC_INVALID_RUN +#define INV 16 + +static const int16_t hq_ac_sym[NUM_HQ_AC_ENTRIES] = { + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 0, 64), + E( 1, 1), E( -1, 1), E( 3, 0), E( -3, 0), E( 4, 0), + E( -4, 0), E( 1, 2), E( -1, 2), E( 2, 1), E( -2, 1), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 1, 5), E( -1, 5), E( 1, 6), + E( -1, 6), E( 2, 2), E( -2, 2), E( 3, 1), E( -3, 1), + E( 4, 1), E( -4, 1), E( 9, 0), E( -9, 0), E( 10, 0), + E( -10, 0), E( 11, 0), E( -11, 0), E( 1, 7), E( -1, 7), + E( 1, 8), E( -1, 8), E( 1, 9), E( -1, 9), E( 1, 10), + E( -1, 10), E( 2, 3), E( -2, 3), E( 2, 4), E( -2, 4), + E( 3, 2), E( -3, 2), E( 5, 1), E( -5, 1), E( 6, 1), + E( -6, 1), E( 7, 1), E( -7, 1), E( 12, 0), E( -12, 0), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 1, 11), E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), + E( -1, 13), E( 1, 14), E( -1, 14), E( 2, 5), E( -2, 5), + E( 2, 6), E( -2, 6), E( 3, 3), E( -3, 3), E( 3, 4), + E( -3, 4), E( 4, 2), E( -4, 2), E( 5, 2), E( -5, 2), + E( 8, 1), E( -8, 1), E( 18, 0), E( -18, 0), E( 19, 0), + E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), + E( 22, 0), E( -22, 0), E( 3, 5), E( -3, 5), E( 4, 3), + E( -4, 3), E( 5, 3), E( -5, 3), E( 6, 2), E( -6, 2), + E( 9, 1), E( -9, 1), E( 10, 1), E( -10, 1), E( 11, 1), + E( -11, 1), E( 0, 0), E( 0, 1), E( 3, 6), E( -3, 6), + E( 4, 4), E( -4, 4), E( 6, 3), E( -6, 3), E( 12, 1), + E( -12, 1), E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), + E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), E( 2, 7), + E( -2, 7), E( 2, 8), E( -2, 8), E( 2, 9), E( -2, 9), + E( 2, 10), E( -2, 10), E( 3, 7), E( -3, 7), E( 3, 8), + E( -3, 8), E( 5, 4), E( -5, 4), E( 7, 3), E( -7, 3), + E( 7, 2), E( -7, 2), E( 8, 2), E( -8, 2), E( 9, 2), + E( -9, 2), E( 10, 2), E( -10, 2), E( 11, 2), E( -11, 2), + E( 15, 1), E( -15, 1), E( 16, 1), E( -16, 1), E( 17, 1), + E( -17, 1), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 0, 0), INVALID_ENT, E( 1, 0), E( -1, 0), E( 2, 0), + E( -2, 0), E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 10, 0), E( -10, 0), E( 11, 0), E( -11, 0), E( 12, 0), + E( -12, 0), E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), + E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), + E( -17, 0), E( 18, 0), E( -18, 0), E( 19, 0), E( -19, 0), + E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), + E( -22, 0), E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), + E( 25, 0), E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), + E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), + E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), + E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), E( -34, 0), + E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), + E( -37, 0), E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), + E( 40, 0), E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), + E( -42, 0), E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), + E( 45, 0), E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), + E( -47, 0), E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), + E( 50, 0), E( -50, 0), E( 51, 0), E( -51, 0), E( 52, 0), + E( -52, 0), E( 53, 0), E( -53, 0), E( 54, 0), E( -54, 0), + E( 55, 0), E( -55, 0), E( 56, 0), E( -56, 0), E( 57, 0), + E( -57, 0), E( 58, 0), E( -58, 0), E( 59, 0), E( -59, 0), + E( 60, 0), E( -60, 0), E( 61, 0), E( -61, 0), E( 62, 0), + E( -62, 0), E( 63, 0), E( -63, 0), E( 64, 0), E( -64, 0), + E( 65, 0), E( -65, 0), E( 66, 0), E( -66, 0), E( 67, 0), + E( -67, 0), E( 68, 0), E( -68, 0), E( 69, 0), E( -69, 0), + E( 70, 0), E( -70, 0), E( 71, 0), E( -71, 0), E( 72, 0), + E( -72, 0), E( 73, 0), E( -73, 0), E( 74, 0), E( -74, 0), + E( 75, 0), E( -75, 0), E( 76, 0), E( -76, 0), E( 77, 0), + E( -77, 0), E( 78, 0), E( -78, 0), E( 79, 0), E( -79, 0), + E( 80, 0), E( -80, 0), E( 81, 0), E( -81, 0), E( 82, 0), + E( -82, 0), E( 83, 0), E( -83, 0), E( 84, 0), E( -84, 0), + E( 85, 0), E( -85, 0), E( 86, 0), E( -86, 0), E( 87, 0), + E( -87, 0), E( 88, 0), E( -88, 0), E( 89, 0), E( -89, 0), + E( 90, 0), E( -90, 0), E( 91, 0), E( -91, 0), E( 92, 0), + E( -92, 0), E( 93, 0), E( -93, 0), E( 94, 0), E( -94, 0), + E( 95, 0), E( -95, 0), E( 96, 0), E( -96, 0), E( 97, 0), + E( -97, 0), E( 98, 0), E( -98, 0), E( 99, 0), E( -99, 0), + E( 100, 0), E(-100, 0), E( 101, 0), E(-101, 0), E( 102, 0), + E(-102, 0), E( 103, 0), E(-103, 0), E( 104, 0), E(-104, 0), + E( 105, 0), E(-105, 0), E( 106, 0), E(-106, 0), E( 107, 0), + E(-107, 0), E( 108, 0), E(-108, 0), E( 109, 0), E(-109, 0), + E( 110, 0), E(-110, 0), E( 111, 0), E(-111, 0), E( 112, 0), + E(-112, 0), E( 113, 0), E(-113, 0), E( 114, 0), E(-114, 0), + E( 115, 0), E(-115, 0), E( 116, 0), E(-116, 0), E( 117, 0), + E(-117, 0), E( 118, 0), E(-118, 0), E( 119, 0), E(-119, 0), + E( 120, 0), E(-120, 0), E( 121, 0), E(-121, 0), E( 122, 0), + E(-122, 0), E( 123, 0), E(-123, 0), E( 124, 0), E(-124, 0), + E( 125, 0), E(-125, 0), E( 126, 0), E(-126, 0), E( 127, 0), + E(-127, 0), E( 128, 0), E(-128, 0), E( 129, 0), E(-129, 0), + E( 130, 0), E(-130, 0), E( 131, 0), E(-131, 0), E( 132, 0), + E(-132, 0), E( 133, 0), E(-133, 0), E( 134, 0), E(-134, 0), + E( 135, 0), E(-135, 0), E( 136, 0), E(-136, 0), E( 137, 0), + E(-137, 0), E( 138, 0), E(-138, 0), E( 139, 0), E(-139, 0), + E( 140, 0), E(-140, 0), E( 141, 0), E(-141, 0), E( 142, 0), + E(-142, 0), E( 143, 0), E(-143, 0), E( 144, 0), E(-144, 0), + E( 145, 0), E(-145, 0), E( 146, 0), E(-146, 0), E( 147, 0), + E(-147, 0), E( 148, 0), E(-148, 0), E( 149, 0), E(-149, 0), + E( 150, 0), E(-150, 0), E( 151, 0), E(-151, 0), E( 152, 0), + E(-152, 0), E( 153, 0), E(-153, 0), E( 154, 0), E(-154, 0), + E( 155, 0), E(-155, 0), E( 156, 0), E(-156, 0), E( 157, 0), + E(-157, 0), E( 158, 0), E(-158, 0), E( 159, 0), E(-159, 0), + E( 160, 0), E(-160, 0), E( 161, 0), E(-161, 0), E( 162, 0), + E(-162, 0), E( 163, 0), E(-163, 0), E( 164, 0), E(-164, 0), + E( 165, 0), E(-165, 0), E( 166, 0), E(-166, 0), E( 167, 0), + E(-167, 0), E( 168, 0), E(-168, 0), E( 169, 0), E(-169, 0), + E( 170, 0), E(-170, 0), E( 171, 0), E(-171, 0), E( 172, 0), + E(-172, 0), E( 173, 0), E(-173, 0), E( 174, 0), E(-174, 0), + E( 175, 0), E(-175, 0), E( 176, 0), E(-176, 0), E( 177, 0), + E(-177, 0), E( 178, 0), E(-178, 0), E( 179, 0), E(-179, 0), + E( 180, 0), E(-180, 0), E( 181, 0), E(-181, 0), E( 182, 0), + E(-182, 0), E( 183, 0), E(-183, 0), E( 184, 0), E(-184, 0), + E( 185, 0), E(-185, 0), E( 186, 0), E(-186, 0), E( 187, 0), + E(-187, 0), E( 188, 0), E(-188, 0), E( 189, 0), E(-189, 0), + E( 190, 0), E(-190, 0), E( 191, 0), E(-191, 0), E( 192, 0), + E(-192, 0), E( 193, 0), E(-193, 0), E( 194, 0), E(-194, 0), + E( 195, 0), E(-195, 0), E( 196, 0), E(-196, 0), E( 197, 0), + E(-197, 0), E( 198, 0), E(-198, 0), E( 199, 0), E(-199, 0), + E( 200, 0), E(-200, 0), E( 201, 0), E(-201, 0), E( 202, 0), + E(-202, 0), E( 203, 0), E(-203, 0), E( 204, 0), E(-204, 0), + E( 205, 0), E(-205, 0), E( 206, 0), E(-206, 0), E( 207, 0), + E(-207, 0), E( 208, 0), E(-208, 0), E( 209, 0), E(-209, 0), + E( 210, 0), E(-210, 0), E( 211, 0), E(-211, 0), E( 212, 0), + E(-212, 0), E( 213, 0), E(-213, 0), E( 214, 0), E(-214, 0), + E( 215, 0), E(-215, 0), E( 216, 0), E(-216, 0), E( 217, 0), + E(-217, 0), E( 218, 0), E(-218, 0), E( 219, 0), E(-219, 0), + E( 220, 0), E(-220, 0), E( 221, 0), E(-221, 0), E( 222, 0), + E(-222, 0), E( 223, 0), E(-223, 0), E( 224, 0), E(-224, 0), + E( 225, 0), E(-225, 0), E( 226, 0), E(-226, 0), E( 227, 0), + E(-227, 0), E( 228, 0), E(-228, 0), E( 229, 0), E(-229, 0), + E( 230, 0), E(-230, 0), E( 231, 0), E(-231, 0), E( 232, 0), + E(-232, 0), E( 233, 0), E(-233, 0), E( 234, 0), E(-234, 0), + E( 235, 0), E(-235, 0), E( 236, 0), E(-236, 0), E( 237, 0), + E(-237, 0), E( 238, 0), E(-238, 0), E( 239, 0), E(-239, 0), + E( 240, 0), E(-240, 0), E( 241, 0), E(-241, 0), E( 242, 0), + E(-242, 0), E( 243, 0), E(-243, 0), E( 244, 0), E(-244, 0), + E( 245, 0), E(-245, 0), E( 246, 0), E(-246, 0), E( 247, 0), + E(-247, 0), E( 248, 0), E(-248, 0), E( 249, 0), E(-249, 0), + E( 250, 0), E(-250, 0), E( 251, 0), E(-251, 0), E( 252, 0), + E(-252, 0), E( 253, 0), E(-253, 0), E( 254, 0), E(-254, 0), + E( 255, 0), E(-255, 0), }; -static const uint16_t hq_ac_codes[NUM_HQ_AC_ENTRIES] = { - 0x0000, 0x0001, 0x0004, 0x0005, 0x0006, 0x000E, 0x000F, 0x0010, - 0x0011, 0x0012, 0x0013, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, - 0x002D, 0x002E, 0x002F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, - 0x0065, 0x0066, 0x0067, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, - 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, - 0x00DD, 0x00DE, 0x00DF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, - 0x01C5, 0x01C6, 0x01C7, 0x01C8, 0x01C9, 0x01CA, 0x01CB, 0x01CC, - 0x01CD, 0x01CE, 0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, - 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, - 0x01DD, 0x01DE, 0x01DF, 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, - 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, - 0x03CD, 0x03CE, 0x03CF, 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, - 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, - 0x03DD, 0x03DE, 0x03DF, 0x07C0, 0x07C1, 0x07C2, 0x07C3, 0x07C4, - 0x07C5, 0x07C6, 0x07C7, 0x07C8, 0x07C9, 0x07CA, 0x07CB, 0x07CC, - 0x07CD, 0x07CE, 0x07CF, 0x0FA0, 0x0FA1, 0x0FA2, 0x0FA3, 0x0FA4, - 0x0FA5, 0x0FA6, 0x0FA7, 0x0FA8, 0x0FA9, 0x0FAA, 0x0FAB, 0x0FAC, - 0x0FAD, 0x0FAE, 0x0FAF, 0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, - 0x1F65, 0x1F66, 0x1F67, 0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, - 0x1F6D, 0x1F6E, 0x1F6F, 0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, - 0x1F75, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, - 0x1F7D, 0x1F7E, 0x1F7F, 0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, - 0x1F85, 0x1F86, 0x1F87, 0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, - 0x1F8D, 0x1F8E, 0x1F8F, 0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, - 0x1F95, 0x1F96, 0x1F97, 0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, - 0x1F9D, 0x1F9E, 0x1F9F, 0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, - 0x1FA5, 0x1FA6, 0x1FA7, 0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, - 0x1FAD, 0x1FAE, 0x1FAF, 0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, - 0x1FB5, 0x1FB6, 0x1FB7, 0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, - 0x1FBD, 0x1FBE, 0x1FBF, 0xFE00, 0xFE02, 0xFE03, 0xFE04, 0xFE05, - 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, - 0xFE0E, 0xFE0F, 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, - 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, - 0xFE1E, 0xFE1F, 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, - 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, - 0xFE2E, 0xFE2F, 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, - 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, - 0xFE3E, 0xFE3F, 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, - 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, - 0xFE4E, 0xFE4F, 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, - 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, - 0xFE5E, 0xFE5F, 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, - 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, - 0xFE6E, 0xFE6F, 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, - 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, - 0xFE7E, 0xFE7F, 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, - 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, - 0xFE8E, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, - 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, - 0xFE9E, 0xFE9F, 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, - 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, - 0xFEAE, 0xFEAF, 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, - 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, - 0xFEBE, 0xFEBF, 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, - 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, - 0xFECE, 0xFECF, 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, - 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, - 0xFEDE, 0xFEDF, 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, - 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, - 0xFEEE, 0xFEEF, 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, - 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, - 0xFEFE, 0xFEFF, 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, - 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, - 0xFF0E, 0xFF0F, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, - 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, - 0xFF1E, 0xFF1F, 0xFF20, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, - 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, - 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, - 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF3B, 0xFF3C, 0xFF3D, - 0xFF3E, 0xFF3F, 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, - 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, - 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, - 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, - 0xFF5E, 0xFF5F, 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, - 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, - 0xFF6E, 0xFF6F, 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, - 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, - 0xFF7E, 0xFF7F, 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, - 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, - 0xFF8E, 0xFF8F, 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, - 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, - 0xFF9E, 0xFF9F, 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, - 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, - 0xFFAE, 0xFFAF, 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, - 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, - 0xFFBE, 0xFFBF, 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, - 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, - 0xFFCE, 0xFFCF, 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, - 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, - 0xFFDE, 0xFFDF, 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, - 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, - 0xFFEE, 0xFFEF, 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, - 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, - 0xFFFE, 0xFFFF, -}; - -static const uint8_t hq_ac_skips[NUM_HQ_AC_ENTRIES] = { - 0, 0, 0, 0, 64, 1, 1, 0, 0, 0, 0, 2, 2, 1, 1, 0, - 0, 0, 0, 3, 3, 4, 4, 0, 0, 0, 0, 5, 5, 6, 6, 2, - 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 7, 7, 8, 8, 9, - 9, 10, 10, 3, 3, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 12, 12, 13, - 13, 14, 14, 5, 5, 6, 6, 3, 3, 4, 4, 2, 2, 2, 2, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 3, 3, 3, - 3, 2, 2, 1, 1, 1, 1, 1, 1, 0, 1, 6, 6, 4, 4, 3, - 3, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 7, 7, 8, 8, 9, - 9, 10, 10, 7, 7, 8, 8, 4, 4, 3, 3, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 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 const int16_t hq_ac_syms[NUM_HQ_AC_ENTRIES] = { - 1, -1, 2, -2, 0, 1, -1, 3, - -3, 4, -4, 1, -1, 2, -2, 5, - -5, 6, -6, 1, -1, 1, -1, 7, - -7, 8, -8, 1, -1, 1, -1, 2, - -2, 3, -3, 4, -4, 9, -9, 10, - -10, 11, -11, 1, -1, 1, -1, 1, - -1, 1, -1, 2, -2, 2, -2, 3, - -3, 5, -5, 6, -6, 7, -7, 12, - -12, 13, -13, 14, -14, 15, -15, 16, - -16, 17, -17, 1, -1, 1, -1, 1, - -1, 1, -1, 2, -2, 2, -2, 3, - -3, 3, -3, 4, -4, 5, -5, 8, - -8, 18, -18, 19, -19, 20, -20, 21, - -21, 22, -22, 3, -3, 4, -4, 5, - -5, 6, -6, 9, -9, 10, -10, 11, - -11, 0, 0, 3, -3, 4, -4, 6, - -6, 12, -12, 13, -13, 14, -14, 0, - 0, 0, 0, 2, -2, 2, -2, 2, - -2, 2, -2, 3, -3, 3, -3, 5, - -5, 7, -7, 7, -7, 8, -8, 9, - -9, 10, -10, 11, -11, 15, -15, 16, - -16, 17, -17, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, -1, 2, -2, - 3, -3, 4, -4, 5, -5, 6, -6, - 7, -7, 8, -8, 9, -9, 10, -10, - 11, -11, 12, -12, 13, -13, 14, -14, - 15, -15, 16, -16, 17, -17, 18, -18, - 19, -19, 20, -20, 21, -21, 22, -22, - 23, -23, 24, -24, 25, -25, 26, -26, - 27, -27, 28, -28, 29, -29, 30, -30, - 31, -31, 32, -32, 33, -33, 34, -34, - 35, -35, 36, -36, 37, -37, 38, -38, - 39, -39, 40, -40, 41, -41, 42, -42, - 43, -43, 44, -44, 45, -45, 46, -46, - 47, -47, 48, -48, 49, -49, 50, -50, - 51, -51, 52, -52, 53, -53, 54, -54, - 55, -55, 56, -56, 57, -57, 58, -58, - 59, -59, 60, -60, 61, -61, 62, -62, - 63, -63, 64, -64, 65, -65, 66, -66, - 67, -67, 68, -68, 69, -69, 70, -70, - 71, -71, 72, -72, 73, -73, 74, -74, - 75, -75, 76, -76, 77, -77, 78, -78, - 79, -79, 80, -80, 81, -81, 82, -82, - 83, -83, 84, -84, 85, -85, 86, -86, - 87, -87, 88, -88, 89, -89, 90, -90, - 91, -91, 92, -92, 93, -93, 94, -94, - 95, -95, 96, -96, 97, -97, 98, -98, - 99, -99, 100, -100, 101, -101, 102, -102, - 103, -103, 104, -104, 105, -105, 106, -106, - 107, -107, 108, -108, 109, -109, 110, -110, - 111, -111, 112, -112, 113, -113, 114, -114, - 115, -115, 116, -116, 117, -117, 118, -118, - 119, -119, 120, -120, 121, -121, 122, -122, - 123, -123, 124, -124, 125, -125, 126, -126, - 127, -127, 128, -128, 129, -129, 130, -130, - 131, -131, 132, -132, 133, -133, 134, -134, - 135, -135, 136, -136, 137, -137, 138, -138, - 139, -139, 140, -140, 141, -141, 142, -142, - 143, -143, 144, -144, 145, -145, 146, -146, - 147, -147, 148, -148, 149, -149, 150, -150, - 151, -151, 152, -152, 153, -153, 154, -154, - 155, -155, 156, -156, 157, -157, 158, -158, - 159, -159, 160, -160, 161, -161, 162, -162, - 163, -163, 164, -164, 165, -165, 166, -166, - 167, -167, 168, -168, 169, -169, 170, -170, - 171, -171, 172, -172, 173, -173, 174, -174, - 175, -175, 176, -176, 177, -177, 178, -178, - 179, -179, 180, -180, 181, -181, 182, -182, - 183, -183, 184, -184, 185, -185, 186, -186, - 187, -187, 188, -188, 189, -189, 190, -190, - 191, -191, 192, -192, 193, -193, 194, -194, - 195, -195, 196, -196, 197, -197, 198, -198, - 199, -199, 200, -200, 201, -201, 202, -202, - 203, -203, 204, -204, 205, -205, 206, -206, - 207, -207, 208, -208, 209, -209, 210, -210, - 211, -211, 212, -212, 213, -213, 214, -214, - 215, -215, 216, -216, 217, -217, 218, -218, - 219, -219, 220, -220, 221, -221, 222, -222, - 223, -223, 224, -224, 225, -225, 226, -226, - 227, -227, 228, -228, 229, -229, 230, -230, - 231, -231, 232, -232, 233, -233, 234, -234, - 235, -235, 236, -236, 237, -237, 238, -238, - 239, -239, 240, -240, 241, -241, 242, -242, - 243, -243, 244, -244, 245, -245, 246, -246, - 247, -247, 248, -248, 249, -249, 250, -250, - 251, -251, 252, -252, 253, -253, 254, -254, - 255, -255, +static const uint8_t hq_ac_lens[NUM_HQ_AC_ENTRIES] = { + 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 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, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 10, 10, 10, + 10, 10, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 16, INV,16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }; /* tables section - one per supported profile */ diff --git a/libavcodec/hqx.c b/libavcodec/hqx.c index ee6c5a6622..9ec6672580 100644 --- a/libavcodec/hqx.c +++ b/libavcodec/hqx.c @@ -20,17 +20,22 @@ #include +#include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/mem_internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "canopus.h" #include "codec_internal.h" #include "get_bits.h" #include "thread.h" +#include "vlc.h" -#include "hqx.h" #include "hqxdsp.h" +#include "hqxvlc.h" +#include "hq_common.h" /* HQX has four modes - 422, 444, 422alpha and 444alpha - all 12-bit */ enum HQXFormat { @@ -40,23 +45,58 @@ enum HQXFormat { HQX_444A, }; +struct HQXContext; + +typedef int (*mb_decode_func)(struct HQXContext *ctx, + int slice_no, int x, int y); + +typedef struct HQXSlice { + GetBitContext gb; + DECLARE_ALIGNED(16, int16_t, block)[16][64]; +} HQXSlice; + +typedef struct HQXContext { + HQXDSPContext hqxdsp; + HQXSlice slice[16]; + + AVFrame *pic; + mb_decode_func decode_func; + + int format, dcb, width, height; + int interlaced; + + const uint8_t *src; + unsigned int data_size; + uint32_t slice_off[17]; + + const VLCElem *dc_vlc; + + VLC dc11_vlc; +} HQXContext; + #define HQX_HEADER_SIZE 59 +#define AC_IDX(q) ((q) >= 128 ? HQX_AC_Q128 : (q) >= 64 ? HQX_AC_Q64 : \ + (q) >= 32 ? HQX_AC_Q32 : (q) >= 16 ? HQX_AC_Q16 : \ + (q) >= 8 ? HQX_AC_Q8 : HQX_AC_Q0) + /* macroblock selects a group of 4 possible quants and * a block can use any of those four quantisers * one column is powers of 2, the other one is powers of 2 * 3, - * then there is the special one, powers of 2 * 5 */ -static const int hqx_quants[16][4] = { - { 0x1, 0x2, 0x4, 0x8 }, { 0x1, 0x3, 0x6, 0xC }, - { 0x2, 0x4, 0x8, 0x10 }, { 0x3, 0x6, 0xC, 0x18 }, - { 0x4, 0x8, 0x10, 0x20 }, { 0x6, 0xC, 0x18, 0x30 }, - { 0x8, 0x10, 0x20, 0x40 }, - { 0xA, 0x14, 0x28, 0x50 }, - { 0xC, 0x18, 0x30, 0x60 }, - { 0x10, 0x20, 0x40, 0x80 }, { 0x18, 0x30, 0x60, 0xC0 }, - { 0x20, 0x40, 0x80, 0x100 }, { 0x30, 0x60, 0xC0, 0x180 }, - { 0x40, 0x80, 0x100, 0x200 }, { 0x60, 0xC0, 0x180, 0x300 }, - { 0x80, 0x100, 0x200, 0x400 } + * then there is the special one, powers of 2 * 5. + * We also encode the corresponding AC index in these tables in bits 29-31. */ +static const unsigned hqx_quants[16][4] = { +#define Q(q) ((unsigned)AC_IDX(q) << 29 | (q)) + { Q( 0x1), Q( 0x2), Q( 0x4), Q( 0x8) }, { Q( 0x1), Q( 0x3), Q( 0x6), Q( 0xC) }, + { Q( 0x2), Q( 0x4), Q( 0x8), Q( 0x10) }, { Q( 0x3), Q( 0x6), Q( 0xC), Q( 0x18) }, + { Q( 0x4), Q( 0x8), Q( 0x10), Q( 0x20) }, { Q( 0x6), Q( 0xC), Q( 0x18), Q( 0x30) }, + { Q( 0x8), Q( 0x10), Q( 0x20), Q( 0x40) }, + { Q(0xA), Q(0x14), Q(0x28), Q(0x50) }, + { Q( 0xC), Q(0x18), Q( 0x30), Q( 0x60) }, + { Q(0x10), Q( 0x20), Q( 0x40), Q( 0x80) }, { Q(0x18), Q(0x30), Q( 0x60), Q( 0xC0) }, + { Q(0x20), Q( 0x40), Q( 0x80), Q(0x100) }, { Q(0x30), Q(0x60), Q( 0xC0), Q(0x180) }, + { Q(0x40), Q( 0x80), Q(0x100), Q(0x200) }, { Q(0x60), Q(0xC0), Q(0x180), Q(0x300) }, + { Q(0x80), Q(0x100), Q(0x200), Q(0x400) } }; static const uint8_t hqx_quant_luma[64] = { @@ -97,56 +137,43 @@ static inline void put_blocks(HQXContext *ctx, int plane, } static inline void hqx_get_ac(GetBitContext *gb, const HQXAC *ac, - int *run, int *lev) + int *runp, int *lev) { - int val; + int level, run; + OPEN_READER(re, gb); - val = show_bits(gb, ac->lut_bits); - if (ac->lut[val].bits == -1) { - GetBitContext gb2 = *gb; - skip_bits(&gb2, ac->lut_bits); - val = ac->lut[val].lev + show_bits(&gb2, ac->extra_bits); - } - *run = ac->lut[val].run; - *lev = ac->lut[val].lev; - skip_bits(gb, ac->lut[val].bits); + UPDATE_CACHE(re, gb); + GET_RL_VLC(level, run, re, gb, ac->lut, ac->bits, 2, 0); + CLOSE_READER(re, gb); + *runp = run; + *lev = level; } -static int decode_block(GetBitContext *gb, VLC *vlc, - const int *quants, int dcb, +static int decode_block(GetBitContext *gb, const VLCElem vlc[], + const unsigned *quants, int dcb, int16_t block[64], int *last_dc) { - int q, dc; - int ac_idx; - int run, lev, pos = 1; + int run, lev, pos = 0; + unsigned ac_idx, q; + int dc; - memset(block, 0, 64 * sizeof(*block)); - dc = get_vlc2(gb, vlc->table, HQX_DC_VLC_BITS, 2); + dc = get_vlc2(gb, vlc, HQX_DC_VLC_BITS, 2); *last_dc += dc; block[0] = sign_extend(*last_dc << (12 - dcb), 12); q = quants[get_bits(gb, 2)]; - if (q >= 128) - ac_idx = HQX_AC_Q128; - else if (q >= 64) - ac_idx = HQX_AC_Q64; - else if (q >= 32) - ac_idx = HQX_AC_Q32; - else if (q >= 16) - ac_idx = HQX_AC_Q16; - else if (q >= 8) - ac_idx = HQX_AC_Q8; - else - ac_idx = HQX_AC_Q0; + // ac_idx is encoded in the high bits of quants; + // because block is 16 bit, we do not even need to clear said bits. + ac_idx = q >> 29; do { - hqx_get_ac(gb, &ff_hqx_ac[ac_idx], &run, &lev); + hqx_get_ac(gb, &hqx_ac[ac_idx], &run, &lev); pos += run; - if (pos >= 64) + if (pos > 63) break; - block[ff_zigzag_direct[pos++]] = lev * q; - } while (pos < 64); + block[ff_zigzag_direct[pos]] = lev * q; + } while (pos < 63); return 0; } @@ -155,11 +182,13 @@ static int hqx_decode_422(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; + const unsigned *quants; int flag; int last_dc; int i, ret; + memset(slice->block, 0, sizeof(*slice->block) * 8); + if (ctx->interlaced) flag = get_bits1(gb); else @@ -168,10 +197,9 @@ static int hqx_decode_422(HQXContext *ctx, int slice_no, int x, int y) quants = hqx_quants[get_bits(gb, 4)]; for (i = 0; i < 8; i++) { - int vlc_index = ctx->dcb - 9; if (i == 0 || i == 4 || i == 6) last_dc = 0; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -189,25 +217,23 @@ static int hqx_decode_422a(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; int flag = 0; int last_dc; int i, ret; - int cbp; - cbp = get_vlc2(gb, ctx->cbp_vlc.table, HQX_CBP_VLC_BITS, 1); - - for (i = 0; i < 12; i++) - memset(slice->block[i], 0, sizeof(**slice->block) * 64); + memset(slice->block, 0, sizeof(*slice->block) * 12); for (i = 0; i < 12; i++) slice->block[i][0] = -0x800; + + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { + const unsigned *quants; + if (ctx->interlaced) flag = get_bits1(gb); quants = hqx_quants[get_bits(gb, 4)]; - cbp |= cbp << 4; // alpha CBP if (cbp & 0x3) // chroma CBP - top cbp |= 0x500; if (cbp & 0xC) // chroma CBP - bottom @@ -216,8 +242,7 @@ static int hqx_decode_422a(HQXContext *ctx, int slice_no, int x, int y) if (i == 0 || i == 4 || i == 8 || i == 10) last_dc = 0; if (cbp & (1 << i)) { - int vlc_index = ctx->dcb - 9; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -239,11 +264,13 @@ static int hqx_decode_444(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; + const unsigned *quants; int flag; int last_dc; int i, ret; + memset(slice->block, 0, sizeof(*slice->block) * 12); + if (ctx->interlaced) flag = get_bits1(gb); else @@ -252,10 +279,9 @@ static int hqx_decode_444(HQXContext *ctx, int slice_no, int x, int y) quants = hqx_quants[get_bits(gb, 4)]; for (i = 0; i < 12; i++) { - int vlc_index = ctx->dcb - 9; - if (i == 0 || i == 4 || i == 8) + if (!(i & 3)) last_dc = 0; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -275,32 +301,29 @@ static int hqx_decode_444a(HQXContext *ctx, int slice_no, int x, int y) { HQXSlice *slice = &ctx->slice[slice_no]; GetBitContext *gb = &slice->gb; - const int *quants; int flag = 0; int last_dc; int i, ret; - int cbp; - cbp = get_vlc2(gb, ctx->cbp_vlc.table, HQX_CBP_VLC_BITS, 1); - - for (i = 0; i < 16; i++) - memset(slice->block[i], 0, sizeof(**slice->block) * 64); + memset(slice->block, 0, sizeof(*slice->block) * 16); for (i = 0; i < 16; i++) slice->block[i][0] = -0x800; + + int cbp = get_vlc2(gb, ff_hq_cbp_vlc, HQ_CBP_VLC_BITS, 1); if (cbp) { + const unsigned *quants; + if (ctx->interlaced) flag = get_bits1(gb); quants = hqx_quants[get_bits(gb, 4)]; - cbp |= cbp << 4; // alpha CBP cbp |= cbp << 8; // chroma CBP for (i = 0; i < 16; i++) { - if (i == 0 || i == 4 || i == 8 || i == 12) + if (!(i & 3)) last_dc = 0; if (cbp & (1 << i)) { - int vlc_index = ctx->dcb - 9; - ret = decode_block(gb, &ctx->dc_vlc[vlc_index], quants, + ret = decode_block(gb, ctx->dc_vlc, quants, ctx->dcb, slice->block[i], &last_dc); if (ret < 0) return ret; @@ -406,7 +429,7 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, HQXContext *ctx = avctx->priv_data; const uint8_t *src = avpkt->data; uint32_t info_tag; - int data_start; + int data_start, dcb_code; int i, ret; if (avpkt->size < 4 + 4) { @@ -445,16 +468,18 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, } ctx->interlaced = !(src[2] & 0x80); ctx->format = src[2] & 7; - ctx->dcb = (src[3] & 3) + 8; + dcb_code = src[3] & 3; ctx->width = AV_RB16(src + 4); ctx->height = AV_RB16(src + 6); for (i = 0; i < 17; i++) ctx->slice_off[i] = AV_RB24(src + 8 + i * 3); - if (ctx->dcb == 8) { - av_log(avctx, AV_LOG_ERROR, "Invalid DC precision %d.\n", ctx->dcb); + if (dcb_code == 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid DC precision 8.\n"); return AVERROR_INVALIDDATA; } + ctx->dc_vlc = dcb_code == 3 ? ctx->dc11_vlc.table : dc_vlc[dcb_code - 1]; + ctx->dcb = dcb_code + 8; ret = av_image_check_size(ctx->width, ctx->height, 0, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid stored dimensions %dx%d.\n", @@ -511,24 +536,28 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, static av_cold int hqx_decode_close(AVCodecContext *avctx) { - int i; HQXContext *ctx = avctx->priv_data; - ff_vlc_free(&ctx->cbp_vlc); - for (i = 0; i < 3; i++) { - ff_vlc_free(&ctx->dc_vlc[i]); - } + ff_vlc_free(&ctx->dc11_vlc); return 0; } static av_cold int hqx_decode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; HQXContext *ctx = avctx->priv_data; + int ret = vlc_init(&ctx->dc11_vlc, HQX_DC_VLC_BITS, FF_ARRAY_ELEMS(dc11_vlc_lens), + dc11_vlc_lens, 1, 1, dc11_vlc_bits, 2, 2, 0); + + if (ret < 0) + return ret; ff_hqxdsp_init(&ctx->hqxdsp); - return ff_hqx_init_vlcs(ctx); + ff_thread_once(&init_static_once, hqx_init_static); + + return 0; } const FFCodec ff_hqx_decoder = { diff --git a/libavcodec/hqx.h b/libavcodec/hqx.h deleted file mode 100644 index 155ec7f84f..0000000000 --- a/libavcodec/hqx.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Canopus HQX decoder - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_HQX_H -#define AVCODEC_HQX_H - -#include - -#include "libavutil/frame.h" -#include "libavutil/mem_internal.h" - -#include "get_bits.h" -#include "hqxdsp.h" - -enum HQXACMode { - HQX_AC_Q0 = 0, - HQX_AC_Q8, - HQX_AC_Q16, - HQX_AC_Q32, - HQX_AC_Q64, - HQX_AC_Q128, - NUM_HQX_AC -}; - -typedef struct HQXLUT { - int16_t lev; - uint8_t run; - int8_t bits; -} HQXLUT; - -typedef struct HQXAC { - int lut_bits, extra_bits; - const HQXLUT *lut; -} HQXAC; - -struct HQXContext; - -typedef int (*mb_decode_func)(struct HQXContext *ctx, - int slice_no, int x, int y); - -typedef struct HQXSlice { - GetBitContext gb; - DECLARE_ALIGNED(16, int16_t, block)[16][64]; -} HQXSlice; - -typedef struct HQXContext { - HQXDSPContext hqxdsp; - HQXSlice slice[16]; - - AVFrame *pic; - mb_decode_func decode_func; - - int format, dcb, width, height; - int interlaced; - - const uint8_t *src; - unsigned int data_size; - uint32_t slice_off[17]; - - VLC cbp_vlc; - VLC dc_vlc[3]; -} HQXContext; - -#define HQX_CBP_VLC_BITS 5 -#define HQX_DC_VLC_BITS 9 - -extern const HQXAC ff_hqx_ac[NUM_HQX_AC]; - -int ff_hqx_init_vlcs(HQXContext *ctx); - -#endif /* AVCODEC_HQX_H */ diff --git a/libavcodec/hqxvlc.c b/libavcodec/hqxvlc.c deleted file mode 100644 index 1eeda4fcce..0000000000 --- a/libavcodec/hqxvlc.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Canopus HQX decoder - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "hqx.h" - -static const uint8_t cbp_vlc_bits[16] = { - 0x04, 0x1C, 0x1D, 0x09, 0x1E, 0x0B, 0x1B, 0x08, - 0x1F, 0x1A, 0x0C, 0x07, 0x0A, 0x06, 0x05, 0x00, -}; - -static const uint8_t cbp_vlc_lens[16] = { - 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 4, 4, 4, 2, -}; - -static const uint16_t dc9_vlc_bits[512] = { - 0x0010, 0x0008, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0074, 0x0076, 0x0078, 0x007A, - 0x007C, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, - 0x003E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, - 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, - 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, - 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, - 0x01FE, 0x06C0, 0x06C2, 0x06C4, 0x06C6, 0x06C8, 0x06CA, 0x06CC, - 0x06CE, 0x06D0, 0x06D2, 0x06D4, 0x06D6, 0x06D8, 0x06DA, 0x06DC, - 0x06DE, 0x06E0, 0x06E2, 0x06E4, 0x06E6, 0x06E8, 0x06EA, 0x06EC, - 0x06EE, 0x06F0, 0x06F2, 0x06F4, 0x06F6, 0x06F8, 0x06FA, 0x06FC, - 0x06FE, 0x0E00, 0x0E02, 0x0E04, 0x0E06, 0x0E08, 0x0E0A, 0x0E0C, - 0x0E0E, 0x0E10, 0x0E12, 0x0E14, 0x0E16, 0x0E18, 0x0E1A, 0x0E1C, - 0x0E1E, 0x0E20, 0x0E22, 0x0E24, 0x0E26, 0x0E28, 0x0E2A, 0x0E2C, - 0x0E2E, 0x0E30, 0x0E32, 0x0E34, 0x0E36, 0x0E38, 0x0E3A, 0x0E3C, - 0x0E3E, 0x0E40, 0x0E42, 0x0E44, 0x0E46, 0x0E48, 0x0E4A, 0x0E4C, - 0x0E4E, 0x0E50, 0x0E52, 0x0E54, 0x0E56, 0x0E58, 0x0E5A, 0x0E5C, - 0x0E5E, 0x0E60, 0x0E62, 0x0E64, 0x0E66, 0x0E68, 0x0E6A, 0x0E6C, - 0x0E6E, 0x0E70, 0x0E72, 0x0E74, 0x0E76, 0x0E78, 0x0E7A, 0x0E7C, - 0x0E7E, 0x1F80, 0x1F82, 0x1F84, 0x1F86, 0x1F88, 0x1F8A, 0x1F8C, - 0x1F8E, 0x1F90, 0x1F92, 0x1F94, 0x1F96, 0x1F98, 0x1F9A, 0x1F9C, - 0x1F9E, 0x1FA0, 0x1FA2, 0x1FA4, 0x1FA6, 0x1FA8, 0x1FAA, 0x1FAC, - 0x1FAE, 0x1FB0, 0x1FB2, 0x1FB4, 0x1FB6, 0x1FB8, 0x1FBA, 0x1FBC, - 0x1FBE, 0x1FC0, 0x1FC2, 0x1FC4, 0x1FC6, 0x1FC8, 0x1FCA, 0x1FCC, - 0x1FCE, 0x1FD0, 0x1FD2, 0x1FD4, 0x1FD6, 0x1FD8, 0x1FDA, 0x1FDC, - 0x1FDE, 0x1FE0, 0x1FE2, 0x1FE4, 0x1FE6, 0x1FE8, 0x1FEA, 0x1FEC, - 0x1FEE, 0x1FF0, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FF8, 0x1FFA, 0x1FFC, - 0x0FFF, 0x1FFD, 0x1FFB, 0x1FF9, 0x1FF7, 0x1FF5, 0x1FF3, 0x1FF1, - 0x1FEF, 0x1FED, 0x1FEB, 0x1FE9, 0x1FE7, 0x1FE5, 0x1FE3, 0x1FE1, - 0x1FDF, 0x1FDD, 0x1FDB, 0x1FD9, 0x1FD7, 0x1FD5, 0x1FD3, 0x1FD1, - 0x1FCF, 0x1FCD, 0x1FCB, 0x1FC9, 0x1FC7, 0x1FC5, 0x1FC3, 0x1FC1, - 0x1FBF, 0x1FBD, 0x1FBB, 0x1FB9, 0x1FB7, 0x1FB5, 0x1FB3, 0x1FB1, - 0x1FAF, 0x1FAD, 0x1FAB, 0x1FA9, 0x1FA7, 0x1FA5, 0x1FA3, 0x1FA1, - 0x1F9F, 0x1F9D, 0x1F9B, 0x1F99, 0x1F97, 0x1F95, 0x1F93, 0x1F91, - 0x1F8F, 0x1F8D, 0x1F8B, 0x1F89, 0x1F87, 0x1F85, 0x1F83, 0x1F81, - 0x0E7F, 0x0E7D, 0x0E7B, 0x0E79, 0x0E77, 0x0E75, 0x0E73, 0x0E71, - 0x0E6F, 0x0E6D, 0x0E6B, 0x0E69, 0x0E67, 0x0E65, 0x0E63, 0x0E61, - 0x0E5F, 0x0E5D, 0x0E5B, 0x0E59, 0x0E57, 0x0E55, 0x0E53, 0x0E51, - 0x0E4F, 0x0E4D, 0x0E4B, 0x0E49, 0x0E47, 0x0E45, 0x0E43, 0x0E41, - 0x0E3F, 0x0E3D, 0x0E3B, 0x0E39, 0x0E37, 0x0E35, 0x0E33, 0x0E31, - 0x0E2F, 0x0E2D, 0x0E2B, 0x0E29, 0x0E27, 0x0E25, 0x0E23, 0x0E21, - 0x0E1F, 0x0E1D, 0x0E1B, 0x0E19, 0x0E17, 0x0E15, 0x0E13, 0x0E11, - 0x0E0F, 0x0E0D, 0x0E0B, 0x0E09, 0x0E07, 0x0E05, 0x0E03, 0x0E01, - 0x06FF, 0x06FD, 0x06FB, 0x06F9, 0x06F7, 0x06F5, 0x06F3, 0x06F1, - 0x06EF, 0x06ED, 0x06EB, 0x06E9, 0x06E7, 0x06E5, 0x06E3, 0x06E1, - 0x06DF, 0x06DD, 0x06DB, 0x06D9, 0x06D7, 0x06D5, 0x06D3, 0x06D1, - 0x06CF, 0x06CD, 0x06CB, 0x06C9, 0x06C7, 0x06C5, 0x06C3, 0x06C1, - 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, - 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, - 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, - 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0009, -}; - -static const uint8_t dc9_vlc_lens[512] = { - 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 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, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 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, 10, 10, 10, 10, 10, 10, - 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, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, -}; - -static const uint16_t dc10_vlc_bits[1024] = { - 0x0014, 0x002A, 0x002C, 0x002E, 0x0064, 0x0066, 0x0068, 0x006A, - 0x006C, 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, - 0x007C, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, - 0x001E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x0060, 0x0062, 0x0064, 0x0066, 0x0068, 0x006A, 0x006C, - 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, 0x007C, - 0x007E, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, - 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, - 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, - 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, - 0x01FE, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, - 0x040E, 0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, - 0x041E, 0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, - 0x042E, 0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, - 0x043E, 0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, - 0x044E, 0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, - 0x045E, 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, - 0x046E, 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x047C, - 0x047E, 0x0C00, 0x0C02, 0x0C04, 0x0C06, 0x0C08, 0x0C0A, 0x0C0C, - 0x0C0E, 0x0C10, 0x0C12, 0x0C14, 0x0C16, 0x0C18, 0x0C1A, 0x0C1C, - 0x0C1E, 0x0C20, 0x0C22, 0x0C24, 0x0C26, 0x0C28, 0x0C2A, 0x0C2C, - 0x0C2E, 0x0C30, 0x0C32, 0x0C34, 0x0C36, 0x0C38, 0x0C3A, 0x0C3C, - 0x0C3E, 0x0C40, 0x0C42, 0x0C44, 0x0C46, 0x0C48, 0x0C4A, 0x0C4C, - 0x0C4E, 0x0C50, 0x0C52, 0x0C54, 0x0C56, 0x0C58, 0x0C5A, 0x0C5C, - 0x0C5E, 0x0C60, 0x0C62, 0x0C64, 0x0C66, 0x0C68, 0x0C6A, 0x0C6C, - 0x0C6E, 0x0C70, 0x0C72, 0x0C74, 0x0C76, 0x0C78, 0x0C7A, 0x0C7C, - 0x0C7E, 0x0900, 0x0902, 0x0904, 0x0906, 0x0908, 0x090A, 0x090C, - 0x090E, 0x0910, 0x0912, 0x0914, 0x0916, 0x0918, 0x091A, 0x091C, - 0x091E, 0x0920, 0x0922, 0x0924, 0x0926, 0x0928, 0x092A, 0x092C, - 0x092E, 0x0930, 0x0932, 0x0934, 0x0936, 0x0938, 0x093A, 0x093C, - 0x093E, 0x0940, 0x0942, 0x0944, 0x0946, 0x0948, 0x094A, 0x094C, - 0x094E, 0x0950, 0x0952, 0x0954, 0x0956, 0x0958, 0x095A, 0x095C, - 0x095E, 0x0960, 0x0962, 0x0964, 0x0966, 0x0968, 0x096A, 0x096C, - 0x096E, 0x0970, 0x0972, 0x0974, 0x0976, 0x0978, 0x097A, 0x097C, - 0x097E, 0x0980, 0x0982, 0x0984, 0x0986, 0x0988, 0x098A, 0x098C, - 0x098E, 0x0990, 0x0992, 0x0994, 0x0996, 0x0998, 0x099A, 0x099C, - 0x099E, 0x09A0, 0x09A2, 0x09A4, 0x09A6, 0x09A8, 0x09AA, 0x09AC, - 0x09AE, 0x09B0, 0x09B2, 0x09B4, 0x09B6, 0x09B8, 0x09BA, 0x09BC, - 0x09BE, 0x09C0, 0x09C2, 0x09C4, 0x09C6, 0x09C8, 0x09CA, 0x09CC, - 0x09CE, 0x09D0, 0x09D2, 0x09D4, 0x09D6, 0x09D8, 0x09DA, 0x09DC, - 0x09DE, 0x09E0, 0x09E2, 0x09E4, 0x09E6, 0x09E8, 0x09EA, 0x09EC, - 0x09EE, 0x09F0, 0x09F2, 0x09F4, 0x09F6, 0x09F8, 0x09FA, 0x09FC, - 0x09FE, 0x3F00, 0x3F02, 0x3F04, 0x3F06, 0x3F08, 0x3F0A, 0x3F0C, - 0x3F0E, 0x3F10, 0x3F12, 0x3F14, 0x3F16, 0x3F18, 0x3F1A, 0x3F1C, - 0x3F1E, 0x3F20, 0x3F22, 0x3F24, 0x3F26, 0x3F28, 0x3F2A, 0x3F2C, - 0x3F2E, 0x3F30, 0x3F32, 0x3F34, 0x3F36, 0x3F38, 0x3F3A, 0x3F3C, - 0x3F3E, 0x3F40, 0x3F42, 0x3F44, 0x3F46, 0x3F48, 0x3F4A, 0x3F4C, - 0x3F4E, 0x3F50, 0x3F52, 0x3F54, 0x3F56, 0x3F58, 0x3F5A, 0x3F5C, - 0x3F5E, 0x3F60, 0x3F62, 0x3F64, 0x3F66, 0x3F68, 0x3F6A, 0x3F6C, - 0x3F6E, 0x3F70, 0x3F72, 0x3F74, 0x3F76, 0x3F78, 0x3F7A, 0x3F7C, - 0x3F7E, 0x3F80, 0x3F82, 0x3F84, 0x3F86, 0x3F88, 0x3F8A, 0x3F8C, - 0x3F8E, 0x3F90, 0x3F92, 0x3F94, 0x3F96, 0x3F98, 0x3F9A, 0x3F9C, - 0x3F9E, 0x3FA0, 0x3FA2, 0x3FA4, 0x3FA6, 0x3FA8, 0x3FAA, 0x3FAC, - 0x3FAE, 0x3FB0, 0x3FB2, 0x3FB4, 0x3FB6, 0x3FB8, 0x3FBA, 0x3FBC, - 0x3FBE, 0x3FC0, 0x3FC2, 0x3FC4, 0x3FC6, 0x3FC8, 0x3FCA, 0x3FCC, - 0x3FCE, 0x3FD0, 0x3FD2, 0x3FD4, 0x3FD6, 0x3FD8, 0x3FDA, 0x3FDC, - 0x3FDE, 0x3FE0, 0x3FE2, 0x3FE4, 0x3FE6, 0x3FE8, 0x3FEA, 0x3FEC, - 0x3FEE, 0x3FF0, 0x3FF2, 0x3FF4, 0x3FF6, 0x3FF8, 0x3FFA, 0x3FFC, - 0x1FFF, 0x3FFD, 0x3FFB, 0x3FF9, 0x3FF7, 0x3FF5, 0x3FF3, 0x3FF1, - 0x3FEF, 0x3FED, 0x3FEB, 0x3FE9, 0x3FE7, 0x3FE5, 0x3FE3, 0x3FE1, - 0x3FDF, 0x3FDD, 0x3FDB, 0x3FD9, 0x3FD7, 0x3FD5, 0x3FD3, 0x3FD1, - 0x3FCF, 0x3FCD, 0x3FCB, 0x3FC9, 0x3FC7, 0x3FC5, 0x3FC3, 0x3FC1, - 0x3FBF, 0x3FBD, 0x3FBB, 0x3FB9, 0x3FB7, 0x3FB5, 0x3FB3, 0x3FB1, - 0x3FAF, 0x3FAD, 0x3FAB, 0x3FA9, 0x3FA7, 0x3FA5, 0x3FA3, 0x3FA1, - 0x3F9F, 0x3F9D, 0x3F9B, 0x3F99, 0x3F97, 0x3F95, 0x3F93, 0x3F91, - 0x3F8F, 0x3F8D, 0x3F8B, 0x3F89, 0x3F87, 0x3F85, 0x3F83, 0x3F81, - 0x3F7F, 0x3F7D, 0x3F7B, 0x3F79, 0x3F77, 0x3F75, 0x3F73, 0x3F71, - 0x3F6F, 0x3F6D, 0x3F6B, 0x3F69, 0x3F67, 0x3F65, 0x3F63, 0x3F61, - 0x3F5F, 0x3F5D, 0x3F5B, 0x3F59, 0x3F57, 0x3F55, 0x3F53, 0x3F51, - 0x3F4F, 0x3F4D, 0x3F4B, 0x3F49, 0x3F47, 0x3F45, 0x3F43, 0x3F41, - 0x3F3F, 0x3F3D, 0x3F3B, 0x3F39, 0x3F37, 0x3F35, 0x3F33, 0x3F31, - 0x3F2F, 0x3F2D, 0x3F2B, 0x3F29, 0x3F27, 0x3F25, 0x3F23, 0x3F21, - 0x3F1F, 0x3F1D, 0x3F1B, 0x3F19, 0x3F17, 0x3F15, 0x3F13, 0x3F11, - 0x3F0F, 0x3F0D, 0x3F0B, 0x3F09, 0x3F07, 0x3F05, 0x3F03, 0x3F01, - 0x09FF, 0x09FD, 0x09FB, 0x09F9, 0x09F7, 0x09F5, 0x09F3, 0x09F1, - 0x09EF, 0x09ED, 0x09EB, 0x09E9, 0x09E7, 0x09E5, 0x09E3, 0x09E1, - 0x09DF, 0x09DD, 0x09DB, 0x09D9, 0x09D7, 0x09D5, 0x09D3, 0x09D1, - 0x09CF, 0x09CD, 0x09CB, 0x09C9, 0x09C7, 0x09C5, 0x09C3, 0x09C1, - 0x09BF, 0x09BD, 0x09BB, 0x09B9, 0x09B7, 0x09B5, 0x09B3, 0x09B1, - 0x09AF, 0x09AD, 0x09AB, 0x09A9, 0x09A7, 0x09A5, 0x09A3, 0x09A1, - 0x099F, 0x099D, 0x099B, 0x0999, 0x0997, 0x0995, 0x0993, 0x0991, - 0x098F, 0x098D, 0x098B, 0x0989, 0x0987, 0x0985, 0x0983, 0x0981, - 0x097F, 0x097D, 0x097B, 0x0979, 0x0977, 0x0975, 0x0973, 0x0971, - 0x096F, 0x096D, 0x096B, 0x0969, 0x0967, 0x0965, 0x0963, 0x0961, - 0x095F, 0x095D, 0x095B, 0x0959, 0x0957, 0x0955, 0x0953, 0x0951, - 0x094F, 0x094D, 0x094B, 0x0949, 0x0947, 0x0945, 0x0943, 0x0941, - 0x093F, 0x093D, 0x093B, 0x0939, 0x0937, 0x0935, 0x0933, 0x0931, - 0x092F, 0x092D, 0x092B, 0x0929, 0x0927, 0x0925, 0x0923, 0x0921, - 0x091F, 0x091D, 0x091B, 0x0919, 0x0917, 0x0915, 0x0913, 0x0911, - 0x090F, 0x090D, 0x090B, 0x0909, 0x0907, 0x0905, 0x0903, 0x0901, - 0x0C7F, 0x0C7D, 0x0C7B, 0x0C79, 0x0C77, 0x0C75, 0x0C73, 0x0C71, - 0x0C6F, 0x0C6D, 0x0C6B, 0x0C69, 0x0C67, 0x0C65, 0x0C63, 0x0C61, - 0x0C5F, 0x0C5D, 0x0C5B, 0x0C59, 0x0C57, 0x0C55, 0x0C53, 0x0C51, - 0x0C4F, 0x0C4D, 0x0C4B, 0x0C49, 0x0C47, 0x0C45, 0x0C43, 0x0C41, - 0x0C3F, 0x0C3D, 0x0C3B, 0x0C39, 0x0C37, 0x0C35, 0x0C33, 0x0C31, - 0x0C2F, 0x0C2D, 0x0C2B, 0x0C29, 0x0C27, 0x0C25, 0x0C23, 0x0C21, - 0x0C1F, 0x0C1D, 0x0C1B, 0x0C19, 0x0C17, 0x0C15, 0x0C13, 0x0C11, - 0x0C0F, 0x0C0D, 0x0C0B, 0x0C09, 0x0C07, 0x0C05, 0x0C03, 0x0C01, - 0x047F, 0x047D, 0x047B, 0x0479, 0x0477, 0x0475, 0x0473, 0x0471, - 0x046F, 0x046D, 0x046B, 0x0469, 0x0467, 0x0465, 0x0463, 0x0461, - 0x045F, 0x045D, 0x045B, 0x0459, 0x0457, 0x0455, 0x0453, 0x0451, - 0x044F, 0x044D, 0x044B, 0x0449, 0x0447, 0x0445, 0x0443, 0x0441, - 0x043F, 0x043D, 0x043B, 0x0439, 0x0437, 0x0435, 0x0433, 0x0431, - 0x042F, 0x042D, 0x042B, 0x0429, 0x0427, 0x0425, 0x0423, 0x0421, - 0x041F, 0x041D, 0x041B, 0x0419, 0x0417, 0x0415, 0x0413, 0x0411, - 0x040F, 0x040D, 0x040B, 0x0409, 0x0407, 0x0405, 0x0403, 0x0401, - 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, - 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, - 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, - 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, - 0x007F, 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, - 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x0063, 0x0061, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, 0x006F, - 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x002F, 0x002D, 0x002B, -}; - -static const uint8_t dc10_vlc_lens[1024] = { - 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 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, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 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, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 10, 10, 10, 10, 10, 10, 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, 9, 9, 9, 9, 9, 9, 9, 9, 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, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, -}; - -static const uint16_t dc11_vlc_bits[2048] = { - 0x0032, 0x0066, 0x0068, 0x006A, 0x006C, 0x006E, 0x0070, 0x0072, - 0x0074, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, - 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, - 0x005E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, - 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, - 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, - 0x001E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, - 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, - 0x003E, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, - 0x020E, 0x0210, 0x0212, 0x0214, 0x0216, 0x0218, 0x021A, 0x021C, - 0x021E, 0x0220, 0x0222, 0x0224, 0x0226, 0x0228, 0x022A, 0x022C, - 0x022E, 0x0230, 0x0232, 0x0234, 0x0236, 0x0238, 0x023A, 0x023C, - 0x023E, 0x0080, 0x0082, 0x0084, 0x0086, 0x0088, 0x008A, 0x008C, - 0x008E, 0x0090, 0x0092, 0x0094, 0x0096, 0x0098, 0x009A, 0x009C, - 0x009E, 0x00A0, 0x00A2, 0x00A4, 0x00A6, 0x00A8, 0x00AA, 0x00AC, - 0x00AE, 0x00B0, 0x00B2, 0x00B4, 0x00B6, 0x00B8, 0x00BA, 0x00BC, - 0x00BE, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, - 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, - 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, - 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, - 0x00FE, 0x0480, 0x0482, 0x0484, 0x0486, 0x0488, 0x048A, 0x048C, - 0x048E, 0x0490, 0x0492, 0x0494, 0x0496, 0x0498, 0x049A, 0x049C, - 0x049E, 0x04A0, 0x04A2, 0x04A4, 0x04A6, 0x04A8, 0x04AA, 0x04AC, - 0x04AE, 0x04B0, 0x04B2, 0x04B4, 0x04B6, 0x04B8, 0x04BA, 0x04BC, - 0x04BE, 0x04C0, 0x04C2, 0x04C4, 0x04C6, 0x04C8, 0x04CA, 0x04CC, - 0x04CE, 0x04D0, 0x04D2, 0x04D4, 0x04D6, 0x04D8, 0x04DA, 0x04DC, - 0x04DE, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA, 0x04EC, - 0x04EE, 0x04F0, 0x04F2, 0x04F4, 0x04F6, 0x04F8, 0x04FA, 0x04FC, - 0x04FE, 0x0A00, 0x0A02, 0x0A04, 0x0A06, 0x0A08, 0x0A0A, 0x0A0C, - 0x0A0E, 0x0A10, 0x0A12, 0x0A14, 0x0A16, 0x0A18, 0x0A1A, 0x0A1C, - 0x0A1E, 0x0A20, 0x0A22, 0x0A24, 0x0A26, 0x0A28, 0x0A2A, 0x0A2C, - 0x0A2E, 0x0A30, 0x0A32, 0x0A34, 0x0A36, 0x0A38, 0x0A3A, 0x0A3C, - 0x0A3E, 0x0A40, 0x0A42, 0x0A44, 0x0A46, 0x0A48, 0x0A4A, 0x0A4C, - 0x0A4E, 0x0A50, 0x0A52, 0x0A54, 0x0A56, 0x0A58, 0x0A5A, 0x0A5C, - 0x0A5E, 0x0A60, 0x0A62, 0x0A64, 0x0A66, 0x0A68, 0x0A6A, 0x0A6C, - 0x0A6E, 0x0A70, 0x0A72, 0x0A74, 0x0A76, 0x0A78, 0x0A7A, 0x0A7C, - 0x0A7E, 0x0A80, 0x0A82, 0x0A84, 0x0A86, 0x0A88, 0x0A8A, 0x0A8C, - 0x0A8E, 0x0A90, 0x0A92, 0x0A94, 0x0A96, 0x0A98, 0x0A9A, 0x0A9C, - 0x0A9E, 0x0AA0, 0x0AA2, 0x0AA4, 0x0AA6, 0x0AA8, 0x0AAA, 0x0AAC, - 0x0AAE, 0x0AB0, 0x0AB2, 0x0AB4, 0x0AB6, 0x0AB8, 0x0ABA, 0x0ABC, - 0x0ABE, 0x0AC0, 0x0AC2, 0x0AC4, 0x0AC6, 0x0AC8, 0x0ACA, 0x0ACC, - 0x0ACE, 0x0AD0, 0x0AD2, 0x0AD4, 0x0AD6, 0x0AD8, 0x0ADA, 0x0ADC, - 0x0ADE, 0x0AE0, 0x0AE2, 0x0AE4, 0x0AE6, 0x0AE8, 0x0AEA, 0x0AEC, - 0x0AEE, 0x0AF0, 0x0AF2, 0x0AF4, 0x0AF6, 0x0AF8, 0x0AFA, 0x0AFC, - 0x0AFE, 0x1800, 0x1802, 0x1804, 0x1806, 0x1808, 0x180A, 0x180C, - 0x180E, 0x1810, 0x1812, 0x1814, 0x1816, 0x1818, 0x181A, 0x181C, - 0x181E, 0x1820, 0x1822, 0x1824, 0x1826, 0x1828, 0x182A, 0x182C, - 0x182E, 0x1830, 0x1832, 0x1834, 0x1836, 0x1838, 0x183A, 0x183C, - 0x183E, 0x1840, 0x1842, 0x1844, 0x1846, 0x1848, 0x184A, 0x184C, - 0x184E, 0x1850, 0x1852, 0x1854, 0x1856, 0x1858, 0x185A, 0x185C, - 0x185E, 0x1860, 0x1862, 0x1864, 0x1866, 0x1868, 0x186A, 0x186C, - 0x186E, 0x1870, 0x1872, 0x1874, 0x1876, 0x1878, 0x187A, 0x187C, - 0x187E, 0x1880, 0x1882, 0x1884, 0x1886, 0x1888, 0x188A, 0x188C, - 0x188E, 0x1890, 0x1892, 0x1894, 0x1896, 0x1898, 0x189A, 0x189C, - 0x189E, 0x18A0, 0x18A2, 0x18A4, 0x18A6, 0x18A8, 0x18AA, 0x18AC, - 0x18AE, 0x18B0, 0x18B2, 0x18B4, 0x18B6, 0x18B8, 0x18BA, 0x18BC, - 0x18BE, 0x18C0, 0x18C2, 0x18C4, 0x18C6, 0x18C8, 0x18CA, 0x18CC, - 0x18CE, 0x18D0, 0x18D2, 0x18D4, 0x18D6, 0x18D8, 0x18DA, 0x18DC, - 0x18DE, 0x18E0, 0x18E2, 0x18E4, 0x18E6, 0x18E8, 0x18EA, 0x18EC, - 0x18EE, 0x18F0, 0x18F2, 0x18F4, 0x18F6, 0x18F8, 0x18FA, 0x18FC, - 0x18FE, 0x1600, 0x1602, 0x1604, 0x1606, 0x1608, 0x160A, 0x160C, - 0x160E, 0x1610, 0x1612, 0x1614, 0x1616, 0x1618, 0x161A, 0x161C, - 0x161E, 0x1620, 0x1622, 0x1624, 0x1626, 0x1628, 0x162A, 0x162C, - 0x162E, 0x1630, 0x1632, 0x1634, 0x1636, 0x1638, 0x163A, 0x163C, - 0x163E, 0x1640, 0x1642, 0x1644, 0x1646, 0x1648, 0x164A, 0x164C, - 0x164E, 0x1650, 0x1652, 0x1654, 0x1656, 0x1658, 0x165A, 0x165C, - 0x165E, 0x1660, 0x1662, 0x1664, 0x1666, 0x1668, 0x166A, 0x166C, - 0x166E, 0x1670, 0x1672, 0x1674, 0x1676, 0x1678, 0x167A, 0x167C, - 0x167E, 0x1680, 0x1682, 0x1684, 0x1686, 0x1688, 0x168A, 0x168C, - 0x168E, 0x1690, 0x1692, 0x1694, 0x1696, 0x1698, 0x169A, 0x169C, - 0x169E, 0x16A0, 0x16A2, 0x16A4, 0x16A6, 0x16A8, 0x16AA, 0x16AC, - 0x16AE, 0x16B0, 0x16B2, 0x16B4, 0x16B6, 0x16B8, 0x16BA, 0x16BC, - 0x16BE, 0x16C0, 0x16C2, 0x16C4, 0x16C6, 0x16C8, 0x16CA, 0x16CC, - 0x16CE, 0x16D0, 0x16D2, 0x16D4, 0x16D6, 0x16D8, 0x16DA, 0x16DC, - 0x16DE, 0x16E0, 0x16E2, 0x16E4, 0x16E6, 0x16E8, 0x16EA, 0x16EC, - 0x16EE, 0x16F0, 0x16F2, 0x16F4, 0x16F6, 0x16F8, 0x16FA, 0x16FC, - 0x16FE, 0x1700, 0x1702, 0x1704, 0x1706, 0x1708, 0x170A, 0x170C, - 0x170E, 0x1710, 0x1712, 0x1714, 0x1716, 0x1718, 0x171A, 0x171C, - 0x171E, 0x1720, 0x1722, 0x1724, 0x1726, 0x1728, 0x172A, 0x172C, - 0x172E, 0x1730, 0x1732, 0x1734, 0x1736, 0x1738, 0x173A, 0x173C, - 0x173E, 0x1740, 0x1742, 0x1744, 0x1746, 0x1748, 0x174A, 0x174C, - 0x174E, 0x1750, 0x1752, 0x1754, 0x1756, 0x1758, 0x175A, 0x175C, - 0x175E, 0x1760, 0x1762, 0x1764, 0x1766, 0x1768, 0x176A, 0x176C, - 0x176E, 0x1770, 0x1772, 0x1774, 0x1776, 0x1778, 0x177A, 0x177C, - 0x177E, 0x1780, 0x1782, 0x1784, 0x1786, 0x1788, 0x178A, 0x178C, - 0x178E, 0x1790, 0x1792, 0x1794, 0x1796, 0x1798, 0x179A, 0x179C, - 0x179E, 0x17A0, 0x17A2, 0x17A4, 0x17A6, 0x17A8, 0x17AA, 0x17AC, - 0x17AE, 0x17B0, 0x17B2, 0x17B4, 0x17B6, 0x17B8, 0x17BA, 0x17BC, - 0x17BE, 0x17C0, 0x17C2, 0x17C4, 0x17C6, 0x17C8, 0x17CA, 0x17CC, - 0x17CE, 0x17D0, 0x17D2, 0x17D4, 0x17D6, 0x17D8, 0x17DA, 0x17DC, - 0x17DE, 0x17E0, 0x17E2, 0x17E4, 0x17E6, 0x17E8, 0x17EA, 0x17EC, - 0x17EE, 0x17F0, 0x17F2, 0x17F4, 0x17F6, 0x17F8, 0x17FA, 0x17FC, - 0x17FE, 0x7600, 0x7602, 0x7604, 0x7606, 0x7608, 0x760A, 0x760C, - 0x760E, 0x7610, 0x7612, 0x7614, 0x7616, 0x7618, 0x761A, 0x761C, - 0x761E, 0x7620, 0x7622, 0x7624, 0x7626, 0x7628, 0x762A, 0x762C, - 0x762E, 0x7630, 0x7632, 0x7634, 0x7636, 0x7638, 0x763A, 0x763C, - 0x763E, 0x7640, 0x7642, 0x7644, 0x7646, 0x7648, 0x764A, 0x764C, - 0x764E, 0x7650, 0x7652, 0x7654, 0x7656, 0x7658, 0x765A, 0x765C, - 0x765E, 0x7660, 0x7662, 0x7664, 0x7666, 0x7668, 0x766A, 0x766C, - 0x766E, 0x7670, 0x7672, 0x7674, 0x7676, 0x7678, 0x767A, 0x767C, - 0x767E, 0x7680, 0x7682, 0x7684, 0x7686, 0x7688, 0x768A, 0x768C, - 0x768E, 0x7690, 0x7692, 0x7694, 0x7696, 0x7698, 0x769A, 0x769C, - 0x769E, 0x76A0, 0x76A2, 0x76A4, 0x76A6, 0x76A8, 0x76AA, 0x76AC, - 0x76AE, 0x76B0, 0x76B2, 0x76B4, 0x76B6, 0x76B8, 0x76BA, 0x76BC, - 0x76BE, 0x76C0, 0x76C2, 0x76C4, 0x76C6, 0x76C8, 0x76CA, 0x76CC, - 0x76CE, 0x76D0, 0x76D2, 0x76D4, 0x76D6, 0x76D8, 0x76DA, 0x76DC, - 0x76DE, 0x76E0, 0x76E2, 0x76E4, 0x76E6, 0x76E8, 0x76EA, 0x76EC, - 0x76EE, 0x76F0, 0x76F2, 0x76F4, 0x76F6, 0x76F8, 0x76FA, 0x76FC, - 0x76FE, 0x7700, 0x7702, 0x7704, 0x7706, 0x7708, 0x770A, 0x770C, - 0x770E, 0x7710, 0x7712, 0x7714, 0x7716, 0x7718, 0x771A, 0x771C, - 0x771E, 0x7720, 0x7722, 0x7724, 0x7726, 0x7728, 0x772A, 0x772C, - 0x772E, 0x7730, 0x7732, 0x7734, 0x7736, 0x7738, 0x773A, 0x773C, - 0x773E, 0x7740, 0x7742, 0x7744, 0x7746, 0x7748, 0x774A, 0x774C, - 0x774E, 0x7750, 0x7752, 0x7754, 0x7756, 0x7758, 0x775A, 0x775C, - 0x775E, 0x7760, 0x7762, 0x7764, 0x7766, 0x7768, 0x776A, 0x776C, - 0x776E, 0x7770, 0x7772, 0x7774, 0x7776, 0x7778, 0x777A, 0x777C, - 0x777E, 0x7780, 0x7782, 0x7784, 0x7786, 0x7788, 0x778A, 0x778C, - 0x778E, 0x7790, 0x7792, 0x7794, 0x7796, 0x7798, 0x779A, 0x779C, - 0x779E, 0x77A0, 0x77A2, 0x77A4, 0x77A6, 0x77A8, 0x77AA, 0x77AC, - 0x77AE, 0x77B0, 0x77B2, 0x77B4, 0x77B6, 0x77B8, 0x77BA, 0x77BC, - 0x77BE, 0x77C0, 0x77C2, 0x77C4, 0x77C6, 0x77C8, 0x77CA, 0x77CC, - 0x77CE, 0x77D0, 0x77D2, 0x77D4, 0x77D6, 0x77D8, 0x77DA, 0x77DC, - 0x77DE, 0x77E0, 0x77E2, 0x77E4, 0x77E6, 0x77E8, 0x77EA, 0x77EC, - 0x77EE, 0x77F0, 0x77F2, 0x77F4, 0x77F6, 0x77F8, 0x77FA, 0x77FC, - 0x3BFF, 0x77FD, 0x77FB, 0x77F9, 0x77F7, 0x77F5, 0x77F3, 0x77F1, - 0x77EF, 0x77ED, 0x77EB, 0x77E9, 0x77E7, 0x77E5, 0x77E3, 0x77E1, - 0x77DF, 0x77DD, 0x77DB, 0x77D9, 0x77D7, 0x77D5, 0x77D3, 0x77D1, - 0x77CF, 0x77CD, 0x77CB, 0x77C9, 0x77C7, 0x77C5, 0x77C3, 0x77C1, - 0x77BF, 0x77BD, 0x77BB, 0x77B9, 0x77B7, 0x77B5, 0x77B3, 0x77B1, - 0x77AF, 0x77AD, 0x77AB, 0x77A9, 0x77A7, 0x77A5, 0x77A3, 0x77A1, - 0x779F, 0x779D, 0x779B, 0x7799, 0x7797, 0x7795, 0x7793, 0x7791, - 0x778F, 0x778D, 0x778B, 0x7789, 0x7787, 0x7785, 0x7783, 0x7781, - 0x777F, 0x777D, 0x777B, 0x7779, 0x7777, 0x7775, 0x7773, 0x7771, - 0x776F, 0x776D, 0x776B, 0x7769, 0x7767, 0x7765, 0x7763, 0x7761, - 0x775F, 0x775D, 0x775B, 0x7759, 0x7757, 0x7755, 0x7753, 0x7751, - 0x774F, 0x774D, 0x774B, 0x7749, 0x7747, 0x7745, 0x7743, 0x7741, - 0x773F, 0x773D, 0x773B, 0x7739, 0x7737, 0x7735, 0x7733, 0x7731, - 0x772F, 0x772D, 0x772B, 0x7729, 0x7727, 0x7725, 0x7723, 0x7721, - 0x771F, 0x771D, 0x771B, 0x7719, 0x7717, 0x7715, 0x7713, 0x7711, - 0x770F, 0x770D, 0x770B, 0x7709, 0x7707, 0x7705, 0x7703, 0x7701, - 0x76FF, 0x76FD, 0x76FB, 0x76F9, 0x76F7, 0x76F5, 0x76F3, 0x76F1, - 0x76EF, 0x76ED, 0x76EB, 0x76E9, 0x76E7, 0x76E5, 0x76E3, 0x76E1, - 0x76DF, 0x76DD, 0x76DB, 0x76D9, 0x76D7, 0x76D5, 0x76D3, 0x76D1, - 0x76CF, 0x76CD, 0x76CB, 0x76C9, 0x76C7, 0x76C5, 0x76C3, 0x76C1, - 0x76BF, 0x76BD, 0x76BB, 0x76B9, 0x76B7, 0x76B5, 0x76B3, 0x76B1, - 0x76AF, 0x76AD, 0x76AB, 0x76A9, 0x76A7, 0x76A5, 0x76A3, 0x76A1, - 0x769F, 0x769D, 0x769B, 0x7699, 0x7697, 0x7695, 0x7693, 0x7691, - 0x768F, 0x768D, 0x768B, 0x7689, 0x7687, 0x7685, 0x7683, 0x7681, - 0x767F, 0x767D, 0x767B, 0x7679, 0x7677, 0x7675, 0x7673, 0x7671, - 0x766F, 0x766D, 0x766B, 0x7669, 0x7667, 0x7665, 0x7663, 0x7661, - 0x765F, 0x765D, 0x765B, 0x7659, 0x7657, 0x7655, 0x7653, 0x7651, - 0x764F, 0x764D, 0x764B, 0x7649, 0x7647, 0x7645, 0x7643, 0x7641, - 0x763F, 0x763D, 0x763B, 0x7639, 0x7637, 0x7635, 0x7633, 0x7631, - 0x762F, 0x762D, 0x762B, 0x7629, 0x7627, 0x7625, 0x7623, 0x7621, - 0x761F, 0x761D, 0x761B, 0x7619, 0x7617, 0x7615, 0x7613, 0x7611, - 0x760F, 0x760D, 0x760B, 0x7609, 0x7607, 0x7605, 0x7603, 0x7601, - 0x17FF, 0x17FD, 0x17FB, 0x17F9, 0x17F7, 0x17F5, 0x17F3, 0x17F1, - 0x17EF, 0x17ED, 0x17EB, 0x17E9, 0x17E7, 0x17E5, 0x17E3, 0x17E1, - 0x17DF, 0x17DD, 0x17DB, 0x17D9, 0x17D7, 0x17D5, 0x17D3, 0x17D1, - 0x17CF, 0x17CD, 0x17CB, 0x17C9, 0x17C7, 0x17C5, 0x17C3, 0x17C1, - 0x17BF, 0x17BD, 0x17BB, 0x17B9, 0x17B7, 0x17B5, 0x17B3, 0x17B1, - 0x17AF, 0x17AD, 0x17AB, 0x17A9, 0x17A7, 0x17A5, 0x17A3, 0x17A1, - 0x179F, 0x179D, 0x179B, 0x1799, 0x1797, 0x1795, 0x1793, 0x1791, - 0x178F, 0x178D, 0x178B, 0x1789, 0x1787, 0x1785, 0x1783, 0x1781, - 0x177F, 0x177D, 0x177B, 0x1779, 0x1777, 0x1775, 0x1773, 0x1771, - 0x176F, 0x176D, 0x176B, 0x1769, 0x1767, 0x1765, 0x1763, 0x1761, - 0x175F, 0x175D, 0x175B, 0x1759, 0x1757, 0x1755, 0x1753, 0x1751, - 0x174F, 0x174D, 0x174B, 0x1749, 0x1747, 0x1745, 0x1743, 0x1741, - 0x173F, 0x173D, 0x173B, 0x1739, 0x1737, 0x1735, 0x1733, 0x1731, - 0x172F, 0x172D, 0x172B, 0x1729, 0x1727, 0x1725, 0x1723, 0x1721, - 0x171F, 0x171D, 0x171B, 0x1719, 0x1717, 0x1715, 0x1713, 0x1711, - 0x170F, 0x170D, 0x170B, 0x1709, 0x1707, 0x1705, 0x1703, 0x1701, - 0x16FF, 0x16FD, 0x16FB, 0x16F9, 0x16F7, 0x16F5, 0x16F3, 0x16F1, - 0x16EF, 0x16ED, 0x16EB, 0x16E9, 0x16E7, 0x16E5, 0x16E3, 0x16E1, - 0x16DF, 0x16DD, 0x16DB, 0x16D9, 0x16D7, 0x16D5, 0x16D3, 0x16D1, - 0x16CF, 0x16CD, 0x16CB, 0x16C9, 0x16C7, 0x16C5, 0x16C3, 0x16C1, - 0x16BF, 0x16BD, 0x16BB, 0x16B9, 0x16B7, 0x16B5, 0x16B3, 0x16B1, - 0x16AF, 0x16AD, 0x16AB, 0x16A9, 0x16A7, 0x16A5, 0x16A3, 0x16A1, - 0x169F, 0x169D, 0x169B, 0x1699, 0x1697, 0x1695, 0x1693, 0x1691, - 0x168F, 0x168D, 0x168B, 0x1689, 0x1687, 0x1685, 0x1683, 0x1681, - 0x167F, 0x167D, 0x167B, 0x1679, 0x1677, 0x1675, 0x1673, 0x1671, - 0x166F, 0x166D, 0x166B, 0x1669, 0x1667, 0x1665, 0x1663, 0x1661, - 0x165F, 0x165D, 0x165B, 0x1659, 0x1657, 0x1655, 0x1653, 0x1651, - 0x164F, 0x164D, 0x164B, 0x1649, 0x1647, 0x1645, 0x1643, 0x1641, - 0x163F, 0x163D, 0x163B, 0x1639, 0x1637, 0x1635, 0x1633, 0x1631, - 0x162F, 0x162D, 0x162B, 0x1629, 0x1627, 0x1625, 0x1623, 0x1621, - 0x161F, 0x161D, 0x161B, 0x1619, 0x1617, 0x1615, 0x1613, 0x1611, - 0x160F, 0x160D, 0x160B, 0x1609, 0x1607, 0x1605, 0x1603, 0x1601, - 0x18FF, 0x18FD, 0x18FB, 0x18F9, 0x18F7, 0x18F5, 0x18F3, 0x18F1, - 0x18EF, 0x18ED, 0x18EB, 0x18E9, 0x18E7, 0x18E5, 0x18E3, 0x18E1, - 0x18DF, 0x18DD, 0x18DB, 0x18D9, 0x18D7, 0x18D5, 0x18D3, 0x18D1, - 0x18CF, 0x18CD, 0x18CB, 0x18C9, 0x18C7, 0x18C5, 0x18C3, 0x18C1, - 0x18BF, 0x18BD, 0x18BB, 0x18B9, 0x18B7, 0x18B5, 0x18B3, 0x18B1, - 0x18AF, 0x18AD, 0x18AB, 0x18A9, 0x18A7, 0x18A5, 0x18A3, 0x18A1, - 0x189F, 0x189D, 0x189B, 0x1899, 0x1897, 0x1895, 0x1893, 0x1891, - 0x188F, 0x188D, 0x188B, 0x1889, 0x1887, 0x1885, 0x1883, 0x1881, - 0x187F, 0x187D, 0x187B, 0x1879, 0x1877, 0x1875, 0x1873, 0x1871, - 0x186F, 0x186D, 0x186B, 0x1869, 0x1867, 0x1865, 0x1863, 0x1861, - 0x185F, 0x185D, 0x185B, 0x1859, 0x1857, 0x1855, 0x1853, 0x1851, - 0x184F, 0x184D, 0x184B, 0x1849, 0x1847, 0x1845, 0x1843, 0x1841, - 0x183F, 0x183D, 0x183B, 0x1839, 0x1837, 0x1835, 0x1833, 0x1831, - 0x182F, 0x182D, 0x182B, 0x1829, 0x1827, 0x1825, 0x1823, 0x1821, - 0x181F, 0x181D, 0x181B, 0x1819, 0x1817, 0x1815, 0x1813, 0x1811, - 0x180F, 0x180D, 0x180B, 0x1809, 0x1807, 0x1805, 0x1803, 0x1801, - 0x0AFF, 0x0AFD, 0x0AFB, 0x0AF9, 0x0AF7, 0x0AF5, 0x0AF3, 0x0AF1, - 0x0AEF, 0x0AED, 0x0AEB, 0x0AE9, 0x0AE7, 0x0AE5, 0x0AE3, 0x0AE1, - 0x0ADF, 0x0ADD, 0x0ADB, 0x0AD9, 0x0AD7, 0x0AD5, 0x0AD3, 0x0AD1, - 0x0ACF, 0x0ACD, 0x0ACB, 0x0AC9, 0x0AC7, 0x0AC5, 0x0AC3, 0x0AC1, - 0x0ABF, 0x0ABD, 0x0ABB, 0x0AB9, 0x0AB7, 0x0AB5, 0x0AB3, 0x0AB1, - 0x0AAF, 0x0AAD, 0x0AAB, 0x0AA9, 0x0AA7, 0x0AA5, 0x0AA3, 0x0AA1, - 0x0A9F, 0x0A9D, 0x0A9B, 0x0A99, 0x0A97, 0x0A95, 0x0A93, 0x0A91, - 0x0A8F, 0x0A8D, 0x0A8B, 0x0A89, 0x0A87, 0x0A85, 0x0A83, 0x0A81, - 0x0A7F, 0x0A7D, 0x0A7B, 0x0A79, 0x0A77, 0x0A75, 0x0A73, 0x0A71, - 0x0A6F, 0x0A6D, 0x0A6B, 0x0A69, 0x0A67, 0x0A65, 0x0A63, 0x0A61, - 0x0A5F, 0x0A5D, 0x0A5B, 0x0A59, 0x0A57, 0x0A55, 0x0A53, 0x0A51, - 0x0A4F, 0x0A4D, 0x0A4B, 0x0A49, 0x0A47, 0x0A45, 0x0A43, 0x0A41, - 0x0A3F, 0x0A3D, 0x0A3B, 0x0A39, 0x0A37, 0x0A35, 0x0A33, 0x0A31, - 0x0A2F, 0x0A2D, 0x0A2B, 0x0A29, 0x0A27, 0x0A25, 0x0A23, 0x0A21, - 0x0A1F, 0x0A1D, 0x0A1B, 0x0A19, 0x0A17, 0x0A15, 0x0A13, 0x0A11, - 0x0A0F, 0x0A0D, 0x0A0B, 0x0A09, 0x0A07, 0x0A05, 0x0A03, 0x0A01, - 0x04FF, 0x04FD, 0x04FB, 0x04F9, 0x04F7, 0x04F5, 0x04F3, 0x04F1, - 0x04EF, 0x04ED, 0x04EB, 0x04E9, 0x04E7, 0x04E5, 0x04E3, 0x04E1, - 0x04DF, 0x04DD, 0x04DB, 0x04D9, 0x04D7, 0x04D5, 0x04D3, 0x04D1, - 0x04CF, 0x04CD, 0x04CB, 0x04C9, 0x04C7, 0x04C5, 0x04C3, 0x04C1, - 0x04BF, 0x04BD, 0x04BB, 0x04B9, 0x04B7, 0x04B5, 0x04B3, 0x04B1, - 0x04AF, 0x04AD, 0x04AB, 0x04A9, 0x04A7, 0x04A5, 0x04A3, 0x04A1, - 0x049F, 0x049D, 0x049B, 0x0499, 0x0497, 0x0495, 0x0493, 0x0491, - 0x048F, 0x048D, 0x048B, 0x0489, 0x0487, 0x0485, 0x0483, 0x0481, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x00BF, 0x00BD, 0x00BB, 0x00B9, 0x00B7, 0x00B5, 0x00B3, 0x00B1, - 0x00AF, 0x00AD, 0x00AB, 0x00A9, 0x00A7, 0x00A5, 0x00A3, 0x00A1, - 0x009F, 0x009D, 0x009B, 0x0099, 0x0097, 0x0095, 0x0093, 0x0091, - 0x008F, 0x008D, 0x008B, 0x0089, 0x0087, 0x0085, 0x0083, 0x0081, - 0x023F, 0x023D, 0x023B, 0x0239, 0x0237, 0x0235, 0x0233, 0x0231, - 0x022F, 0x022D, 0x022B, 0x0229, 0x0227, 0x0225, 0x0223, 0x0221, - 0x021F, 0x021D, 0x021B, 0x0219, 0x0217, 0x0215, 0x0213, 0x0211, - 0x020F, 0x020D, 0x020B, 0x0209, 0x0207, 0x0205, 0x0203, 0x0201, - 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, - 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, - 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, - 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, - 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, - 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, - 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, - 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, - 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, - 0x0075, 0x0073, 0x0071, 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, -}; - -static const uint8_t dc11_vlc_lens[2048] = { - 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 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, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 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, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, -}; - -#define RPT_2(a, b, c) { a, b, c }, { a, b, c } -#define RPT_4(a, b, c) RPT_2( a, b, c), RPT_2( a, b, c) -#define RPT_8(a, b, c) RPT_4( a, b, c), RPT_4( a, b, c) -#define RPT_16(a, b, c) RPT_8( a, b, c), RPT_8( a, b, c) -#define RPT_32(a, b, c) RPT_16( a, b, c), RPT_16( a, b, c) -#define RPT_64(a, b, c) RPT_32( a, b, c), RPT_32( a, b, c) -#define RPT_128(a, b, c) RPT_64( a, b, c), RPT_64( a, b, c) -#define RPT_256(a, b, c) RPT_128(a, b, c), RPT_128(a, b, c) -#define RPT_512(a, b, c) RPT_256(a, b, c), RPT_256(a, b, c) -#define RPT_1024(a, b, c) RPT_512(a, b, c), RPT_512(a, b, c) - -static const HQXLUT ac0_lut[] = { - RPT_64 ( 1, 0, 4 ), RPT_64 ( -1, 0, 4 ), - RPT_64 ( 2, 0, 4 ), RPT_64 ( -2, 0, 4 ), - RPT_32 ( 3, 0, 5 ), RPT_32 ( -3, 0, 5 ), - RPT_32 ( 4, 0, 5 ), RPT_32 ( -4, 0, 5 ), - RPT_32 ( 1, 1, 5 ), RPT_32 ( -1, 1, 5 ), - RPT_16 ( 5, 0, 6 ), RPT_16 ( -5, 0, 6 ), - RPT_16 ( 6, 0, 6 ), RPT_16 ( -6, 0, 6 ), - RPT_16 ( 7, 0, 6 ), RPT_16 ( -7, 0, 6 ), - RPT_16 ( 8, 0, 6 ), RPT_16 ( -8, 0, 6 ), - { 1024, 0, -1 }, { 1056, 0, -1 }, { 1088, 0, -1 }, { 1120, 0, -1 }, - { 1152, 0, -1 }, { 1184, 0, -1 }, { 1216, 0, -1 }, { 1248, 0, -1 }, - { 1280, 0, -1 }, { 1312, 0, -1 }, { 1344, 0, -1 }, { 1376, 0, -1 }, - { 1408, 0, -1 }, { 1440, 0, -1 }, { 1472, 0, -1 }, { 1504, 0, -1 }, - { 1536, 0, -1 }, { 1568, 0, -1 }, { 1600, 0, -1 }, { 1632, 0, -1 }, - { 1664, 0, -1 }, { 1696, 0, -1 }, { 1728, 0, -1 }, { 1760, 0, -1 }, - { 1792, 0, -1 }, { 1824, 0, -1 }, { 1856, 0, -1 }, { 1888, 0, -1 }, - { 1920, 0, -1 }, { 1952, 0, -1 }, { 1984, 0, -1 }, { 2016, 0, -1 }, - RPT_32 ( 0, 64, 5 ), RPT_8 ( 9, 0, 7 ), - RPT_8 ( -9, 0, 7 ), RPT_8 ( 10, 0, 7 ), - RPT_8 ( -10, 0, 7 ), RPT_8 ( 11, 0, 7 ), - RPT_8 ( -11, 0, 7 ), RPT_8 ( 12, 0, 7 ), - RPT_8 ( -12, 0, 7 ), RPT_8 ( 13, 0, 7 ), - RPT_8 ( -13, 0, 7 ), RPT_8 ( 14, 0, 7 ), - RPT_8 ( -14, 0, 7 ), RPT_8 ( 2, 1, 7 ), - RPT_8 ( -2, 1, 7 ), RPT_8 ( 1, 2, 7 ), - RPT_8 ( -1, 2, 7 ), RPT_4 ( 15, 0, 8 ), - RPT_4 ( -15, 0, 8 ), RPT_4 ( 16, 0, 8 ), - RPT_4 ( -16, 0, 8 ), RPT_4 ( 17, 0, 8 ), - RPT_4 ( -17, 0, 8 ), RPT_4 ( 18, 0, 8 ), - RPT_4 ( -18, 0, 8 ), RPT_4 ( 19, 0, 8 ), - RPT_4 ( -19, 0, 8 ), RPT_4 ( 20, 0, 8 ), - RPT_4 ( -20, 0, 8 ), RPT_4 ( 21, 0, 8 ), - RPT_4 ( -21, 0, 8 ), RPT_4 ( 3, 1, 8 ), - RPT_4 ( -3, 1, 8 ), RPT_4 ( 4, 1, 8 ), - RPT_4 ( -4, 1, 8 ), RPT_4 ( 1, 3, 8 ), - RPT_4 ( -1, 3, 8 ), RPT_4 ( 1, 4, 8 ), - RPT_4 ( -1, 4, 8 ), RPT_4 ( 0, 0, 8 ), - RPT_2 ( 22, 0, 9 ), RPT_2 ( -22, 0, 9 ), - RPT_2 ( 23, 0, 9 ), RPT_2 ( -23, 0, 9 ), - RPT_2 ( 24, 0, 9 ), RPT_2 ( -24, 0, 9 ), - RPT_2 ( 25, 0, 9 ), RPT_2 ( -25, 0, 9 ), - RPT_2 ( 26, 0, 9 ), RPT_2 ( -26, 0, 9 ), - RPT_2 ( 27, 0, 9 ), RPT_2 ( -27, 0, 9 ), - RPT_2 ( 28, 0, 9 ), RPT_2 ( -28, 0, 9 ), - RPT_2 ( 29, 0, 9 ), RPT_2 ( -29, 0, 9 ), - RPT_2 ( 30, 0, 9 ), RPT_2 ( -30, 0, 9 ), - RPT_2 ( 31, 0, 9 ), RPT_2 ( -31, 0, 9 ), - RPT_2 ( 32, 0, 9 ), RPT_2 ( -32, 0, 9 ), - RPT_2 ( 33, 0, 9 ), RPT_2 ( -33, 0, 9 ), - RPT_2 ( 5, 1, 9 ), RPT_2 ( -5, 1, 9 ), - RPT_2 ( 6, 1, 9 ), RPT_2 ( -6, 1, 9 ), - RPT_2 ( 2, 2, 9 ), RPT_2 ( -2, 2, 9 ), - RPT_2 ( 1, 5, 9 ), RPT_2 ( -1, 5, 9 ), - RPT_2 ( 1, 6, 9 ), RPT_2 ( -1, 6, 9 ), - { 34, 0, 10 }, { -34, 0, 10 }, { 35, 0, 10 }, { -35, 0, 10 }, - { 36, 0, 10 }, { -36, 0, 10 }, { 37, 0, 10 }, { -37, 0, 10 }, - { 38, 0, 10 }, { -38, 0, 10 }, { 39, 0, 10 }, { -39, 0, 10 }, - { 40, 0, 10 }, { -40, 0, 10 }, { 41, 0, 10 }, { -41, 0, 10 }, - { 42, 0, 10 }, { -42, 0, 10 }, { 43, 0, 10 }, { -43, 0, 10 }, - { 44, 0, 10 }, { -44, 0, 10 }, { 45, 0, 10 }, { -45, 0, 10 }, - { 46, 0, 10 }, { -46, 0, 10 }, { 47, 0, 10 }, { -47, 0, 10 }, - { 48, 0, 10 }, { -48, 0, 10 }, { 49, 0, 10 }, { -49, 0, 10 }, - { 50, 0, 10 }, { -50, 0, 10 }, RPT_2 ( 0, 1, 9 ), - { 7, 1, 10 }, { -7, 1, 10 }, { 8, 1, 10 }, { -8, 1, 10 }, - { 9, 1, 10 }, { -9, 1, 10 }, { 10, 1, 10 }, { -10, 1, 10 }, - RPT_2 ( 0, 2, 9 ), { 3, 2, 10 }, { -3, 2, 10 }, - RPT_2 ( 0, 3, 9 ), { 2, 3, 10 }, { -2, 3, 10 }, - { 1, 7, 10 }, { -1, 7, 10 }, { 1, 8, 10 }, { -1, 8, 10 }, - { 2048, 0, -1 }, { 2080, 0, -1 }, { 2112, 0, -1 }, { 2144, 0, -1 }, - { 2176, 0, -1 }, { 2208, 0, -1 }, { 2240, 0, -1 }, { 2272, 0, -1 }, - { 2304, 0, -1 }, { 2336, 0, -1 }, { 2368, 0, -1 }, { 2400, 0, -1 }, - { 2432, 0, -1 }, { 2464, 0, -1 }, { 2496, 0, -1 }, { 2528, 0, -1 }, - { 2560, 0, -1 }, { 2592, 0, -1 }, { 2624, 0, -1 }, { 2656, 0, -1 }, - { 2688, 0, -1 }, { 2720, 0, -1 }, { 2752, 0, -1 }, { 0, 4, 10 }, - { 2784, 0, -1 }, { 0, 5, 10 }, { 0, 6, 10 }, { 2816, 0, -1 }, - { 2848, 0, -1 }, { 2880, 0, -1 }, { 2912, 0, -1 }, { 2944, 0, -1 }, - { 2976, 0, -1 }, { 3008, 0, -1 }, { 3040, 0, -1 }, { 3072, 0, -1 }, - { 3104, 0, -1 }, { 3136, 0, -1 }, { 3168, 0, -1 }, { 3200, 0, -1 }, - RPT_4 ( 0, 0, 13 ), RPT_2 ( 1, 0, 14 ), - RPT_2 ( -1, 0, 14 ), RPT_2 ( 2, 0, 14 ), - RPT_2 ( -2, 0, 14 ), RPT_2 ( 3, 0, 14 ), - RPT_2 ( -3, 0, 14 ), RPT_2 ( 4, 0, 14 ), - RPT_2 ( -4, 0, 14 ), RPT_2 ( 5, 0, 14 ), - RPT_2 ( -5, 0, 14 ), RPT_2 ( 6, 0, 14 ), - RPT_2 ( -6, 0, 14 ), RPT_2 ( 7, 0, 14 ), - RPT_2 ( -7, 0, 14 ), RPT_2 ( 8, 0, 14 ), - RPT_2 ( -8, 0, 14 ), RPT_2 ( 9, 0, 14 ), - RPT_2 ( -9, 0, 14 ), RPT_2 ( 10, 0, 14 ), - RPT_2 ( -10, 0, 14 ), RPT_2 ( 11, 0, 14 ), - RPT_2 ( -11, 0, 14 ), RPT_2 ( 12, 0, 14 ), - RPT_2 ( -12, 0, 14 ), RPT_2 ( 13, 0, 14 ), - RPT_2 ( -13, 0, 14 ), RPT_2 ( 14, 0, 14 ), - RPT_2 ( -14, 0, 14 ), RPT_2 ( 15, 0, 14 ), - RPT_2 ( -15, 0, 14 ), RPT_2 ( 16, 0, 14 ), - RPT_2 ( -16, 0, 14 ), RPT_2 ( 17, 0, 14 ), - RPT_2 ( -17, 0, 14 ), RPT_2 ( 18, 0, 14 ), - RPT_2 ( -18, 0, 14 ), RPT_2 ( 19, 0, 14 ), - RPT_2 ( -19, 0, 14 ), RPT_2 ( 20, 0, 14 ), - RPT_2 ( -20, 0, 14 ), RPT_2 ( 21, 0, 14 ), - RPT_2 ( -21, 0, 14 ), RPT_2 ( 22, 0, 14 ), - RPT_2 ( -22, 0, 14 ), RPT_2 ( 23, 0, 14 ), - RPT_2 ( -23, 0, 14 ), RPT_2 ( 24, 0, 14 ), - RPT_2 ( -24, 0, 14 ), RPT_2 ( 25, 0, 14 ), - RPT_2 ( -25, 0, 14 ), RPT_2 ( 26, 0, 14 ), - RPT_2 ( -26, 0, 14 ), RPT_2 ( 27, 0, 14 ), - RPT_2 ( -27, 0, 14 ), RPT_2 ( 28, 0, 14 ), - RPT_2 ( -28, 0, 14 ), RPT_2 ( 29, 0, 14 ), - RPT_2 ( -29, 0, 14 ), RPT_2 ( 30, 0, 14 ), - RPT_2 ( -30, 0, 14 ), RPT_2 ( 31, 0, 14 ), - RPT_2 ( -31, 0, 14 ), RPT_2 ( 32, 0, 14 ), - RPT_2 ( -32, 0, 14 ), RPT_2 ( 33, 0, 14 ), - RPT_2 ( -33, 0, 14 ), RPT_2 ( 34, 0, 14 ), - RPT_2 ( -34, 0, 14 ), RPT_2 ( 35, 0, 14 ), - RPT_2 ( -35, 0, 14 ), RPT_2 ( 36, 0, 14 ), - RPT_2 ( -36, 0, 14 ), RPT_2 ( 37, 0, 14 ), - RPT_2 ( -37, 0, 14 ), RPT_2 ( 38, 0, 14 ), - RPT_2 ( -38, 0, 14 ), RPT_2 ( 39, 0, 14 ), - RPT_2 ( -39, 0, 14 ), RPT_2 ( 40, 0, 14 ), - RPT_2 ( -40, 0, 14 ), RPT_2 ( 41, 0, 14 ), - RPT_2 ( -41, 0, 14 ), RPT_2 ( 42, 0, 14 ), - RPT_2 ( -42, 0, 14 ), RPT_2 ( 43, 0, 14 ), - RPT_2 ( -43, 0, 14 ), RPT_2 ( 44, 0, 14 ), - RPT_2 ( -44, 0, 14 ), RPT_2 ( 45, 0, 14 ), - RPT_2 ( -45, 0, 14 ), RPT_2 ( 46, 0, 14 ), - RPT_2 ( -46, 0, 14 ), RPT_2 ( 47, 0, 14 ), - RPT_2 ( -47, 0, 14 ), RPT_2 ( 48, 0, 14 ), - RPT_2 ( -48, 0, 14 ), RPT_2 ( 49, 0, 14 ), - RPT_2 ( -49, 0, 14 ), RPT_2 ( 50, 0, 14 ), - RPT_2 ( -50, 0, 14 ), RPT_2 ( 51, 0, 14 ), - RPT_2 ( -51, 0, 14 ), RPT_2 ( 52, 0, 14 ), - RPT_2 ( -52, 0, 14 ), RPT_2 ( 53, 0, 14 ), - RPT_2 ( -53, 0, 14 ), RPT_2 ( 54, 0, 14 ), - RPT_2 ( -54, 0, 14 ), RPT_2 ( 55, 0, 14 ), - RPT_2 ( -55, 0, 14 ), RPT_2 ( 56, 0, 14 ), - RPT_2 ( -56, 0, 14 ), RPT_2 ( 57, 0, 14 ), - RPT_2 ( -57, 0, 14 ), RPT_2 ( 58, 0, 14 ), - RPT_2 ( -58, 0, 14 ), RPT_2 ( 59, 0, 14 ), - RPT_2 ( -59, 0, 14 ), RPT_2 ( 60, 0, 14 ), - RPT_2 ( -60, 0, 14 ), RPT_2 ( 61, 0, 14 ), - RPT_2 ( -61, 0, 14 ), RPT_2 ( 62, 0, 14 ), - RPT_2 ( -62, 0, 14 ), RPT_2 ( 63, 0, 14 ), - RPT_2 ( -63, 0, 14 ), RPT_2 ( 64, 0, 14 ), - RPT_2 ( -64, 0, 14 ), RPT_2 ( 65, 0, 14 ), - RPT_2 ( -65, 0, 14 ), RPT_2 ( 66, 0, 14 ), - RPT_2 ( -66, 0, 14 ), RPT_2 ( 67, 0, 14 ), - RPT_2 ( -67, 0, 14 ), RPT_2 ( 68, 0, 14 ), - RPT_2 ( -68, 0, 14 ), RPT_2 ( 69, 0, 14 ), - RPT_2 ( -69, 0, 14 ), RPT_2 ( 70, 0, 14 ), - RPT_2 ( -70, 0, 14 ), RPT_2 ( 71, 0, 14 ), - RPT_2 ( -71, 0, 14 ), RPT_2 ( 72, 0, 14 ), - RPT_2 ( -72, 0, 14 ), RPT_2 ( 73, 0, 14 ), - RPT_2 ( -73, 0, 14 ), RPT_2 ( 74, 0, 14 ), - RPT_2 ( -74, 0, 14 ), RPT_2 ( 75, 0, 14 ), - RPT_2 ( -75, 0, 14 ), RPT_2 ( 76, 0, 14 ), - RPT_2 ( -76, 0, 14 ), RPT_2 ( 77, 0, 14 ), - RPT_2 ( -77, 0, 14 ), RPT_2 ( 78, 0, 14 ), - RPT_2 ( -78, 0, 14 ), RPT_2 ( 79, 0, 14 ), - RPT_2 ( -79, 0, 14 ), RPT_2 ( 80, 0, 14 ), - RPT_2 ( -80, 0, 14 ), RPT_2 ( 81, 0, 14 ), - RPT_2 ( -81, 0, 14 ), RPT_2 ( 82, 0, 14 ), - RPT_2 ( -82, 0, 14 ), RPT_2 ( 83, 0, 14 ), - RPT_2 ( -83, 0, 14 ), RPT_2 ( 84, 0, 14 ), - RPT_2 ( -84, 0, 14 ), RPT_2 ( 85, 0, 14 ), - RPT_2 ( -85, 0, 14 ), RPT_2 ( 86, 0, 14 ), - RPT_2 ( -86, 0, 14 ), RPT_2 ( 87, 0, 14 ), - RPT_2 ( -87, 0, 14 ), RPT_2 ( 88, 0, 14 ), - RPT_2 ( -88, 0, 14 ), RPT_2 ( 89, 0, 14 ), - RPT_2 ( -89, 0, 14 ), RPT_2 ( 90, 0, 14 ), - RPT_2 ( -90, 0, 14 ), RPT_2 ( 91, 0, 14 ), - RPT_2 ( -91, 0, 14 ), RPT_2 ( 92, 0, 14 ), - RPT_2 ( -92, 0, 14 ), RPT_2 ( 93, 0, 14 ), - RPT_2 ( -93, 0, 14 ), RPT_2 ( 94, 0, 14 ), - RPT_2 ( -94, 0, 14 ), RPT_2 ( 95, 0, 14 ), - RPT_2 ( -95, 0, 14 ), RPT_2 ( 96, 0, 14 ), - RPT_2 ( -96, 0, 14 ), RPT_2 ( 97, 0, 14 ), - RPT_2 ( -97, 0, 14 ), RPT_2 ( 98, 0, 14 ), - RPT_2 ( -98, 0, 14 ), RPT_2 ( 99, 0, 14 ), - RPT_2 ( -99, 0, 14 ), RPT_2 ( 100, 0, 14 ), - RPT_2 (-100, 0, 14 ), RPT_2 ( 101, 0, 14 ), - RPT_2 (-101, 0, 14 ), RPT_2 ( 102, 0, 14 ), - RPT_2 (-102, 0, 14 ), RPT_2 ( 103, 0, 14 ), - RPT_2 (-103, 0, 14 ), RPT_2 ( 104, 0, 14 ), - RPT_2 (-104, 0, 14 ), RPT_2 ( 105, 0, 14 ), - RPT_2 (-105, 0, 14 ), RPT_2 ( 106, 0, 14 ), - RPT_2 (-106, 0, 14 ), RPT_2 ( 107, 0, 14 ), - RPT_2 (-107, 0, 14 ), RPT_2 ( 108, 0, 14 ), - RPT_2 (-108, 0, 14 ), RPT_2 ( 109, 0, 14 ), - RPT_2 (-109, 0, 14 ), RPT_2 ( 110, 0, 14 ), - RPT_2 (-110, 0, 14 ), RPT_2 ( 111, 0, 14 ), - RPT_2 (-111, 0, 14 ), RPT_2 ( 112, 0, 14 ), - RPT_2 (-112, 0, 14 ), RPT_2 ( 113, 0, 14 ), - RPT_2 (-113, 0, 14 ), RPT_2 ( 114, 0, 14 ), - RPT_2 (-114, 0, 14 ), RPT_2 ( 115, 0, 14 ), - RPT_2 (-115, 0, 14 ), RPT_2 ( 116, 0, 14 ), - RPT_2 (-116, 0, 14 ), RPT_2 ( 117, 0, 14 ), - RPT_2 (-117, 0, 14 ), RPT_2 ( 118, 0, 14 ), - RPT_2 (-118, 0, 14 ), RPT_2 ( 119, 0, 14 ), - RPT_2 (-119, 0, 14 ), RPT_2 ( 120, 0, 14 ), - RPT_2 (-120, 0, 14 ), RPT_2 ( 121, 0, 14 ), - RPT_2 (-121, 0, 14 ), RPT_2 ( 122, 0, 14 ), - RPT_2 (-122, 0, 14 ), RPT_2 ( 123, 0, 14 ), - RPT_2 (-123, 0, 14 ), RPT_2 ( 124, 0, 14 ), - RPT_2 (-124, 0, 14 ), RPT_2 ( 125, 0, 14 ), - RPT_2 (-125, 0, 14 ), RPT_2 ( 126, 0, 14 ), - RPT_2 (-126, 0, 14 ), RPT_2 ( 127, 0, 14 ), - RPT_2 (-127, 0, 14 ), RPT_2 ( 128, 0, 14 ), - RPT_2 (-128, 0, 14 ), RPT_2 ( 129, 0, 14 ), - RPT_2 (-129, 0, 14 ), RPT_2 ( 130, 0, 14 ), - RPT_2 (-130, 0, 14 ), RPT_2 ( 131, 0, 14 ), - RPT_2 (-131, 0, 14 ), RPT_2 ( 132, 0, 14 ), - RPT_2 (-132, 0, 14 ), RPT_2 ( 133, 0, 14 ), - RPT_2 (-133, 0, 14 ), RPT_2 ( 134, 0, 14 ), - RPT_2 (-134, 0, 14 ), RPT_2 ( 135, 0, 14 ), - RPT_2 (-135, 0, 14 ), RPT_2 ( 136, 0, 14 ), - RPT_2 (-136, 0, 14 ), RPT_2 ( 137, 0, 14 ), - RPT_2 (-137, 0, 14 ), RPT_2 ( 138, 0, 14 ), - RPT_2 (-138, 0, 14 ), RPT_2 ( 139, 0, 14 ), - RPT_2 (-139, 0, 14 ), RPT_2 ( 140, 0, 14 ), - RPT_2 (-140, 0, 14 ), RPT_2 ( 141, 0, 14 ), - RPT_2 (-141, 0, 14 ), RPT_2 ( 142, 0, 14 ), - RPT_2 (-142, 0, 14 ), RPT_2 ( 143, 0, 14 ), - RPT_2 (-143, 0, 14 ), RPT_2 ( 144, 0, 14 ), - RPT_2 (-144, 0, 14 ), RPT_2 ( 145, 0, 14 ), - RPT_2 (-145, 0, 14 ), RPT_2 ( 146, 0, 14 ), - RPT_2 (-146, 0, 14 ), RPT_2 ( 147, 0, 14 ), - RPT_2 (-147, 0, 14 ), RPT_2 ( 148, 0, 14 ), - RPT_2 (-148, 0, 14 ), RPT_2 ( 149, 0, 14 ), - RPT_2 (-149, 0, 14 ), RPT_2 ( 150, 0, 14 ), - RPT_2 (-150, 0, 14 ), RPT_2 ( 151, 0, 14 ), - RPT_2 (-151, 0, 14 ), RPT_2 ( 152, 0, 14 ), - RPT_2 (-152, 0, 14 ), RPT_2 ( 153, 0, 14 ), - RPT_2 (-153, 0, 14 ), RPT_2 ( 154, 0, 14 ), - RPT_2 (-154, 0, 14 ), RPT_2 ( 155, 0, 14 ), - RPT_2 (-155, 0, 14 ), RPT_2 ( 156, 0, 14 ), - RPT_2 (-156, 0, 14 ), RPT_2 ( 157, 0, 14 ), - RPT_2 (-157, 0, 14 ), RPT_2 ( 158, 0, 14 ), - RPT_2 (-158, 0, 14 ), RPT_2 ( 159, 0, 14 ), - RPT_2 (-159, 0, 14 ), RPT_2 ( 160, 0, 14 ), - RPT_2 (-160, 0, 14 ), RPT_2 ( 161, 0, 14 ), - RPT_2 (-161, 0, 14 ), RPT_2 ( 162, 0, 14 ), - RPT_2 (-162, 0, 14 ), RPT_2 ( 163, 0, 14 ), - RPT_2 (-163, 0, 14 ), RPT_2 ( 164, 0, 14 ), - RPT_2 (-164, 0, 14 ), RPT_2 ( 165, 0, 14 ), - RPT_2 (-165, 0, 14 ), RPT_2 ( 166, 0, 14 ), - RPT_2 (-166, 0, 14 ), RPT_2 ( 167, 0, 14 ), - RPT_2 (-167, 0, 14 ), RPT_2 ( 168, 0, 14 ), - RPT_2 (-168, 0, 14 ), RPT_2 ( 169, 0, 14 ), - RPT_2 (-169, 0, 14 ), RPT_2 ( 170, 0, 14 ), - RPT_2 (-170, 0, 14 ), RPT_2 ( 171, 0, 14 ), - RPT_2 (-171, 0, 14 ), RPT_2 ( 172, 0, 14 ), - RPT_2 (-172, 0, 14 ), RPT_2 ( 173, 0, 14 ), - RPT_2 (-173, 0, 14 ), RPT_2 ( 174, 0, 14 ), - RPT_2 (-174, 0, 14 ), RPT_2 ( 175, 0, 14 ), - RPT_2 (-175, 0, 14 ), RPT_2 ( 176, 0, 14 ), - RPT_2 (-176, 0, 14 ), RPT_2 ( 177, 0, 14 ), - RPT_2 (-177, 0, 14 ), RPT_2 ( 178, 0, 14 ), - RPT_2 (-178, 0, 14 ), RPT_2 ( 179, 0, 14 ), - RPT_2 (-179, 0, 14 ), RPT_2 ( 180, 0, 14 ), - RPT_2 (-180, 0, 14 ), RPT_2 ( 181, 0, 14 ), - RPT_2 (-181, 0, 14 ), RPT_2 ( 182, 0, 14 ), - RPT_2 (-182, 0, 14 ), RPT_2 ( 183, 0, 14 ), - RPT_2 (-183, 0, 14 ), RPT_2 ( 184, 0, 14 ), - RPT_2 (-184, 0, 14 ), RPT_2 ( 185, 0, 14 ), - RPT_2 (-185, 0, 14 ), RPT_2 ( 186, 0, 14 ), - RPT_2 (-186, 0, 14 ), RPT_2 ( 187, 0, 14 ), - RPT_2 (-187, 0, 14 ), RPT_2 ( 188, 0, 14 ), - RPT_2 (-188, 0, 14 ), RPT_2 ( 189, 0, 14 ), - RPT_2 (-189, 0, 14 ), RPT_2 ( 190, 0, 14 ), - RPT_2 (-190, 0, 14 ), RPT_2 ( 191, 0, 14 ), - RPT_2 (-191, 0, 14 ), RPT_2 ( 192, 0, 14 ), - RPT_2 (-192, 0, 14 ), RPT_2 ( 193, 0, 14 ), - RPT_2 (-193, 0, 14 ), RPT_2 ( 194, 0, 14 ), - RPT_2 (-194, 0, 14 ), RPT_2 ( 195, 0, 14 ), - RPT_2 (-195, 0, 14 ), RPT_2 ( 196, 0, 14 ), - RPT_2 (-196, 0, 14 ), RPT_2 ( 197, 0, 14 ), - RPT_2 (-197, 0, 14 ), RPT_2 ( 198, 0, 14 ), - RPT_2 (-198, 0, 14 ), RPT_2 ( 199, 0, 14 ), - RPT_2 (-199, 0, 14 ), RPT_2 ( 200, 0, 14 ), - RPT_2 (-200, 0, 14 ), RPT_2 ( 201, 0, 14 ), - RPT_2 (-201, 0, 14 ), RPT_2 ( 202, 0, 14 ), - RPT_2 (-202, 0, 14 ), RPT_2 ( 203, 0, 14 ), - RPT_2 (-203, 0, 14 ), RPT_2 ( 204, 0, 14 ), - RPT_2 (-204, 0, 14 ), RPT_2 ( 205, 0, 14 ), - RPT_2 (-205, 0, 14 ), RPT_2 ( 206, 0, 14 ), - RPT_2 (-206, 0, 14 ), RPT_2 ( 207, 0, 14 ), - RPT_2 (-207, 0, 14 ), RPT_2 ( 208, 0, 14 ), - RPT_2 (-208, 0, 14 ), RPT_2 ( 209, 0, 14 ), - RPT_2 (-209, 0, 14 ), RPT_2 ( 210, 0, 14 ), - RPT_2 (-210, 0, 14 ), RPT_2 ( 211, 0, 14 ), - RPT_2 (-211, 0, 14 ), RPT_2 ( 212, 0, 14 ), - RPT_2 (-212, 0, 14 ), RPT_2 ( 213, 0, 14 ), - RPT_2 (-213, 0, 14 ), RPT_2 ( 214, 0, 14 ), - RPT_2 (-214, 0, 14 ), RPT_2 ( 215, 0, 14 ), - RPT_2 (-215, 0, 14 ), RPT_2 ( 216, 0, 14 ), - RPT_2 (-216, 0, 14 ), RPT_2 ( 217, 0, 14 ), - RPT_2 (-217, 0, 14 ), RPT_2 ( 218, 0, 14 ), - RPT_2 (-218, 0, 14 ), RPT_2 ( 219, 0, 14 ), - RPT_2 (-219, 0, 14 ), RPT_2 ( 220, 0, 14 ), - RPT_2 (-220, 0, 14 ), RPT_2 ( 221, 0, 14 ), - RPT_2 (-221, 0, 14 ), RPT_2 ( 222, 0, 14 ), - RPT_2 (-222, 0, 14 ), RPT_2 ( 223, 0, 14 ), - RPT_2 (-223, 0, 14 ), RPT_2 ( 224, 0, 14 ), - RPT_2 (-224, 0, 14 ), RPT_2 ( 225, 0, 14 ), - RPT_2 (-225, 0, 14 ), RPT_2 ( 226, 0, 14 ), - RPT_2 (-226, 0, 14 ), RPT_2 ( 227, 0, 14 ), - RPT_2 (-227, 0, 14 ), RPT_2 ( 228, 0, 14 ), - RPT_2 (-228, 0, 14 ), RPT_2 ( 229, 0, 14 ), - RPT_2 (-229, 0, 14 ), RPT_2 ( 230, 0, 14 ), - RPT_2 (-230, 0, 14 ), RPT_2 ( 231, 0, 14 ), - RPT_2 (-231, 0, 14 ), RPT_2 ( 232, 0, 14 ), - RPT_2 (-232, 0, 14 ), RPT_2 ( 233, 0, 14 ), - RPT_2 (-233, 0, 14 ), RPT_2 ( 234, 0, 14 ), - RPT_2 (-234, 0, 14 ), RPT_2 ( 235, 0, 14 ), - RPT_2 (-235, 0, 14 ), RPT_2 ( 236, 0, 14 ), - RPT_2 (-236, 0, 14 ), RPT_2 ( 237, 0, 14 ), - RPT_2 (-237, 0, 14 ), RPT_2 ( 238, 0, 14 ), - RPT_2 (-238, 0, 14 ), RPT_2 ( 239, 0, 14 ), - RPT_2 (-239, 0, 14 ), RPT_2 ( 240, 0, 14 ), - RPT_2 (-240, 0, 14 ), RPT_2 ( 241, 0, 14 ), - RPT_2 (-241, 0, 14 ), RPT_2 ( 242, 0, 14 ), - RPT_2 (-242, 0, 14 ), RPT_2 ( 243, 0, 14 ), - RPT_2 (-243, 0, 14 ), RPT_2 ( 244, 0, 14 ), - RPT_2 (-244, 0, 14 ), RPT_2 ( 245, 0, 14 ), - RPT_2 (-245, 0, 14 ), RPT_2 ( 246, 0, 14 ), - RPT_2 (-246, 0, 14 ), RPT_2 ( 247, 0, 14 ), - RPT_2 (-247, 0, 14 ), RPT_2 ( 248, 0, 14 ), - RPT_2 (-248, 0, 14 ), RPT_2 ( 249, 0, 14 ), - RPT_2 (-249, 0, 14 ), RPT_2 ( 250, 0, 14 ), - RPT_2 (-250, 0, 14 ), RPT_2 ( 251, 0, 14 ), - RPT_2 (-251, 0, 14 ), RPT_2 ( 252, 0, 14 ), - RPT_2 (-252, 0, 14 ), RPT_2 ( 253, 0, 14 ), - RPT_2 (-253, 0, 14 ), RPT_2 ( 254, 0, 14 ), - RPT_2 (-254, 0, 14 ), RPT_2 ( 255, 0, 14 ), - RPT_2 (-255, 0, 14 ), { 0, 0, 15 }, { 0, 1, 15 }, - { 0, 2, 15 }, { 0, 3, 15 }, { 0, 4, 15 }, { 0, 5, 15 }, - { 0, 6, 15 }, { 0, 7, 15 }, { 0, 8, 15 }, { 0, 9, 15 }, - { 0, 10, 15 }, { 0, 11, 15 }, { 0, 12, 15 }, { 0, 13, 15 }, - { 0, 14, 15 }, { 0, 15, 15 }, { 0, 16, 15 }, { 0, 17, 15 }, - { 0, 18, 15 }, { 0, 19, 15 }, { 0, 20, 15 }, { 0, 21, 15 }, - { 0, 22, 15 }, { 0, 23, 15 }, { 0, 24, 15 }, { 0, 25, 15 }, - { 0, 26, 15 }, { 0, 27, 15 }, { 0, 28, 15 }, { 0, 29, 15 }, - { 0, 30, 15 }, { 0, 31, 15 }, { 0, 32, 15 }, { 0, 33, 15 }, - { 0, 34, 15 }, { 0, 35, 15 }, { 0, 36, 15 }, { 0, 37, 15 }, - { 0, 38, 15 }, { 0, 39, 15 }, { 0, 40, 15 }, { 0, 41, 15 }, - { 0, 42, 15 }, { 0, 43, 15 }, { 0, 44, 15 }, { 0, 45, 15 }, - { 0, 46, 15 }, { 0, 47, 15 }, { 0, 48, 15 }, { 0, 49, 15 }, - { 0, 50, 15 }, { 0, 51, 15 }, { 0, 52, 15 }, { 0, 53, 15 }, - { 0, 54, 15 }, { 0, 55, 15 }, { 0, 56, 15 }, { 0, 57, 15 }, - { 0, 58, 15 }, { 0, 59, 15 }, { 0, 60, 15 }, { 0, 61, 15 }, - { 0, 62, 15 }, { 0, 63, 15 }, RPT_16 ( 51, 0, 11 ), - RPT_16 ( -51, 0, 11 ), RPT_16 ( 52, 0, 11 ), - RPT_16 ( -52, 0, 11 ), RPT_16 ( 53, 0, 11 ), - RPT_16 ( -53, 0, 11 ), RPT_16 ( 54, 0, 11 ), - RPT_16 ( -54, 0, 11 ), RPT_16 ( 55, 0, 11 ), - RPT_16 ( -55, 0, 11 ), RPT_16 ( 56, 0, 11 ), - RPT_16 ( -56, 0, 11 ), RPT_16 ( 57, 0, 11 ), - RPT_16 ( -57, 0, 11 ), RPT_16 ( 58, 0, 11 ), - RPT_16 ( -58, 0, 11 ), RPT_16 ( 59, 0, 11 ), - RPT_16 ( -59, 0, 11 ), RPT_16 ( 60, 0, 11 ), - RPT_16 ( -60, 0, 11 ), RPT_16 ( 61, 0, 11 ), - RPT_16 ( -61, 0, 11 ), RPT_16 ( 62, 0, 11 ), - RPT_16 ( -62, 0, 11 ), RPT_16 ( 63, 0, 11 ), - RPT_16 ( -63, 0, 11 ), RPT_16 ( 11, 1, 11 ), - RPT_16 ( -11, 1, 11 ), RPT_16 ( 12, 1, 11 ), - RPT_16 ( -12, 1, 11 ), RPT_16 ( 13, 1, 11 ), - RPT_16 ( -13, 1, 11 ), RPT_16 ( 14, 1, 11 ), - RPT_16 ( -14, 1, 11 ), RPT_16 ( 4, 2, 11 ), - RPT_16 ( -4, 2, 11 ), RPT_16 ( 5, 2, 11 ), - RPT_16 ( -5, 2, 11 ), RPT_16 ( 6, 2, 11 ), - RPT_16 ( -6, 2, 11 ), RPT_16 ( 3, 3, 11 ), - RPT_16 ( -3, 3, 11 ), RPT_16 ( 2, 4, 11 ), - RPT_16 ( -2, 4, 11 ), RPT_16 ( 1, 9, 11 ), - RPT_16 ( -1, 9, 11 ), RPT_16 ( 1, 10, 11 ), - RPT_16 ( -1, 10, 11 ), RPT_8 ( 15, 1, 12 ), - RPT_8 ( -15, 1, 12 ), RPT_8 ( 16, 1, 12 ), - RPT_8 ( -16, 1, 12 ), RPT_8 ( 17, 1, 12 ), - RPT_8 ( -17, 1, 12 ), RPT_8 ( 18, 1, 12 ), - RPT_8 ( -18, 1, 12 ), RPT_8 ( 7, 2, 12 ), - RPT_8 ( -7, 2, 12 ), RPT_8 ( 8, 2, 12 ), - RPT_8 ( -8, 2, 12 ), RPT_8 ( 9, 2, 12 ), - RPT_8 ( -9, 2, 12 ), RPT_8 ( 10, 2, 12 ), - RPT_8 ( -10, 2, 12 ), RPT_8 ( 4, 3, 12 ), - RPT_8 ( -4, 3, 12 ), RPT_8 ( 5, 3, 12 ), - RPT_8 ( -5, 3, 12 ), RPT_8 ( 6, 3, 12 ), - RPT_8 ( -6, 3, 12 ), RPT_8 ( 2, 5, 12 ), - RPT_8 ( -2, 5, 12 ), RPT_16 ( 0, 7, 11 ), - RPT_16 ( 0, 8, 11 ), RPT_16 ( 0, 9, 11 ), - RPT_16 ( 0, 10, 11 ), RPT_8 ( 1, 11, 12 ), - RPT_8 ( -1, 11, 12 ), RPT_8 ( 1, 12, 12 ), - RPT_8 ( -1, 12, 12 ), RPT_8 ( 1, 13, 12 ), - RPT_8 ( -1, 13, 12 ), RPT_8 ( 1, 14, 12 ), - RPT_8 ( -1, 14, 12 ), RPT_4 ( 19, 1, 13 ), - RPT_4 ( -19, 1, 13 ), RPT_4 ( 20, 1, 13 ), - RPT_4 ( -20, 1, 13 ), RPT_4 ( 3, 4, 13 ), - RPT_4 ( -3, 4, 13 ), RPT_4 ( 2, 6, 13 ), - RPT_4 ( -2, 6, 13 ), -}; - -static const HQXLUT ac8_lut[] = { - RPT_128 ( 1, 0, 4 ), RPT_128 ( -1, 0, 4 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_64 ( 3, 0, 5 ), RPT_64 ( -3, 0, 5 ), - RPT_64 ( 4, 0, 5 ), RPT_64 ( -4, 0, 5 ), - RPT_128 ( 0, 64, 4 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 6, 0, 6 ), - RPT_32 ( -6, 0, 6 ), RPT_32 ( 7, 0, 6 ), - RPT_32 ( -7, 0, 6 ), RPT_32 ( 8, 0, 6 ), - RPT_32 ( -8, 0, 6 ), RPT_32 ( 1, 1, 6 ), - RPT_32 ( -1, 1, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_16 ( 9, 0, 7 ), - RPT_16 ( -9, 0, 7 ), RPT_16 ( 10, 0, 7 ), - RPT_16 ( -10, 0, 7 ), RPT_16 ( 11, 0, 7 ), - RPT_16 ( -11, 0, 7 ), RPT_16 ( 12, 0, 7 ), - RPT_16 ( -12, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 4, 1, 7 ), - RPT_16 ( -4, 1, 7 ), RPT_16 ( 1, 2, 7 ), - RPT_16 ( -1, 2, 7 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, { 2304, 0, -1 }, { 2368, 0, -1 }, - { 2432, 0, -1 }, { 2496, 0, -1 }, { 2560, 0, -1 }, { 2624, 0, -1 }, - { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 2880, 0, -1 }, - { 2944, 0, -1 }, { 3008, 0, -1 }, { 3072, 0, -1 }, { 3136, 0, -1 }, - { 3200, 0, -1 }, { 3264, 0, -1 }, { 3328, 0, -1 }, { 3392, 0, -1 }, - { 3456, 0, -1 }, { 3520, 0, -1 }, { 3584, 0, -1 }, { 3648, 0, -1 }, - { 3712, 0, -1 }, { 3776, 0, -1 }, { 3840, 0, -1 }, { 3904, 0, -1 }, - { 3968, 0, -1 }, { 4032, 0, -1 }, RPT_8 ( 13, 0, 8 ), - RPT_8 ( -13, 0, 8 ), RPT_8 ( 14, 0, 8 ), - RPT_8 ( -14, 0, 8 ), RPT_8 ( 15, 0, 8 ), - RPT_8 ( -15, 0, 8 ), RPT_8 ( 16, 0, 8 ), - RPT_8 ( -16, 0, 8 ), RPT_8 ( 17, 0, 8 ), - RPT_8 ( -17, 0, 8 ), RPT_8 ( 18, 0, 8 ), - RPT_8 ( -18, 0, 8 ), RPT_8 ( 5, 1, 8 ), - RPT_8 ( -5, 1, 8 ), RPT_8 ( 6, 1, 8 ), - RPT_8 ( -6, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 3, 8 ), - RPT_8 ( -1, 3, 8 ), RPT_8 ( 0, 0, 8 ), - RPT_4 ( 19, 0, 9 ), RPT_4 ( -19, 0, 9 ), - RPT_4 ( 20, 0, 9 ), RPT_4 ( -20, 0, 9 ), - RPT_4 ( 21, 0, 9 ), RPT_4 ( -21, 0, 9 ), - RPT_4 ( 22, 0, 9 ), RPT_4 ( -22, 0, 9 ), - RPT_4 ( 23, 0, 9 ), RPT_4 ( -23, 0, 9 ), - RPT_4 ( 24, 0, 9 ), RPT_4 ( -24, 0, 9 ), - RPT_4 ( 25, 0, 9 ), RPT_4 ( -25, 0, 9 ), - RPT_4 ( 7, 1, 9 ), RPT_4 ( -7, 1, 9 ), - RPT_4 ( 8, 1, 9 ), RPT_4 ( -8, 1, 9 ), - RPT_4 ( 3, 2, 9 ), RPT_4 ( -3, 2, 9 ), - RPT_4 ( 2, 3, 9 ), RPT_4 ( -2, 3, 9 ), - RPT_4 ( 1, 4, 9 ), RPT_4 ( -1, 4, 9 ), - RPT_4 ( 1, 5, 9 ), RPT_4 ( -1, 5, 9 ), - RPT_2 ( 26, 0, 10 ), RPT_2 ( -26, 0, 10 ), - RPT_2 ( 27, 0, 10 ), RPT_2 ( -27, 0, 10 ), - RPT_2 ( 28, 0, 10 ), RPT_2 ( -28, 0, 10 ), - RPT_2 ( 29, 0, 10 ), RPT_2 ( -29, 0, 10 ), - RPT_2 ( 30, 0, 10 ), RPT_2 ( -30, 0, 10 ), - RPT_2 ( 31, 0, 10 ), RPT_2 ( -31, 0, 10 ), - RPT_2 ( 32, 0, 10 ), RPT_2 ( -32, 0, 10 ), - RPT_2 ( 33, 0, 10 ), RPT_2 ( -33, 0, 10 ), - RPT_2 ( 34, 0, 10 ), RPT_2 ( -34, 0, 10 ), - RPT_2 ( 35, 0, 10 ), RPT_2 ( -35, 0, 10 ), - RPT_2 ( 36, 0, 10 ), RPT_2 ( -36, 0, 10 ), - RPT_4 ( 0, 1, 9 ), RPT_2 ( 9, 1, 10 ), - RPT_2 ( -9, 1, 10 ), RPT_2 ( 10, 1, 10 ), - RPT_2 ( -10, 1, 10 ), RPT_2 ( 11, 1, 10 ), - RPT_2 ( -11, 1, 10 ), RPT_2 ( 12, 1, 10 ), - RPT_2 ( -12, 1, 10 ), RPT_4 ( 0, 2, 9 ), - RPT_2 ( 4, 2, 10 ), RPT_2 ( -4, 2, 10 ), - RPT_2 ( 5, 2, 10 ), RPT_2 ( -5, 2, 10 ), - RPT_2 ( 6, 2, 10 ), RPT_2 ( -6, 2, 10 ), - RPT_4 ( 0, 3, 9 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 4, 3, 10 ), - RPT_2 ( -4, 3, 10 ), RPT_4 ( 0, 4, 9 ), - RPT_2 ( 2, 4, 10 ), RPT_2 ( -2, 4, 10 ), - RPT_4 ( 0, 5, 9 ), RPT_2 ( 1, 6, 10 ), - RPT_2 ( -1, 6, 10 ), RPT_2 ( 1, 7, 10 ), - RPT_2 ( -1, 7, 10 ), RPT_2 ( 1, 8, 10 ), - RPT_2 ( -1, 8, 10 ), { 37, 0, 11 }, { -37, 0, 11 }, - { 38, 0, 11 }, { -38, 0, 11 }, { 39, 0, 11 }, { -39, 0, 11 }, - { 40, 0, 11 }, { -40, 0, 11 }, { 41, 0, 11 }, { -41, 0, 11 }, - { 42, 0, 11 }, { -42, 0, 11 }, { 43, 0, 11 }, { -43, 0, 11 }, - { 44, 0, 11 }, { -44, 0, 11 }, { 45, 0, 11 }, { -45, 0, 11 }, - { 46, 0, 11 }, { -46, 0, 11 }, { 47, 0, 11 }, { -47, 0, 11 }, - { 48, 0, 11 }, { -48, 0, 11 }, { 13, 1, 11 }, { -13, 1, 11 }, - { 14, 1, 11 }, { -14, 1, 11 }, { 15, 1, 11 }, { -15, 1, 11 }, - { 16, 1, 11 }, { -16, 1, 11 }, { 7, 2, 11 }, { -7, 2, 11 }, - { 8, 2, 11 }, { -8, 2, 11 }, { 5, 3, 11 }, { -5, 3, 11 }, - { 6, 3, 11 }, { -6, 3, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 4, 4, 11 }, { -4, 4, 11 }, { 2, 5, 11 }, { -2, 5, 11 }, - RPT_2 ( 0, 6, 10 ), { 2, 6, 11 }, { -2, 6, 11 }, - RPT_2 ( 0, 7, 10 ), RPT_2 ( 0, 8, 10 ), - RPT_2 ( 0, 9, 10 ), { 1, 9, 11 }, { -1, 9, 11 }, - { 1, 10, 11 }, { -1, 10, 11 }, { 1, 11, 11 }, { -1, 11, 11 }, - { 1, 12, 11 }, { -1, 12, 11 }, { 4096, 0, -1 }, { 4160, 0, -1 }, - { 4224, 0, -1 }, { 4288, 0, -1 }, { 4352, 0, -1 }, { 4416, 0, -1 }, - { 4480, 0, -1 }, { 4544, 0, -1 }, { 4608, 0, -1 }, { 4672, 0, -1 }, - { 4736, 0, -1 }, { 4800, 0, -1 }, { 4864, 0, -1 }, { 4928, 0, -1 }, - { 4992, 0, -1 }, { 5056, 0, -1 }, { 5120, 0, -1 }, { 5184, 0, -1 }, - { 5248, 0, -1 }, { 5312, 0, -1 }, { 5376, 0, -1 }, { 5440, 0, -1 }, - { 5504, 0, -1 }, { 5568, 0, -1 }, { 5632, 0, -1 }, { 5696, 0, -1 }, - { 5760, 0, -1 }, { 5824, 0, -1 }, { 5888, 0, -1 }, { 5952, 0, -1 }, - { 6016, 0, -1 }, { 6080, 0, -1 }, { 6144, 0, -1 }, { 6208, 0, -1 }, - { 6272, 0, -1 }, { 6336, 0, -1 }, { 6400, 0, -1 }, { 6464, 0, -1 }, - { 6528, 0, -1 }, { 6592, 0, -1 }, { 0, 10, 11 }, { 6656, 0, -1 }, - { 0, 11, 11 }, { 0, 12, 11 }, { 0, 13, 11 }, { 6720, 0, -1 }, - { 6784, 0, -1 }, { 6848, 0, -1 }, { 6912, 0, -1 }, { 6976, 0, -1 }, - { 7040, 0, -1 }, { 7104, 0, -1 }, { 7168, 0, -1 }, { 7232, 0, -1 }, - { 7296, 0, -1 }, { 7360, 0, -1 }, { 7424, 0, -1 }, { 7488, 0, -1 }, - { 7552, 0, -1 }, { 7616, 0, -1 }, RPT_8 ( 0, 0, 14 ), - RPT_4 ( 1, 0, 15 ), RPT_4 ( -1, 0, 15 ), - RPT_4 ( 2, 0, 15 ), RPT_4 ( -2, 0, 15 ), - RPT_4 ( 3, 0, 15 ), RPT_4 ( -3, 0, 15 ), - RPT_4 ( 4, 0, 15 ), RPT_4 ( -4, 0, 15 ), - RPT_4 ( 5, 0, 15 ), RPT_4 ( -5, 0, 15 ), - RPT_4 ( 6, 0, 15 ), RPT_4 ( -6, 0, 15 ), - RPT_4 ( 7, 0, 15 ), RPT_4 ( -7, 0, 15 ), - RPT_4 ( 8, 0, 15 ), RPT_4 ( -8, 0, 15 ), - RPT_4 ( 9, 0, 15 ), RPT_4 ( -9, 0, 15 ), - RPT_4 ( 10, 0, 15 ), RPT_4 ( -10, 0, 15 ), - RPT_4 ( 11, 0, 15 ), RPT_4 ( -11, 0, 15 ), - RPT_4 ( 12, 0, 15 ), RPT_4 ( -12, 0, 15 ), - RPT_4 ( 13, 0, 15 ), RPT_4 ( -13, 0, 15 ), - RPT_4 ( 14, 0, 15 ), RPT_4 ( -14, 0, 15 ), - RPT_4 ( 15, 0, 15 ), RPT_4 ( -15, 0, 15 ), - RPT_4 ( 16, 0, 15 ), RPT_4 ( -16, 0, 15 ), - RPT_4 ( 17, 0, 15 ), RPT_4 ( -17, 0, 15 ), - RPT_4 ( 18, 0, 15 ), RPT_4 ( -18, 0, 15 ), - RPT_4 ( 19, 0, 15 ), RPT_4 ( -19, 0, 15 ), - RPT_4 ( 20, 0, 15 ), RPT_4 ( -20, 0, 15 ), - RPT_4 ( 21, 0, 15 ), RPT_4 ( -21, 0, 15 ), - RPT_4 ( 22, 0, 15 ), RPT_4 ( -22, 0, 15 ), - RPT_4 ( 23, 0, 15 ), RPT_4 ( -23, 0, 15 ), - RPT_4 ( 24, 0, 15 ), RPT_4 ( -24, 0, 15 ), - RPT_4 ( 25, 0, 15 ), RPT_4 ( -25, 0, 15 ), - RPT_4 ( 26, 0, 15 ), RPT_4 ( -26, 0, 15 ), - RPT_4 ( 27, 0, 15 ), RPT_4 ( -27, 0, 15 ), - RPT_4 ( 28, 0, 15 ), RPT_4 ( -28, 0, 15 ), - RPT_4 ( 29, 0, 15 ), RPT_4 ( -29, 0, 15 ), - RPT_4 ( 30, 0, 15 ), RPT_4 ( -30, 0, 15 ), - RPT_4 ( 31, 0, 15 ), RPT_4 ( -31, 0, 15 ), - RPT_4 ( 32, 0, 15 ), RPT_4 ( -32, 0, 15 ), - RPT_4 ( 33, 0, 15 ), RPT_4 ( -33, 0, 15 ), - RPT_4 ( 34, 0, 15 ), RPT_4 ( -34, 0, 15 ), - RPT_4 ( 35, 0, 15 ), RPT_4 ( -35, 0, 15 ), - RPT_4 ( 36, 0, 15 ), RPT_4 ( -36, 0, 15 ), - RPT_4 ( 37, 0, 15 ), RPT_4 ( -37, 0, 15 ), - RPT_4 ( 38, 0, 15 ), RPT_4 ( -38, 0, 15 ), - RPT_4 ( 39, 0, 15 ), RPT_4 ( -39, 0, 15 ), - RPT_4 ( 40, 0, 15 ), RPT_4 ( -40, 0, 15 ), - RPT_4 ( 41, 0, 15 ), RPT_4 ( -41, 0, 15 ), - RPT_4 ( 42, 0, 15 ), RPT_4 ( -42, 0, 15 ), - RPT_4 ( 43, 0, 15 ), RPT_4 ( -43, 0, 15 ), - RPT_4 ( 44, 0, 15 ), RPT_4 ( -44, 0, 15 ), - RPT_4 ( 45, 0, 15 ), RPT_4 ( -45, 0, 15 ), - RPT_4 ( 46, 0, 15 ), RPT_4 ( -46, 0, 15 ), - RPT_4 ( 47, 0, 15 ), RPT_4 ( -47, 0, 15 ), - RPT_4 ( 48, 0, 15 ), RPT_4 ( -48, 0, 15 ), - RPT_4 ( 49, 0, 15 ), RPT_4 ( -49, 0, 15 ), - RPT_4 ( 50, 0, 15 ), RPT_4 ( -50, 0, 15 ), - RPT_4 ( 51, 0, 15 ), RPT_4 ( -51, 0, 15 ), - RPT_4 ( 52, 0, 15 ), RPT_4 ( -52, 0, 15 ), - RPT_4 ( 53, 0, 15 ), RPT_4 ( -53, 0, 15 ), - RPT_4 ( 54, 0, 15 ), RPT_4 ( -54, 0, 15 ), - RPT_4 ( 55, 0, 15 ), RPT_4 ( -55, 0, 15 ), - RPT_4 ( 56, 0, 15 ), RPT_4 ( -56, 0, 15 ), - RPT_4 ( 57, 0, 15 ), RPT_4 ( -57, 0, 15 ), - RPT_4 ( 58, 0, 15 ), RPT_4 ( -58, 0, 15 ), - RPT_4 ( 59, 0, 15 ), RPT_4 ( -59, 0, 15 ), - RPT_4 ( 60, 0, 15 ), RPT_4 ( -60, 0, 15 ), - RPT_4 ( 61, 0, 15 ), RPT_4 ( -61, 0, 15 ), - RPT_4 ( 62, 0, 15 ), RPT_4 ( -62, 0, 15 ), - RPT_4 ( 63, 0, 15 ), RPT_4 ( -63, 0, 15 ), - RPT_4 ( 64, 0, 15 ), RPT_4 ( -64, 0, 15 ), - RPT_4 ( 65, 0, 15 ), RPT_4 ( -65, 0, 15 ), - RPT_4 ( 66, 0, 15 ), RPT_4 ( -66, 0, 15 ), - RPT_4 ( 67, 0, 15 ), RPT_4 ( -67, 0, 15 ), - RPT_4 ( 68, 0, 15 ), RPT_4 ( -68, 0, 15 ), - RPT_4 ( 69, 0, 15 ), RPT_4 ( -69, 0, 15 ), - RPT_4 ( 70, 0, 15 ), RPT_4 ( -70, 0, 15 ), - RPT_4 ( 71, 0, 15 ), RPT_4 ( -71, 0, 15 ), - RPT_4 ( 72, 0, 15 ), RPT_4 ( -72, 0, 15 ), - RPT_4 ( 73, 0, 15 ), RPT_4 ( -73, 0, 15 ), - RPT_4 ( 74, 0, 15 ), RPT_4 ( -74, 0, 15 ), - RPT_4 ( 75, 0, 15 ), RPT_4 ( -75, 0, 15 ), - RPT_4 ( 76, 0, 15 ), RPT_4 ( -76, 0, 15 ), - RPT_4 ( 77, 0, 15 ), RPT_4 ( -77, 0, 15 ), - RPT_4 ( 78, 0, 15 ), RPT_4 ( -78, 0, 15 ), - RPT_4 ( 79, 0, 15 ), RPT_4 ( -79, 0, 15 ), - RPT_4 ( 80, 0, 15 ), RPT_4 ( -80, 0, 15 ), - RPT_4 ( 81, 0, 15 ), RPT_4 ( -81, 0, 15 ), - RPT_4 ( 82, 0, 15 ), RPT_4 ( -82, 0, 15 ), - RPT_4 ( 83, 0, 15 ), RPT_4 ( -83, 0, 15 ), - RPT_4 ( 84, 0, 15 ), RPT_4 ( -84, 0, 15 ), - RPT_4 ( 85, 0, 15 ), RPT_4 ( -85, 0, 15 ), - RPT_4 ( 86, 0, 15 ), RPT_4 ( -86, 0, 15 ), - RPT_4 ( 87, 0, 15 ), RPT_4 ( -87, 0, 15 ), - RPT_4 ( 88, 0, 15 ), RPT_4 ( -88, 0, 15 ), - RPT_4 ( 89, 0, 15 ), RPT_4 ( -89, 0, 15 ), - RPT_4 ( 90, 0, 15 ), RPT_4 ( -90, 0, 15 ), - RPT_4 ( 91, 0, 15 ), RPT_4 ( -91, 0, 15 ), - RPT_4 ( 92, 0, 15 ), RPT_4 ( -92, 0, 15 ), - RPT_4 ( 93, 0, 15 ), RPT_4 ( -93, 0, 15 ), - RPT_4 ( 94, 0, 15 ), RPT_4 ( -94, 0, 15 ), - RPT_4 ( 95, 0, 15 ), RPT_4 ( -95, 0, 15 ), - RPT_4 ( 96, 0, 15 ), RPT_4 ( -96, 0, 15 ), - RPT_4 ( 97, 0, 15 ), RPT_4 ( -97, 0, 15 ), - RPT_4 ( 98, 0, 15 ), RPT_4 ( -98, 0, 15 ), - RPT_4 ( 99, 0, 15 ), RPT_4 ( -99, 0, 15 ), - RPT_4 ( 100, 0, 15 ), RPT_4 (-100, 0, 15 ), - RPT_4 ( 101, 0, 15 ), RPT_4 (-101, 0, 15 ), - RPT_4 ( 102, 0, 15 ), RPT_4 (-102, 0, 15 ), - RPT_4 ( 103, 0, 15 ), RPT_4 (-103, 0, 15 ), - RPT_4 ( 104, 0, 15 ), RPT_4 (-104, 0, 15 ), - RPT_4 ( 105, 0, 15 ), RPT_4 (-105, 0, 15 ), - RPT_4 ( 106, 0, 15 ), RPT_4 (-106, 0, 15 ), - RPT_4 ( 107, 0, 15 ), RPT_4 (-107, 0, 15 ), - RPT_4 ( 108, 0, 15 ), RPT_4 (-108, 0, 15 ), - RPT_4 ( 109, 0, 15 ), RPT_4 (-109, 0, 15 ), - RPT_4 ( 110, 0, 15 ), RPT_4 (-110, 0, 15 ), - RPT_4 ( 111, 0, 15 ), RPT_4 (-111, 0, 15 ), - RPT_4 ( 112, 0, 15 ), RPT_4 (-112, 0, 15 ), - RPT_4 ( 113, 0, 15 ), RPT_4 (-113, 0, 15 ), - RPT_4 ( 114, 0, 15 ), RPT_4 (-114, 0, 15 ), - RPT_4 ( 115, 0, 15 ), RPT_4 (-115, 0, 15 ), - RPT_4 ( 116, 0, 15 ), RPT_4 (-116, 0, 15 ), - RPT_4 ( 117, 0, 15 ), RPT_4 (-117, 0, 15 ), - RPT_4 ( 118, 0, 15 ), RPT_4 (-118, 0, 15 ), - RPT_4 ( 119, 0, 15 ), RPT_4 (-119, 0, 15 ), - RPT_4 ( 120, 0, 15 ), RPT_4 (-120, 0, 15 ), - RPT_4 ( 121, 0, 15 ), RPT_4 (-121, 0, 15 ), - RPT_4 ( 122, 0, 15 ), RPT_4 (-122, 0, 15 ), - RPT_4 ( 123, 0, 15 ), RPT_4 (-123, 0, 15 ), - RPT_4 ( 124, 0, 15 ), RPT_4 (-124, 0, 15 ), - RPT_4 ( 125, 0, 15 ), RPT_4 (-125, 0, 15 ), - RPT_4 ( 126, 0, 15 ), RPT_4 (-126, 0, 15 ), - RPT_4 ( 127, 0, 15 ), RPT_4 (-127, 0, 15 ), - RPT_4 ( 128, 0, 15 ), RPT_4 (-128, 0, 15 ), - RPT_4 ( 129, 0, 15 ), RPT_4 (-129, 0, 15 ), - RPT_4 ( 130, 0, 15 ), RPT_4 (-130, 0, 15 ), - RPT_4 ( 131, 0, 15 ), RPT_4 (-131, 0, 15 ), - RPT_4 ( 132, 0, 15 ), RPT_4 (-132, 0, 15 ), - RPT_4 ( 133, 0, 15 ), RPT_4 (-133, 0, 15 ), - RPT_4 ( 134, 0, 15 ), RPT_4 (-134, 0, 15 ), - RPT_4 ( 135, 0, 15 ), RPT_4 (-135, 0, 15 ), - RPT_4 ( 136, 0, 15 ), RPT_4 (-136, 0, 15 ), - RPT_4 ( 137, 0, 15 ), RPT_4 (-137, 0, 15 ), - RPT_4 ( 138, 0, 15 ), RPT_4 (-138, 0, 15 ), - RPT_4 ( 139, 0, 15 ), RPT_4 (-139, 0, 15 ), - RPT_4 ( 140, 0, 15 ), RPT_4 (-140, 0, 15 ), - RPT_4 ( 141, 0, 15 ), RPT_4 (-141, 0, 15 ), - RPT_4 ( 142, 0, 15 ), RPT_4 (-142, 0, 15 ), - RPT_4 ( 143, 0, 15 ), RPT_4 (-143, 0, 15 ), - RPT_4 ( 144, 0, 15 ), RPT_4 (-144, 0, 15 ), - RPT_4 ( 145, 0, 15 ), RPT_4 (-145, 0, 15 ), - RPT_4 ( 146, 0, 15 ), RPT_4 (-146, 0, 15 ), - RPT_4 ( 147, 0, 15 ), RPT_4 (-147, 0, 15 ), - RPT_4 ( 148, 0, 15 ), RPT_4 (-148, 0, 15 ), - RPT_4 ( 149, 0, 15 ), RPT_4 (-149, 0, 15 ), - RPT_4 ( 150, 0, 15 ), RPT_4 (-150, 0, 15 ), - RPT_4 ( 151, 0, 15 ), RPT_4 (-151, 0, 15 ), - RPT_4 ( 152, 0, 15 ), RPT_4 (-152, 0, 15 ), - RPT_4 ( 153, 0, 15 ), RPT_4 (-153, 0, 15 ), - RPT_4 ( 154, 0, 15 ), RPT_4 (-154, 0, 15 ), - RPT_4 ( 155, 0, 15 ), RPT_4 (-155, 0, 15 ), - RPT_4 ( 156, 0, 15 ), RPT_4 (-156, 0, 15 ), - RPT_4 ( 157, 0, 15 ), RPT_4 (-157, 0, 15 ), - RPT_4 ( 158, 0, 15 ), RPT_4 (-158, 0, 15 ), - RPT_4 ( 159, 0, 15 ), RPT_4 (-159, 0, 15 ), - RPT_4 ( 160, 0, 15 ), RPT_4 (-160, 0, 15 ), - RPT_4 ( 161, 0, 15 ), RPT_4 (-161, 0, 15 ), - RPT_4 ( 162, 0, 15 ), RPT_4 (-162, 0, 15 ), - RPT_4 ( 163, 0, 15 ), RPT_4 (-163, 0, 15 ), - RPT_4 ( 164, 0, 15 ), RPT_4 (-164, 0, 15 ), - RPT_4 ( 165, 0, 15 ), RPT_4 (-165, 0, 15 ), - RPT_4 ( 166, 0, 15 ), RPT_4 (-166, 0, 15 ), - RPT_4 ( 167, 0, 15 ), RPT_4 (-167, 0, 15 ), - RPT_4 ( 168, 0, 15 ), RPT_4 (-168, 0, 15 ), - RPT_4 ( 169, 0, 15 ), RPT_4 (-169, 0, 15 ), - RPT_4 ( 170, 0, 15 ), RPT_4 (-170, 0, 15 ), - RPT_4 ( 171, 0, 15 ), RPT_4 (-171, 0, 15 ), - RPT_4 ( 172, 0, 15 ), RPT_4 (-172, 0, 15 ), - RPT_4 ( 173, 0, 15 ), RPT_4 (-173, 0, 15 ), - RPT_4 ( 174, 0, 15 ), RPT_4 (-174, 0, 15 ), - RPT_4 ( 175, 0, 15 ), RPT_4 (-175, 0, 15 ), - RPT_4 ( 176, 0, 15 ), RPT_4 (-176, 0, 15 ), - RPT_4 ( 177, 0, 15 ), RPT_4 (-177, 0, 15 ), - RPT_4 ( 178, 0, 15 ), RPT_4 (-178, 0, 15 ), - RPT_4 ( 179, 0, 15 ), RPT_4 (-179, 0, 15 ), - RPT_4 ( 180, 0, 15 ), RPT_4 (-180, 0, 15 ), - RPT_4 ( 181, 0, 15 ), RPT_4 (-181, 0, 15 ), - RPT_4 ( 182, 0, 15 ), RPT_4 (-182, 0, 15 ), - RPT_4 ( 183, 0, 15 ), RPT_4 (-183, 0, 15 ), - RPT_4 ( 184, 0, 15 ), RPT_4 (-184, 0, 15 ), - RPT_4 ( 185, 0, 15 ), RPT_4 (-185, 0, 15 ), - RPT_4 ( 186, 0, 15 ), RPT_4 (-186, 0, 15 ), - RPT_4 ( 187, 0, 15 ), RPT_4 (-187, 0, 15 ), - RPT_4 ( 188, 0, 15 ), RPT_4 (-188, 0, 15 ), - RPT_4 ( 189, 0, 15 ), RPT_4 (-189, 0, 15 ), - RPT_4 ( 190, 0, 15 ), RPT_4 (-190, 0, 15 ), - RPT_4 ( 191, 0, 15 ), RPT_4 (-191, 0, 15 ), - RPT_4 ( 192, 0, 15 ), RPT_4 (-192, 0, 15 ), - RPT_4 ( 193, 0, 15 ), RPT_4 (-193, 0, 15 ), - RPT_4 ( 194, 0, 15 ), RPT_4 (-194, 0, 15 ), - RPT_4 ( 195, 0, 15 ), RPT_4 (-195, 0, 15 ), - RPT_4 ( 196, 0, 15 ), RPT_4 (-196, 0, 15 ), - RPT_4 ( 197, 0, 15 ), RPT_4 (-197, 0, 15 ), - RPT_4 ( 198, 0, 15 ), RPT_4 (-198, 0, 15 ), - RPT_4 ( 199, 0, 15 ), RPT_4 (-199, 0, 15 ), - RPT_4 ( 200, 0, 15 ), RPT_4 (-200, 0, 15 ), - RPT_4 ( 201, 0, 15 ), RPT_4 (-201, 0, 15 ), - RPT_4 ( 202, 0, 15 ), RPT_4 (-202, 0, 15 ), - RPT_4 ( 203, 0, 15 ), RPT_4 (-203, 0, 15 ), - RPT_4 ( 204, 0, 15 ), RPT_4 (-204, 0, 15 ), - RPT_4 ( 205, 0, 15 ), RPT_4 (-205, 0, 15 ), - RPT_4 ( 206, 0, 15 ), RPT_4 (-206, 0, 15 ), - RPT_4 ( 207, 0, 15 ), RPT_4 (-207, 0, 15 ), - RPT_4 ( 208, 0, 15 ), RPT_4 (-208, 0, 15 ), - RPT_4 ( 209, 0, 15 ), RPT_4 (-209, 0, 15 ), - RPT_4 ( 210, 0, 15 ), RPT_4 (-210, 0, 15 ), - RPT_4 ( 211, 0, 15 ), RPT_4 (-211, 0, 15 ), - RPT_4 ( 212, 0, 15 ), RPT_4 (-212, 0, 15 ), - RPT_4 ( 213, 0, 15 ), RPT_4 (-213, 0, 15 ), - RPT_4 ( 214, 0, 15 ), RPT_4 (-214, 0, 15 ), - RPT_4 ( 215, 0, 15 ), RPT_4 (-215, 0, 15 ), - RPT_4 ( 216, 0, 15 ), RPT_4 (-216, 0, 15 ), - RPT_4 ( 217, 0, 15 ), RPT_4 (-217, 0, 15 ), - RPT_4 ( 218, 0, 15 ), RPT_4 (-218, 0, 15 ), - RPT_4 ( 219, 0, 15 ), RPT_4 (-219, 0, 15 ), - RPT_4 ( 220, 0, 15 ), RPT_4 (-220, 0, 15 ), - RPT_4 ( 221, 0, 15 ), RPT_4 (-221, 0, 15 ), - RPT_4 ( 222, 0, 15 ), RPT_4 (-222, 0, 15 ), - RPT_4 ( 223, 0, 15 ), RPT_4 (-223, 0, 15 ), - RPT_4 ( 224, 0, 15 ), RPT_4 (-224, 0, 15 ), - RPT_4 ( 225, 0, 15 ), RPT_4 (-225, 0, 15 ), - RPT_4 ( 226, 0, 15 ), RPT_4 (-226, 0, 15 ), - RPT_4 ( 227, 0, 15 ), RPT_4 (-227, 0, 15 ), - RPT_4 ( 228, 0, 15 ), RPT_4 (-228, 0, 15 ), - RPT_4 ( 229, 0, 15 ), RPT_4 (-229, 0, 15 ), - RPT_4 ( 230, 0, 15 ), RPT_4 (-230, 0, 15 ), - RPT_4 ( 231, 0, 15 ), RPT_4 (-231, 0, 15 ), - RPT_4 ( 232, 0, 15 ), RPT_4 (-232, 0, 15 ), - RPT_4 ( 233, 0, 15 ), RPT_4 (-233, 0, 15 ), - RPT_4 ( 234, 0, 15 ), RPT_4 (-234, 0, 15 ), - RPT_4 ( 235, 0, 15 ), RPT_4 (-235, 0, 15 ), - RPT_4 ( 236, 0, 15 ), RPT_4 (-236, 0, 15 ), - RPT_4 ( 237, 0, 15 ), RPT_4 (-237, 0, 15 ), - RPT_4 ( 238, 0, 15 ), RPT_4 (-238, 0, 15 ), - RPT_4 ( 239, 0, 15 ), RPT_4 (-239, 0, 15 ), - RPT_4 ( 240, 0, 15 ), RPT_4 (-240, 0, 15 ), - RPT_4 ( 241, 0, 15 ), RPT_4 (-241, 0, 15 ), - RPT_4 ( 242, 0, 15 ), RPT_4 (-242, 0, 15 ), - RPT_4 ( 243, 0, 15 ), RPT_4 (-243, 0, 15 ), - RPT_4 ( 244, 0, 15 ), RPT_4 (-244, 0, 15 ), - RPT_4 ( 245, 0, 15 ), RPT_4 (-245, 0, 15 ), - RPT_4 ( 246, 0, 15 ), RPT_4 (-246, 0, 15 ), - RPT_4 ( 247, 0, 15 ), RPT_4 (-247, 0, 15 ), - RPT_4 ( 248, 0, 15 ), RPT_4 (-248, 0, 15 ), - RPT_4 ( 249, 0, 15 ), RPT_4 (-249, 0, 15 ), - RPT_4 ( 250, 0, 15 ), RPT_4 (-250, 0, 15 ), - RPT_4 ( 251, 0, 15 ), RPT_4 (-251, 0, 15 ), - RPT_4 ( 252, 0, 15 ), RPT_4 (-252, 0, 15 ), - RPT_4 ( 253, 0, 15 ), RPT_4 (-253, 0, 15 ), - RPT_4 ( 254, 0, 15 ), RPT_4 (-254, 0, 15 ), - RPT_4 ( 255, 0, 15 ), RPT_4 (-255, 0, 15 ), - RPT_32 ( 49, 0, 12 ), RPT_32 ( -49, 0, 12 ), - RPT_32 ( 50, 0, 12 ), RPT_32 ( -50, 0, 12 ), - RPT_32 ( 51, 0, 12 ), RPT_32 ( -51, 0, 12 ), - RPT_32 ( 52, 0, 12 ), RPT_32 ( -52, 0, 12 ), - RPT_32 ( 53, 0, 12 ), RPT_32 ( -53, 0, 12 ), - RPT_32 ( 54, 0, 12 ), RPT_32 ( -54, 0, 12 ), - RPT_32 ( 55, 0, 12 ), RPT_32 ( -55, 0, 12 ), - RPT_32 ( 56, 0, 12 ), RPT_32 ( -56, 0, 12 ), - RPT_32 ( 57, 0, 12 ), RPT_32 ( -57, 0, 12 ), - RPT_32 ( 58, 0, 12 ), RPT_32 ( -58, 0, 12 ), - RPT_32 ( 59, 0, 12 ), RPT_32 ( -59, 0, 12 ), - RPT_32 ( 60, 0, 12 ), RPT_32 ( -60, 0, 12 ), - RPT_32 ( 61, 0, 12 ), RPT_32 ( -61, 0, 12 ), - RPT_32 ( 62, 0, 12 ), RPT_32 ( -62, 0, 12 ), - RPT_32 ( 63, 0, 12 ), RPT_32 ( -63, 0, 12 ), - RPT_32 ( 17, 1, 12 ), RPT_32 ( -17, 1, 12 ), - RPT_32 ( 18, 1, 12 ), RPT_32 ( -18, 1, 12 ), - RPT_32 ( 19, 1, 12 ), RPT_32 ( -19, 1, 12 ), - RPT_32 ( 20, 1, 12 ), RPT_32 ( -20, 1, 12 ), - RPT_32 ( 21, 1, 12 ), RPT_32 ( -21, 1, 12 ), - RPT_32 ( 22, 1, 12 ), RPT_32 ( -22, 1, 12 ), - RPT_32 ( 23, 1, 12 ), RPT_32 ( -23, 1, 12 ), - RPT_32 ( 24, 1, 12 ), RPT_32 ( -24, 1, 12 ), - RPT_32 ( 9, 2, 12 ), RPT_32 ( -9, 2, 12 ), - RPT_32 ( 10, 2, 12 ), RPT_32 ( -10, 2, 12 ), - RPT_32 ( 11, 2, 12 ), RPT_32 ( -11, 2, 12 ), - RPT_32 ( 12, 2, 12 ), RPT_32 ( -12, 2, 12 ), - RPT_32 ( 7, 3, 12 ), RPT_32 ( -7, 3, 12 ), - RPT_32 ( 8, 3, 12 ), RPT_32 ( -8, 3, 12 ), - RPT_32 ( 5, 4, 12 ), RPT_32 ( -5, 4, 12 ), - RPT_32 ( 6, 4, 12 ), RPT_32 ( -6, 4, 12 ), - RPT_32 ( 3, 5, 12 ), RPT_32 ( -3, 5, 12 ), - RPT_32 ( 4, 5, 12 ), RPT_32 ( -4, 5, 12 ), - RPT_32 ( 5, 5, 12 ), RPT_32 ( -5, 5, 12 ), - RPT_32 ( 6, 5, 12 ), RPT_32 ( -6, 5, 12 ), - RPT_32 ( 3, 6, 12 ), RPT_32 ( -3, 6, 12 ), - RPT_32 ( 4, 6, 12 ), RPT_32 ( -4, 6, 12 ), - RPT_32 ( 2, 7, 12 ), RPT_32 ( -2, 7, 12 ), - RPT_32 ( 2, 8, 12 ), RPT_32 ( -2, 8, 12 ), - RPT_32 ( 2, 9, 12 ), RPT_32 ( -2, 9, 12 ), - RPT_32 ( 2, 10, 12 ), RPT_32 ( -2, 10, 12 ), - RPT_32 ( 1, 13, 12 ), RPT_32 ( -1, 13, 12 ), - RPT_32 ( 1, 14, 12 ), RPT_32 ( -1, 14, 12 ), - { 0, 0, 17 }, { 0, 1, 17 }, { 0, 2, 17 }, { 0, 3, 17 }, - { 0, 4, 17 }, { 0, 5, 17 }, { 0, 6, 17 }, { 0, 7, 17 }, - { 0, 8, 17 }, { 0, 9, 17 }, { 0, 10, 17 }, { 0, 11, 17 }, - { 0, 12, 17 }, { 0, 13, 17 }, { 0, 14, 17 }, { 0, 15, 17 }, - { 0, 16, 17 }, { 0, 17, 17 }, { 0, 18, 17 }, { 0, 19, 17 }, - { 0, 20, 17 }, { 0, 21, 17 }, { 0, 22, 17 }, { 0, 23, 17 }, - { 0, 24, 17 }, { 0, 25, 17 }, { 0, 26, 17 }, { 0, 27, 17 }, - { 0, 28, 17 }, { 0, 29, 17 }, { 0, 30, 17 }, { 0, 31, 17 }, - { 0, 32, 17 }, { 0, 33, 17 }, { 0, 34, 17 }, { 0, 35, 17 }, - { 0, 36, 17 }, { 0, 37, 17 }, { 0, 38, 17 }, { 0, 39, 17 }, - { 0, 40, 17 }, { 0, 41, 17 }, { 0, 42, 17 }, { 0, 43, 17 }, - { 0, 44, 17 }, { 0, 45, 17 }, { 0, 46, 17 }, { 0, 47, 17 }, - { 0, 48, 17 }, { 0, 49, 17 }, { 0, 50, 17 }, { 0, 51, 17 }, - { 0, 52, 17 }, { 0, 53, 17 }, { 0, 54, 17 }, { 0, 55, 17 }, - { 0, 56, 17 }, { 0, 57, 17 }, { 0, 58, 17 }, { 0, 59, 17 }, - { 0, 60, 17 }, { 0, 61, 17 }, { 0, 62, 17 }, { 0, 63, 17 }, - RPT_16 ( 25, 1, 13 ), RPT_16 ( -25, 1, 13 ), - RPT_16 ( 26, 1, 13 ), RPT_16 ( -26, 1, 13 ), - RPT_16 ( 27, 1, 13 ), RPT_16 ( -27, 1, 13 ), - RPT_16 ( 28, 1, 13 ), RPT_16 ( -28, 1, 13 ), - RPT_16 ( 29, 1, 13 ), RPT_16 ( -29, 1, 13 ), - RPT_16 ( 30, 1, 13 ), RPT_16 ( -30, 1, 13 ), - RPT_16 ( 31, 1, 13 ), RPT_16 ( -31, 1, 13 ), - RPT_16 ( 32, 1, 13 ), RPT_16 ( -32, 1, 13 ), - RPT_16 ( 13, 2, 13 ), RPT_16 ( -13, 2, 13 ), - RPT_16 ( 14, 2, 13 ), RPT_16 ( -14, 2, 13 ), - RPT_16 ( 15, 2, 13 ), RPT_16 ( -15, 2, 13 ), - RPT_16 ( 16, 2, 13 ), RPT_16 ( -16, 2, 13 ), - RPT_16 ( 9, 3, 13 ), RPT_16 ( -9, 3, 13 ), - RPT_16 ( 10, 3, 13 ), RPT_16 ( -10, 3, 13 ), - RPT_16 ( 11, 3, 13 ), RPT_16 ( -11, 3, 13 ), - RPT_16 ( 7, 4, 13 ), RPT_16 ( -7, 4, 13 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 4, 7, 13 ), RPT_16 ( -4, 7, 13 ), - RPT_16 ( 3, 8, 13 ), RPT_16 ( -3, 8, 13 ), - RPT_16 ( 4, 8, 13 ), RPT_16 ( -4, 8, 13 ), - RPT_16 ( 3, 9, 13 ), RPT_16 ( -3, 9, 13 ), - RPT_16 ( 2, 11, 13 ), RPT_16 ( -2, 11, 13 ), - RPT_16 ( 2, 12, 13 ), RPT_16 ( -2, 12, 13 ), - RPT_32 ( 0, 14, 12 ), -}; - -static const HQXLUT ac16_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_64 ( 3, 0, 5 ), RPT_64 ( -3, 0, 5 ), - RPT_64 ( 4, 0, 5 ), RPT_64 ( -4, 0, 5 ), - RPT_64 ( 1, 1, 5 ), RPT_64 ( -1, 1, 5 ), - RPT_128 ( 0, 64, 4 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 6, 0, 6 ), - RPT_32 ( -6, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_16 ( 7, 0, 7 ), - RPT_16 ( -7, 0, 7 ), RPT_16 ( 8, 0, 7 ), - RPT_16 ( -8, 0, 7 ), RPT_16 ( 9, 0, 7 ), - RPT_16 ( -9, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 1, 3, 7 ), - RPT_16 ( -1, 3, 7 ), RPT_16 ( 1, 4, 7 ), - RPT_16 ( -1, 4, 7 ), RPT_8 ( 10, 0, 8 ), - RPT_8 ( -10, 0, 8 ), RPT_8 ( 11, 0, 8 ), - RPT_8 ( -11, 0, 8 ), RPT_8 ( 12, 0, 8 ), - RPT_8 ( -12, 0, 8 ), RPT_8 ( 4, 1, 8 ), - RPT_8 ( -4, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 5, 8 ), - RPT_8 ( -1, 5, 8 ), RPT_8 ( 1, 6, 8 ), - RPT_8 ( -1, 6, 8 ), RPT_4 ( 13, 0, 9 ), - RPT_4 ( -13, 0, 9 ), RPT_4 ( 14, 0, 9 ), - RPT_4 ( -14, 0, 9 ), RPT_4 ( 15, 0, 9 ), - RPT_4 ( -15, 0, 9 ), RPT_4 ( 16, 0, 9 ), - RPT_4 ( -16, 0, 9 ), RPT_4 ( 17, 0, 9 ), - RPT_4 ( -17, 0, 9 ), RPT_4 ( 5, 1, 9 ), - RPT_4 ( -5, 1, 9 ), RPT_4 ( 2, 3, 9 ), - RPT_4 ( -2, 3, 9 ), RPT_4 ( 1, 7, 9 ), - RPT_4 ( -1, 7, 9 ), RPT_4 ( 1, 8, 9 ), - RPT_4 ( -1, 8, 9 ), RPT_4 ( 1, 9, 9 ), - RPT_4 ( -1, 9, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_4 ( 0, 0, 9 ), - RPT_2 ( 18, 0, 10 ), RPT_2 ( -18, 0, 10 ), - RPT_2 ( 19, 0, 10 ), RPT_2 ( -19, 0, 10 ), - RPT_2 ( 20, 0, 10 ), RPT_2 ( -20, 0, 10 ), - RPT_2 ( 21, 0, 10 ), RPT_2 ( -21, 0, 10 ), - RPT_2 ( 22, 0, 10 ), RPT_2 ( -22, 0, 10 ), - RPT_2 ( 6, 1, 10 ), RPT_2 ( -6, 1, 10 ), - RPT_2 ( 7, 1, 10 ), RPT_2 ( -7, 1, 10 ), - RPT_2 ( 3, 2, 10 ), RPT_2 ( -3, 2, 10 ), - RPT_2 ( 2, 4, 10 ), RPT_2 ( -2, 4, 10 ), - RPT_2 ( 2, 5, 10 ), RPT_2 ( -2, 5, 10 ), - RPT_2 ( 1, 11, 10 ), RPT_2 ( -1, 11, 10 ), - RPT_2 ( 1, 12, 10 ), RPT_2 ( -1, 12, 10 ), - RPT_2 ( 1, 13, 10 ), RPT_2 ( -1, 13, 10 ), - { 2048, 0, -1 }, { 2112, 0, -1 }, { 2176, 0, -1 }, { 2240, 0, -1 }, - { 2304, 0, -1 }, { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, - { 23, 0, 11 }, { -23, 0, 11 }, { 24, 0, 11 }, { -24, 0, 11 }, - { 25, 0, 11 }, { -25, 0, 11 }, { 26, 0, 11 }, { -26, 0, 11 }, - { 27, 0, 11 }, { -27, 0, 11 }, { 28, 0, 11 }, { -28, 0, 11 }, - { 8, 1, 11 }, { -8, 1, 11 }, { 9, 1, 11 }, { -9, 1, 11 }, - { 4, 2, 11 }, { -4, 2, 11 }, { 3, 3, 11 }, { -3, 3, 11 }, - { 3, 4, 11 }, { -3, 4, 11 }, { 2, 6, 11 }, { -2, 6, 11 }, - { 2, 7, 11 }, { -2, 7, 11 }, { 2560, 0, -1 }, { 2624, 0, -1 }, - { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 2880, 0, -1 }, - { 2944, 0, -1 }, { 0, 1, 11 }, { 3008, 0, -1 }, { 3072, 0, -1 }, - { 3136, 0, -1 }, { 0, 2, 11 }, { 3200, 0, -1 }, { 0, 3, 11 }, - { 3264, 0, -1 }, { 3328, 0, -1 }, { 3392, 0, -1 }, { 3456, 0, -1 }, - { 3520, 0, -1 }, { 3584, 0, -1 }, { 3648, 0, -1 }, { 3712, 0, -1 }, - { 3776, 0, -1 }, { 3840, 0, -1 }, { 3904, 0, -1 }, { 3968, 0, -1 }, - { 4032, 0, -1 }, { 4096, 0, -1 }, { 4160, 0, -1 }, { 4224, 0, -1 }, - RPT_4 ( 0, 0, 15 ), RPT_4 ( 0, 1, 15 ), - RPT_4 ( 0, 2, 15 ), RPT_4 ( 0, 3, 15 ), - RPT_4 ( 0, 4, 15 ), RPT_4 ( 0, 5, 15 ), - RPT_4 ( 0, 6, 15 ), RPT_4 ( 0, 7, 15 ), - RPT_4 ( 0, 8, 15 ), RPT_4 ( 0, 9, 15 ), - RPT_4 ( 0, 10, 15 ), RPT_4 ( 0, 11, 15 ), - RPT_4 ( 0, 12, 15 ), RPT_4 ( 0, 13, 15 ), - RPT_4 ( 0, 14, 15 ), RPT_4 ( 0, 15, 15 ), - RPT_4 ( 0, 16, 15 ), RPT_4 ( 0, 17, 15 ), - RPT_4 ( 0, 18, 15 ), RPT_4 ( 0, 19, 15 ), - RPT_4 ( 0, 20, 15 ), RPT_4 ( 0, 21, 15 ), - RPT_4 ( 0, 22, 15 ), RPT_4 ( 0, 23, 15 ), - RPT_4 ( 0, 24, 15 ), RPT_4 ( 0, 25, 15 ), - RPT_4 ( 0, 26, 15 ), RPT_4 ( 0, 27, 15 ), - RPT_4 ( 0, 28, 15 ), RPT_4 ( 0, 29, 15 ), - RPT_4 ( 0, 30, 15 ), RPT_4 ( 0, 31, 15 ), - RPT_4 ( 0, 32, 15 ), RPT_4 ( 0, 33, 15 ), - RPT_4 ( 0, 34, 15 ), RPT_4 ( 0, 35, 15 ), - RPT_4 ( 0, 36, 15 ), RPT_4 ( 0, 37, 15 ), - RPT_4 ( 0, 38, 15 ), RPT_4 ( 0, 39, 15 ), - RPT_4 ( 0, 40, 15 ), RPT_4 ( 0, 41, 15 ), - RPT_4 ( 0, 42, 15 ), RPT_4 ( 0, 43, 15 ), - RPT_4 ( 0, 44, 15 ), RPT_4 ( 0, 45, 15 ), - RPT_4 ( 0, 46, 15 ), RPT_4 ( 0, 47, 15 ), - RPT_4 ( 0, 48, 15 ), RPT_4 ( 0, 49, 15 ), - RPT_4 ( 0, 50, 15 ), RPT_4 ( 0, 51, 15 ), - RPT_4 ( 0, 52, 15 ), RPT_4 ( 0, 53, 15 ), - RPT_4 ( 0, 54, 15 ), RPT_4 ( 0, 55, 15 ), - RPT_4 ( 0, 56, 15 ), RPT_4 ( 0, 57, 15 ), - RPT_4 ( 0, 58, 15 ), RPT_4 ( 0, 59, 15 ), - RPT_4 ( 0, 60, 15 ), RPT_4 ( 0, 61, 15 ), - RPT_4 ( 0, 62, 15 ), RPT_4 ( 0, 63, 15 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, - { 16, 0, 17 }, { -16, 0, 17 }, { 17, 0, 17 }, { -17, 0, 17 }, - { 18, 0, 17 }, { -18, 0, 17 }, { 19, 0, 17 }, { -19, 0, 17 }, - { 20, 0, 17 }, { -20, 0, 17 }, { 21, 0, 17 }, { -21, 0, 17 }, - { 22, 0, 17 }, { -22, 0, 17 }, { 23, 0, 17 }, { -23, 0, 17 }, - { 24, 0, 17 }, { -24, 0, 17 }, { 25, 0, 17 }, { -25, 0, 17 }, - { 26, 0, 17 }, { -26, 0, 17 }, { 27, 0, 17 }, { -27, 0, 17 }, - { 28, 0, 17 }, { -28, 0, 17 }, { 29, 0, 17 }, { -29, 0, 17 }, - { 30, 0, 17 }, { -30, 0, 17 }, { 31, 0, 17 }, { -31, 0, 17 }, - { 32, 0, 17 }, { -32, 0, 17 }, { 33, 0, 17 }, { -33, 0, 17 }, - { 34, 0, 17 }, { -34, 0, 17 }, { 35, 0, 17 }, { -35, 0, 17 }, - { 36, 0, 17 }, { -36, 0, 17 }, { 37, 0, 17 }, { -37, 0, 17 }, - { 38, 0, 17 }, { -38, 0, 17 }, { 39, 0, 17 }, { -39, 0, 17 }, - { 40, 0, 17 }, { -40, 0, 17 }, { 41, 0, 17 }, { -41, 0, 17 }, - { 42, 0, 17 }, { -42, 0, 17 }, { 43, 0, 17 }, { -43, 0, 17 }, - { 44, 0, 17 }, { -44, 0, 17 }, { 45, 0, 17 }, { -45, 0, 17 }, - { 46, 0, 17 }, { -46, 0, 17 }, { 47, 0, 17 }, { -47, 0, 17 }, - { 48, 0, 17 }, { -48, 0, 17 }, { 49, 0, 17 }, { -49, 0, 17 }, - { 50, 0, 17 }, { -50, 0, 17 }, { 51, 0, 17 }, { -51, 0, 17 }, - { 52, 0, 17 }, { -52, 0, 17 }, { 53, 0, 17 }, { -53, 0, 17 }, - { 54, 0, 17 }, { -54, 0, 17 }, { 55, 0, 17 }, { -55, 0, 17 }, - { 56, 0, 17 }, { -56, 0, 17 }, { 57, 0, 17 }, { -57, 0, 17 }, - { 58, 0, 17 }, { -58, 0, 17 }, { 59, 0, 17 }, { -59, 0, 17 }, - { 60, 0, 17 }, { -60, 0, 17 }, { 61, 0, 17 }, { -61, 0, 17 }, - { 62, 0, 17 }, { -62, 0, 17 }, { 63, 0, 17 }, { -63, 0, 17 }, - { 64, 0, 17 }, { -64, 0, 17 }, { 65, 0, 17 }, { -65, 0, 17 }, - { 66, 0, 17 }, { -66, 0, 17 }, { 67, 0, 17 }, { -67, 0, 17 }, - { 68, 0, 17 }, { -68, 0, 17 }, { 69, 0, 17 }, { -69, 0, 17 }, - { 70, 0, 17 }, { -70, 0, 17 }, { 71, 0, 17 }, { -71, 0, 17 }, - { 72, 0, 17 }, { -72, 0, 17 }, { 73, 0, 17 }, { -73, 0, 17 }, - { 74, 0, 17 }, { -74, 0, 17 }, { 75, 0, 17 }, { -75, 0, 17 }, - { 76, 0, 17 }, { -76, 0, 17 }, { 77, 0, 17 }, { -77, 0, 17 }, - { 78, 0, 17 }, { -78, 0, 17 }, { 79, 0, 17 }, { -79, 0, 17 }, - { 80, 0, 17 }, { -80, 0, 17 }, { 81, 0, 17 }, { -81, 0, 17 }, - { 82, 0, 17 }, { -82, 0, 17 }, { 83, 0, 17 }, { -83, 0, 17 }, - { 84, 0, 17 }, { -84, 0, 17 }, { 85, 0, 17 }, { -85, 0, 17 }, - { 86, 0, 17 }, { -86, 0, 17 }, { 87, 0, 17 }, { -87, 0, 17 }, - { 88, 0, 17 }, { -88, 0, 17 }, { 89, 0, 17 }, { -89, 0, 17 }, - { 90, 0, 17 }, { -90, 0, 17 }, { 91, 0, 17 }, { -91, 0, 17 }, - { 92, 0, 17 }, { -92, 0, 17 }, { 93, 0, 17 }, { -93, 0, 17 }, - { 94, 0, 17 }, { -94, 0, 17 }, { 95, 0, 17 }, { -95, 0, 17 }, - { 96, 0, 17 }, { -96, 0, 17 }, { 97, 0, 17 }, { -97, 0, 17 }, - { 98, 0, 17 }, { -98, 0, 17 }, { 99, 0, 17 }, { -99, 0, 17 }, - { 100, 0, 17 }, { -100, 0, 17 }, { 101, 0, 17 }, { -101, 0, 17 }, - { 102, 0, 17 }, { -102, 0, 17 }, { 103, 0, 17 }, { -103, 0, 17 }, - { 104, 0, 17 }, { -104, 0, 17 }, { 105, 0, 17 }, { -105, 0, 17 }, - { 106, 0, 17 }, { -106, 0, 17 }, { 107, 0, 17 }, { -107, 0, 17 }, - { 108, 0, 17 }, { -108, 0, 17 }, { 109, 0, 17 }, { -109, 0, 17 }, - { 110, 0, 17 }, { -110, 0, 17 }, { 111, 0, 17 }, { -111, 0, 17 }, - { 112, 0, 17 }, { -112, 0, 17 }, { 113, 0, 17 }, { -113, 0, 17 }, - { 114, 0, 17 }, { -114, 0, 17 }, { 115, 0, 17 }, { -115, 0, 17 }, - { 116, 0, 17 }, { -116, 0, 17 }, { 117, 0, 17 }, { -117, 0, 17 }, - { 118, 0, 17 }, { -118, 0, 17 }, { 119, 0, 17 }, { -119, 0, 17 }, - { 120, 0, 17 }, { -120, 0, 17 }, { 121, 0, 17 }, { -121, 0, 17 }, - { 122, 0, 17 }, { -122, 0, 17 }, { 123, 0, 17 }, { -123, 0, 17 }, - { 124, 0, 17 }, { -124, 0, 17 }, { 125, 0, 17 }, { -125, 0, 17 }, - { 126, 0, 17 }, { -126, 0, 17 }, { 127, 0, 17 }, { -127, 0, 17 }, - RPT_32 ( 29, 0, 12 ), RPT_32 ( -29, 0, 12 ), - RPT_32 ( 30, 0, 12 ), RPT_32 ( -30, 0, 12 ), - RPT_32 ( 31, 0, 12 ), RPT_32 ( -31, 0, 12 ), - RPT_32 ( 32, 0, 12 ), RPT_32 ( -32, 0, 12 ), - RPT_32 ( 33, 0, 12 ), RPT_32 ( -33, 0, 12 ), - RPT_32 ( 34, 0, 12 ), RPT_32 ( -34, 0, 12 ), - RPT_32 ( 35, 0, 12 ), RPT_32 ( -35, 0, 12 ), - RPT_32 ( 10, 1, 12 ), RPT_32 ( -10, 1, 12 ), - RPT_32 ( 11, 1, 12 ), RPT_32 ( -11, 1, 12 ), - RPT_32 ( 12, 1, 12 ), RPT_32 ( -12, 1, 12 ), - RPT_32 ( 5, 2, 12 ), RPT_32 ( -5, 2, 12 ), - RPT_32 ( 4, 3, 12 ), RPT_32 ( -4, 3, 12 ), - RPT_32 ( 3, 5, 12 ), RPT_32 ( -3, 5, 12 ), - RPT_32 ( 2, 8, 12 ), RPT_32 ( -2, 8, 12 ), - RPT_32 ( 2, 9, 12 ), RPT_32 ( -2, 9, 12 ), - RPT_32 ( 1, 14, 12 ), RPT_32 ( -1, 14, 12 ), - RPT_32 ( 1, 15, 12 ), RPT_32 ( -1, 15, 12 ), - RPT_16 ( 36, 0, 13 ), RPT_16 ( -36, 0, 13 ), - RPT_16 ( 37, 0, 13 ), RPT_16 ( -37, 0, 13 ), - RPT_16 ( 38, 0, 13 ), RPT_16 ( -38, 0, 13 ), - RPT_16 ( 39, 0, 13 ), RPT_16 ( -39, 0, 13 ), - RPT_16 ( 40, 0, 13 ), RPT_16 ( -40, 0, 13 ), - RPT_16 ( 13, 1, 13 ), RPT_16 ( -13, 1, 13 ), - RPT_16 ( 14, 1, 13 ), RPT_16 ( -14, 1, 13 ), - RPT_16 ( 15, 1, 13 ), RPT_16 ( -15, 1, 13 ), - RPT_16 ( 6, 2, 13 ), RPT_16 ( -6, 2, 13 ), - RPT_16 ( 7, 2, 13 ), RPT_16 ( -7, 2, 13 ), - RPT_16 ( 5, 3, 13 ), RPT_16 ( -5, 3, 13 ), - RPT_32 ( 0, 4, 12 ), RPT_16 ( 4, 4, 13 ), - RPT_16 ( -4, 4, 13 ), RPT_32 ( 0, 5, 12 ), - RPT_32 ( 0, 6, 12 ), RPT_16 ( 3, 6, 13 ), - RPT_16 ( -3, 6, 13 ), RPT_32 ( 0, 7, 12 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 2, 10, 13 ), RPT_16 ( -2, 10, 13 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), -}; - -static const HQXLUT ac32_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_128 ( 2, 0, 4 ), RPT_128 ( -2, 0, 4 ), - RPT_256 ( 0, 64, 3 ), RPT_64 ( 3, 0, 5 ), - RPT_64 ( -3, 0, 5 ), RPT_64 ( 1, 1, 5 ), - RPT_64 ( -1, 1, 5 ), RPT_32 ( 4, 0, 6 ), - RPT_32 ( -4, 0, 6 ), RPT_32 ( 5, 0, 6 ), - RPT_32 ( -5, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_32 ( 1, 3, 6 ), - RPT_32 ( -1, 3, 6 ), RPT_16 ( 6, 0, 7 ), - RPT_16 ( -6, 0, 7 ), RPT_16 ( 7, 0, 7 ), - RPT_16 ( -7, 0, 7 ), RPT_16 ( 3, 1, 7 ), - RPT_16 ( -3, 1, 7 ), RPT_16 ( 1, 4, 7 ), - RPT_16 ( -1, 4, 7 ), RPT_16 ( 1, 5, 7 ), - RPT_16 ( -1, 5, 7 ), RPT_8 ( 8, 0, 8 ), - RPT_8 ( -8, 0, 8 ), RPT_8 ( 9, 0, 8 ), - RPT_8 ( -9, 0, 8 ), RPT_8 ( 10, 0, 8 ), - RPT_8 ( -10, 0, 8 ), RPT_8 ( 4, 1, 8 ), - RPT_8 ( -4, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 1, 6, 8 ), - RPT_8 ( -1, 6, 8 ), RPT_8 ( 1, 7, 8 ), - RPT_8 ( -1, 7, 8 ), RPT_8 ( 1, 8, 8 ), - RPT_8 ( -1, 8, 8 ), RPT_4 ( 11, 0, 9 ), - RPT_4 ( -11, 0, 9 ), RPT_4 ( 12, 0, 9 ), - RPT_4 ( -12, 0, 9 ), RPT_4 ( 13, 0, 9 ), - RPT_4 ( -13, 0, 9 ), RPT_4 ( 5, 1, 9 ), - RPT_4 ( -5, 1, 9 ), RPT_4 ( 2, 3, 9 ), - RPT_4 ( -2, 3, 9 ), RPT_4 ( 1, 9, 9 ), - RPT_4 ( -1, 9, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_2 ( 14, 0, 10 ), - RPT_2 ( -14, 0, 10 ), RPT_2 ( 15, 0, 10 ), - RPT_2 ( -15, 0, 10 ), RPT_2 ( 16, 0, 10 ), - RPT_2 ( -16, 0, 10 ), RPT_2 ( 6, 1, 10 ), - RPT_2 ( -6, 1, 10 ), RPT_2 ( 7, 1, 10 ), - RPT_2 ( -7, 1, 10 ), RPT_2 ( 3, 2, 10 ), - RPT_2 ( -3, 2, 10 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 2, 4, 10 ), - RPT_2 ( -2, 4, 10 ), RPT_2 ( 2, 5, 10 ), - RPT_2 ( -2, 5, 10 ), RPT_2 ( 1, 11, 10 ), - RPT_2 ( -1, 11, 10 ), RPT_2 ( 1, 12, 10 ), - RPT_2 ( -1, 12, 10 ), RPT_2 ( 1, 13, 10 ), - RPT_2 ( -1, 13, 10 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, RPT_2 ( 0, 0, 10 ), - { 17, 0, 11 }, { -17, 0, 11 }, { 18, 0, 11 }, { -18, 0, 11 }, - { 19, 0, 11 }, { -19, 0, 11 }, { 20, 0, 11 }, { -20, 0, 11 }, - { 8, 1, 11 }, { -8, 1, 11 }, { 9, 1, 11 }, { -9, 1, 11 }, - { 4, 2, 11 }, { -4, 2, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 2, 6, 11 }, { -2, 6, 11 }, { 2, 7, 11 }, { -2, 7, 11 }, - { 2, 8, 11 }, { -2, 8, 11 }, { 1, 14, 11 }, { -1, 14, 11 }, - { 2304, 0, -1 }, { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, - { 2560, 0, -1 }, { 0, 1, 11 }, { 2624, 0, -1 }, { 2688, 0, -1 }, - { 0, 2, 11 }, { 2752, 0, -1 }, { 2816, 0, -1 }, { 0, 3, 11 }, - { 2880, 0, -1 }, { 0, 4, 11 }, { 2944, 0, -1 }, { 3008, 0, -1 }, - { 3072, 0, -1 }, { 3136, 0, -1 }, { 3200, 0, -1 }, { 3264, 0, -1 }, - { 3328, 0, -1 }, { 3392, 0, -1 }, { 3456, 0, -1 }, { 3520, 0, -1 }, - { 3584, 0, -1 }, { 3648, 0, -1 }, RPT_4 ( 0, 0, 15 ), - RPT_4 ( 0, 1, 15 ), RPT_4 ( 0, 2, 15 ), - RPT_4 ( 0, 3, 15 ), RPT_4 ( 0, 4, 15 ), - RPT_4 ( 0, 5, 15 ), RPT_4 ( 0, 6, 15 ), - RPT_4 ( 0, 7, 15 ), RPT_4 ( 0, 8, 15 ), - RPT_4 ( 0, 9, 15 ), RPT_4 ( 0, 10, 15 ), - RPT_4 ( 0, 11, 15 ), RPT_4 ( 0, 12, 15 ), - RPT_4 ( 0, 13, 15 ), RPT_4 ( 0, 14, 15 ), - RPT_4 ( 0, 15, 15 ), RPT_4 ( 0, 16, 15 ), - RPT_4 ( 0, 17, 15 ), RPT_4 ( 0, 18, 15 ), - RPT_4 ( 0, 19, 15 ), RPT_4 ( 0, 20, 15 ), - RPT_4 ( 0, 21, 15 ), RPT_4 ( 0, 22, 15 ), - RPT_4 ( 0, 23, 15 ), RPT_4 ( 0, 24, 15 ), - RPT_4 ( 0, 25, 15 ), RPT_4 ( 0, 26, 15 ), - RPT_4 ( 0, 27, 15 ), RPT_4 ( 0, 28, 15 ), - RPT_4 ( 0, 29, 15 ), RPT_4 ( 0, 30, 15 ), - RPT_4 ( 0, 31, 15 ), RPT_4 ( 0, 32, 15 ), - RPT_4 ( 0, 33, 15 ), RPT_4 ( 0, 34, 15 ), - RPT_4 ( 0, 35, 15 ), RPT_4 ( 0, 36, 15 ), - RPT_4 ( 0, 37, 15 ), RPT_4 ( 0, 38, 15 ), - RPT_4 ( 0, 39, 15 ), RPT_4 ( 0, 40, 15 ), - RPT_4 ( 0, 41, 15 ), RPT_4 ( 0, 42, 15 ), - RPT_4 ( 0, 43, 15 ), RPT_4 ( 0, 44, 15 ), - RPT_4 ( 0, 45, 15 ), RPT_4 ( 0, 46, 15 ), - RPT_4 ( 0, 47, 15 ), RPT_4 ( 0, 48, 15 ), - RPT_4 ( 0, 49, 15 ), RPT_4 ( 0, 50, 15 ), - RPT_4 ( 0, 51, 15 ), RPT_4 ( 0, 52, 15 ), - RPT_4 ( 0, 53, 15 ), RPT_4 ( 0, 54, 15 ), - RPT_4 ( 0, 55, 15 ), RPT_4 ( 0, 56, 15 ), - RPT_4 ( 0, 57, 15 ), RPT_4 ( 0, 58, 15 ), - RPT_4 ( 0, 59, 15 ), RPT_4 ( 0, 60, 15 ), - RPT_4 ( 0, 61, 15 ), RPT_4 ( 0, 62, 15 ), - RPT_4 ( 0, 63, 15 ), RPT_2 ( 0, 0, 16 ), - { 1, 0, 17 }, { -1, 0, 17 }, { 2, 0, 17 }, { -2, 0, 17 }, - { 3, 0, 17 }, { -3, 0, 17 }, { 4, 0, 17 }, { -4, 0, 17 }, - { 5, 0, 17 }, { -5, 0, 17 }, { 6, 0, 17 }, { -6, 0, 17 }, - { 7, 0, 17 }, { -7, 0, 17 }, { 8, 0, 17 }, { -8, 0, 17 }, - { 9, 0, 17 }, { -9, 0, 17 }, { 10, 0, 17 }, { -10, 0, 17 }, - { 11, 0, 17 }, { -11, 0, 17 }, { 12, 0, 17 }, { -12, 0, 17 }, - { 13, 0, 17 }, { -13, 0, 17 }, { 14, 0, 17 }, { -14, 0, 17 }, - { 15, 0, 17 }, { -15, 0, 17 }, { 16, 0, 17 }, { -16, 0, 17 }, - { 17, 0, 17 }, { -17, 0, 17 }, { 18, 0, 17 }, { -18, 0, 17 }, - { 19, 0, 17 }, { -19, 0, 17 }, { 20, 0, 17 }, { -20, 0, 17 }, - { 21, 0, 17 }, { -21, 0, 17 }, { 22, 0, 17 }, { -22, 0, 17 }, - { 23, 0, 17 }, { -23, 0, 17 }, { 24, 0, 17 }, { -24, 0, 17 }, - { 25, 0, 17 }, { -25, 0, 17 }, { 26, 0, 17 }, { -26, 0, 17 }, - { 27, 0, 17 }, { -27, 0, 17 }, { 28, 0, 17 }, { -28, 0, 17 }, - { 29, 0, 17 }, { -29, 0, 17 }, { 30, 0, 17 }, { -30, 0, 17 }, - { 31, 0, 17 }, { -31, 0, 17 }, { 32, 0, 17 }, { -32, 0, 17 }, - { 33, 0, 17 }, { -33, 0, 17 }, { 34, 0, 17 }, { -34, 0, 17 }, - { 35, 0, 17 }, { -35, 0, 17 }, { 36, 0, 17 }, { -36, 0, 17 }, - { 37, 0, 17 }, { -37, 0, 17 }, { 38, 0, 17 }, { -38, 0, 17 }, - { 39, 0, 17 }, { -39, 0, 17 }, { 40, 0, 17 }, { -40, 0, 17 }, - { 41, 0, 17 }, { -41, 0, 17 }, { 42, 0, 17 }, { -42, 0, 17 }, - { 43, 0, 17 }, { -43, 0, 17 }, { 44, 0, 17 }, { -44, 0, 17 }, - { 45, 0, 17 }, { -45, 0, 17 }, { 46, 0, 17 }, { -46, 0, 17 }, - { 47, 0, 17 }, { -47, 0, 17 }, { 48, 0, 17 }, { -48, 0, 17 }, - { 49, 0, 17 }, { -49, 0, 17 }, { 50, 0, 17 }, { -50, 0, 17 }, - { 51, 0, 17 }, { -51, 0, 17 }, { 52, 0, 17 }, { -52, 0, 17 }, - { 53, 0, 17 }, { -53, 0, 17 }, { 54, 0, 17 }, { -54, 0, 17 }, - { 55, 0, 17 }, { -55, 0, 17 }, { 56, 0, 17 }, { -56, 0, 17 }, - { 57, 0, 17 }, { -57, 0, 17 }, { 58, 0, 17 }, { -58, 0, 17 }, - { 59, 0, 17 }, { -59, 0, 17 }, { 60, 0, 17 }, { -60, 0, 17 }, - { 61, 0, 17 }, { -61, 0, 17 }, { 62, 0, 17 }, { -62, 0, 17 }, - { 63, 0, 17 }, { -63, 0, 17 }, RPT_32 ( 21, 0, 12 ), - RPT_32 ( -21, 0, 12 ), RPT_32 ( 22, 0, 12 ), - RPT_32 ( -22, 0, 12 ), RPT_32 ( 23, 0, 12 ), - RPT_32 ( -23, 0, 12 ), RPT_32 ( 10, 1, 12 ), - RPT_32 ( -10, 1, 12 ), RPT_32 ( 11, 1, 12 ), - RPT_32 ( -11, 1, 12 ), RPT_32 ( 5, 2, 12 ), - RPT_32 ( -5, 2, 12 ), RPT_32 ( 6, 2, 12 ), - RPT_32 ( -6, 2, 12 ), RPT_32 ( 4, 3, 12 ), - RPT_32 ( -4, 3, 12 ), RPT_32 ( 3, 5, 12 ), - RPT_32 ( -3, 5, 12 ), RPT_32 ( 3, 6, 12 ), - RPT_32 ( -3, 6, 12 ), RPT_32 ( 2, 9, 12 ), - RPT_32 ( -2, 9, 12 ), RPT_32 ( 1, 15, 12 ), - RPT_32 ( -1, 15, 12 ), RPT_16 ( 24, 0, 13 ), - RPT_16 ( -24, 0, 13 ), RPT_16 ( 25, 0, 13 ), - RPT_16 ( -25, 0, 13 ), RPT_16 ( 26, 0, 13 ), - RPT_16 ( -26, 0, 13 ), RPT_16 ( 12, 1, 13 ), - RPT_16 ( -12, 1, 13 ), RPT_16 ( 13, 1, 13 ), - RPT_16 ( -13, 1, 13 ), RPT_16 ( 5, 3, 13 ), - RPT_16 ( -5, 3, 13 ), RPT_16 ( 4, 4, 13 ), - RPT_16 ( -4, 4, 13 ), RPT_32 ( 0, 5, 12 ), - RPT_16 ( 4, 5, 13 ), RPT_16 ( -4, 5, 13 ), - RPT_32 ( 0, 6, 12 ), RPT_32 ( 0, 7, 12 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_32 ( 0, 8, 12 ), RPT_16 ( 3, 8, 13 ), - RPT_16 ( -3, 8, 13 ), RPT_32 ( 0, 9, 12 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), -}; - -static const HQXLUT ac64_lut[] = { - RPT_512 ( 1, 0, 3 ), RPT_512 ( -1, 0, 3 ), - RPT_1024( 0, 64, 2 ), RPT_256 ( 2, 0, 4 ), - RPT_256 ( -2, 0, 4 ), RPT_128 ( 3, 0, 5 ), - RPT_128 ( -3, 0, 5 ), RPT_128 ( 1, 1, 5 ), - RPT_128 ( -1, 1, 5 ), RPT_64 ( 4, 0, 6 ), - RPT_64 ( -4, 0, 6 ), RPT_64 ( 2, 1, 6 ), - RPT_64 ( -2, 1, 6 ), RPT_64 ( 1, 2, 6 ), - RPT_64 ( -1, 2, 6 ), RPT_32 ( 5, 0, 7 ), - RPT_32 ( -5, 0, 7 ), RPT_32 ( 1, 3, 7 ), - RPT_32 ( -1, 3, 7 ), RPT_32 ( 1, 4, 7 ), - RPT_32 ( -1, 4, 7 ), RPT_16 ( 6, 0, 8 ), - RPT_16 ( -6, 0, 8 ), RPT_16 ( 3, 1, 8 ), - RPT_16 ( -3, 1, 8 ), RPT_16 ( 2, 2, 8 ), - RPT_16 ( -2, 2, 8 ), RPT_16 ( 1, 5, 8 ), - RPT_16 ( -1, 5, 8 ), RPT_16 ( 1, 6, 8 ), - RPT_16 ( -1, 6, 8 ), RPT_16 ( 1, 7, 8 ), - RPT_16 ( -1, 7, 8 ), RPT_8 ( 7, 0, 9 ), - RPT_8 ( -7, 0, 9 ), RPT_8 ( 8, 0, 9 ), - RPT_8 ( -8, 0, 9 ), RPT_8 ( 4, 1, 9 ), - RPT_8 ( -4, 1, 9 ), RPT_8 ( 2, 3, 9 ), - RPT_8 ( -2, 3, 9 ), RPT_8 ( 1, 8, 9 ), - RPT_8 ( -1, 8, 9 ), RPT_8 ( 1, 9, 9 ), - RPT_8 ( -1, 9, 9 ), RPT_4 ( 9, 0, 10 ), - RPT_4 ( -9, 0, 10 ), RPT_4 ( 10, 0, 10 ), - RPT_4 ( -10, 0, 10 ), RPT_4 ( 5, 1, 10 ), - RPT_4 ( -5, 1, 10 ), RPT_4 ( 3, 2, 10 ), - RPT_4 ( -3, 2, 10 ), RPT_4 ( 2, 4, 10 ), - RPT_4 ( -2, 4, 10 ), RPT_4 ( 2, 5, 10 ), - RPT_4 ( -2, 5, 10 ), RPT_4 ( 1, 10, 10 ), - RPT_4 ( -1, 10, 10 ), RPT_4 ( 1, 11, 10 ), - RPT_4 ( -1, 11, 10 ), { 4096, 0, -1 }, { 4128, 0, -1 }, - { 4160, 0, -1 }, { 4192, 0, -1 }, { 4224, 0, -1 }, { 4256, 0, -1 }, - { 4288, 0, -1 }, { 4320, 0, -1 }, RPT_4 ( 0, 0, 10 ), - RPT_2 ( 11, 0, 11 ), RPT_2 ( -11, 0, 11 ), - RPT_2 ( 12, 0, 11 ), RPT_2 ( -12, 0, 11 ), - RPT_2 ( 6, 1, 11 ), RPT_2 ( -6, 1, 11 ), - RPT_2 ( 7, 1, 11 ), RPT_2 ( -7, 1, 11 ), - RPT_2 ( 3, 3, 11 ), RPT_2 ( -3, 3, 11 ), - RPT_2 ( 3, 4, 11 ), RPT_2 ( -3, 4, 11 ), - RPT_2 ( 3, 5, 11 ), RPT_2 ( -3, 5, 11 ), - RPT_2 ( 2, 6, 11 ), RPT_2 ( -2, 6, 11 ), - RPT_2 ( 2, 7, 11 ), RPT_2 ( -2, 7, 11 ), - RPT_2 ( 1, 12, 11 ), RPT_2 ( -1, 12, 11 ), - RPT_2 ( 1, 13, 11 ), RPT_2 ( -1, 13, 11 ), - RPT_2 ( 1, 14, 11 ), RPT_2 ( -1, 14, 11 ), - { 13, 0, 12 }, { -13, 0, 12 }, { 14, 0, 12 }, { -14, 0, 12 }, - RPT_2 ( 0, 1, 11 ), { 8, 1, 12 }, { -8, 1, 12 }, - { 4, 2, 12 }, { -4, 2, 12 }, { 4, 3, 12 }, { -4, 3, 12 }, - { 2, 8, 12 }, { -2, 8, 12 }, { 2, 9, 12 }, { -2, 9, 12 }, - { 1, 15, 12 }, { -1, 15, 12 }, { 4352, 0, -1 }, { 4384, 0, -1 }, - { 4416, 0, -1 }, { 4448, 0, -1 }, { 4480, 0, -1 }, { 0, 2, 12 }, - { 4512, 0, -1 }, { 0, 3, 12 }, { 4544, 0, -1 }, { 0, 4, 12 }, - { 4576, 0, -1 }, { 0, 5, 12 }, { 4608, 0, -1 }, { 0, 6, 12 }, - { 4640, 0, -1 }, { 4672, 0, -1 }, { 4704, 0, -1 }, { 4736, 0, -1 }, - RPT_4 ( 0, 0, 15 ), RPT_4 ( 0, 1, 15 ), - RPT_4 ( 0, 2, 15 ), RPT_4 ( 0, 3, 15 ), - RPT_4 ( 0, 4, 15 ), RPT_4 ( 0, 5, 15 ), - RPT_4 ( 0, 6, 15 ), RPT_4 ( 0, 7, 15 ), - RPT_4 ( 0, 8, 15 ), RPT_4 ( 0, 9, 15 ), - RPT_4 ( 0, 10, 15 ), RPT_4 ( 0, 11, 15 ), - RPT_4 ( 0, 12, 15 ), RPT_4 ( 0, 13, 15 ), - RPT_4 ( 0, 14, 15 ), RPT_4 ( 0, 15, 15 ), - RPT_4 ( 0, 16, 15 ), RPT_4 ( 0, 17, 15 ), - RPT_4 ( 0, 18, 15 ), RPT_4 ( 0, 19, 15 ), - RPT_4 ( 0, 20, 15 ), RPT_4 ( 0, 21, 15 ), - RPT_4 ( 0, 22, 15 ), RPT_4 ( 0, 23, 15 ), - RPT_4 ( 0, 24, 15 ), RPT_4 ( 0, 25, 15 ), - RPT_4 ( 0, 26, 15 ), RPT_4 ( 0, 27, 15 ), - RPT_4 ( 0, 28, 15 ), RPT_4 ( 0, 29, 15 ), - RPT_4 ( 0, 30, 15 ), RPT_4 ( 0, 31, 15 ), - RPT_4 ( 0, 32, 15 ), RPT_4 ( 0, 33, 15 ), - RPT_4 ( 0, 34, 15 ), RPT_4 ( 0, 35, 15 ), - RPT_4 ( 0, 36, 15 ), RPT_4 ( 0, 37, 15 ), - RPT_4 ( 0, 38, 15 ), RPT_4 ( 0, 39, 15 ), - RPT_4 ( 0, 40, 15 ), RPT_4 ( 0, 41, 15 ), - RPT_4 ( 0, 42, 15 ), RPT_4 ( 0, 43, 15 ), - RPT_4 ( 0, 44, 15 ), RPT_4 ( 0, 45, 15 ), - RPT_4 ( 0, 46, 15 ), RPT_4 ( 0, 47, 15 ), - RPT_4 ( 0, 48, 15 ), RPT_4 ( 0, 49, 15 ), - RPT_4 ( 0, 50, 15 ), RPT_4 ( 0, 51, 15 ), - RPT_4 ( 0, 52, 15 ), RPT_4 ( 0, 53, 15 ), - RPT_4 ( 0, 54, 15 ), RPT_4 ( 0, 55, 15 ), - RPT_4 ( 0, 56, 15 ), RPT_4 ( 0, 57, 15 ), - RPT_4 ( 0, 58, 15 ), RPT_4 ( 0, 59, 15 ), - RPT_4 ( 0, 60, 15 ), RPT_4 ( 0, 61, 15 ), - RPT_4 ( 0, 62, 15 ), RPT_4 ( 0, 63, 15 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, - { 16, 0, 17 }, { -16, 0, 17 }, { 17, 0, 17 }, { -17, 0, 17 }, - { 18, 0, 17 }, { -18, 0, 17 }, { 19, 0, 17 }, { -19, 0, 17 }, - { 20, 0, 17 }, { -20, 0, 17 }, { 21, 0, 17 }, { -21, 0, 17 }, - { 22, 0, 17 }, { -22, 0, 17 }, { 23, 0, 17 }, { -23, 0, 17 }, - { 24, 0, 17 }, { -24, 0, 17 }, { 25, 0, 17 }, { -25, 0, 17 }, - { 26, 0, 17 }, { -26, 0, 17 }, { 27, 0, 17 }, { -27, 0, 17 }, - { 28, 0, 17 }, { -28, 0, 17 }, { 29, 0, 17 }, { -29, 0, 17 }, - { 30, 0, 17 }, { -30, 0, 17 }, { 31, 0, 17 }, { -31, 0, 17 }, - RPT_16 ( 15, 0, 13 ), RPT_16 ( -15, 0, 13 ), - RPT_16 ( 9, 1, 13 ), RPT_16 ( -9, 1, 13 ), - RPT_16 ( 10, 1, 13 ), RPT_16 ( -10, 1, 13 ), - RPT_16 ( 5, 2, 13 ), RPT_16 ( -5, 2, 13 ), - RPT_16 ( 5, 3, 13 ), RPT_16 ( -5, 3, 13 ), - RPT_16 ( 4, 4, 13 ), RPT_16 ( -4, 4, 13 ), - RPT_16 ( 4, 5, 13 ), RPT_16 ( -4, 5, 13 ), - RPT_16 ( 3, 6, 13 ), RPT_16 ( -3, 6, 13 ), - RPT_16 ( 3, 7, 13 ), RPT_16 ( -3, 7, 13 ), - RPT_16 ( 1, 16, 13 ), RPT_16 ( -1, 16, 13 ), - RPT_16 ( 1, 17, 13 ), RPT_16 ( -1, 17, 13 ), -}; - -static const HQXLUT ac128_lut[] = { - RPT_256 ( 1, 0, 3 ), RPT_256 ( -1, 0, 3 ), - RPT_512 ( 0, 64, 2 ), RPT_128 ( 1, 1, 4 ), - RPT_128 ( -1, 1, 4 ), RPT_64 ( 2, 0, 5 ), - RPT_64 ( -2, 0, 5 ), RPT_32 ( 3, 0, 6 ), - RPT_32 ( -3, 0, 6 ), RPT_32 ( 2, 1, 6 ), - RPT_32 ( -2, 1, 6 ), RPT_32 ( 1, 2, 6 ), - RPT_32 ( -1, 2, 6 ), RPT_32 ( 1, 3, 6 ), - RPT_32 ( -1, 3, 6 ), RPT_32 ( 1, 4, 6 ), - RPT_32 ( -1, 4, 6 ), RPT_16 ( 4, 0, 7 ), - RPT_16 ( -4, 0, 7 ), RPT_16 ( 1, 5, 7 ), - RPT_16 ( -1, 5, 7 ), RPT_16 ( 1, 6, 7 ), - RPT_16 ( -1, 6, 7 ), RPT_16 ( 1, 7, 7 ), - RPT_16 ( -1, 7, 7 ), RPT_8 ( 5, 0, 8 ), - RPT_8 ( -5, 0, 8 ), RPT_8 ( 3, 1, 8 ), - RPT_8 ( -3, 1, 8 ), RPT_8 ( 2, 2, 8 ), - RPT_8 ( -2, 2, 8 ), RPT_8 ( 2, 3, 8 ), - RPT_8 ( -2, 3, 8 ), RPT_8 ( 1, 8, 8 ), - RPT_8 ( -1, 8, 8 ), RPT_8 ( 1, 9, 8 ), - RPT_8 ( -1, 9, 8 ), RPT_4 ( 6, 0, 9 ), - RPT_4 ( -6, 0, 9 ), RPT_4 ( 4, 1, 9 ), - RPT_4 ( -4, 1, 9 ), RPT_4 ( 2, 4, 9 ), - RPT_4 ( -2, 4, 9 ), RPT_4 ( 2, 5, 9 ), - RPT_4 ( -2, 5, 9 ), RPT_4 ( 1, 10, 9 ), - RPT_4 ( -1, 10, 9 ), RPT_2 ( 7, 0, 10 ), - RPT_2 ( -7, 0, 10 ), RPT_2 ( 5, 1, 10 ), - RPT_2 ( -5, 1, 10 ), RPT_2 ( 3, 2, 10 ), - RPT_2 ( -3, 2, 10 ), RPT_2 ( 3, 3, 10 ), - RPT_2 ( -3, 3, 10 ), RPT_2 ( 2, 6, 10 ), - RPT_2 ( -2, 6, 10 ), { 2048, 0, -1 }, { 2112, 0, -1 }, - { 2176, 0, -1 }, { 2240, 0, -1 }, { 6, 1, 11 }, { -6, 1, 11 }, - { 7, 1, 11 }, { -7, 1, 11 }, { 3, 4, 11 }, { -3, 4, 11 }, - { 3, 5, 11 }, { -3, 5, 11 }, { 2, 7, 11 }, { -2, 7, 11 }, - { 2, 8, 11 }, { -2, 8, 11 }, { 2, 9, 11 }, { -2, 9, 11 }, - { 1, 11, 11 }, { -1, 11, 11 }, { 1, 12, 11 }, { -1, 12, 11 }, - { 1, 13, 11 }, { -1, 13, 11 }, { 0, 0, 11 }, { 2304, 0, -1 }, - { 2368, 0, -1 }, { 2432, 0, -1 }, { 2496, 0, -1 }, { 2560, 0, -1 }, - { 2624, 0, -1 }, { 2688, 0, -1 }, { 2752, 0, -1 }, { 2816, 0, -1 }, - { 2880, 0, -1 }, { 2944, 0, -1 }, RPT_4 ( 0, 0, 15 ), - RPT_4 ( 0, 1, 15 ), RPT_4 ( 0, 2, 15 ), - RPT_4 ( 0, 3, 15 ), RPT_4 ( 0, 4, 15 ), - RPT_4 ( 0, 5, 15 ), RPT_4 ( 0, 6, 15 ), - RPT_4 ( 0, 7, 15 ), RPT_4 ( 0, 8, 15 ), - RPT_4 ( 0, 9, 15 ), RPT_4 ( 0, 10, 15 ), - RPT_4 ( 0, 11, 15 ), RPT_4 ( 0, 12, 15 ), - RPT_4 ( 0, 13, 15 ), RPT_4 ( 0, 14, 15 ), - RPT_4 ( 0, 15, 15 ), RPT_4 ( 0, 16, 15 ), - RPT_4 ( 0, 17, 15 ), RPT_4 ( 0, 18, 15 ), - RPT_4 ( 0, 19, 15 ), RPT_4 ( 0, 20, 15 ), - RPT_4 ( 0, 21, 15 ), RPT_4 ( 0, 22, 15 ), - RPT_4 ( 0, 23, 15 ), RPT_4 ( 0, 24, 15 ), - RPT_4 ( 0, 25, 15 ), RPT_4 ( 0, 26, 15 ), - RPT_4 ( 0, 27, 15 ), RPT_4 ( 0, 28, 15 ), - RPT_4 ( 0, 29, 15 ), RPT_4 ( 0, 30, 15 ), - RPT_4 ( 0, 31, 15 ), RPT_4 ( 0, 32, 15 ), - RPT_4 ( 0, 33, 15 ), RPT_4 ( 0, 34, 15 ), - RPT_4 ( 0, 35, 15 ), RPT_4 ( 0, 36, 15 ), - RPT_4 ( 0, 37, 15 ), RPT_4 ( 0, 38, 15 ), - RPT_4 ( 0, 39, 15 ), RPT_4 ( 0, 40, 15 ), - RPT_4 ( 0, 41, 15 ), RPT_4 ( 0, 42, 15 ), - RPT_4 ( 0, 43, 15 ), RPT_4 ( 0, 44, 15 ), - RPT_4 ( 0, 45, 15 ), RPT_4 ( 0, 46, 15 ), - RPT_4 ( 0, 47, 15 ), RPT_4 ( 0, 48, 15 ), - RPT_4 ( 0, 49, 15 ), RPT_4 ( 0, 50, 15 ), - RPT_4 ( 0, 51, 15 ), RPT_4 ( 0, 52, 15 ), - RPT_4 ( 0, 53, 15 ), RPT_4 ( 0, 54, 15 ), - RPT_4 ( 0, 55, 15 ), RPT_4 ( 0, 56, 15 ), - RPT_4 ( 0, 57, 15 ), RPT_4 ( 0, 58, 15 ), - RPT_4 ( 0, 59, 15 ), RPT_4 ( 0, 60, 15 ), - RPT_4 ( 0, 61, 15 ), RPT_4 ( 0, 62, 15 ), - RPT_4 ( 0, 63, 15 ), RPT_32 ( 8, 0, 12 ), - RPT_32 ( -8, 0, 12 ), RPT_32 ( 9, 0, 12 ), - RPT_32 ( -9, 0, 12 ), RPT_32 ( 8, 1, 12 ), - RPT_32 ( -8, 1, 12 ), RPT_32 ( 4, 2, 12 ), - RPT_32 ( -4, 2, 12 ), RPT_32 ( 4, 3, 12 ), - RPT_32 ( -4, 3, 12 ), RPT_32 ( 3, 6, 12 ), - RPT_32 ( -3, 6, 12 ), RPT_32 ( 1, 14, 12 ), - RPT_32 ( -1, 14, 12 ), RPT_32 ( 1, 15, 12 ), - RPT_32 ( -1, 15, 12 ), RPT_32 ( 1, 16, 12 ), - RPT_32 ( -1, 16, 12 ), RPT_32 ( 0, 1, 12 ), - RPT_32 ( 0, 2, 12 ), RPT_32 ( 0, 3, 12 ), - RPT_2 ( 0, 0, 16 ), { 1, 0, 17 }, { -1, 0, 17 }, - { 2, 0, 17 }, { -2, 0, 17 }, { 3, 0, 17 }, { -3, 0, 17 }, - { 4, 0, 17 }, { -4, 0, 17 }, { 5, 0, 17 }, { -5, 0, 17 }, - { 6, 0, 17 }, { -6, 0, 17 }, { 7, 0, 17 }, { -7, 0, 17 }, - { 8, 0, 17 }, { -8, 0, 17 }, { 9, 0, 17 }, { -9, 0, 17 }, - { 10, 0, 17 }, { -10, 0, 17 }, { 11, 0, 17 }, { -11, 0, 17 }, - { 12, 0, 17 }, { -12, 0, 17 }, { 13, 0, 17 }, { -13, 0, 17 }, - { 14, 0, 17 }, { -14, 0, 17 }, { 15, 0, 17 }, { -15, 0, 17 }, -}; - -const HQXAC ff_hqx_ac[NUM_HQX_AC] = { - { 10, 5, ac0_lut }, - { 11, 6, ac8_lut }, - { 11, 6, ac16_lut }, - { 11, 6, ac32_lut }, - { 12, 5, ac64_lut }, - { 11, 6, ac128_lut }, -}; - -#define INIT_DC_TABLE(idx, name) \ - do { \ - ret = vlc_init(&ctx->dc_vlc[idx], HQX_DC_VLC_BITS, \ - FF_ARRAY_ELEMS(name ## _vlc_lens), \ - name ## _vlc_lens, 1, 1, \ - name ## _vlc_bits, 2, 2, 0); \ - if (ret < 0) \ - return ret; \ - } while (0) - -av_cold int ff_hqx_init_vlcs(HQXContext *ctx) -{ - int ret = vlc_init(&ctx->cbp_vlc, HQX_CBP_VLC_BITS, FF_ARRAY_ELEMS(cbp_vlc_lens), - cbp_vlc_lens, 1, 1, cbp_vlc_bits, 1, 1, 0); - if (ret < 0) - return ret; - - INIT_DC_TABLE(0, dc9); - INIT_DC_TABLE(1, dc10); - INIT_DC_TABLE(2, dc11); - - return 0; -} diff --git a/libavcodec/hqxvlc.h b/libavcodec/hqxvlc.h new file mode 100644 index 0000000000..abf81f60ad --- /dev/null +++ b/libavcodec/hqxvlc.h @@ -0,0 +1,1575 @@ +/* + * Canopus HQX decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HQXVLC_H +#define AVCODEC_HQXVLC_H + +#include + +#include "vlc.h" + +#include "libavutil/attributes.h" +#include "libavutil/macros.h" + +#define HQX_DC_VLC_BITS 9 + +enum HQXACMode { + HQX_AC_Q0 = 0, + HQX_AC_Q8, + HQX_AC_Q16, + HQX_AC_Q32, + HQX_AC_Q64, + HQX_AC_Q128, + NUM_HQX_AC +}; + +typedef struct HQXAC { + int bits; + const RL_VLC_ELEM *lut; +} HQXAC; + +static const uint16_t dc9_vlc_bits[512] = { + 0x0010, 0x0008, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0074, 0x0076, 0x0078, 0x007A, + 0x007C, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, + 0x003E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, + 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, + 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, + 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, + 0x01FE, 0x06C0, 0x06C2, 0x06C4, 0x06C6, 0x06C8, 0x06CA, 0x06CC, + 0x06CE, 0x06D0, 0x06D2, 0x06D4, 0x06D6, 0x06D8, 0x06DA, 0x06DC, + 0x06DE, 0x06E0, 0x06E2, 0x06E4, 0x06E6, 0x06E8, 0x06EA, 0x06EC, + 0x06EE, 0x06F0, 0x06F2, 0x06F4, 0x06F6, 0x06F8, 0x06FA, 0x06FC, + 0x06FE, 0x0E00, 0x0E02, 0x0E04, 0x0E06, 0x0E08, 0x0E0A, 0x0E0C, + 0x0E0E, 0x0E10, 0x0E12, 0x0E14, 0x0E16, 0x0E18, 0x0E1A, 0x0E1C, + 0x0E1E, 0x0E20, 0x0E22, 0x0E24, 0x0E26, 0x0E28, 0x0E2A, 0x0E2C, + 0x0E2E, 0x0E30, 0x0E32, 0x0E34, 0x0E36, 0x0E38, 0x0E3A, 0x0E3C, + 0x0E3E, 0x0E40, 0x0E42, 0x0E44, 0x0E46, 0x0E48, 0x0E4A, 0x0E4C, + 0x0E4E, 0x0E50, 0x0E52, 0x0E54, 0x0E56, 0x0E58, 0x0E5A, 0x0E5C, + 0x0E5E, 0x0E60, 0x0E62, 0x0E64, 0x0E66, 0x0E68, 0x0E6A, 0x0E6C, + 0x0E6E, 0x0E70, 0x0E72, 0x0E74, 0x0E76, 0x0E78, 0x0E7A, 0x0E7C, + 0x0E7E, 0x1F80, 0x1F82, 0x1F84, 0x1F86, 0x1F88, 0x1F8A, 0x1F8C, + 0x1F8E, 0x1F90, 0x1F92, 0x1F94, 0x1F96, 0x1F98, 0x1F9A, 0x1F9C, + 0x1F9E, 0x1FA0, 0x1FA2, 0x1FA4, 0x1FA6, 0x1FA8, 0x1FAA, 0x1FAC, + 0x1FAE, 0x1FB0, 0x1FB2, 0x1FB4, 0x1FB6, 0x1FB8, 0x1FBA, 0x1FBC, + 0x1FBE, 0x1FC0, 0x1FC2, 0x1FC4, 0x1FC6, 0x1FC8, 0x1FCA, 0x1FCC, + 0x1FCE, 0x1FD0, 0x1FD2, 0x1FD4, 0x1FD6, 0x1FD8, 0x1FDA, 0x1FDC, + 0x1FDE, 0x1FE0, 0x1FE2, 0x1FE4, 0x1FE6, 0x1FE8, 0x1FEA, 0x1FEC, + 0x1FEE, 0x1FF0, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FF8, 0x1FFA, 0x1FFC, + 0x0FFF, 0x1FFD, 0x1FFB, 0x1FF9, 0x1FF7, 0x1FF5, 0x1FF3, 0x1FF1, + 0x1FEF, 0x1FED, 0x1FEB, 0x1FE9, 0x1FE7, 0x1FE5, 0x1FE3, 0x1FE1, + 0x1FDF, 0x1FDD, 0x1FDB, 0x1FD9, 0x1FD7, 0x1FD5, 0x1FD3, 0x1FD1, + 0x1FCF, 0x1FCD, 0x1FCB, 0x1FC9, 0x1FC7, 0x1FC5, 0x1FC3, 0x1FC1, + 0x1FBF, 0x1FBD, 0x1FBB, 0x1FB9, 0x1FB7, 0x1FB5, 0x1FB3, 0x1FB1, + 0x1FAF, 0x1FAD, 0x1FAB, 0x1FA9, 0x1FA7, 0x1FA5, 0x1FA3, 0x1FA1, + 0x1F9F, 0x1F9D, 0x1F9B, 0x1F99, 0x1F97, 0x1F95, 0x1F93, 0x1F91, + 0x1F8F, 0x1F8D, 0x1F8B, 0x1F89, 0x1F87, 0x1F85, 0x1F83, 0x1F81, + 0x0E7F, 0x0E7D, 0x0E7B, 0x0E79, 0x0E77, 0x0E75, 0x0E73, 0x0E71, + 0x0E6F, 0x0E6D, 0x0E6B, 0x0E69, 0x0E67, 0x0E65, 0x0E63, 0x0E61, + 0x0E5F, 0x0E5D, 0x0E5B, 0x0E59, 0x0E57, 0x0E55, 0x0E53, 0x0E51, + 0x0E4F, 0x0E4D, 0x0E4B, 0x0E49, 0x0E47, 0x0E45, 0x0E43, 0x0E41, + 0x0E3F, 0x0E3D, 0x0E3B, 0x0E39, 0x0E37, 0x0E35, 0x0E33, 0x0E31, + 0x0E2F, 0x0E2D, 0x0E2B, 0x0E29, 0x0E27, 0x0E25, 0x0E23, 0x0E21, + 0x0E1F, 0x0E1D, 0x0E1B, 0x0E19, 0x0E17, 0x0E15, 0x0E13, 0x0E11, + 0x0E0F, 0x0E0D, 0x0E0B, 0x0E09, 0x0E07, 0x0E05, 0x0E03, 0x0E01, + 0x06FF, 0x06FD, 0x06FB, 0x06F9, 0x06F7, 0x06F5, 0x06F3, 0x06F1, + 0x06EF, 0x06ED, 0x06EB, 0x06E9, 0x06E7, 0x06E5, 0x06E3, 0x06E1, + 0x06DF, 0x06DD, 0x06DB, 0x06D9, 0x06D7, 0x06D5, 0x06D3, 0x06D1, + 0x06CF, 0x06CD, 0x06CB, 0x06C9, 0x06C7, 0x06C5, 0x06C3, 0x06C1, + 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, + 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, + 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, + 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0009, +}; + +static const uint8_t dc9_vlc_lens[512] = { + 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 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, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 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, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 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, 10, 10, 10, 10, 10, 10, + 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, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, +}; + +static const uint16_t dc10_vlc_bits[1024] = { + 0x0014, 0x002A, 0x002C, 0x002E, 0x0064, 0x0066, 0x0068, 0x006A, + 0x006C, 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, + 0x007C, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, + 0x001E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x0060, 0x0062, 0x0064, 0x0066, 0x0068, 0x006A, 0x006C, + 0x006E, 0x0070, 0x0072, 0x0074, 0x0076, 0x0078, 0x007A, 0x007C, + 0x007E, 0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, + 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, + 0x01DE, 0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, + 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, + 0x01FE, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, + 0x040E, 0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, + 0x041E, 0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, + 0x042E, 0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, + 0x043E, 0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, + 0x044E, 0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, + 0x045E, 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, + 0x046E, 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x047C, + 0x047E, 0x0C00, 0x0C02, 0x0C04, 0x0C06, 0x0C08, 0x0C0A, 0x0C0C, + 0x0C0E, 0x0C10, 0x0C12, 0x0C14, 0x0C16, 0x0C18, 0x0C1A, 0x0C1C, + 0x0C1E, 0x0C20, 0x0C22, 0x0C24, 0x0C26, 0x0C28, 0x0C2A, 0x0C2C, + 0x0C2E, 0x0C30, 0x0C32, 0x0C34, 0x0C36, 0x0C38, 0x0C3A, 0x0C3C, + 0x0C3E, 0x0C40, 0x0C42, 0x0C44, 0x0C46, 0x0C48, 0x0C4A, 0x0C4C, + 0x0C4E, 0x0C50, 0x0C52, 0x0C54, 0x0C56, 0x0C58, 0x0C5A, 0x0C5C, + 0x0C5E, 0x0C60, 0x0C62, 0x0C64, 0x0C66, 0x0C68, 0x0C6A, 0x0C6C, + 0x0C6E, 0x0C70, 0x0C72, 0x0C74, 0x0C76, 0x0C78, 0x0C7A, 0x0C7C, + 0x0C7E, 0x0900, 0x0902, 0x0904, 0x0906, 0x0908, 0x090A, 0x090C, + 0x090E, 0x0910, 0x0912, 0x0914, 0x0916, 0x0918, 0x091A, 0x091C, + 0x091E, 0x0920, 0x0922, 0x0924, 0x0926, 0x0928, 0x092A, 0x092C, + 0x092E, 0x0930, 0x0932, 0x0934, 0x0936, 0x0938, 0x093A, 0x093C, + 0x093E, 0x0940, 0x0942, 0x0944, 0x0946, 0x0948, 0x094A, 0x094C, + 0x094E, 0x0950, 0x0952, 0x0954, 0x0956, 0x0958, 0x095A, 0x095C, + 0x095E, 0x0960, 0x0962, 0x0964, 0x0966, 0x0968, 0x096A, 0x096C, + 0x096E, 0x0970, 0x0972, 0x0974, 0x0976, 0x0978, 0x097A, 0x097C, + 0x097E, 0x0980, 0x0982, 0x0984, 0x0986, 0x0988, 0x098A, 0x098C, + 0x098E, 0x0990, 0x0992, 0x0994, 0x0996, 0x0998, 0x099A, 0x099C, + 0x099E, 0x09A0, 0x09A2, 0x09A4, 0x09A6, 0x09A8, 0x09AA, 0x09AC, + 0x09AE, 0x09B0, 0x09B2, 0x09B4, 0x09B6, 0x09B8, 0x09BA, 0x09BC, + 0x09BE, 0x09C0, 0x09C2, 0x09C4, 0x09C6, 0x09C8, 0x09CA, 0x09CC, + 0x09CE, 0x09D0, 0x09D2, 0x09D4, 0x09D6, 0x09D8, 0x09DA, 0x09DC, + 0x09DE, 0x09E0, 0x09E2, 0x09E4, 0x09E6, 0x09E8, 0x09EA, 0x09EC, + 0x09EE, 0x09F0, 0x09F2, 0x09F4, 0x09F6, 0x09F8, 0x09FA, 0x09FC, + 0x09FE, 0x3F00, 0x3F02, 0x3F04, 0x3F06, 0x3F08, 0x3F0A, 0x3F0C, + 0x3F0E, 0x3F10, 0x3F12, 0x3F14, 0x3F16, 0x3F18, 0x3F1A, 0x3F1C, + 0x3F1E, 0x3F20, 0x3F22, 0x3F24, 0x3F26, 0x3F28, 0x3F2A, 0x3F2C, + 0x3F2E, 0x3F30, 0x3F32, 0x3F34, 0x3F36, 0x3F38, 0x3F3A, 0x3F3C, + 0x3F3E, 0x3F40, 0x3F42, 0x3F44, 0x3F46, 0x3F48, 0x3F4A, 0x3F4C, + 0x3F4E, 0x3F50, 0x3F52, 0x3F54, 0x3F56, 0x3F58, 0x3F5A, 0x3F5C, + 0x3F5E, 0x3F60, 0x3F62, 0x3F64, 0x3F66, 0x3F68, 0x3F6A, 0x3F6C, + 0x3F6E, 0x3F70, 0x3F72, 0x3F74, 0x3F76, 0x3F78, 0x3F7A, 0x3F7C, + 0x3F7E, 0x3F80, 0x3F82, 0x3F84, 0x3F86, 0x3F88, 0x3F8A, 0x3F8C, + 0x3F8E, 0x3F90, 0x3F92, 0x3F94, 0x3F96, 0x3F98, 0x3F9A, 0x3F9C, + 0x3F9E, 0x3FA0, 0x3FA2, 0x3FA4, 0x3FA6, 0x3FA8, 0x3FAA, 0x3FAC, + 0x3FAE, 0x3FB0, 0x3FB2, 0x3FB4, 0x3FB6, 0x3FB8, 0x3FBA, 0x3FBC, + 0x3FBE, 0x3FC0, 0x3FC2, 0x3FC4, 0x3FC6, 0x3FC8, 0x3FCA, 0x3FCC, + 0x3FCE, 0x3FD0, 0x3FD2, 0x3FD4, 0x3FD6, 0x3FD8, 0x3FDA, 0x3FDC, + 0x3FDE, 0x3FE0, 0x3FE2, 0x3FE4, 0x3FE6, 0x3FE8, 0x3FEA, 0x3FEC, + 0x3FEE, 0x3FF0, 0x3FF2, 0x3FF4, 0x3FF6, 0x3FF8, 0x3FFA, 0x3FFC, + 0x1FFF, 0x3FFD, 0x3FFB, 0x3FF9, 0x3FF7, 0x3FF5, 0x3FF3, 0x3FF1, + 0x3FEF, 0x3FED, 0x3FEB, 0x3FE9, 0x3FE7, 0x3FE5, 0x3FE3, 0x3FE1, + 0x3FDF, 0x3FDD, 0x3FDB, 0x3FD9, 0x3FD7, 0x3FD5, 0x3FD3, 0x3FD1, + 0x3FCF, 0x3FCD, 0x3FCB, 0x3FC9, 0x3FC7, 0x3FC5, 0x3FC3, 0x3FC1, + 0x3FBF, 0x3FBD, 0x3FBB, 0x3FB9, 0x3FB7, 0x3FB5, 0x3FB3, 0x3FB1, + 0x3FAF, 0x3FAD, 0x3FAB, 0x3FA9, 0x3FA7, 0x3FA5, 0x3FA3, 0x3FA1, + 0x3F9F, 0x3F9D, 0x3F9B, 0x3F99, 0x3F97, 0x3F95, 0x3F93, 0x3F91, + 0x3F8F, 0x3F8D, 0x3F8B, 0x3F89, 0x3F87, 0x3F85, 0x3F83, 0x3F81, + 0x3F7F, 0x3F7D, 0x3F7B, 0x3F79, 0x3F77, 0x3F75, 0x3F73, 0x3F71, + 0x3F6F, 0x3F6D, 0x3F6B, 0x3F69, 0x3F67, 0x3F65, 0x3F63, 0x3F61, + 0x3F5F, 0x3F5D, 0x3F5B, 0x3F59, 0x3F57, 0x3F55, 0x3F53, 0x3F51, + 0x3F4F, 0x3F4D, 0x3F4B, 0x3F49, 0x3F47, 0x3F45, 0x3F43, 0x3F41, + 0x3F3F, 0x3F3D, 0x3F3B, 0x3F39, 0x3F37, 0x3F35, 0x3F33, 0x3F31, + 0x3F2F, 0x3F2D, 0x3F2B, 0x3F29, 0x3F27, 0x3F25, 0x3F23, 0x3F21, + 0x3F1F, 0x3F1D, 0x3F1B, 0x3F19, 0x3F17, 0x3F15, 0x3F13, 0x3F11, + 0x3F0F, 0x3F0D, 0x3F0B, 0x3F09, 0x3F07, 0x3F05, 0x3F03, 0x3F01, + 0x09FF, 0x09FD, 0x09FB, 0x09F9, 0x09F7, 0x09F5, 0x09F3, 0x09F1, + 0x09EF, 0x09ED, 0x09EB, 0x09E9, 0x09E7, 0x09E5, 0x09E3, 0x09E1, + 0x09DF, 0x09DD, 0x09DB, 0x09D9, 0x09D7, 0x09D5, 0x09D3, 0x09D1, + 0x09CF, 0x09CD, 0x09CB, 0x09C9, 0x09C7, 0x09C5, 0x09C3, 0x09C1, + 0x09BF, 0x09BD, 0x09BB, 0x09B9, 0x09B7, 0x09B5, 0x09B3, 0x09B1, + 0x09AF, 0x09AD, 0x09AB, 0x09A9, 0x09A7, 0x09A5, 0x09A3, 0x09A1, + 0x099F, 0x099D, 0x099B, 0x0999, 0x0997, 0x0995, 0x0993, 0x0991, + 0x098F, 0x098D, 0x098B, 0x0989, 0x0987, 0x0985, 0x0983, 0x0981, + 0x097F, 0x097D, 0x097B, 0x0979, 0x0977, 0x0975, 0x0973, 0x0971, + 0x096F, 0x096D, 0x096B, 0x0969, 0x0967, 0x0965, 0x0963, 0x0961, + 0x095F, 0x095D, 0x095B, 0x0959, 0x0957, 0x0955, 0x0953, 0x0951, + 0x094F, 0x094D, 0x094B, 0x0949, 0x0947, 0x0945, 0x0943, 0x0941, + 0x093F, 0x093D, 0x093B, 0x0939, 0x0937, 0x0935, 0x0933, 0x0931, + 0x092F, 0x092D, 0x092B, 0x0929, 0x0927, 0x0925, 0x0923, 0x0921, + 0x091F, 0x091D, 0x091B, 0x0919, 0x0917, 0x0915, 0x0913, 0x0911, + 0x090F, 0x090D, 0x090B, 0x0909, 0x0907, 0x0905, 0x0903, 0x0901, + 0x0C7F, 0x0C7D, 0x0C7B, 0x0C79, 0x0C77, 0x0C75, 0x0C73, 0x0C71, + 0x0C6F, 0x0C6D, 0x0C6B, 0x0C69, 0x0C67, 0x0C65, 0x0C63, 0x0C61, + 0x0C5F, 0x0C5D, 0x0C5B, 0x0C59, 0x0C57, 0x0C55, 0x0C53, 0x0C51, + 0x0C4F, 0x0C4D, 0x0C4B, 0x0C49, 0x0C47, 0x0C45, 0x0C43, 0x0C41, + 0x0C3F, 0x0C3D, 0x0C3B, 0x0C39, 0x0C37, 0x0C35, 0x0C33, 0x0C31, + 0x0C2F, 0x0C2D, 0x0C2B, 0x0C29, 0x0C27, 0x0C25, 0x0C23, 0x0C21, + 0x0C1F, 0x0C1D, 0x0C1B, 0x0C19, 0x0C17, 0x0C15, 0x0C13, 0x0C11, + 0x0C0F, 0x0C0D, 0x0C0B, 0x0C09, 0x0C07, 0x0C05, 0x0C03, 0x0C01, + 0x047F, 0x047D, 0x047B, 0x0479, 0x0477, 0x0475, 0x0473, 0x0471, + 0x046F, 0x046D, 0x046B, 0x0469, 0x0467, 0x0465, 0x0463, 0x0461, + 0x045F, 0x045D, 0x045B, 0x0459, 0x0457, 0x0455, 0x0453, 0x0451, + 0x044F, 0x044D, 0x044B, 0x0449, 0x0447, 0x0445, 0x0443, 0x0441, + 0x043F, 0x043D, 0x043B, 0x0439, 0x0437, 0x0435, 0x0433, 0x0431, + 0x042F, 0x042D, 0x042B, 0x0429, 0x0427, 0x0425, 0x0423, 0x0421, + 0x041F, 0x041D, 0x041B, 0x0419, 0x0417, 0x0415, 0x0413, 0x0411, + 0x040F, 0x040D, 0x040B, 0x0409, 0x0407, 0x0405, 0x0403, 0x0401, + 0x01FF, 0x01FD, 0x01FB, 0x01F9, 0x01F7, 0x01F5, 0x01F3, 0x01F1, + 0x01EF, 0x01ED, 0x01EB, 0x01E9, 0x01E7, 0x01E5, 0x01E3, 0x01E1, + 0x01DF, 0x01DD, 0x01DB, 0x01D9, 0x01D7, 0x01D5, 0x01D3, 0x01D1, + 0x01CF, 0x01CD, 0x01CB, 0x01C9, 0x01C7, 0x01C5, 0x01C3, 0x01C1, + 0x007F, 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, + 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x0063, 0x0061, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x007D, 0x007B, 0x0079, 0x0077, 0x0075, 0x0073, 0x0071, 0x006F, + 0x006D, 0x006B, 0x0069, 0x0067, 0x0065, 0x002F, 0x002D, 0x002B, +}; + +static const uint8_t dc10_vlc_lens[1024] = { + 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 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, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 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, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 10, 10, 10, 10, 10, 10, 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, 9, 9, 9, 9, 9, 9, 9, 9, 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, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, +}; + +static const uint16_t dc11_vlc_bits[2048] = { + 0x0032, 0x0066, 0x0068, 0x006A, 0x006C, 0x006E, 0x0070, 0x0072, + 0x0074, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048, 0x004A, 0x004C, + 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058, 0x005A, 0x005C, + 0x005E, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, + 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, + 0x000E, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001A, 0x001C, + 0x001E, 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002A, 0x002C, + 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003A, 0x003C, + 0x003E, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, + 0x020E, 0x0210, 0x0212, 0x0214, 0x0216, 0x0218, 0x021A, 0x021C, + 0x021E, 0x0220, 0x0222, 0x0224, 0x0226, 0x0228, 0x022A, 0x022C, + 0x022E, 0x0230, 0x0232, 0x0234, 0x0236, 0x0238, 0x023A, 0x023C, + 0x023E, 0x0080, 0x0082, 0x0084, 0x0086, 0x0088, 0x008A, 0x008C, + 0x008E, 0x0090, 0x0092, 0x0094, 0x0096, 0x0098, 0x009A, 0x009C, + 0x009E, 0x00A0, 0x00A2, 0x00A4, 0x00A6, 0x00A8, 0x00AA, 0x00AC, + 0x00AE, 0x00B0, 0x00B2, 0x00B4, 0x00B6, 0x00B8, 0x00BA, 0x00BC, + 0x00BE, 0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, + 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, + 0x00DE, 0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, + 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, + 0x00FE, 0x0480, 0x0482, 0x0484, 0x0486, 0x0488, 0x048A, 0x048C, + 0x048E, 0x0490, 0x0492, 0x0494, 0x0496, 0x0498, 0x049A, 0x049C, + 0x049E, 0x04A0, 0x04A2, 0x04A4, 0x04A6, 0x04A8, 0x04AA, 0x04AC, + 0x04AE, 0x04B0, 0x04B2, 0x04B4, 0x04B6, 0x04B8, 0x04BA, 0x04BC, + 0x04BE, 0x04C0, 0x04C2, 0x04C4, 0x04C6, 0x04C8, 0x04CA, 0x04CC, + 0x04CE, 0x04D0, 0x04D2, 0x04D4, 0x04D6, 0x04D8, 0x04DA, 0x04DC, + 0x04DE, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA, 0x04EC, + 0x04EE, 0x04F0, 0x04F2, 0x04F4, 0x04F6, 0x04F8, 0x04FA, 0x04FC, + 0x04FE, 0x0A00, 0x0A02, 0x0A04, 0x0A06, 0x0A08, 0x0A0A, 0x0A0C, + 0x0A0E, 0x0A10, 0x0A12, 0x0A14, 0x0A16, 0x0A18, 0x0A1A, 0x0A1C, + 0x0A1E, 0x0A20, 0x0A22, 0x0A24, 0x0A26, 0x0A28, 0x0A2A, 0x0A2C, + 0x0A2E, 0x0A30, 0x0A32, 0x0A34, 0x0A36, 0x0A38, 0x0A3A, 0x0A3C, + 0x0A3E, 0x0A40, 0x0A42, 0x0A44, 0x0A46, 0x0A48, 0x0A4A, 0x0A4C, + 0x0A4E, 0x0A50, 0x0A52, 0x0A54, 0x0A56, 0x0A58, 0x0A5A, 0x0A5C, + 0x0A5E, 0x0A60, 0x0A62, 0x0A64, 0x0A66, 0x0A68, 0x0A6A, 0x0A6C, + 0x0A6E, 0x0A70, 0x0A72, 0x0A74, 0x0A76, 0x0A78, 0x0A7A, 0x0A7C, + 0x0A7E, 0x0A80, 0x0A82, 0x0A84, 0x0A86, 0x0A88, 0x0A8A, 0x0A8C, + 0x0A8E, 0x0A90, 0x0A92, 0x0A94, 0x0A96, 0x0A98, 0x0A9A, 0x0A9C, + 0x0A9E, 0x0AA0, 0x0AA2, 0x0AA4, 0x0AA6, 0x0AA8, 0x0AAA, 0x0AAC, + 0x0AAE, 0x0AB0, 0x0AB2, 0x0AB4, 0x0AB6, 0x0AB8, 0x0ABA, 0x0ABC, + 0x0ABE, 0x0AC0, 0x0AC2, 0x0AC4, 0x0AC6, 0x0AC8, 0x0ACA, 0x0ACC, + 0x0ACE, 0x0AD0, 0x0AD2, 0x0AD4, 0x0AD6, 0x0AD8, 0x0ADA, 0x0ADC, + 0x0ADE, 0x0AE0, 0x0AE2, 0x0AE4, 0x0AE6, 0x0AE8, 0x0AEA, 0x0AEC, + 0x0AEE, 0x0AF0, 0x0AF2, 0x0AF4, 0x0AF6, 0x0AF8, 0x0AFA, 0x0AFC, + 0x0AFE, 0x1800, 0x1802, 0x1804, 0x1806, 0x1808, 0x180A, 0x180C, + 0x180E, 0x1810, 0x1812, 0x1814, 0x1816, 0x1818, 0x181A, 0x181C, + 0x181E, 0x1820, 0x1822, 0x1824, 0x1826, 0x1828, 0x182A, 0x182C, + 0x182E, 0x1830, 0x1832, 0x1834, 0x1836, 0x1838, 0x183A, 0x183C, + 0x183E, 0x1840, 0x1842, 0x1844, 0x1846, 0x1848, 0x184A, 0x184C, + 0x184E, 0x1850, 0x1852, 0x1854, 0x1856, 0x1858, 0x185A, 0x185C, + 0x185E, 0x1860, 0x1862, 0x1864, 0x1866, 0x1868, 0x186A, 0x186C, + 0x186E, 0x1870, 0x1872, 0x1874, 0x1876, 0x1878, 0x187A, 0x187C, + 0x187E, 0x1880, 0x1882, 0x1884, 0x1886, 0x1888, 0x188A, 0x188C, + 0x188E, 0x1890, 0x1892, 0x1894, 0x1896, 0x1898, 0x189A, 0x189C, + 0x189E, 0x18A0, 0x18A2, 0x18A4, 0x18A6, 0x18A8, 0x18AA, 0x18AC, + 0x18AE, 0x18B0, 0x18B2, 0x18B4, 0x18B6, 0x18B8, 0x18BA, 0x18BC, + 0x18BE, 0x18C0, 0x18C2, 0x18C4, 0x18C6, 0x18C8, 0x18CA, 0x18CC, + 0x18CE, 0x18D0, 0x18D2, 0x18D4, 0x18D6, 0x18D8, 0x18DA, 0x18DC, + 0x18DE, 0x18E0, 0x18E2, 0x18E4, 0x18E6, 0x18E8, 0x18EA, 0x18EC, + 0x18EE, 0x18F0, 0x18F2, 0x18F4, 0x18F6, 0x18F8, 0x18FA, 0x18FC, + 0x18FE, 0x1600, 0x1602, 0x1604, 0x1606, 0x1608, 0x160A, 0x160C, + 0x160E, 0x1610, 0x1612, 0x1614, 0x1616, 0x1618, 0x161A, 0x161C, + 0x161E, 0x1620, 0x1622, 0x1624, 0x1626, 0x1628, 0x162A, 0x162C, + 0x162E, 0x1630, 0x1632, 0x1634, 0x1636, 0x1638, 0x163A, 0x163C, + 0x163E, 0x1640, 0x1642, 0x1644, 0x1646, 0x1648, 0x164A, 0x164C, + 0x164E, 0x1650, 0x1652, 0x1654, 0x1656, 0x1658, 0x165A, 0x165C, + 0x165E, 0x1660, 0x1662, 0x1664, 0x1666, 0x1668, 0x166A, 0x166C, + 0x166E, 0x1670, 0x1672, 0x1674, 0x1676, 0x1678, 0x167A, 0x167C, + 0x167E, 0x1680, 0x1682, 0x1684, 0x1686, 0x1688, 0x168A, 0x168C, + 0x168E, 0x1690, 0x1692, 0x1694, 0x1696, 0x1698, 0x169A, 0x169C, + 0x169E, 0x16A0, 0x16A2, 0x16A4, 0x16A6, 0x16A8, 0x16AA, 0x16AC, + 0x16AE, 0x16B0, 0x16B2, 0x16B4, 0x16B6, 0x16B8, 0x16BA, 0x16BC, + 0x16BE, 0x16C0, 0x16C2, 0x16C4, 0x16C6, 0x16C8, 0x16CA, 0x16CC, + 0x16CE, 0x16D0, 0x16D2, 0x16D4, 0x16D6, 0x16D8, 0x16DA, 0x16DC, + 0x16DE, 0x16E0, 0x16E2, 0x16E4, 0x16E6, 0x16E8, 0x16EA, 0x16EC, + 0x16EE, 0x16F0, 0x16F2, 0x16F4, 0x16F6, 0x16F8, 0x16FA, 0x16FC, + 0x16FE, 0x1700, 0x1702, 0x1704, 0x1706, 0x1708, 0x170A, 0x170C, + 0x170E, 0x1710, 0x1712, 0x1714, 0x1716, 0x1718, 0x171A, 0x171C, + 0x171E, 0x1720, 0x1722, 0x1724, 0x1726, 0x1728, 0x172A, 0x172C, + 0x172E, 0x1730, 0x1732, 0x1734, 0x1736, 0x1738, 0x173A, 0x173C, + 0x173E, 0x1740, 0x1742, 0x1744, 0x1746, 0x1748, 0x174A, 0x174C, + 0x174E, 0x1750, 0x1752, 0x1754, 0x1756, 0x1758, 0x175A, 0x175C, + 0x175E, 0x1760, 0x1762, 0x1764, 0x1766, 0x1768, 0x176A, 0x176C, + 0x176E, 0x1770, 0x1772, 0x1774, 0x1776, 0x1778, 0x177A, 0x177C, + 0x177E, 0x1780, 0x1782, 0x1784, 0x1786, 0x1788, 0x178A, 0x178C, + 0x178E, 0x1790, 0x1792, 0x1794, 0x1796, 0x1798, 0x179A, 0x179C, + 0x179E, 0x17A0, 0x17A2, 0x17A4, 0x17A6, 0x17A8, 0x17AA, 0x17AC, + 0x17AE, 0x17B0, 0x17B2, 0x17B4, 0x17B6, 0x17B8, 0x17BA, 0x17BC, + 0x17BE, 0x17C0, 0x17C2, 0x17C4, 0x17C6, 0x17C8, 0x17CA, 0x17CC, + 0x17CE, 0x17D0, 0x17D2, 0x17D4, 0x17D6, 0x17D8, 0x17DA, 0x17DC, + 0x17DE, 0x17E0, 0x17E2, 0x17E4, 0x17E6, 0x17E8, 0x17EA, 0x17EC, + 0x17EE, 0x17F0, 0x17F2, 0x17F4, 0x17F6, 0x17F8, 0x17FA, 0x17FC, + 0x17FE, 0x7600, 0x7602, 0x7604, 0x7606, 0x7608, 0x760A, 0x760C, + 0x760E, 0x7610, 0x7612, 0x7614, 0x7616, 0x7618, 0x761A, 0x761C, + 0x761E, 0x7620, 0x7622, 0x7624, 0x7626, 0x7628, 0x762A, 0x762C, + 0x762E, 0x7630, 0x7632, 0x7634, 0x7636, 0x7638, 0x763A, 0x763C, + 0x763E, 0x7640, 0x7642, 0x7644, 0x7646, 0x7648, 0x764A, 0x764C, + 0x764E, 0x7650, 0x7652, 0x7654, 0x7656, 0x7658, 0x765A, 0x765C, + 0x765E, 0x7660, 0x7662, 0x7664, 0x7666, 0x7668, 0x766A, 0x766C, + 0x766E, 0x7670, 0x7672, 0x7674, 0x7676, 0x7678, 0x767A, 0x767C, + 0x767E, 0x7680, 0x7682, 0x7684, 0x7686, 0x7688, 0x768A, 0x768C, + 0x768E, 0x7690, 0x7692, 0x7694, 0x7696, 0x7698, 0x769A, 0x769C, + 0x769E, 0x76A0, 0x76A2, 0x76A4, 0x76A6, 0x76A8, 0x76AA, 0x76AC, + 0x76AE, 0x76B0, 0x76B2, 0x76B4, 0x76B6, 0x76B8, 0x76BA, 0x76BC, + 0x76BE, 0x76C0, 0x76C2, 0x76C4, 0x76C6, 0x76C8, 0x76CA, 0x76CC, + 0x76CE, 0x76D0, 0x76D2, 0x76D4, 0x76D6, 0x76D8, 0x76DA, 0x76DC, + 0x76DE, 0x76E0, 0x76E2, 0x76E4, 0x76E6, 0x76E8, 0x76EA, 0x76EC, + 0x76EE, 0x76F0, 0x76F2, 0x76F4, 0x76F6, 0x76F8, 0x76FA, 0x76FC, + 0x76FE, 0x7700, 0x7702, 0x7704, 0x7706, 0x7708, 0x770A, 0x770C, + 0x770E, 0x7710, 0x7712, 0x7714, 0x7716, 0x7718, 0x771A, 0x771C, + 0x771E, 0x7720, 0x7722, 0x7724, 0x7726, 0x7728, 0x772A, 0x772C, + 0x772E, 0x7730, 0x7732, 0x7734, 0x7736, 0x7738, 0x773A, 0x773C, + 0x773E, 0x7740, 0x7742, 0x7744, 0x7746, 0x7748, 0x774A, 0x774C, + 0x774E, 0x7750, 0x7752, 0x7754, 0x7756, 0x7758, 0x775A, 0x775C, + 0x775E, 0x7760, 0x7762, 0x7764, 0x7766, 0x7768, 0x776A, 0x776C, + 0x776E, 0x7770, 0x7772, 0x7774, 0x7776, 0x7778, 0x777A, 0x777C, + 0x777E, 0x7780, 0x7782, 0x7784, 0x7786, 0x7788, 0x778A, 0x778C, + 0x778E, 0x7790, 0x7792, 0x7794, 0x7796, 0x7798, 0x779A, 0x779C, + 0x779E, 0x77A0, 0x77A2, 0x77A4, 0x77A6, 0x77A8, 0x77AA, 0x77AC, + 0x77AE, 0x77B0, 0x77B2, 0x77B4, 0x77B6, 0x77B8, 0x77BA, 0x77BC, + 0x77BE, 0x77C0, 0x77C2, 0x77C4, 0x77C6, 0x77C8, 0x77CA, 0x77CC, + 0x77CE, 0x77D0, 0x77D2, 0x77D4, 0x77D6, 0x77D8, 0x77DA, 0x77DC, + 0x77DE, 0x77E0, 0x77E2, 0x77E4, 0x77E6, 0x77E8, 0x77EA, 0x77EC, + 0x77EE, 0x77F0, 0x77F2, 0x77F4, 0x77F6, 0x77F8, 0x77FA, 0x77FC, + 0x3BFF, 0x77FD, 0x77FB, 0x77F9, 0x77F7, 0x77F5, 0x77F3, 0x77F1, + 0x77EF, 0x77ED, 0x77EB, 0x77E9, 0x77E7, 0x77E5, 0x77E3, 0x77E1, + 0x77DF, 0x77DD, 0x77DB, 0x77D9, 0x77D7, 0x77D5, 0x77D3, 0x77D1, + 0x77CF, 0x77CD, 0x77CB, 0x77C9, 0x77C7, 0x77C5, 0x77C3, 0x77C1, + 0x77BF, 0x77BD, 0x77BB, 0x77B9, 0x77B7, 0x77B5, 0x77B3, 0x77B1, + 0x77AF, 0x77AD, 0x77AB, 0x77A9, 0x77A7, 0x77A5, 0x77A3, 0x77A1, + 0x779F, 0x779D, 0x779B, 0x7799, 0x7797, 0x7795, 0x7793, 0x7791, + 0x778F, 0x778D, 0x778B, 0x7789, 0x7787, 0x7785, 0x7783, 0x7781, + 0x777F, 0x777D, 0x777B, 0x7779, 0x7777, 0x7775, 0x7773, 0x7771, + 0x776F, 0x776D, 0x776B, 0x7769, 0x7767, 0x7765, 0x7763, 0x7761, + 0x775F, 0x775D, 0x775B, 0x7759, 0x7757, 0x7755, 0x7753, 0x7751, + 0x774F, 0x774D, 0x774B, 0x7749, 0x7747, 0x7745, 0x7743, 0x7741, + 0x773F, 0x773D, 0x773B, 0x7739, 0x7737, 0x7735, 0x7733, 0x7731, + 0x772F, 0x772D, 0x772B, 0x7729, 0x7727, 0x7725, 0x7723, 0x7721, + 0x771F, 0x771D, 0x771B, 0x7719, 0x7717, 0x7715, 0x7713, 0x7711, + 0x770F, 0x770D, 0x770B, 0x7709, 0x7707, 0x7705, 0x7703, 0x7701, + 0x76FF, 0x76FD, 0x76FB, 0x76F9, 0x76F7, 0x76F5, 0x76F3, 0x76F1, + 0x76EF, 0x76ED, 0x76EB, 0x76E9, 0x76E7, 0x76E5, 0x76E3, 0x76E1, + 0x76DF, 0x76DD, 0x76DB, 0x76D9, 0x76D7, 0x76D5, 0x76D3, 0x76D1, + 0x76CF, 0x76CD, 0x76CB, 0x76C9, 0x76C7, 0x76C5, 0x76C3, 0x76C1, + 0x76BF, 0x76BD, 0x76BB, 0x76B9, 0x76B7, 0x76B5, 0x76B3, 0x76B1, + 0x76AF, 0x76AD, 0x76AB, 0x76A9, 0x76A7, 0x76A5, 0x76A3, 0x76A1, + 0x769F, 0x769D, 0x769B, 0x7699, 0x7697, 0x7695, 0x7693, 0x7691, + 0x768F, 0x768D, 0x768B, 0x7689, 0x7687, 0x7685, 0x7683, 0x7681, + 0x767F, 0x767D, 0x767B, 0x7679, 0x7677, 0x7675, 0x7673, 0x7671, + 0x766F, 0x766D, 0x766B, 0x7669, 0x7667, 0x7665, 0x7663, 0x7661, + 0x765F, 0x765D, 0x765B, 0x7659, 0x7657, 0x7655, 0x7653, 0x7651, + 0x764F, 0x764D, 0x764B, 0x7649, 0x7647, 0x7645, 0x7643, 0x7641, + 0x763F, 0x763D, 0x763B, 0x7639, 0x7637, 0x7635, 0x7633, 0x7631, + 0x762F, 0x762D, 0x762B, 0x7629, 0x7627, 0x7625, 0x7623, 0x7621, + 0x761F, 0x761D, 0x761B, 0x7619, 0x7617, 0x7615, 0x7613, 0x7611, + 0x760F, 0x760D, 0x760B, 0x7609, 0x7607, 0x7605, 0x7603, 0x7601, + 0x17FF, 0x17FD, 0x17FB, 0x17F9, 0x17F7, 0x17F5, 0x17F3, 0x17F1, + 0x17EF, 0x17ED, 0x17EB, 0x17E9, 0x17E7, 0x17E5, 0x17E3, 0x17E1, + 0x17DF, 0x17DD, 0x17DB, 0x17D9, 0x17D7, 0x17D5, 0x17D3, 0x17D1, + 0x17CF, 0x17CD, 0x17CB, 0x17C9, 0x17C7, 0x17C5, 0x17C3, 0x17C1, + 0x17BF, 0x17BD, 0x17BB, 0x17B9, 0x17B7, 0x17B5, 0x17B3, 0x17B1, + 0x17AF, 0x17AD, 0x17AB, 0x17A9, 0x17A7, 0x17A5, 0x17A3, 0x17A1, + 0x179F, 0x179D, 0x179B, 0x1799, 0x1797, 0x1795, 0x1793, 0x1791, + 0x178F, 0x178D, 0x178B, 0x1789, 0x1787, 0x1785, 0x1783, 0x1781, + 0x177F, 0x177D, 0x177B, 0x1779, 0x1777, 0x1775, 0x1773, 0x1771, + 0x176F, 0x176D, 0x176B, 0x1769, 0x1767, 0x1765, 0x1763, 0x1761, + 0x175F, 0x175D, 0x175B, 0x1759, 0x1757, 0x1755, 0x1753, 0x1751, + 0x174F, 0x174D, 0x174B, 0x1749, 0x1747, 0x1745, 0x1743, 0x1741, + 0x173F, 0x173D, 0x173B, 0x1739, 0x1737, 0x1735, 0x1733, 0x1731, + 0x172F, 0x172D, 0x172B, 0x1729, 0x1727, 0x1725, 0x1723, 0x1721, + 0x171F, 0x171D, 0x171B, 0x1719, 0x1717, 0x1715, 0x1713, 0x1711, + 0x170F, 0x170D, 0x170B, 0x1709, 0x1707, 0x1705, 0x1703, 0x1701, + 0x16FF, 0x16FD, 0x16FB, 0x16F9, 0x16F7, 0x16F5, 0x16F3, 0x16F1, + 0x16EF, 0x16ED, 0x16EB, 0x16E9, 0x16E7, 0x16E5, 0x16E3, 0x16E1, + 0x16DF, 0x16DD, 0x16DB, 0x16D9, 0x16D7, 0x16D5, 0x16D3, 0x16D1, + 0x16CF, 0x16CD, 0x16CB, 0x16C9, 0x16C7, 0x16C5, 0x16C3, 0x16C1, + 0x16BF, 0x16BD, 0x16BB, 0x16B9, 0x16B7, 0x16B5, 0x16B3, 0x16B1, + 0x16AF, 0x16AD, 0x16AB, 0x16A9, 0x16A7, 0x16A5, 0x16A3, 0x16A1, + 0x169F, 0x169D, 0x169B, 0x1699, 0x1697, 0x1695, 0x1693, 0x1691, + 0x168F, 0x168D, 0x168B, 0x1689, 0x1687, 0x1685, 0x1683, 0x1681, + 0x167F, 0x167D, 0x167B, 0x1679, 0x1677, 0x1675, 0x1673, 0x1671, + 0x166F, 0x166D, 0x166B, 0x1669, 0x1667, 0x1665, 0x1663, 0x1661, + 0x165F, 0x165D, 0x165B, 0x1659, 0x1657, 0x1655, 0x1653, 0x1651, + 0x164F, 0x164D, 0x164B, 0x1649, 0x1647, 0x1645, 0x1643, 0x1641, + 0x163F, 0x163D, 0x163B, 0x1639, 0x1637, 0x1635, 0x1633, 0x1631, + 0x162F, 0x162D, 0x162B, 0x1629, 0x1627, 0x1625, 0x1623, 0x1621, + 0x161F, 0x161D, 0x161B, 0x1619, 0x1617, 0x1615, 0x1613, 0x1611, + 0x160F, 0x160D, 0x160B, 0x1609, 0x1607, 0x1605, 0x1603, 0x1601, + 0x18FF, 0x18FD, 0x18FB, 0x18F9, 0x18F7, 0x18F5, 0x18F3, 0x18F1, + 0x18EF, 0x18ED, 0x18EB, 0x18E9, 0x18E7, 0x18E5, 0x18E3, 0x18E1, + 0x18DF, 0x18DD, 0x18DB, 0x18D9, 0x18D7, 0x18D5, 0x18D3, 0x18D1, + 0x18CF, 0x18CD, 0x18CB, 0x18C9, 0x18C7, 0x18C5, 0x18C3, 0x18C1, + 0x18BF, 0x18BD, 0x18BB, 0x18B9, 0x18B7, 0x18B5, 0x18B3, 0x18B1, + 0x18AF, 0x18AD, 0x18AB, 0x18A9, 0x18A7, 0x18A5, 0x18A3, 0x18A1, + 0x189F, 0x189D, 0x189B, 0x1899, 0x1897, 0x1895, 0x1893, 0x1891, + 0x188F, 0x188D, 0x188B, 0x1889, 0x1887, 0x1885, 0x1883, 0x1881, + 0x187F, 0x187D, 0x187B, 0x1879, 0x1877, 0x1875, 0x1873, 0x1871, + 0x186F, 0x186D, 0x186B, 0x1869, 0x1867, 0x1865, 0x1863, 0x1861, + 0x185F, 0x185D, 0x185B, 0x1859, 0x1857, 0x1855, 0x1853, 0x1851, + 0x184F, 0x184D, 0x184B, 0x1849, 0x1847, 0x1845, 0x1843, 0x1841, + 0x183F, 0x183D, 0x183B, 0x1839, 0x1837, 0x1835, 0x1833, 0x1831, + 0x182F, 0x182D, 0x182B, 0x1829, 0x1827, 0x1825, 0x1823, 0x1821, + 0x181F, 0x181D, 0x181B, 0x1819, 0x1817, 0x1815, 0x1813, 0x1811, + 0x180F, 0x180D, 0x180B, 0x1809, 0x1807, 0x1805, 0x1803, 0x1801, + 0x0AFF, 0x0AFD, 0x0AFB, 0x0AF9, 0x0AF7, 0x0AF5, 0x0AF3, 0x0AF1, + 0x0AEF, 0x0AED, 0x0AEB, 0x0AE9, 0x0AE7, 0x0AE5, 0x0AE3, 0x0AE1, + 0x0ADF, 0x0ADD, 0x0ADB, 0x0AD9, 0x0AD7, 0x0AD5, 0x0AD3, 0x0AD1, + 0x0ACF, 0x0ACD, 0x0ACB, 0x0AC9, 0x0AC7, 0x0AC5, 0x0AC3, 0x0AC1, + 0x0ABF, 0x0ABD, 0x0ABB, 0x0AB9, 0x0AB7, 0x0AB5, 0x0AB3, 0x0AB1, + 0x0AAF, 0x0AAD, 0x0AAB, 0x0AA9, 0x0AA7, 0x0AA5, 0x0AA3, 0x0AA1, + 0x0A9F, 0x0A9D, 0x0A9B, 0x0A99, 0x0A97, 0x0A95, 0x0A93, 0x0A91, + 0x0A8F, 0x0A8D, 0x0A8B, 0x0A89, 0x0A87, 0x0A85, 0x0A83, 0x0A81, + 0x0A7F, 0x0A7D, 0x0A7B, 0x0A79, 0x0A77, 0x0A75, 0x0A73, 0x0A71, + 0x0A6F, 0x0A6D, 0x0A6B, 0x0A69, 0x0A67, 0x0A65, 0x0A63, 0x0A61, + 0x0A5F, 0x0A5D, 0x0A5B, 0x0A59, 0x0A57, 0x0A55, 0x0A53, 0x0A51, + 0x0A4F, 0x0A4D, 0x0A4B, 0x0A49, 0x0A47, 0x0A45, 0x0A43, 0x0A41, + 0x0A3F, 0x0A3D, 0x0A3B, 0x0A39, 0x0A37, 0x0A35, 0x0A33, 0x0A31, + 0x0A2F, 0x0A2D, 0x0A2B, 0x0A29, 0x0A27, 0x0A25, 0x0A23, 0x0A21, + 0x0A1F, 0x0A1D, 0x0A1B, 0x0A19, 0x0A17, 0x0A15, 0x0A13, 0x0A11, + 0x0A0F, 0x0A0D, 0x0A0B, 0x0A09, 0x0A07, 0x0A05, 0x0A03, 0x0A01, + 0x04FF, 0x04FD, 0x04FB, 0x04F9, 0x04F7, 0x04F5, 0x04F3, 0x04F1, + 0x04EF, 0x04ED, 0x04EB, 0x04E9, 0x04E7, 0x04E5, 0x04E3, 0x04E1, + 0x04DF, 0x04DD, 0x04DB, 0x04D9, 0x04D7, 0x04D5, 0x04D3, 0x04D1, + 0x04CF, 0x04CD, 0x04CB, 0x04C9, 0x04C7, 0x04C5, 0x04C3, 0x04C1, + 0x04BF, 0x04BD, 0x04BB, 0x04B9, 0x04B7, 0x04B5, 0x04B3, 0x04B1, + 0x04AF, 0x04AD, 0x04AB, 0x04A9, 0x04A7, 0x04A5, 0x04A3, 0x04A1, + 0x049F, 0x049D, 0x049B, 0x0499, 0x0497, 0x0495, 0x0493, 0x0491, + 0x048F, 0x048D, 0x048B, 0x0489, 0x0487, 0x0485, 0x0483, 0x0481, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x00BF, 0x00BD, 0x00BB, 0x00B9, 0x00B7, 0x00B5, 0x00B3, 0x00B1, + 0x00AF, 0x00AD, 0x00AB, 0x00A9, 0x00A7, 0x00A5, 0x00A3, 0x00A1, + 0x009F, 0x009D, 0x009B, 0x0099, 0x0097, 0x0095, 0x0093, 0x0091, + 0x008F, 0x008D, 0x008B, 0x0089, 0x0087, 0x0085, 0x0083, 0x0081, + 0x023F, 0x023D, 0x023B, 0x0239, 0x0237, 0x0235, 0x0233, 0x0231, + 0x022F, 0x022D, 0x022B, 0x0229, 0x0227, 0x0225, 0x0223, 0x0221, + 0x021F, 0x021D, 0x021B, 0x0219, 0x0217, 0x0215, 0x0213, 0x0211, + 0x020F, 0x020D, 0x020B, 0x0209, 0x0207, 0x0205, 0x0203, 0x0201, + 0x003F, 0x003D, 0x003B, 0x0039, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002F, 0x002D, 0x002B, 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, + 0x001F, 0x001D, 0x001B, 0x0019, 0x0017, 0x0015, 0x0013, 0x0011, + 0x000F, 0x000D, 0x000B, 0x0009, 0x0007, 0x0005, 0x0003, 0x0001, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x00EF, 0x00ED, 0x00EB, 0x00E9, 0x00E7, 0x00E5, 0x00E3, 0x00E1, + 0x00DF, 0x00DD, 0x00DB, 0x00D9, 0x00D7, 0x00D5, 0x00D3, 0x00D1, + 0x00CF, 0x00CD, 0x00CB, 0x00C9, 0x00C7, 0x00C5, 0x00C3, 0x00C1, + 0x005F, 0x005D, 0x005B, 0x0059, 0x0057, 0x0055, 0x0053, 0x0051, + 0x004F, 0x004D, 0x004B, 0x0049, 0x0047, 0x0045, 0x0043, 0x0041, + 0x00FF, 0x00FD, 0x00FB, 0x00F9, 0x00F7, 0x00F5, 0x00F3, 0x00F1, + 0x0075, 0x0073, 0x0071, 0x006F, 0x006D, 0x006B, 0x0069, 0x0067, +}; + +static const uint8_t dc11_vlc_lens[2048] = { + 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 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, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 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, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, +}; + + +static HQXAC hqx_ac[NUM_HQX_AC] = { + { 10 }, { 11 }, { 11 }, { 11 }, { 12 }, { 11 }, +}; + +// level is in -255..255 range, run 0..64, so it fits into 16 bits. +// We offset run by 1 in order to include the implicit run of 1. +#define E(level, run) ((level * 128) | (run + 1)) + +static const int16_t hqx_ac_run_level[] = { + // AC table Q0 - 815 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 1, 1), E( -1, 1), + E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), + E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 15, 0), E( -15, 0), E( 16, 0), + E( -16, 0), E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 29, 0), E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), + E( -31, 0), E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), + E( 34, 0), E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), + E( -36, 0), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), E( 51, 0), + E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), E( -53, 0), + E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), E( 56, 0), + E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), E( -58, 0), + E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), E( 61, 0), + E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), E( -63, 0), + E( 64, 0), E( -64, 0), E( 65, 0), E( -65, 0), E( 66, 0), + E( -66, 0), E( 67, 0), E( -67, 0), E( 68, 0), E( -68, 0), + E( 69, 0), E( -69, 0), E( 70, 0), E( -70, 0), E( 71, 0), + E( -71, 0), E( 72, 0), E( -72, 0), E( 73, 0), E( -73, 0), + E( 74, 0), E( -74, 0), E( 75, 0), E( -75, 0), E( 76, 0), + E( -76, 0), E( 77, 0), E( -77, 0), E( 78, 0), E( -78, 0), + E( 79, 0), E( -79, 0), E( 80, 0), E( -80, 0), E( 81, 0), + E( -81, 0), E( 82, 0), E( -82, 0), E( 83, 0), E( -83, 0), + E( 84, 0), E( -84, 0), E( 85, 0), E( -85, 0), E( 86, 0), + E( -86, 0), E( 87, 0), E( -87, 0), E( 88, 0), E( -88, 0), + E( 89, 0), E( -89, 0), E( 90, 0), E( -90, 0), E( 91, 0), + E( -91, 0), E( 92, 0), E( -92, 0), E( 93, 0), E( -93, 0), + E( 94, 0), E( -94, 0), E( 95, 0), E( -95, 0), E( 96, 0), + E( -96, 0), E( 97, 0), E( -97, 0), E( 98, 0), E( -98, 0), + E( 99, 0), E( -99, 0), E( 100, 0), E(-100, 0), E( 101, 0), + E(-101, 0), E( 102, 0), E(-102, 0), E( 103, 0), E(-103, 0), + E( 104, 0), E(-104, 0), E( 105, 0), E(-105, 0), E( 106, 0), + E(-106, 0), E( 107, 0), E(-107, 0), E( 108, 0), E(-108, 0), + E( 109, 0), E(-109, 0), E( 110, 0), E(-110, 0), E( 111, 0), + E(-111, 0), E( 112, 0), E(-112, 0), E( 113, 0), E(-113, 0), + E( 114, 0), E(-114, 0), E( 115, 0), E(-115, 0), E( 116, 0), + E(-116, 0), E( 117, 0), E(-117, 0), E( 118, 0), E(-118, 0), + E( 119, 0), E(-119, 0), E( 120, 0), E(-120, 0), E( 121, 0), + E(-121, 0), E( 122, 0), E(-122, 0), E( 123, 0), E(-123, 0), + E( 124, 0), E(-124, 0), E( 125, 0), E(-125, 0), E( 126, 0), + E(-126, 0), E( 127, 0), E(-127, 0), E( 128, 0), E(-128, 0), + E( 129, 0), E(-129, 0), E( 130, 0), E(-130, 0), E( 131, 0), + E(-131, 0), E( 132, 0), E(-132, 0), E( 133, 0), E(-133, 0), + E( 134, 0), E(-134, 0), E( 135, 0), E(-135, 0), E( 136, 0), + E(-136, 0), E( 137, 0), E(-137, 0), E( 138, 0), E(-138, 0), + E( 139, 0), E(-139, 0), E( 140, 0), E(-140, 0), E( 141, 0), + E(-141, 0), E( 142, 0), E(-142, 0), E( 143, 0), E(-143, 0), + E( 144, 0), E(-144, 0), E( 145, 0), E(-145, 0), E( 146, 0), + E(-146, 0), E( 147, 0), E(-147, 0), E( 148, 0), E(-148, 0), + E( 149, 0), E(-149, 0), E( 150, 0), E(-150, 0), E( 151, 0), + E(-151, 0), E( 152, 0), E(-152, 0), E( 153, 0), E(-153, 0), + E( 154, 0), E(-154, 0), E( 155, 0), E(-155, 0), E( 156, 0), + E(-156, 0), E( 157, 0), E(-157, 0), E( 158, 0), E(-158, 0), + E( 159, 0), E(-159, 0), E( 160, 0), E(-160, 0), E( 161, 0), + E(-161, 0), E( 162, 0), E(-162, 0), E( 163, 0), E(-163, 0), + E( 164, 0), E(-164, 0), E( 165, 0), E(-165, 0), E( 166, 0), + E(-166, 0), E( 167, 0), E(-167, 0), E( 168, 0), E(-168, 0), + E( 169, 0), E(-169, 0), E( 170, 0), E(-170, 0), E( 171, 0), + E(-171, 0), E( 172, 0), E(-172, 0), E( 173, 0), E(-173, 0), + E( 174, 0), E(-174, 0), E( 175, 0), E(-175, 0), E( 176, 0), + E(-176, 0), E( 177, 0), E(-177, 0), E( 178, 0), E(-178, 0), + E( 179, 0), E(-179, 0), E( 180, 0), E(-180, 0), E( 181, 0), + E(-181, 0), E( 182, 0), E(-182, 0), E( 183, 0), E(-183, 0), + E( 184, 0), E(-184, 0), E( 185, 0), E(-185, 0), E( 186, 0), + E(-186, 0), E( 187, 0), E(-187, 0), E( 188, 0), E(-188, 0), + E( 189, 0), E(-189, 0), E( 190, 0), E(-190, 0), E( 191, 0), + E(-191, 0), E( 192, 0), E(-192, 0), E( 193, 0), E(-193, 0), + E( 194, 0), E(-194, 0), E( 195, 0), E(-195, 0), E( 196, 0), + E(-196, 0), E( 197, 0), E(-197, 0), E( 198, 0), E(-198, 0), + E( 199, 0), E(-199, 0), E( 200, 0), E(-200, 0), E( 201, 0), + E(-201, 0), E( 202, 0), E(-202, 0), E( 203, 0), E(-203, 0), + E( 204, 0), E(-204, 0), E( 205, 0), E(-205, 0), E( 206, 0), + E(-206, 0), E( 207, 0), E(-207, 0), E( 208, 0), E(-208, 0), + E( 209, 0), E(-209, 0), E( 210, 0), E(-210, 0), E( 211, 0), + E(-211, 0), E( 212, 0), E(-212, 0), E( 213, 0), E(-213, 0), + E( 214, 0), E(-214, 0), E( 215, 0), E(-215, 0), E( 216, 0), + E(-216, 0), E( 217, 0), E(-217, 0), E( 218, 0), E(-218, 0), + E( 219, 0), E(-219, 0), E( 220, 0), E(-220, 0), E( 221, 0), + E(-221, 0), E( 222, 0), E(-222, 0), E( 223, 0), E(-223, 0), + E( 224, 0), E(-224, 0), E( 225, 0), E(-225, 0), E( 226, 0), + E(-226, 0), E( 227, 0), E(-227, 0), E( 228, 0), E(-228, 0), + E( 229, 0), E(-229, 0), E( 230, 0), E(-230, 0), E( 231, 0), + E(-231, 0), E( 232, 0), E(-232, 0), E( 233, 0), E(-233, 0), + E( 234, 0), E(-234, 0), E( 235, 0), E(-235, 0), E( 236, 0), + E(-236, 0), E( 237, 0), E(-237, 0), E( 238, 0), E(-238, 0), + E( 239, 0), E(-239, 0), E( 240, 0), E(-240, 0), E( 241, 0), + E(-241, 0), E( 242, 0), E(-242, 0), E( 243, 0), E(-243, 0), + E( 244, 0), E(-244, 0), E( 245, 0), E(-245, 0), E( 246, 0), + E(-246, 0), E( 247, 0), E(-247, 0), E( 248, 0), E(-248, 0), + E( 249, 0), E(-249, 0), E( 250, 0), E(-250, 0), E( 251, 0), + E(-251, 0), E( 252, 0), E(-252, 0), E( 253, 0), E(-253, 0), + E( 254, 0), E(-254, 0), E( 255, 0), E(-255, 0), E( 0, 64), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 2, 1), E( -2, 1), E( 1, 2), + E( -1, 2), E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), + E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), E( 19, 0), + E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), E( -21, 0), + E( 3, 1), E( -3, 1), E( 4, 1), E( -4, 1), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 0, 0), E( 22, 0), + E( -22, 0), E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), + E( 25, 0), E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), + E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), + E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), + E( -32, 0), E( 33, 0), E( -33, 0), E( 5, 1), E( -5, 1), + E( 6, 1), E( -6, 1), E( 2, 2), E( -2, 2), E( 1, 5), + E( -1, 5), E( 1, 6), E( -1, 6), E( 34, 0), E( -34, 0), + E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), + E( -37, 0), E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), + E( 40, 0), E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), + E( -42, 0), E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), + E( 45, 0), E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), + E( -47, 0), E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), + E( 50, 0), E( -50, 0), E( 0, 1), E( 7, 1), E( -7, 1), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 10, 1), + E( -10, 1), E( 0, 2), E( 3, 2), E( -3, 2), E( 0, 3), + E( 2, 3), E( -2, 3), E( 1, 7), E( -1, 7), E( 1, 8), + E( -1, 8), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), + E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), + E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), + E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), + E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), + E( -63, 0), E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), + E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), E( 4, 2), + E( -4, 2), E( 5, 2), E( -5, 2), E( 6, 2), E( -6, 2), + E( 3, 3), E( -3, 3), E( 0, 4), E( 2, 4), E( -2, 4), + E( 0, 5), E( 0, 6), E( 1, 9), E( -1, 9), E( 1, 10), + E( -1, 10), E( 15, 1), E( -15, 1), E( 16, 1), E( -16, 1), + E( 17, 1), E( -17, 1), E( 18, 1), E( -18, 1), E( 7, 2), + E( -7, 2), E( 8, 2), E( -8, 2), E( 9, 2), E( -9, 2), + E( 10, 2), E( -10, 2), E( 4, 3), E( -4, 3), E( 5, 3), + E( -5, 3), E( 6, 3), E( -6, 3), E( 2, 5), E( -2, 5), + E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), E( 1, 11), + E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), + E( 1, 14), E( -1, 14), E( 19, 1), E( -19, 1), E( 20, 1), + E( -20, 1), E( 3, 4), E( -3, 4), E( 2, 6), E( -2, 6), + // AC table Q8 - 907 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 0, 64), E( 5, 0), + E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 1, 1), E( -1, 1), E( 2, 1), + E( -2, 1), E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), + E( 11, 0), E( -11, 0), E( 12, 0), E( -12, 0), E( 3, 1), + E( -3, 1), E( 4, 1), E( -4, 1), E( 1, 2), E( -1, 2), + E( 0, 0), E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), + E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), E( 5, 0), + E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), + E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), + E( -10, 0), E( 11, 0), E( -11, 0), E( 12, 0), E( -12, 0), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 18, 0), E( -18, 0), E( 19, 0), E( -19, 0), E( 20, 0), + E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), E( -22, 0), + E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), E( 25, 0), + E( -25, 0), E( 26, 0), E( -26, 0), E( 27, 0), E( -27, 0), + E( 28, 0), E( -28, 0), E( 29, 0), E( -29, 0), E( 30, 0), + E( -30, 0), E( 31, 0), E( -31, 0), E( 32, 0), E( -32, 0), + E( 33, 0), E( -33, 0), E( 34, 0), E( -34, 0), E( 35, 0), + E( -35, 0), E( 36, 0), E( -36, 0), E( 37, 0), E( -37, 0), + E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), E( 40, 0), + E( -40, 0), E( 41, 0), E( -41, 0), E( 42, 0), E( -42, 0), + E( 43, 0), E( -43, 0), E( 44, 0), E( -44, 0), E( 45, 0), + E( -45, 0), E( 46, 0), E( -46, 0), E( 47, 0), E( -47, 0), + E( 48, 0), E( -48, 0), E( 49, 0), E( -49, 0), E( 50, 0), + E( -50, 0), E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), + E( 53, 0), E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), + E( -55, 0), E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), + E( 58, 0), E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), + E( -60, 0), E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), + E( 63, 0), E( -63, 0), E( 64, 0), E( -64, 0), E( 65, 0), + E( -65, 0), E( 66, 0), E( -66, 0), E( 67, 0), E( -67, 0), + E( 68, 0), E( -68, 0), E( 69, 0), E( -69, 0), E( 70, 0), + E( -70, 0), E( 71, 0), E( -71, 0), E( 72, 0), E( -72, 0), + E( 73, 0), E( -73, 0), E( 74, 0), E( -74, 0), E( 75, 0), + E( -75, 0), E( 76, 0), E( -76, 0), E( 77, 0), E( -77, 0), + E( 78, 0), E( -78, 0), E( 79, 0), E( -79, 0), E( 80, 0), + E( -80, 0), E( 81, 0), E( -81, 0), E( 82, 0), E( -82, 0), + E( 83, 0), E( -83, 0), E( 84, 0), E( -84, 0), E( 85, 0), + E( -85, 0), E( 86, 0), E( -86, 0), E( 87, 0), E( -87, 0), + E( 88, 0), E( -88, 0), E( 89, 0), E( -89, 0), E( 90, 0), + E( -90, 0), E( 91, 0), E( -91, 0), E( 92, 0), E( -92, 0), + E( 93, 0), E( -93, 0), E( 94, 0), E( -94, 0), E( 95, 0), + E( -95, 0), E( 96, 0), E( -96, 0), E( 97, 0), E( -97, 0), + E( 98, 0), E( -98, 0), E( 99, 0), E( -99, 0), E( 100, 0), + E(-100, 0), E( 101, 0), E(-101, 0), E( 102, 0), E(-102, 0), + E( 103, 0), E(-103, 0), E( 104, 0), E(-104, 0), E( 105, 0), + E(-105, 0), E( 106, 0), E(-106, 0), E( 107, 0), E(-107, 0), + E( 108, 0), E(-108, 0), E( 109, 0), E(-109, 0), E( 110, 0), + E(-110, 0), E( 111, 0), E(-111, 0), E( 112, 0), E(-112, 0), + E( 113, 0), E(-113, 0), E( 114, 0), E(-114, 0), E( 115, 0), + E(-115, 0), E( 116, 0), E(-116, 0), E( 117, 0), E(-117, 0), + E( 118, 0), E(-118, 0), E( 119, 0), E(-119, 0), E( 120, 0), + E(-120, 0), E( 121, 0), E(-121, 0), E( 122, 0), E(-122, 0), + E( 123, 0), E(-123, 0), E( 124, 0), E(-124, 0), E( 125, 0), + E(-125, 0), E( 126, 0), E(-126, 0), E( 127, 0), E(-127, 0), + E( 128, 0), E(-128, 0), E( 129, 0), E(-129, 0), E( 130, 0), + E(-130, 0), E( 131, 0), E(-131, 0), E( 132, 0), E(-132, 0), + E( 133, 0), E(-133, 0), E( 134, 0), E(-134, 0), E( 135, 0), + E(-135, 0), E( 136, 0), E(-136, 0), E( 137, 0), E(-137, 0), + E( 138, 0), E(-138, 0), E( 139, 0), E(-139, 0), E( 140, 0), + E(-140, 0), E( 141, 0), E(-141, 0), E( 142, 0), E(-142, 0), + E( 143, 0), E(-143, 0), E( 144, 0), E(-144, 0), E( 145, 0), + E(-145, 0), E( 146, 0), E(-146, 0), E( 147, 0), E(-147, 0), + E( 148, 0), E(-148, 0), E( 149, 0), E(-149, 0), E( 150, 0), + E(-150, 0), E( 151, 0), E(-151, 0), E( 152, 0), E(-152, 0), + E( 153, 0), E(-153, 0), E( 154, 0), E(-154, 0), E( 155, 0), + E(-155, 0), E( 156, 0), E(-156, 0), E( 157, 0), E(-157, 0), + E( 158, 0), E(-158, 0), E( 159, 0), E(-159, 0), E( 160, 0), + E(-160, 0), E( 161, 0), E(-161, 0), E( 162, 0), E(-162, 0), + E( 163, 0), E(-163, 0), E( 164, 0), E(-164, 0), E( 165, 0), + E(-165, 0), E( 166, 0), E(-166, 0), E( 167, 0), E(-167, 0), + E( 168, 0), E(-168, 0), E( 169, 0), E(-169, 0), E( 170, 0), + E(-170, 0), E( 171, 0), E(-171, 0), E( 172, 0), E(-172, 0), + E( 173, 0), E(-173, 0), E( 174, 0), E(-174, 0), E( 175, 0), + E(-175, 0), E( 176, 0), E(-176, 0), E( 177, 0), E(-177, 0), + E( 178, 0), E(-178, 0), E( 179, 0), E(-179, 0), E( 180, 0), + E(-180, 0), E( 181, 0), E(-181, 0), E( 182, 0), E(-182, 0), + E( 183, 0), E(-183, 0), E( 184, 0), E(-184, 0), E( 185, 0), + E(-185, 0), E( 186, 0), E(-186, 0), E( 187, 0), E(-187, 0), + E( 188, 0), E(-188, 0), E( 189, 0), E(-189, 0), E( 190, 0), + E(-190, 0), E( 191, 0), E(-191, 0), E( 192, 0), E(-192, 0), + E( 193, 0), E(-193, 0), E( 194, 0), E(-194, 0), E( 195, 0), + E(-195, 0), E( 196, 0), E(-196, 0), E( 197, 0), E(-197, 0), + E( 198, 0), E(-198, 0), E( 199, 0), E(-199, 0), E( 200, 0), + E(-200, 0), E( 201, 0), E(-201, 0), E( 202, 0), E(-202, 0), + E( 203, 0), E(-203, 0), E( 204, 0), E(-204, 0), E( 205, 0), + E(-205, 0), E( 206, 0), E(-206, 0), E( 207, 0), E(-207, 0), + E( 208, 0), E(-208, 0), E( 209, 0), E(-209, 0), E( 210, 0), + E(-210, 0), E( 211, 0), E(-211, 0), E( 212, 0), E(-212, 0), + E( 213, 0), E(-213, 0), E( 214, 0), E(-214, 0), E( 215, 0), + E(-215, 0), E( 216, 0), E(-216, 0), E( 217, 0), E(-217, 0), + E( 218, 0), E(-218, 0), E( 219, 0), E(-219, 0), E( 220, 0), + E(-220, 0), E( 221, 0), E(-221, 0), E( 222, 0), E(-222, 0), + E( 223, 0), E(-223, 0), E( 224, 0), E(-224, 0), E( 225, 0), + E(-225, 0), E( 226, 0), E(-226, 0), E( 227, 0), E(-227, 0), + E( 228, 0), E(-228, 0), E( 229, 0), E(-229, 0), E( 230, 0), + E(-230, 0), E( 231, 0), E(-231, 0), E( 232, 0), E(-232, 0), + E( 233, 0), E(-233, 0), E( 234, 0), E(-234, 0), E( 235, 0), + E(-235, 0), E( 236, 0), E(-236, 0), E( 237, 0), E(-237, 0), + E( 238, 0), E(-238, 0), E( 239, 0), E(-239, 0), E( 240, 0), + E(-240, 0), E( 241, 0), E(-241, 0), E( 242, 0), E(-242, 0), + E( 243, 0), E(-243, 0), E( 244, 0), E(-244, 0), E( 245, 0), + E(-245, 0), E( 246, 0), E(-246, 0), E( 247, 0), E(-247, 0), + E( 248, 0), E(-248, 0), E( 249, 0), E(-249, 0), E( 250, 0), + E(-250, 0), E( 251, 0), E(-251, 0), E( 252, 0), E(-252, 0), + E( 253, 0), E(-253, 0), E( 254, 0), E(-254, 0), E( 255, 0), + E(-255, 0), E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), + E( 15, 0), E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), + E( -17, 0), E( 18, 0), E( -18, 0), E( 5, 1), E( -5, 1), + E( 6, 1), E( -6, 1), E( 2, 2), E( -2, 2), E( 1, 3), + E( -1, 3), E( 0, 0), E( 19, 0), E( -19, 0), E( 20, 0), + E( -20, 0), E( 21, 0), E( -21, 0), E( 22, 0), E( -22, 0), + E( 23, 0), E( -23, 0), E( 24, 0), E( -24, 0), E( 25, 0), + E( -25, 0), E( 7, 1), E( -7, 1), E( 8, 1), E( -8, 1), + E( 3, 2), E( -3, 2), E( 2, 3), E( -2, 3), E( 1, 4), + E( -1, 4), E( 1, 5), E( -1, 5), E( 26, 0), E( -26, 0), + E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), E( 29, 0), + E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), + E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), + E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), E( -36, 0), + E( 0, 1), E( 9, 1), E( -9, 1), E( 10, 1), E( -10, 1), + E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), E( 0, 2), + E( 4, 2), E( -4, 2), E( 5, 2), E( -5, 2), E( 6, 2), + E( -6, 2), E( 0, 3), E( 3, 3), E( -3, 3), E( 4, 3), + E( -4, 3), E( 0, 4), E( 2, 4), E( -2, 4), E( 0, 5), + E( 1, 6), E( -1, 6), E( 1, 7), E( -1, 7), E( 1, 8), + E( -1, 8), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), E( 15, 1), + E( -15, 1), E( 16, 1), E( -16, 1), E( 7, 2), E( -7, 2), + E( 8, 2), E( -8, 2), E( 5, 3), E( -5, 3), E( 6, 3), + E( -6, 3), E( 3, 4), E( -3, 4), E( 4, 4), E( -4, 4), + E( 2, 5), E( -2, 5), E( 0, 6), E( 2, 6), E( -2, 6), + E( 0, 7), E( 0, 8), E( 0, 9), E( 1, 9), E( -1, 9), + E( 1, 10), E( -1, 10), E( 1, 11), E( -1, 11), E( 1, 12), + E( -1, 12), E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), + E( 51, 0), E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), + E( -53, 0), E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), + E( 56, 0), E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), + E( -58, 0), E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), + E( 61, 0), E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), + E( -63, 0), E( 17, 1), E( -17, 1), E( 18, 1), E( -18, 1), + E( 19, 1), E( -19, 1), E( 20, 1), E( -20, 1), E( 21, 1), + E( -21, 1), E( 22, 1), E( -22, 1), E( 23, 1), E( -23, 1), + E( 24, 1), E( -24, 1), E( 9, 2), E( -9, 2), E( 10, 2), + E( -10, 2), E( 11, 2), E( -11, 2), E( 12, 2), E( -12, 2), + E( 7, 3), E( -7, 3), E( 8, 3), E( -8, 3), E( 5, 4), + E( -5, 4), E( 6, 4), E( -6, 4), E( 3, 5), E( -3, 5), + E( 4, 5), E( -4, 5), E( 5, 5), E( -5, 5), E( 6, 5), + E( -6, 5), E( 3, 6), E( -3, 6), E( 4, 6), E( -4, 6), + E( 2, 7), E( -2, 7), E( 2, 8), E( -2, 8), E( 2, 9), + E( -2, 9), E( 0, 10), E( 2, 10), E( -2, 10), E( 0, 11), + E( 0, 12), E( 0, 13), E( 1, 13), E( -1, 13), E( 1, 14), + E( -1, 14), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), + E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), + E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), + E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), + E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), + E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), + E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), + E( 25, 1), E( -25, 1), E( 26, 1), E( -26, 1), E( 27, 1), + E( -27, 1), E( 28, 1), E( -28, 1), E( 29, 1), E( -29, 1), + E( 30, 1), E( -30, 1), E( 31, 1), E( -31, 1), E( 32, 1), + E( -32, 1), E( 13, 2), E( -13, 2), E( 14, 2), E( -14, 2), + E( 15, 2), E( -15, 2), E( 16, 2), E( -16, 2), E( 9, 3), + E( -9, 3), E( 10, 3), E( -10, 3), E( 11, 3), E( -11, 3), + E( 7, 4), E( -7, 4), E( 3, 7), E( -3, 7), E( 4, 7), + E( -4, 7), E( 3, 8), E( -3, 8), E( 4, 8), E( -4, 8), + E( 3, 9), E( -3, 9), E( 2, 11), E( -2, 11), E( 2, 12), + E( -2, 12), E( 0, 14), + // AC table Q16 - 512 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 4, 0), E( -4, 0), E( 1, 1), E( -1, 1), + E( 0, 64), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), + E( 2, 1), E( -2, 1), E( 1, 2), E( -1, 2), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 3, 1), E( -3, 1), E( 1, 3), E( -1, 3), E( 1, 4), + E( -1, 4), E( 10, 0), E( -10, 0), E( 11, 0), E( -11, 0), + E( 12, 0), E( -12, 0), E( 4, 1), E( -4, 1), E( 2, 2), + E( -2, 2), E( 1, 5), E( -1, 5), E( 1, 6), E( -1, 6), + E( 13, 0), E( -13, 0), E( 14, 0), E( -14, 0), E( 15, 0), + E( -15, 0), E( 16, 0), E( -16, 0), E( 17, 0), E( -17, 0), + E( 5, 1), E( -5, 1), E( 2, 3), E( -2, 3), E( 1, 7), + E( -1, 7), E( 1, 8), E( -1, 8), E( 1, 9), E( -1, 9), + E( 1, 10), E( -1, 10), E( 0, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 6, 1), E( -6, 1), + E( 7, 1), E( -7, 1), E( 3, 2), E( -3, 2), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 11), E( -1, 11), + E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), + E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), + E( 0, 6), E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), + E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), E( 0, 15), + E( 0, 16), E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), + E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), E( 0, 25), + E( 0, 26), E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), + E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), E( 0, 35), + E( 0, 36), E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), + E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), E( 0, 45), + E( 0, 46), E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), + E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), E( 0, 55), + E( 0, 56), E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), + E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), + E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E( -10, 0), E( 11, 0), + E( -11, 0), E( 12, 0), E( -12, 0), E( 13, 0), E( -13, 0), + E( 14, 0), E( -14, 0), E( 15, 0), E( -15, 0), E( 16, 0), + E( -16, 0), E( 17, 0), E( -17, 0), E( 18, 0), E( -18, 0), + E( 19, 0), E( -19, 0), E( 20, 0), E( -20, 0), E( 21, 0), + E( -21, 0), E( 22, 0), E( -22, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 29, 0), E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), + E( -31, 0), E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), + E( 34, 0), E( -34, 0), E( 35, 0), E( -35, 0), E( 36, 0), + E( -36, 0), E( 37, 0), E( -37, 0), E( 38, 0), E( -38, 0), + E( 39, 0), E( -39, 0), E( 40, 0), E( -40, 0), E( 41, 0), + E( -41, 0), E( 42, 0), E( -42, 0), E( 43, 0), E( -43, 0), + E( 44, 0), E( -44, 0), E( 45, 0), E( -45, 0), E( 46, 0), + E( -46, 0), E( 47, 0), E( -47, 0), E( 48, 0), E( -48, 0), + E( 49, 0), E( -49, 0), E( 50, 0), E( -50, 0), E( 51, 0), + E( -51, 0), E( 52, 0), E( -52, 0), E( 53, 0), E( -53, 0), + E( 54, 0), E( -54, 0), E( 55, 0), E( -55, 0), E( 56, 0), + E( -56, 0), E( 57, 0), E( -57, 0), E( 58, 0), E( -58, 0), + E( 59, 0), E( -59, 0), E( 60, 0), E( -60, 0), E( 61, 0), + E( -61, 0), E( 62, 0), E( -62, 0), E( 63, 0), E( -63, 0), + E( 64, 0), E( -64, 0), E( 65, 0), E( -65, 0), E( 66, 0), + E( -66, 0), E( 67, 0), E( -67, 0), E( 68, 0), E( -68, 0), + E( 69, 0), E( -69, 0), E( 70, 0), E( -70, 0), E( 71, 0), + E( -71, 0), E( 72, 0), E( -72, 0), E( 73, 0), E( -73, 0), + E( 74, 0), E( -74, 0), E( 75, 0), E( -75, 0), E( 76, 0), + E( -76, 0), E( 77, 0), E( -77, 0), E( 78, 0), E( -78, 0), + E( 79, 0), E( -79, 0), E( 80, 0), E( -80, 0), E( 81, 0), + E( -81, 0), E( 82, 0), E( -82, 0), E( 83, 0), E( -83, 0), + E( 84, 0), E( -84, 0), E( 85, 0), E( -85, 0), E( 86, 0), + E( -86, 0), E( 87, 0), E( -87, 0), E( 88, 0), E( -88, 0), + E( 89, 0), E( -89, 0), E( 90, 0), E( -90, 0), E( 91, 0), + E( -91, 0), E( 92, 0), E( -92, 0), E( 93, 0), E( -93, 0), + E( 94, 0), E( -94, 0), E( 95, 0), E( -95, 0), E( 96, 0), + E( -96, 0), E( 97, 0), E( -97, 0), E( 98, 0), E( -98, 0), + E( 99, 0), E( -99, 0), E( 100, 0), E(-100, 0), E( 101, 0), + E(-101, 0), E( 102, 0), E(-102, 0), E( 103, 0), E(-103, 0), + E( 104, 0), E(-104, 0), E( 105, 0), E(-105, 0), E( 106, 0), + E(-106, 0), E( 107, 0), E(-107, 0), E( 108, 0), E(-108, 0), + E( 109, 0), E(-109, 0), E( 110, 0), E(-110, 0), E( 111, 0), + E(-111, 0), E( 112, 0), E(-112, 0), E( 113, 0), E(-113, 0), + E( 114, 0), E(-114, 0), E( 115, 0), E(-115, 0), E( 116, 0), + E(-116, 0), E( 117, 0), E(-117, 0), E( 118, 0), E(-118, 0), + E( 119, 0), E(-119, 0), E( 120, 0), E(-120, 0), E( 121, 0), + E(-121, 0), E( 122, 0), E(-122, 0), E( 123, 0), E(-123, 0), + E( 124, 0), E(-124, 0), E( 125, 0), E(-125, 0), E( 126, 0), + E(-126, 0), E( 127, 0), E(-127, 0), E( 23, 0), E( -23, 0), + E( 24, 0), E( -24, 0), E( 25, 0), E( -25, 0), E( 26, 0), + E( -26, 0), E( 27, 0), E( -27, 0), E( 28, 0), E( -28, 0), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 4, 2), + E( -4, 2), E( 3, 3), E( -3, 3), E( 3, 4), E( -3, 4), + E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), E( 29, 0), + E( -29, 0), E( 30, 0), E( -30, 0), E( 31, 0), E( -31, 0), + E( 32, 0), E( -32, 0), E( 33, 0), E( -33, 0), E( 34, 0), + E( -34, 0), E( 35, 0), E( -35, 0), E( 0, 1), E( 10, 1), + E( -10, 1), E( 11, 1), E( -11, 1), E( 12, 1), E( -12, 1), + E( 0, 2), E( 5, 2), E( -5, 2), E( 0, 3), E( 4, 3), + E( -4, 3), E( 3, 5), E( -3, 5), E( 2, 8), E( -2, 8), + E( 2, 9), E( -2, 9), E( 1, 14), E( -1, 14), E( 1, 15), + E( -1, 15), E( 36, 0), E( -36, 0), E( 37, 0), E( -37, 0), + E( 38, 0), E( -38, 0), E( 39, 0), E( -39, 0), E( 40, 0), + E( -40, 0), E( 13, 1), E( -13, 1), E( 14, 1), E( -14, 1), + E( 15, 1), E( -15, 1), E( 6, 2), E( -6, 2), E( 7, 2), + E( -7, 2), E( 5, 3), E( -5, 3), E( 0, 4), E( 4, 4), + E( -4, 4), E( 0, 5), E( 0, 6), E( 3, 6), E( -3, 6), + E( 0, 7), E( 3, 7), E( -3, 7), E( 2, 10), E( -2, 10), + E( 1, 16), E( -1, 16), + // AC table Q32 - 354 elements + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 0, 64), E( 3, 0), + E( -3, 0), E( 1, 1), E( -1, 1), E( 4, 0), E( -4, 0), E( 5, 0), + E( -5, 0), E( 2, 1), E( -2, 1), E( 1, 2), E( -1, 2), E( 1, 3), + E( -1, 3), E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), E( 3, 1), + E( -3, 1), E( 1, 4), E( -1, 4), E( 1, 5), E( -1, 5), E( 8, 0), + E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), E(-10, 0), E( 4, 1), + E( -4, 1), E( 2, 2), E( -2, 2), E( 1, 6), E( -1, 6), E( 1, 7), + E( -1, 7), E( 1, 8), E( -1, 8), E( 11, 0), E(-11, 0), E( 12, 0), + E(-12, 0), E( 13, 0), E(-13, 0), E( 5, 1), E( -5, 1), E( 2, 3), + E( -2, 3), E( 1, 9), E( -1, 9), E( 1, 10), E( -1, 10), E( 14, 0), + E(-14, 0), E( 15, 0), E(-15, 0), E( 16, 0), E(-16, 0), E( 6, 1), + E( -6, 1), E( 7, 1), E( -7, 1), E( 3, 2), E( -3, 2), E( 3, 3), + E( -3, 3), E( 2, 4), E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 11), + E( -1, 11), E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), + E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), E( 0, 5), E( 0, 6), + E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), + E( 0, 13), E( 0, 14), E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), + E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), + E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), + E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), E( 0, 35), E( 0, 36), + E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), + E( 0, 43), E( 0, 44), E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), + E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), + E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), + E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), E( 17, 0), E(-17, 0), + E( 18, 0), E(-18, 0), E( 19, 0), E(-19, 0), E( 20, 0), E(-20, 0), + E( 8, 1), E( -8, 1), E( 9, 1), E( -9, 1), E( 4, 2), E( -4, 2), + E( 3, 4), E( -3, 4), E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), + E( 2, 8), E( -2, 8), E( 1, 14), E( -1, 14), E( 0, 0), E( 1, 0), + E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), E( 4, 0), + E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), E( 7, 0), + E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), E( 10, 0), + E(-10, 0), E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), E( 13, 0), + E(-13, 0), E( 14, 0), E(-14, 0), E( 15, 0), E(-15, 0), E( 16, 0), + E(-16, 0), E( 17, 0), E(-17, 0), E( 18, 0), E(-18, 0), E( 19, 0), + E(-19, 0), E( 20, 0), E(-20, 0), E( 21, 0), E(-21, 0), E( 22, 0), + E(-22, 0), E( 23, 0), E(-23, 0), E( 24, 0), E(-24, 0), E( 25, 0), + E(-25, 0), E( 26, 0), E(-26, 0), E( 27, 0), E(-27, 0), E( 28, 0), + E(-28, 0), E( 29, 0), E(-29, 0), E( 30, 0), E(-30, 0), E( 31, 0), + E(-31, 0), E( 32, 0), E(-32, 0), E( 33, 0), E(-33, 0), E( 34, 0), + E(-34, 0), E( 35, 0), E(-35, 0), E( 36, 0), E(-36, 0), E( 37, 0), + E(-37, 0), E( 38, 0), E(-38, 0), E( 39, 0), E(-39, 0), E( 40, 0), + E(-40, 0), E( 41, 0), E(-41, 0), E( 42, 0), E(-42, 0), E( 43, 0), + E(-43, 0), E( 44, 0), E(-44, 0), E( 45, 0), E(-45, 0), E( 46, 0), + E(-46, 0), E( 47, 0), E(-47, 0), E( 48, 0), E(-48, 0), E( 49, 0), + E(-49, 0), E( 50, 0), E(-50, 0), E( 51, 0), E(-51, 0), E( 52, 0), + E(-52, 0), E( 53, 0), E(-53, 0), E( 54, 0), E(-54, 0), E( 55, 0), + E(-55, 0), E( 56, 0), E(-56, 0), E( 57, 0), E(-57, 0), E( 58, 0), + E(-58, 0), E( 59, 0), E(-59, 0), E( 60, 0), E(-60, 0), E( 61, 0), + E(-61, 0), E( 62, 0), E(-62, 0), E( 63, 0), E(-63, 0), E( 21, 0), + E(-21, 0), E( 22, 0), E(-22, 0), E( 23, 0), E(-23, 0), E( 0, 1), + E( 10, 1), E(-10, 1), E( 11, 1), E(-11, 1), E( 0, 2), E( 5, 2), + E( -5, 2), E( 6, 2), E( -6, 2), E( 0, 3), E( 4, 3), E( -4, 3), + E( 0, 4), E( 3, 5), E( -3, 5), E( 3, 6), E( -3, 6), E( 2, 9), + E( -2, 9), E( 1, 15), E( -1, 15), E( 24, 0), E(-24, 0), E( 25, 0), + E(-25, 0), E( 26, 0), E(-26, 0), E( 12, 1), E(-12, 1), E( 13, 1), + E(-13, 1), E( 5, 3), E( -5, 3), E( 4, 4), E( -4, 4), E( 0, 5), + E( 4, 5), E( -4, 5), E( 0, 6), E( 0, 7), E( 3, 7), E( -3, 7), + E( 0, 8), E( 3, 8), E( -3, 8), E( 0, 9), E( 1, 16), E( -1, 16), + // AC table Q64 - 257 elements + E( 1, 0), E( -1, 0), E( 0, 64), E( 2, 0), E( -2, 0), E( 3, 0), + E( -3, 0), E( 1, 1), E( -1, 1), E( 4, 0), E( -4, 0), E( 2, 1), + E( -2, 1), E( 1, 2), E( -1, 2), E( 5, 0), E( -5, 0), E( 1, 3), + E( -1, 3), E( 1, 4), E( -1, 4), E( 6, 0), E( -6, 0), E( 3, 1), + E( -3, 1), E( 2, 2), E( -2, 2), E( 1, 5), E( -1, 5), E( 1, 6), + E( -1, 6), E( 1, 7), E( -1, 7), E( 7, 0), E( -7, 0), E( 8, 0), + E( -8, 0), E( 4, 1), E( -4, 1), E( 2, 3), E( -2, 3), E( 1, 8), + E( -1, 8), E( 1, 9), E( -1, 9), E( 9, 0), E( -9, 0), E( 10, 0), + E(-10, 0), E( 5, 1), E( -5, 1), E( 3, 2), E( -3, 2), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 10), E( -1, 10), E( 1, 11), + E( -1, 11), E( 0, 0), E( 0, 1), E( 0, 2), E( 0, 3), E( 0, 4), + E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), E( 0, 9), E( 0, 10), + E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), E( 0, 15), E( 0, 16), + E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), E( 0, 21), E( 0, 22), + E( 0, 23), E( 0, 24), E( 0, 25), E( 0, 26), E( 0, 27), E( 0, 28), + E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), E( 0, 33), E( 0, 34), + E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), E( 0, 39), E( 0, 40), + E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), E( 0, 45), E( 0, 46), + E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), E( 0, 51), E( 0, 52), + E( 0, 53), E( 0, 54), E( 0, 55), E( 0, 56), E( 0, 57), E( 0, 58), + E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), E( 0, 63), E( 0, 0), + E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), E( 6, 1), E( -6, 1), + E( 7, 1), E( -7, 1), E( 3, 3), E( -3, 3), E( 3, 4), E( -3, 4), + E( 3, 5), E( -3, 5), E( 2, 6), E( -2, 6), E( 2, 7), E( -2, 7), + E( 1, 12), E( -1, 12), E( 1, 13), E( -1, 13), E( 1, 14), E( -1, 14), + E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), E( 0, 1), E( 8, 1), + E( -8, 1), E( 4, 2), E( -4, 2), E( 4, 3), E( -4, 3), E( 2, 8), + E( -2, 8), E( 2, 9), E( -2, 9), E( 1, 15), E( -1, 15), E( 0, 0), + E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), E( 3, 0), E( -3, 0), + E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), E( 6, 0), E( -6, 0), + E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), E( 9, 0), E( -9, 0), + E( 10, 0), E(-10, 0), E( 11, 0), E(-11, 0), E( 12, 0), E(-12, 0), + E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), E( 15, 0), E(-15, 0), + E( 16, 0), E(-16, 0), E( 17, 0), E(-17, 0), E( 18, 0), E(-18, 0), + E( 19, 0), E(-19, 0), E( 20, 0), E(-20, 0), E( 21, 0), E(-21, 0), + E( 22, 0), E(-22, 0), E( 23, 0), E(-23, 0), E( 24, 0), E(-24, 0), + E( 25, 0), E(-25, 0), E( 26, 0), E(-26, 0), E( 27, 0), E(-27, 0), + E( 28, 0), E(-28, 0), E( 29, 0), E(-29, 0), E( 30, 0), E(-30, 0), + E( 31, 0), E(-31, 0), E( 15, 0), E(-15, 0), E( 9, 1), E( -9, 1), + E( 10, 1), E(-10, 1), E( 0, 2), E( 5, 2), E( -5, 2), E( 0, 3), + E( 5, 3), E( -5, 3), E( 0, 4), E( 4, 4), E( -4, 4), E( 0, 5), + E( 4, 5), E( -4, 5), E( 0, 6), E( 3, 6), E( -3, 6), E( 3, 7), + E( -3, 7), E( 1, 16), E( -1, 16), E( 1, 17), E( -1, 17), + // AC table Q128 - 194 elements + E( 1, 0), E( -1, 0), E( 0, 64), E( 1, 1), E( -1, 1), E( 2, 0), + E( -2, 0), E( 3, 0), E( -3, 0), E( 2, 1), E( -2, 1), E( 1, 2), + E( -1, 2), E( 1, 3), E( -1, 3), E( 1, 4), E( -1, 4), E( 4, 0), + E( -4, 0), E( 1, 5), E( -1, 5), E( 1, 6), E( -1, 6), E( 1, 7), + E( -1, 7), E( 5, 0), E( -5, 0), E( 3, 1), E( -3, 1), E( 2, 2), + E( -2, 2), E( 2, 3), E( -2, 3), E( 1, 8), E( -1, 8), E( 1, 9), + E( -1, 9), E( 6, 0), E( -6, 0), E( 4, 1), E( -4, 1), E( 2, 4), + E( -2, 4), E( 2, 5), E( -2, 5), E( 1, 10), E( -1, 10), E( 7, 0), + E( -7, 0), E( 5, 1), E( -5, 1), E( 3, 2), E( -3, 2), E( 3, 3), + E( -3, 3), E( 2, 6), E( -2, 6), E( 0, 0), E( 0, 1), E( 0, 2), + E( 0, 3), E( 0, 4), E( 0, 5), E( 0, 6), E( 0, 7), E( 0, 8), + E( 0, 9), E( 0, 10), E( 0, 11), E( 0, 12), E( 0, 13), E( 0, 14), + E( 0, 15), E( 0, 16), E( 0, 17), E( 0, 18), E( 0, 19), E( 0, 20), + E( 0, 21), E( 0, 22), E( 0, 23), E( 0, 24), E( 0, 25), E( 0, 26), + E( 0, 27), E( 0, 28), E( 0, 29), E( 0, 30), E( 0, 31), E( 0, 32), + E( 0, 33), E( 0, 34), E( 0, 35), E( 0, 36), E( 0, 37), E( 0, 38), + E( 0, 39), E( 0, 40), E( 0, 41), E( 0, 42), E( 0, 43), E( 0, 44), + E( 0, 45), E( 0, 46), E( 0, 47), E( 0, 48), E( 0, 49), E( 0, 50), + E( 0, 51), E( 0, 52), E( 0, 53), E( 0, 54), E( 0, 55), E( 0, 56), + E( 0, 57), E( 0, 58), E( 0, 59), E( 0, 60), E( 0, 61), E( 0, 62), + E( 0, 63), E( 6, 1), E( -6, 1), E( 7, 1), E( -7, 1), E( 3, 4), + E( -3, 4), E( 3, 5), E( -3, 5), E( 2, 7), E( -2, 7), E( 2, 8), + E( -2, 8), E( 2, 9), E( -2, 9), E( 1, 11), E( -1, 11), E( 1, 12), + E( -1, 12), E( 1, 13), E( -1, 13), E( 0, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 8, 1), E( -8, 1), E( 4, 2), E( -4, 2), + E( 4, 3), E( -4, 3), E( 3, 6), E( -3, 6), E( 1, 14), E( -1, 14), + E( 1, 15), E( -1, 15), E( 1, 16), E( -1, 16), E( 0, 1), E( 0, 2), + E( 0, 3), E( 0, 0), E( 1, 0), E( -1, 0), E( 2, 0), E( -2, 0), + E( 3, 0), E( -3, 0), E( 4, 0), E( -4, 0), E( 5, 0), E( -5, 0), + E( 6, 0), E( -6, 0), E( 7, 0), E( -7, 0), E( 8, 0), E( -8, 0), + E( 9, 0), E( -9, 0), E( 10, 0), E(-10, 0), E( 11, 0), E(-11, 0), + E( 12, 0), E(-12, 0), E( 13, 0), E(-13, 0), E( 14, 0), E(-14, 0), + E( 15, 0), E(-15, 0), +}; + +static const uint8_t hqx_ac_lens[] = { + // AC table Q0 - 815 elements + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 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, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 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, 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, + 10, 10, 10, 10, 10, 10, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 10, + 10, 9, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 10, 11, 11, 10, 10, 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, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, + // AC table Q8 - 907 elements + 4, 4, 4, 4, 5, 5, 5, 5, 4, 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, 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, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 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, 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, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 10, 10, 10, 10, 10, + 10, 9, 10, 10, 10, 10, 9, 10, 10, 9, 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, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 10, 10, 10, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12, 12, 11, 11, 11, + 12, 12, 12, 12, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 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, + // AC table Q16 - 512 elements + 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 4, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 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, 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, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 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, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 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, 11, 12, 12, 12, 12, 12, 12, 11, 12, 12, 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, 13, 13, 13, 13, 13, 13, 12, 13, 13, 12, 12, 13, + 13, 12, 13, 13, 13, 13, 13, 13, + // AC table Q32 - 354 elements + 3, 3, 4, 4, 3, 5, 5, 5, 5, 6, 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, 8, 8, 8, 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, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 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, 16, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 11, 12, 12, 12, 12, 11, 12, 12, 11, 12, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 13, 13, 12, 12, 13, 13, 12, 13, 13, 12, 13, 13, + // AC table Q64 - 257 elements + 3, 3, 2, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 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, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 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, 12, 12, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 13, 13, 13, + 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 12, 13, 13, 13, + 13, 13, 13, 13, 13, + // AC table Q128 - 194 elements + 3, 3, 2, 4, 4, 5, 5, 6, 6, 6, 6, 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, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 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, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +}; + +static const uint16_t hqx_ac_nb_elems[] = { 815, 907, 512, 354, 257, 194 }; + +static VLCElem cbp_vlc[896 /* dc9 */ + 1344 /* dc10 */ + + 15630 /* RL_VLC_ELEMS for hqx_ac */]; + +static const VLCElem *dc_vlc[2]; +#define INIT_DC_TABLE(idx, name) \ + do { \ + dc_vlc[idx] = ff_vlc_init_tables(&state, HQX_DC_VLC_BITS, \ + FF_ARRAY_ELEMS(name ## _vlc_lens), \ + name ## _vlc_lens, 1, 1, \ + name ## _vlc_bits, 2, 2, 0); \ + } while (0) + +static av_cold av_unused void hqx_init_static(void) +{ + VLCInitState state = VLC_INIT_STATE(cbp_vlc); + const uint8_t *lens = hqx_ac_lens; + const int16_t *run_level = hqx_ac_run_level; + + INIT_DC_TABLE(0, dc9); + INIT_DC_TABLE(1, dc10); + + for (int i = 0; i < NUM_HQX_AC; ++i) { + RL_VLC_ELEM *lut = state.table; + unsigned nb_codes = state.size; + + hqx_ac[i].lut = + ff_vlc_init_tables_from_lengths(&state, hqx_ac[i].bits, + hqx_ac_nb_elems[i], lens, 1, + run_level, 2, 2, 0, 0); + + nb_codes -= state.size; + + for (unsigned j = 0; j < nb_codes; ++j) { + // lut[j] is in VLC (not RL_VLC) state + int sym = lut[j].sym; + int len = lut[j].len; + int level; + + if (len < 0) { + level = sym; + } else { + level = sym >> 7; + lut[j].run = sym & 0x7f; + } + // lut[j] is now in RL_VLC state + lut[j].len8 = len; + lut[j].level = level; + } + lens += hqx_ac_nb_elems[i]; + run_level += hqx_ac_nb_elems[i]; + } +} + +#endif /* AVCODEC_HQXVLC_H*/ diff --git a/libavcodec/huffman.c b/libavcodec/huffman.c index d47fe10087..0c2d0c27e1 100644 --- a/libavcodec/huffman.c +++ b/libavcodec/huffman.c @@ -39,7 +39,10 @@ #define HNODE -1 typedef struct HeapElem { - uint64_t val; + union { + uint64_t val; + uint16_t dummy; // exists solely to ensure alignof(HeapElem) >= alignof(uint16_t) + }; int name; } HeapElem; @@ -59,19 +62,23 @@ static void heap_sift(HeapElem *h, int root, int size) int ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats, int stats_size, int skip0) { - HeapElem *h = av_malloc_array(sizeof(*h), stats_size); - int *up = av_malloc_array(sizeof(*up) * 2, stats_size); - uint8_t *len = av_malloc_array(sizeof(*len) * 2, stats_size); - uint16_t *map= av_malloc_array(sizeof(*map), stats_size); + int *up; + uint16_t *map; + uint8_t *len; + HeapElem *h = av_malloc_array(stats_size, + sizeof(*h) + 2 * sizeof(up) + 2 * sizeof(len) + sizeof(map)); + if (!h) + return AVERROR(ENOMEM); + up = (int*)(h + stats_size); + // map is suitably aligned because up uses an even number of elements + // and alignof(uint16_t) is either 1 or 2. + map = (uint16_t*)(up + 2 * stats_size); + len = (uint8_t*)(map + stats_size); + int offset, i, next; int size = 0; int ret = 0; - if (!h || !up || !len || !map) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; igb) > 0; i++) { READ_2PIX(s->temp[0][2 * i], s->temp[0][2 * i + 1], 0); } + for (; i < count; i++) + s->temp[0][2 * i] = s->temp[0][2 * i + 1] = 0; } else { for (i = 0; i < count; i++) { READ_2PIX(s->temp[0][2 * i], s->temp[0][2 * i + 1], 0); diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 5e8b5c0dd7..b213d4dc95 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -1022,10 +1022,7 @@ const FFCodec ff_huffyuv_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, .p.priv_class = &normal_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -1050,7 +1047,7 @@ const FFCodec ff_ffvhuff_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, .p.priv_class = &ff_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ + CODEC_PIXFMTS( AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_GBRP, @@ -1065,8 +1062,7 @@ const FFCodec ff_ffvhuff_encoder = { AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE - }, + AV_PIX_FMT_RGB32), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c index 7b6ec97d3b..927aeb4bad 100644 --- a/libavcodec/hw_base_encode.c +++ b/libavcodec/hw_base_encode.c @@ -18,6 +18,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/error.h" #include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/mem.h" @@ -190,12 +191,12 @@ static void hw_base_encode_add_next_prev(FFHWBaseEncodeContext *ctx, return; } - if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) { + if (ctx->nb_next_prev < ctx->ref_l0) { ctx->next_prev[ctx->nb_next_prev++] = pic; ++pic->ref_count[0]; } else { --ctx->next_prev[0]->ref_count[0]; - for (i = 0; i < MAX_PICTURE_REFERENCES - 1; i++) + for (i = 0; i < ctx->ref_l0 - 1; i++) ctx->next_prev[i] = ctx->next_prev[i + 1]; ctx->next_prev[i] = pic; ++pic->ref_count[0]; @@ -603,7 +604,7 @@ start: av_fifo_can_read(ctx->encode_fifo); err = ctx->op->issue(avctx, pic); if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + av_log(avctx, AV_LOG_ERROR, "Encode failed: %s.\n", av_err2str(err)); return err; } pic->encode_issued = 1; @@ -630,7 +631,7 @@ start: err = ctx->op->issue(avctx, pic); if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + av_log(avctx, AV_LOG_ERROR, "Encode failed: %s.\n", av_err2str(err)); return err; } @@ -662,6 +663,14 @@ int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *av uint32_t ref_l0, uint32_t ref_l1, int flags, int prediction_pre_only) { + ctx->ref_l0 = FFMIN(ref_l0, MAX_PICTURE_REFERENCES); + ctx->ref_l1 = FFMIN(ref_l1, MAX_PICTURE_REFERENCES); + + if (avctx->refs > 0) { + ctx->ref_l0 = FFMIN(ctx->ref_l0, avctx->refs); + ctx->ref_l1 = FFMIN(ctx->ref_l1, avctx->refs); + } + if (flags & FF_HW_FLAG_INTRA_ONLY || avctx->gop_size <= 1) { av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); ctx->gop_size = 1; @@ -804,6 +813,11 @@ int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx) int ff_hw_base_encode_close(FFHWBaseEncodeContext *ctx) { + for (FFHWBaseEncodePicture *pic = ctx->pic_start, *next_pic = pic; pic; pic = next_pic) { + next_pic = pic->next; + base_encode_pic_free(pic); + } + av_fifo_freep2(&ctx->encode_fifo); av_frame_free(&ctx->frame); diff --git a/libavcodec/hw_base_encode.h b/libavcodec/hw_base_encode.h index e30b1e60ad..e768579722 100644 --- a/libavcodec/hw_base_encode.h +++ b/libavcodec/hw_base_encode.h @@ -193,6 +193,10 @@ typedef struct FFHWBaseEncodeContext { int end_of_stream; int p_to_gpb; + // The number of L0/L1 references supported by the driver. + int ref_l0; + int ref_l1; + // Whether the driver supports ROI at all. int roi_allowed; diff --git a/libavcodec/hwaccel_internal.h b/libavcodec/hwaccel_internal.h index b0cc22bb68..7224406815 100644 --- a/libavcodec/hwaccel_internal.h +++ b/libavcodec/hwaccel_internal.h @@ -26,7 +26,7 @@ #include #include "avcodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define HWACCEL_CAP_ASYNC_SAFE (1 << 0) #define HWACCEL_CAP_THREAD_SAFE (1 << 1) @@ -52,11 +52,13 @@ typedef struct FFHWAccel { * Otherwise, this means the whole frame is available at this point. * * @param avctx the codec context + * @param buf_ref the frame data buffer reference (optional) * @param buf the frame data buffer base * @param buf_size the size of the frame in bytes * @return zero if successful, a negative value otherwise */ - int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + int (*start_frame)(AVCodecContext *avctx, const AVBufferRef *buf_ref, + const uint8_t *buf, uint32_t buf_size); /** * Callback for parameter data (SPS/PPS/VPS etc). @@ -155,7 +157,7 @@ typedef struct FFHWAccel { * @param hwctx a pointer to an AVHWDeviceContext. * @param data the per-frame hardware accelerator private data to be freed. */ - void (*free_frame_priv)(FFRefStructOpaque hwctx, void *data); + void (*free_frame_priv)(AVRefStructOpaque hwctx, void *data); /** * Callback to flush the hwaccel state. diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h index 5171e4c7d7..4b205d386e 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h @@ -26,7 +26,9 @@ extern const struct FFHWAccel ff_av1_dxva2_hwaccel; extern const struct FFHWAccel ff_av1_nvdec_hwaccel; extern const struct FFHWAccel ff_av1_vaapi_hwaccel; extern const struct FFHWAccel ff_av1_vdpau_hwaccel; +extern const struct FFHWAccel ff_av1_videotoolbox_hwaccel; extern const struct FFHWAccel ff_av1_vulkan_hwaccel; +extern const struct FFHWAccel ff_ffv1_vulkan_hwaccel; extern const struct FFHWAccel ff_h263_vaapi_hwaccel; extern const struct FFHWAccel ff_h263_videotoolbox_hwaccel; extern const struct FFHWAccel ff_h264_d3d11va_hwaccel; @@ -65,6 +67,7 @@ extern const struct FFHWAccel ff_mpeg4_vaapi_hwaccel; extern const struct FFHWAccel ff_mpeg4_vdpau_hwaccel; extern const struct FFHWAccel ff_mpeg4_videotoolbox_hwaccel; extern const struct FFHWAccel ff_prores_videotoolbox_hwaccel; +extern const struct FFHWAccel ff_prores_raw_vulkan_hwaccel; extern const struct FFHWAccel ff_vc1_d3d11va_hwaccel; extern const struct FFHWAccel ff_vc1_d3d11va2_hwaccel; extern const struct FFHWAccel ff_vc1_d3d12va_hwaccel; @@ -82,6 +85,8 @@ extern const struct FFHWAccel ff_vp9_nvdec_hwaccel; extern const struct FFHWAccel ff_vp9_vaapi_hwaccel; extern const struct FFHWAccel ff_vp9_vdpau_hwaccel; extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel; +extern const struct FFHWAccel ff_vp9_vulkan_hwaccel; +extern const struct FFHWAccel ff_vvc_vaapi_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel; extern const struct FFHWAccel ff_wmv3_d3d12va_hwaccel; diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c index d9e4633548..da17ea35b1 100644 --- a/libavcodec/idcinvideo.c +++ b/libavcodec/idcinvideo.c @@ -224,14 +224,7 @@ static int idcin_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (idcin_decode_vlcs(s, frame)) return AVERROR_INVALIDDATA; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* make the palette available on the way out */ memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); diff --git a/libavcodec/idctdsp.c b/libavcodec/idctdsp.c index 4259a117dc..8a71c7ef77 100644 --- a/libavcodec/idctdsp.c +++ b/libavcodec/idctdsp.c @@ -276,6 +276,10 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->idct = ff_faanidct; c->perm_type = FF_IDCT_PERM_NONE; #endif /* CONFIG_FAANIDCT */ +#if CONFIG_MPEG4_DECODER + } else if (avctx->idct_algo == FF_IDCT_XVID) { + ff_xvid_idct_init(c); +#endif } else { // accurate/default c->idct_put = ff_simple_idct_put_int16_8bit; c->idct_add = ff_simple_idct_add_int16_8bit; @@ -289,9 +293,6 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->put_signed_pixels_clamped = put_signed_pixels_clamped_c; c->add_pixels_clamped = ff_add_pixels_clamped_c; - if (CONFIG_MPEG4_DECODER && avctx->idct_algo == FF_IDCT_XVID) - ff_xvid_idct_init(c, avctx); - #if ARCH_AARCH64 ff_idctdsp_init_aarch64(c, avctx, high_bit_depth); #elif ARCH_ARM diff --git a/libavcodec/idctdsp.h b/libavcodec/idctdsp.h index c08242881c..7783d7098a 100644 --- a/libavcodec/idctdsp.h +++ b/libavcodec/idctdsp.h @@ -98,8 +98,6 @@ void ff_idctdsp_init(IDCTDSPContext *c, struct AVCodecContext *avctx); void ff_idctdsp_init_aarch64(IDCTDSPContext *c, struct AVCodecContext *avctx, unsigned high_bit_depth); -void ff_idctdsp_init_alpha(IDCTDSPContext *c, struct AVCodecContext *avctx, - unsigned high_bit_depth); void ff_idctdsp_init_arm(IDCTDSPContext *c, struct AVCodecContext *avctx, unsigned high_bit_depth); void ff_idctdsp_init_ppc(IDCTDSPContext *c, struct AVCodecContext *avctx, diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 13010b451e..66839c3c39 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -279,7 +279,7 @@ static int extract_header(AVCodecContext *const avctx, if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ') && s->ham == 4) extra_space = 4; - s->ham_buf = av_malloc((s->planesize * 8) + AV_INPUT_BUFFER_PADDING_SIZE); + s->ham_buf = av_mallocz((s->planesize * 8) + AV_INPUT_BUFFER_PADDING_SIZE); if (!s->ham_buf) return AVERROR(ENOMEM); diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c deleted file mode 100644 index cefe35ab6e..0000000000 --- a/libavcodec/iirfilter.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * IIR filter - * Copyright (c) 2008 Konstantin Shishkov - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * different IIR filters implementation - */ - -#include - -#include "config.h" - -#include "libavutil/attributes.h" -#include "libavutil/common.h" -#include "libavutil/log.h" -#include "libavutil/mem.h" - -#include "iirfilter.h" - -/** - * IIR filter global parameters - */ -typedef struct FFIIRFilterCoeffs { - int order; - float gain; - int *cx; - float *cy; -} FFIIRFilterCoeffs; - -/** - * IIR filter state - */ -typedef struct FFIIRFilterState { - float x[1]; -} FFIIRFilterState; - -/// maximum supported filter order -#define MAXORDER 30 - -static av_cold int butterworth_init_coeffs(void *avc, - struct FFIIRFilterCoeffs *c, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband) -{ - int i, j; - double wa; - double p[MAXORDER + 1][2]; - - if (filt_mode != FF_FILTER_MODE_LOWPASS) { - av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " - "low-pass filter mode\n"); - return -1; - } - if (order & 1) { - av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " - "even filter orders\n"); - return -1; - } - - wa = 2 * tan(M_PI * 0.5 * cutoff_ratio); - - c->cx[0] = 1; - for (i = 1; i < (order >> 1) + 1; i++) - c->cx[i] = c->cx[i - 1] * (order - i + 1LL) / i; - - p[0][0] = 1.0; - p[0][1] = 0.0; - for (i = 1; i <= order; i++) - p[i][0] = p[i][1] = 0.0; - for (i = 0; i < order; i++) { - double zp[2]; - double th = (i + (order >> 1) + 0.5) * M_PI / order; - double a_re, a_im, c_re, c_im; - zp[0] = cos(th) * wa; - zp[1] = sin(th) * wa; - a_re = zp[0] + 2.0; - c_re = zp[0] - 2.0; - a_im = - c_im = zp[1]; - zp[0] = (a_re * c_re + a_im * c_im) / (c_re * c_re + c_im * c_im); - zp[1] = (a_im * c_re - a_re * c_im) / (c_re * c_re + c_im * c_im); - - for (j = order; j >= 1; j--) { - a_re = p[j][0]; - a_im = p[j][1]; - p[j][0] = a_re * zp[0] - a_im * zp[1] + p[j - 1][0]; - p[j][1] = a_re * zp[1] + a_im * zp[0] + p[j - 1][1]; - } - a_re = p[0][0] * zp[0] - p[0][1] * zp[1]; - p[0][1] = p[0][0] * zp[1] + p[0][1] * zp[0]; - p[0][0] = a_re; - } - c->gain = p[order][0]; - for (i = 0; i < order; i++) { - c->gain += p[i][0]; - c->cy[i] = (-p[i][0] * p[order][0] + -p[i][1] * p[order][1]) / - (p[order][0] * p[order][0] + p[order][1] * p[order][1]); - } - c->gain /= 1 << order; - - return 0; -} - -static av_cold int biquad_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, - enum IIRFilterMode filt_mode, int order, - float cutoff_ratio, float stopband) -{ - double cos_w0, sin_w0; - double a0, x0, x1; - - if (filt_mode != FF_FILTER_MODE_HIGHPASS && - filt_mode != FF_FILTER_MODE_LOWPASS) { - av_log(avc, AV_LOG_ERROR, "Biquad filter currently only supports " - "high-pass and low-pass filter modes\n"); - return -1; - } - if (order != 2) { - av_log(avc, AV_LOG_ERROR, "Biquad filter must have order of 2\n"); - return -1; - } - - cos_w0 = cos(M_PI * cutoff_ratio); - sin_w0 = sin(M_PI * cutoff_ratio); - - a0 = 1.0 + (sin_w0 / 2.0); - - if (filt_mode == FF_FILTER_MODE_HIGHPASS) { - c->gain = ((1.0 + cos_w0) / 2.0) / a0; - x0 = ((1.0 + cos_w0) / 2.0) / a0; - x1 = (-(1.0 + cos_w0)) / a0; - } else { // FF_FILTER_MODE_LOWPASS - c->gain = ((1.0 - cos_w0) / 2.0) / a0; - x0 = ((1.0 - cos_w0) / 2.0) / a0; - x1 = (1.0 - cos_w0) / a0; - } - c->cy[0] = (-1.0 + (sin_w0 / 2.0)) / a0; - c->cy[1] = (2.0 * cos_w0) / a0; - - // divide by gain to make the x coeffs integers. - // during filtering, the delay state will include the gain multiplication - c->cx[0] = lrintf(x0 / c->gain); - c->cx[1] = lrintf(x1 / c->gain); - - return 0; -} - -av_cold struct FFIIRFilterCoeffs *ff_iir_filter_init_coeffs(void *avc, - enum IIRFilterType filt_type, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband, float ripple) -{ - FFIIRFilterCoeffs *c; - int ret = 0; - - if (order <= 0 || order > MAXORDER || cutoff_ratio >= 1.0) - return NULL; - - if (!(c = av_mallocz(sizeof(*c))) || - !(c->cx = av_malloc (sizeof(c->cx[0]) * ((order >> 1) + 1))) || - !(c->cy = av_malloc (sizeof(c->cy[0]) * order))) - goto free; - c->order = order; - - switch (filt_type) { - case FF_FILTER_TYPE_BUTTERWORTH: - ret = butterworth_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, - stopband); - break; - case FF_FILTER_TYPE_BIQUAD: - ret = biquad_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, - stopband); - break; - default: - av_log(avc, AV_LOG_ERROR, "filter type is not currently implemented\n"); - goto free; - } - - if (!ret) - return c; -free: - ff_iir_filter_free_coeffsp(&c); - return NULL; -} - -av_cold struct FFIIRFilterState *ff_iir_filter_init_state(int order) -{ - FFIIRFilterState *s = av_mallocz(sizeof(FFIIRFilterState) + sizeof(s->x[0]) * (order - 1)); - return s; -} - -#define CONV_S16(dest, source) dest = av_clip_int16(lrintf(source)); - -#define CONV_FLT(dest, source) dest = source; - -#define FILTER_BW_O4_1(i0, i1, i2, i3, fmt) \ - in = *src0 * c->gain + \ - c->cy[0] * s->x[i0] + \ - c->cy[1] * s->x[i1] + \ - c->cy[2] * s->x[i2] + \ - c->cy[3] * s->x[i3]; \ - res = (s->x[i0] + in) * 1 + \ - (s->x[i1] + s->x[i3]) * 4 + \ - s->x[i2] * 6; \ - CONV_ ## fmt(*dst0, res) \ - s->x[i0] = in; \ - src0 += sstep; \ - dst0 += dstep; - -#define FILTER_BW_O4(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i += 4) { \ - float in, res; \ - FILTER_BW_O4_1(0, 1, 2, 3, fmt); \ - FILTER_BW_O4_1(1, 2, 3, 0, fmt); \ - FILTER_BW_O4_1(2, 3, 0, 1, fmt); \ - FILTER_BW_O4_1(3, 0, 1, 2, fmt); \ - } \ -} - -#define FILTER_DIRECT_FORM_II(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i++) { \ - int j; \ - float in, res; \ - in = *src0 * c->gain; \ - for (j = 0; j < c->order; j++) \ - in += c->cy[j] * s->x[j]; \ - res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; \ - for (j = 1; j < c->order >> 1; j++) \ - res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; \ - for (j = 0; j < c->order - 1; j++) \ - s->x[j] = s->x[j + 1]; \ - CONV_ ## fmt(*dst0, res) \ - s->x[c->order - 1] = in; \ - src0 += sstep; \ - dst0 += dstep; \ - } \ -} - -#define FILTER_O2(type, fmt) { \ - int i; \ - const type *src0 = src; \ - type *dst0 = dst; \ - for (i = 0; i < size; i++) { \ - float in = *src0 * c->gain + \ - s->x[0] * c->cy[0] + \ - s->x[1] * c->cy[1]; \ - CONV_ ## fmt(*dst0, s->x[0] + in + s->x[1] * c->cx[1]) \ - s->x[0] = s->x[1]; \ - s->x[1] = in; \ - src0 += sstep; \ - dst0 += dstep; \ - } \ -} - -/** - * Perform IIR filtering on floating-point input samples. - * - * @param coeffs pointer to filter coefficients - * @param state pointer to filter state - * @param size input length - * @param src source samples - * @param sstep source stride - * @param dst filtered samples (destination may be the same as input) - * @param dstep destination stride - */ -static void iir_filter_flt(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const float *src, ptrdiff_t sstep, - float *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - FILTER_O2(float, FLT) - } else if (c->order == 4) { - FILTER_BW_O4(float, FLT) - } else { - FILTER_DIRECT_FORM_II(float, FLT) - } -} - -av_cold void ff_iir_filter_free_statep(struct FFIIRFilterState **state) -{ - av_freep(state); -} - -av_cold void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffsp) -{ - struct FFIIRFilterCoeffs *coeffs = *coeffsp; - if (coeffs) { - av_freep(&coeffs->cx); - av_freep(&coeffs->cy); - } - av_freep(coeffsp); -} - -void ff_iir_filter_init(FFIIRFilterContext *f) { - f->filter_flt = iir_filter_flt; - -#if HAVE_MIPSFPU - ff_iir_filter_init_mips(f); -#endif -} diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h deleted file mode 100644 index 8ab8ae68c6..0000000000 --- a/libavcodec/iirfilter.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * IIR filter - * Copyright (c) 2008 Konstantin Shishkov - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * IIR filter interface - */ - -#ifndef AVCODEC_IIRFILTER_H -#define AVCODEC_IIRFILTER_H - -#include - -struct FFIIRFilterCoeffs; -struct FFIIRFilterState; - -enum IIRFilterType{ - FF_FILTER_TYPE_BESSEL, - FF_FILTER_TYPE_BIQUAD, - FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_TYPE_CHEBYSHEV, - FF_FILTER_TYPE_ELLIPTIC, -}; - -enum IIRFilterMode{ - FF_FILTER_MODE_LOWPASS, - FF_FILTER_MODE_HIGHPASS, - FF_FILTER_MODE_BANDPASS, - FF_FILTER_MODE_BANDSTOP, -}; - -typedef struct FFIIRFilterContext { - /** - * Perform IIR filtering on floating-point input samples. - * - * @param coeffs pointer to filter coefficients - * @param state pointer to filter state - * @param size input length - * @param src source samples - * @param sstep source stride - * @param dst filtered samples (destination may be the same as input) - * @param dstep destination stride - */ - void (*filter_flt)(const struct FFIIRFilterCoeffs *coeffs, - struct FFIIRFilterState *state, int size, - const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep); -} FFIIRFilterContext; - -/** - * Initialize FFIIRFilterContext - */ -void ff_iir_filter_init(FFIIRFilterContext *f); -void ff_iir_filter_init_mips(FFIIRFilterContext *f); - -/** - * Initialize filter coefficients. - * - * @param avc a pointer to an arbitrary struct of which the first - * field is a pointer to an AVClass struct - * @param filt_type filter type (e.g. Butterworth) - * @param filt_mode filter mode (e.g. lowpass) - * @param order filter order - * @param cutoff_ratio cutoff to input frequency ratio - * @param stopband stopband to input frequency ratio (used by bandpass and bandstop filter modes) - * @param ripple ripple factor (used only in Chebyshev filters) - * - * @return pointer to filter coefficients structure or NULL if filter cannot be created - */ -struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, - enum IIRFilterType filt_type, - enum IIRFilterMode filt_mode, - int order, float cutoff_ratio, - float stopband, float ripple); - -/** - * Create new filter state. - * - * @param order filter order - * - * @return pointer to new filter state or NULL if state creation fails - */ -struct FFIIRFilterState* ff_iir_filter_init_state(int order); - -/** - * Free filter coefficients. - * - * @param coeffs pointer allocated with ff_iir_filter_init_coeffs() - */ -void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffs); - -/** - * Free and zero filter state. - * - * @param state pointer to pointer allocated with ff_iir_filter_init_state() - */ -void ff_iir_filter_free_statep(struct FFIIRFilterState **state); - -#endif /* AVCODEC_IIRFILTER_H */ diff --git a/libavcodec/ilbcdec.c b/libavcodec/ilbcdec.c index ba1da168bc..8b495a2f8e 100644 --- a/libavcodec/ilbcdec.c +++ b/libavcodec/ilbcdec.c @@ -658,7 +658,7 @@ static void get_codebook(int16_t * cbvec, /* (o) Constructed codebook vector * int16_t k, base_size; int16_t lag; /* Stack based */ - int16_t tempbuff2[SUBL + 5]; + int16_t tempbuff2[SUBL + 5] = {0}; /* Determine size of codebook sections */ base_size = lMem - cbveclen + 1; @@ -675,6 +675,7 @@ static void get_codebook(int16_t * cbvec, /* (o) Constructed codebook vector * /* get vector */ memcpy(cbvec, mem + lMem - k, cbveclen * 2); } else if (index < base_size) { + memset(cbvec, 0, cbveclen * 2); /* Calculate lag */ @@ -701,6 +702,7 @@ static void get_codebook(int16_t * cbvec, /* (o) Constructed codebook vector * filter_mafq12(&mem[memIndTest + 4], cbvec, kCbFiltersRev, CB_FILTERLEN, cbveclen); } else { + memset(cbvec, 0, cbveclen * 2); /* interpolated vectors */ /* Stuff zeros outside memory buffer */ memIndTest = lMem - cbveclen - CB_FILTERLEN; @@ -1097,7 +1099,7 @@ static void do_plc(int16_t *plc_residual, /* (o) concealed residual */ use_gain = 29491; /* 0.9 in Q15 */ } - /* Compute mixing factor of picth repeatition and noise: + /* Compute mixing factor of picth repetition and noise: for max_per>0.7 set periodicity to 1.0 0.4prevResidual[pick]; } - /* pitch repeatition component */ + /* pitch repetition component */ pick = i - use_lag; if (pick < 0) { @@ -1160,7 +1162,7 @@ static void do_plc(int16_t *plc_residual, /* (o) concealed residual */ tot_gain = SPL_MUL_16_16_RSFT(29491, use_gain, 15); /* 0.9*use_gain */ } - /* mix noise and pitch repeatition */ + /* mix noise and pitch repetition */ plc_residual[i] = SPL_MUL_16_16_RSFT(tot_gain, (pitchfact * plc_residual[i] + (32767 - pitchfact) * randvec[i] + 16384) >> 15, 15); /* Shifting down the result one step extra to ensure that no overflow diff --git a/libavcodec/imc.c b/libavcodec/imc.c index 5891e3621a..2e4a74f46f 100644 --- a/libavcodec/imc.c +++ b/libavcodec/imc.c @@ -966,6 +966,8 @@ static int imc_decode_frame(AVCodecContext *avctx, AVFrame *frame, LOCAL_ALIGNED_16(uint16_t, buf16, [(IMC_BLOCK_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / 2]); + memset(buf16 + IMC_BLOCK_SIZE/2, 0, AV_INPUT_BUFFER_PADDING_SIZE); + q->avctx = avctx; if (buf_size < IMC_BLOCK_SIZE * avctx->ch_layout.nb_channels) { @@ -1031,8 +1033,7 @@ const FFCodec ff_imc_decoder = { FF_CODEC_DECODE_CB(imc_decode_frame), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -1048,8 +1049,7 @@ const FFCodec ff_iac_decoder = { FF_CODEC_DECODE_CB(imc_decode_frame), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/imgconvert.c b/libavcodec/imgconvert.c index 96511ac7d6..86cfce1e46 100644 --- a/libavcodec/imgconvert.c +++ b/libavcodec/imgconvert.c @@ -45,4 +45,3 @@ enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *p *loss_ptr = loss; return best; } - diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c index 2535e7726c..4b9f3f6b75 100644 --- a/libavcodec/imm5.c +++ b/libavcodec/imm5.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes_internal.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" @@ -51,32 +52,27 @@ static const struct IMM5_unit { static av_cold int imm5_init(AVCodecContext *avctx) { IMM5Context *ctx = avctx->priv_data; - const AVCodec *codec; int ret; - codec = avcodec_find_decoder(AV_CODEC_ID_H264); - if (!codec) - return AVERROR_BUG; - ctx->h264_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_h264_decoder; + ctx->h264_avctx = avcodec_alloc_context3(&ff_h264_decoder.p); if (!ctx->h264_avctx) return AVERROR(ENOMEM); ctx->h264_avctx->thread_count = 1; ctx->h264_avctx->flags = avctx->flags; ctx->h264_avctx->flags2 = avctx->flags2; - ret = avcodec_open2(ctx->h264_avctx, codec, NULL); + ret = avcodec_open2(ctx->h264_avctx, NULL, NULL); if (ret < 0) return ret; - codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); - if (!codec) - return AVERROR_BUG; - ctx->hevc_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_hevc_decoder; + ctx->hevc_avctx = avcodec_alloc_context3(&ff_hevc_decoder.p); if (!ctx->hevc_avctx) return AVERROR(ENOMEM); ctx->hevc_avctx->thread_count = 1; ctx->hevc_avctx->flags = avctx->flags; ctx->hevc_avctx->flags2 = avctx->flags2; - ret = avcodec_open2(ctx->hevc_avctx, codec, NULL); + ret = avcodec_open2(ctx->hevc_avctx, NULL, NULL); if (ret < 0) return ret; diff --git a/libavcodec/imx.c b/libavcodec/imx.c index 0d9d9b5bb9..9f7f2aa829 100644 --- a/libavcodec/imx.c +++ b/libavcodec/imx.c @@ -58,19 +58,9 @@ static int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (ff_copy_palette(imx->pal, avpkt, avctx)) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->flags |= AV_FRAME_FLAG_KEY; } else { frame->flags &= ~AV_FRAME_FLAG_KEY; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } bytestream2_init(&gb, avpkt->data, avpkt->size); diff --git a/libavcodec/indeo3.c b/libavcodec/indeo3.c index fbabd4b6ad..ae6fd7290e 100644 --- a/libavcodec/indeo3.c +++ b/libavcodec/indeo3.c @@ -324,7 +324,7 @@ static inline uint32_t replicate32(uint32_t a) { /* Fill n lines with 64-bit pixel value pix */ static inline void fill_64(uint8_t *dst, const uint64_t pix, int32_t n, - int32_t row_offset) + ptrdiff_t row_offset) { for (; n > 0; dst += row_offset, n--) AV_WN64A(dst, pix); @@ -429,30 +429,28 @@ if (*data_ptr >= last_ptr) \ static int decode_cell_data(Indeo3DecodeContext *ctx, Cell *cell, - uint8_t *block, uint8_t *ref_block, + uint8_t *block, const uint8_t *ref_block, ptrdiff_t row_offset, int h_zoom, int v_zoom, int mode, const vqEntry *delta[2], int swap_quads[2], const uint8_t **data_ptr, const uint8_t *last_ptr) { int x, y, line, num_lines; int rle_blocks = 0; - uint8_t code, *dst, *ref; const vqEntry *delta_tab; unsigned int dyad1, dyad2; uint64_t pix64; int skip_flag = 0, is_top_of_cell, is_first_row = 1; - int blk_row_offset, line_offset; - blk_row_offset = (row_offset << (2 + v_zoom)) - (cell->width << 2); - line_offset = v_zoom ? row_offset : 0; + const ptrdiff_t blk_row_offset = (row_offset << (2 + v_zoom)) - (cell->width << 2); + const ptrdiff_t line_offset = v_zoom ? row_offset : 0; if (cell->height & v_zoom || cell->width & h_zoom) return IV3_BAD_DATA; for (y = 0; y < cell->height; is_first_row = 0, y += 1 + v_zoom) { for (x = 0; x < cell->width; x += 1 + h_zoom) { - ref = ref_block; - dst = block; + const uint8_t *ref = ref_block; + uint8_t *dst = block; if (rle_blocks > 0) { if (mode <= 4) { @@ -472,7 +470,7 @@ static int decode_cell_data(Indeo3DecodeContext *ctx, Cell *cell, else delta_tab = delta[1]; BUFFER_PRECHECK; - code = bytestream_get_byte(data_ptr); + uint8_t code = bytestream_get_byte(data_ptr); if (code < 248) { if (code < delta_tab->num_dyads) { BUFFER_PRECHECK; @@ -691,9 +689,11 @@ static int decode_cell(Indeo3DecodeContext *ctx, AVCodecContext *avctx, } zoom_fac = mode == 10; - error = decode_cell_data(ctx, cell, block, ref_block, plane->pitch, - zoom_fac, 1, mode, delta, swap_quads, - &data_ptr, last_ptr); + av_assert2(!ref_block); + error = decode_cell_data(ctx, cell, block, + block /* dummy to avoid UB pointer arithmetic */, + plane->pitch, zoom_fac, 1, mode, delta, + swap_quads, &data_ptr, last_ptr); } break; default: diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c index 4efae7938c..27a3cadbad 100644 --- a/libavcodec/intelh263dec.c +++ b/libavcodec/intelh263dec.c @@ -19,108 +19,109 @@ */ #include "codec_internal.h" +#include "h263.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "h263data.h" #include "h263dec.h" /* don't understand why they choose a different header ! */ -int ff_intel_h263_decode_picture_header(MpegEncContext *s) +int ff_intel_h263_decode_picture_header(H263DecContext *const h) { int format; - if (get_bits_left(&s->gb) == 64) { /* special dummy frames */ + if (get_bits_left(&h->gb) == 64) { /* special dummy frames */ return FRAME_SKIPPED; } /* picture header */ - if (get_bits(&s->gb, 22) != 0x20) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + if (get_bits(&h->gb, 22) != 0x20) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return -1; } - s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */ + h->picture_number = get_bits(&h->gb, 8); /* picture timestamp */ - if (check_marker(s->avctx, &s->gb, "after picture_number") != 1) { + if (check_marker(h->c.avctx, &h->gb, "after picture_number") != 1) { return -1; /* marker */ } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad H.263 id\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad H.263 id\n"); return -1; /* H.263 id */ } - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + skip_bits1(&h->gb); /* freeze picture release off */ - format = get_bits(&s->gb, 3); + format = get_bits(&h->gb, 3); if (format == 0 || format == 6) { - av_log(s->avctx, AV_LOG_ERROR, "Intel H.263 free format not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Intel H.263 free format not supported\n"); return -1; } - s->h263_plus = 0; - s->pict_type = AV_PICTURE_TYPE_I + get_bits1(&s->gb); + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits1(&h->gb); - s->h263_long_vectors = get_bits1(&s->gb); + h->h263_long_vectors = get_bits1(&h->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "SAC not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "SAC not supported\n"); return -1; /* SAC: off */ } - s->obmc= get_bits1(&s->gb); - s->pb_frame = get_bits1(&s->gb); + h->c.obmc = get_bits1(&h->gb); + h->pb_frame = get_bits1(&h->gb); if (format < 6) { - s->width = ff_h263_format[format][0]; - s->height = ff_h263_format[format][1]; - s->avctx->sample_aspect_ratio.num = 12; - s->avctx->sample_aspect_ratio.den = 11; + h->c.width = ff_h263_format[format][0]; + h->c.height = ff_h263_format[format][1]; + h->c.avctx->sample_aspect_ratio.num = 12; + h->c.avctx->sample_aspect_ratio.den = 11; } else { - format = get_bits(&s->gb, 3); + format = get_bits(&h->gb, 3); if(format == 0 || format == 7){ - av_log(s->avctx, AV_LOG_ERROR, "Wrong Intel H.263 format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Wrong Intel H.263 format\n"); return -1; } - if(get_bits(&s->gb, 2)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - s->loop_filter = get_bits1(&s->gb) * !s->avctx->lowres; - if(get_bits1(&s->gb)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - if(get_bits1(&s->gb)) - s->pb_frame = 2; - if(get_bits(&s->gb, 5)) - av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); - if(get_bits(&s->gb, 5) != 1) - av_log(s->avctx, AV_LOG_ERROR, "Invalid marker\n"); + if (get_bits(&h->gb, 2)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + h->loop_filter = get_bits1(&h->gb) * !h->c.avctx->lowres; + if (get_bits1(&h->gb)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + if (get_bits1(&h->gb)) + h->pb_frame = 2; + if (get_bits(&h->gb, 5)) + av_log(h->c.avctx, AV_LOG_ERROR, "Bad value for reserved field\n"); + if (get_bits(&h->gb, 5) != 1) + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid marker\n"); } if(format == 6){ - int ar = get_bits(&s->gb, 4); - skip_bits(&s->gb, 9); // display width - check_marker(s->avctx, &s->gb, "in dimensions"); - skip_bits(&s->gb, 9); // display height - if(ar == 15){ - s->avctx->sample_aspect_ratio.num = get_bits(&s->gb, 8); // aspect ratio - width - s->avctx->sample_aspect_ratio.den = get_bits(&s->gb, 8); // aspect ratio - height + int ar = get_bits(&h->gb, 4); + skip_bits(&h->gb, 9); // display width + check_marker(h->c.avctx, &h->gb, "in dimensions"); + skip_bits(&h->gb, 9); // display height + if (ar == 15) { + h->c.avctx->sample_aspect_ratio.num = get_bits(&h->gb, 8); // aspect ratio - width + h->c.avctx->sample_aspect_ratio.den = get_bits(&h->gb, 8); // aspect ratio - height } else { - s->avctx->sample_aspect_ratio = ff_h263_pixel_aspect[ar]; + h->c.avctx->sample_aspect_ratio = ff_h263_pixel_aspect[ar]; } - if (s->avctx->sample_aspect_ratio.num == 0) - av_log(s->avctx, AV_LOG_ERROR, "Invalid aspect ratio.\n"); + if (h->c.avctx->sample_aspect_ratio.num == 0) + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid aspect ratio.\n"); } - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - skip_bits1(&s->gb); /* Continuous Presence Multipoint mode: off */ + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + skip_bits1(&h->gb); /* Continuous Presence Multipoint mode: off */ - if(s->pb_frame){ - skip_bits(&s->gb, 3); //temporal reference for B-frame - skip_bits(&s->gb, 2); //dbquant + if (h->pb_frame) { + skip_bits(&h->gb, 3); //temporal reference for B-frame + skip_bits(&h->gb, 2); //dbquant } /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - s->f_code = 1; - ff_h263_show_pict_info(s); + h->gob_index = H263_GOB_HEIGHT(h->c.height); + + ff_h263_show_pict_info(h, 0); return 0; } @@ -130,7 +131,7 @@ const FFCodec ff_h263i_decoder = { CODEC_LONG_NAME("Intel H.263"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263I, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(H263DecContext), .init = ff_h263_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 98ab2797ce..137fd52745 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -68,7 +68,7 @@ typedef struct AVCodecInternal { struct FramePool *pool; - struct FFRefStructPool *progress_frame_pool; + struct AVRefStructPool *progress_frame_pool; void *thread_ctx; @@ -145,15 +145,6 @@ typedef struct AVCodecInternal { AVFrame *buffer_frame; int draining_done; -#if FF_API_DROPCHANGED - /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */ - int changed_frames_dropped; - int initial_format; - int initial_width, initial_height; - int initial_sample_rate; - AVChannelLayout initial_ch_layout; -#endif - #if CONFIG_LCMS2 FFIccContext icc; /* used to read and write embedded ICC profiles */ #endif diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index 9c13707f87..a3bd931264 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -1315,14 +1315,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; if (!s->is_16bpp) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } switch (frame_format) { diff --git a/libavcodec/intrax8.c b/libavcodec/intrax8.c index f1dce86a50..89b70e5902 100644 --- a/libavcodec/intrax8.c +++ b/libavcodec/intrax8.c @@ -437,7 +437,7 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction, const int dc_level) { int t; -#define B(x,y) w->block[0][w->idct_permutation[(x) + (y) * 8]] +#define B(x,y) w->block[w->idct_permutation[(x) + (y) * 8]] #define T(x) ((x) * dc_level + 0x8000) >> 16; switch (direction) { case 0: @@ -480,24 +480,18 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction, t = T(1084); // g B(1, 1) += t; - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8); break; case 1: B(0, 1) -= T(6269); B(0, 3) -= T(708); B(0, 5) -= T(172); B(0, 7) -= T(73); - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8); break; case 2: B(1, 0) -= T(6269); B(3, 0) -= T(708); B(5, 0) -= T(172); B(7, 0) -= T(73); - - w->block_last_index[0] = FFMAX(w->block_last_index[0], 7); break; } #undef B @@ -536,7 +530,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) int sign; av_assert2(w->orient < 12); - w->bdsp.clear_block(w->block[0]); + w->bdsp.clear_block(w->block); if (chroma) dc_mode = 2; @@ -597,12 +591,9 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) if (use_quant_matrix) level = (level * quant_table[pos]) >> 8; - w->block[0][scantable[pos]] = level; + w->block[scantable[pos]] = level; } while (!final); - - w->block_last_index[0] = pos; } else { // DC only - w->block_last_index[0] = 0; if (w->flat_dc && ((unsigned) (dc_level + 1)) < 3) { // [-1; 1] int32_t divide_quant = !chroma ? w->divide_quant_dc_luma : w->divide_quant_dc_chroma; @@ -622,9 +613,9 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) zeros_only = dc_level == 0; } if (!chroma) - w->block[0][0] = dc_level * w->quant; + w->block[0] = dc_level * w->quant; else - w->block[0][0] = dc_level * w->quant_dc_chroma; + w->block[0] = dc_level * w->quant_dc_chroma; // there is !zero_only check in the original, but dc_level check is enough if ((unsigned int) (dc_level + 1) >= 3 && (w->edges & 3) != 3) { @@ -633,8 +624,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) * -> 01'10' 10'10' 00'00' 00'01' 01'11' 11'00 => 0x6A017C */ direction = (0x6A017C >> (w->orient * 2)) & 3; if (direction != 3) { - // modify block_last[] - x8_ac_compensation(w, direction, w->block[0][0]); + x8_ac_compensation(w, direction, w->block[0]); } } @@ -649,7 +639,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) if (!zeros_only) w->wdsp.idct_add(w->dest[chroma], w->frame->linesize[!!chroma], - w->block[0]); + w->block); block_placed: if (!chroma) @@ -688,8 +678,7 @@ static void x8_init_block_index(IntraX8Context *w, AVFrame *frame) av_cold int ff_intrax8_common_init(AVCodecContext *avctx, IntraX8Context *w, - int16_t (*block)[64], - int block_last_index[12], + int16_t block[64], int mb_width, int mb_height) { static AVOnce init_static_once = AV_ONCE_INIT; @@ -698,7 +687,6 @@ av_cold int ff_intrax8_common_init(AVCodecContext *avctx, w->mb_width = mb_width; w->mb_height = mb_height; w->block = block; - w->block_last_index = block_last_index; // two rows, 2 blocks per cannon mb w->prediction_table = av_mallocz(w->mb_width * 2 * 2); diff --git a/libavcodec/intrax8.h b/libavcodec/intrax8.h index b9f8c4250b..2ec90963a8 100644 --- a/libavcodec/intrax8.h +++ b/libavcodec/intrax8.h @@ -38,8 +38,7 @@ typedef struct IntraX8Context { WMV2DSPContext wdsp; uint8_t idct_permutation[64]; AVCodecContext *avctx; - int *block_last_index; ///< last nonzero coefficient in block - int16_t (*block)[64]; + int16_t *block; // set by the caller codec IntraX8DSPContext dsp; @@ -77,15 +76,13 @@ typedef struct IntraX8Context { * @param avctx pointer to AVCodecContext * @param w pointer to IntraX8Context * @param block pointer to block array - * @param block_last_index pointer to index array * @param mb_width macroblock width * @param mb_height macroblock height * @return 0 on success, a negative AVERROR value on error */ int ff_intrax8_common_init(AVCodecContext *avctx, IntraX8Context *w, - int16_t (*block)[64], - int block_last_index[12], + int16_t block[64], int mb_width, int mb_height); /** diff --git a/libavcodec/intrax8dsp.c b/libavcodec/intrax8dsp.c index 80c3929f71..2673316369 100644 --- a/libavcodec/intrax8dsp.c +++ b/libavcodec/intrax8dsp.c @@ -23,6 +23,7 @@ #include "intrax8dsp.h" #include "libavutil/common.h" +#include "libavutil/intreadwrite.h" /* * area positions, #3 is 1 pixel only, other are 8 pixels @@ -62,11 +63,12 @@ note: 1|2 - mb_x==mb_y==0 - first block, use 0x80 value for all areas; 4 - mb_x>= (mb_width-1) last block in the row, interpolate area #5; -*/ -static void x8_setup_spatial_compensation(uint8_t *src, uint8_t *dst, +static void x8_setup_spatial_compensation(const uint8_t *restrict src, + uint8_t *restrict dst, ptrdiff_t stride, int *range, int *psum, int edges) { - uint8_t *ptr; + const uint8_t *ptr; int sum; int i; int min_pix, max_pix; @@ -160,7 +162,7 @@ static const uint16_t zero_prediction_weights[64 * 2] = { 317, 846, 366, 731, 458, 611, 499, 499, }; -static void spatial_compensation_0(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_0(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int i, j; int x, y; @@ -212,7 +214,7 @@ static void spatial_compensation_0(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_1(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -223,29 +225,23 @@ static void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_2(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_2(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area4 + 1 + y + x]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area4 + 1 + y); dst += stride; } } -static void spatial_compensation_3(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_3(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area4 + ((y + 1) >> 1) + x]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area4 + ((y + 1) >> 1)); dst += stride; } } -static void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_4(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -256,7 +252,7 @@ static void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_5(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -271,18 +267,15 @@ static void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_6(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_6(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - dst[x] = src[area3 + x - y]; + for (int y = 0; y < 8; y++) { + AV_COPY64U(dst, src + area3 - y); dst += stride; } } -static void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_7(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -297,7 +290,7 @@ static void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_8(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -308,7 +301,7 @@ static void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_9(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -319,7 +312,7 @@ static void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride) } } -static void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_10(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; @@ -330,7 +323,7 @@ static void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride } } -static void spatial_compensation_11(uint8_t *src, uint8_t *dst, ptrdiff_t stride) +static void spatial_compensation_11(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride) { int x, y; diff --git a/libavcodec/intrax8dsp.h b/libavcodec/intrax8dsp.h index bf42698ed7..6cf673c364 100644 --- a/libavcodec/intrax8dsp.h +++ b/libavcodec/intrax8dsp.h @@ -26,9 +26,9 @@ typedef struct IntraX8DSPContext { void (*v_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale); void (*h_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale); - void (*spatial_compensation[12])(uint8_t *src, uint8_t *dst, + void (*spatial_compensation[12])(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride); - void (*setup_spatial_compensation)(uint8_t *src, uint8_t *dst, + void (*setup_spatial_compensation)(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride, int *range, int *sum, int edges); } IntraX8DSPContext; diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c index e0f3034e57..7a78b95c50 100644 --- a/libavcodec/ituh263dec.c +++ b/libavcodec/ituh263dec.c @@ -77,22 +77,22 @@ static const int16_t h263_mb_type_b_map[15]= { MB_TYPE_INTRA4x4 | MB_TYPE_CBP | MB_TYPE_QUANT, }; -void ff_h263_show_pict_info(MpegEncContext *s){ - if(s->avctx->debug&FF_DEBUG_PICT_INFO){ - av_log(s->avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s%s%s %d/%d\n", - s->qscale, av_get_picture_type_char(s->pict_type), - s->gb.size_in_bits, 1-s->no_rounding, - s->obmc ? " AP" : "", - s->umvplus ? " UMV" : "", - s->h263_long_vectors ? " LONG" : "", - s->h263_plus ? " +" : "", - s->h263_aic ? " AIC" : "", - s->alt_inter_vlc ? " AIV" : "", - s->modified_quant ? " MQ" : "", - s->loop_filter ? " LOOP" : "", - s->h263_slice_structured ? " SS" : "", - s->avctx->framerate.num, s->avctx->framerate.den - ); +void ff_h263_show_pict_info(H263DecContext *const h, int h263_plus) +{ + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s%s%s %d/%d\n", + h->c.qscale, av_get_picture_type_char(h->c.pict_type), + h->gb.size_in_bits, 1-h->c.no_rounding, + h->c.obmc ? " AP" : "", + h->umvplus ? " UMV" : "", + h->h263_long_vectors ? " LONG" : "", + h263_plus ? " +" : "", + h->c.h263_aic ? " AIC" : "", + h->alt_inter_vlc ? " AIV" : "", + h->modified_quant ? " MQ" : "", + h->loop_filter ? " LOOP" : "", + h->h263_slice_structured ? " SS" : "", + h->c.avctx->framerate.num, h->c.avctx->framerate.den); } } @@ -122,7 +122,6 @@ static av_cold void h263_decode_init_vlc(void) VLC_INIT_STATIC_TABLE(ff_h263_mv_vlc, H263_MV_VLC_BITS, 33, &ff_mvtab[0][1], 2, 1, &ff_mvtab[0][0], 2, 1, 0); - ff_h263_init_rl_inter(); VLC_INIT_RL(ff_h263_rl_inter, 554); INIT_FIRST_VLC_RL(ff_rl_intra_aic, 554); VLC_INIT_STATIC_SPARSE_TABLE(h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 15, @@ -140,16 +139,16 @@ av_cold void ff_h263_decode_init_vlc(void) ff_thread_once(&init_static_once, h263_decode_init_vlc); } -int ff_h263_decode_mba(MpegEncContext *s) +int ff_h263_decode_mba(H263DecContext *const h) { int i, mb_pos; for (i = 0; i < 6; i++) - if (s->mb_num - 1 <= ff_mba_max[i]) + if (h->c.mb_num - 1 <= ff_mba_max[i]) break; - mb_pos = get_bits(&s->gb, ff_mba_length[i]); - s->mb_x = mb_pos % s->mb_width; - s->mb_y = mb_pos / s->mb_width; + mb_pos = get_bits(&h->gb, ff_mba_length[i]); + h->c.mb_x = mb_pos % h->c.mb_width; + h->c.mb_y = mb_pos / h->c.mb_width; return mb_pos; } @@ -158,53 +157,54 @@ int ff_h263_decode_mba(MpegEncContext *s) * Decode the group of blocks header or slice header. * @return <0 if an error occurred */ -static int h263_decode_gob_header(MpegEncContext *s) +static int h263_decode_gob_header(H263DecContext *const h) { unsigned int val, gob_number; int left; /* Check for GOB Start Code */ - val = show_bits(&s->gb, 16); + val = show_bits(&h->gb, 16); if(val) return -1; /* We have a GBSC probably with GSTUFF */ - skip_bits(&s->gb, 16); /* Drop the zeros */ - left= get_bits_left(&s->gb); + skip_bits(&h->gb, 16); /* Drop the zeros */ + left = get_bits_left(&h->gb); left = FFMIN(left, 32); //MN: we must check the bits left or we might end in an infinite loop (or segfault) for(;left>13; left--){ - if(get_bits1(&s->gb)) break; /* Seek the '1' bit */ + if (get_bits1(&h->gb)) + break; /* Seek the '1' bit */ } if(left<=13) return -1; - if(s->h263_slice_structured){ - if(check_marker(s->avctx, &s->gb, "before MBA")==0) + if (h->h263_slice_structured) { + if (check_marker(h->c.avctx, &h->gb, "before MBA")==0) return -1; - ff_h263_decode_mba(s); + ff_h263_decode_mba(h); - if(s->mb_num > 1583) - if(check_marker(s->avctx, &s->gb, "after MBA")==0) + if (h->c.mb_num > 1583) + if (check_marker(h->c.avctx, &h->gb, "after MBA")==0) return -1; - s->qscale = get_bits(&s->gb, 5); /* SQUANT */ - if(check_marker(s->avctx, &s->gb, "after SQUANT")==0) + h->c.qscale = get_bits(&h->gb, 5); /* SQUANT */ + if (check_marker(h->c.avctx, &h->gb, "after SQUANT")==0) return -1; - skip_bits(&s->gb, 2); /* GFID */ + skip_bits(&h->gb, 2); /* GFID */ }else{ - gob_number = get_bits(&s->gb, 5); /* GN */ - s->mb_x= 0; - s->mb_y= s->gob_index* gob_number; - skip_bits(&s->gb, 2); /* GFID */ - s->qscale = get_bits(&s->gb, 5); /* GQUANT */ + gob_number = get_bits(&h->gb, 5); /* GN */ + h->c.mb_x = 0; + h->c.mb_y = h->gob_index* gob_number; + skip_bits(&h->gb, 2); /* GFID */ + h->c.qscale = get_bits(&h->gb, 5); /* GQUANT */ } - if(s->mb_y >= s->mb_height) + if (h->c.mb_y >= h->c.mb_height) return -1; - if(s->qscale==0) + if (h->c.qscale==0) return -1; return 0; @@ -214,79 +214,80 @@ static int h263_decode_gob_header(MpegEncContext *s) * 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 ff_h263_resync(H263DecContext *const h) +{ 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); + if (h->c.codec_id==AV_CODEC_ID_MPEG4 && h->c.studio_profile) { + align_get_bits(&h->gb); - while (get_bits_left(&s->gb) >= 32 && show_bits_long(&s->gb, 32) != SLICE_STARTCODE) { - get_bits(&s->gb, 8); + while (get_bits_left(&h->gb) >= 32 && show_bits_long(&h->gb, 32) != SLICE_STARTCODE) { + get_bits(&h->gb, 8); } - if (get_bits_left(&s->gb) >= 32 && show_bits_long(&s->gb, 32) == SLICE_STARTCODE) - return get_bits_count(&s->gb); + if (get_bits_left(&h->gb) >= 32 && show_bits_long(&h->gb, 32) == SLICE_STARTCODE) + return get_bits_count(&h->gb); else return -1; } - if(s->codec_id==AV_CODEC_ID_MPEG4){ - skip_bits1(&s->gb); - align_get_bits(&s->gb); + if (h->c.codec_id==AV_CODEC_ID_MPEG4){ + skip_bits1(&h->gb); + align_get_bits(&h->gb); } - if(show_bits(&s->gb, 16)==0){ - pos= get_bits_count(&s->gb); - if(CONFIG_MPEG4_DECODER && s->codec_id==AV_CODEC_ID_MPEG4) - ret= ff_mpeg4_decode_video_packet_header(s->avctx->priv_data); + if (show_bits(&h->gb, 16) ==0) { + pos = get_bits_count(&h->gb); + if(CONFIG_MPEG4_DECODER && h->c.codec_id==AV_CODEC_ID_MPEG4) + ret = ff_mpeg4_decode_video_packet_header(h); else - ret= h263_decode_gob_header(s); + ret = h263_decode_gob_header(h); if(ret>=0) return pos; } //OK, it's not where it is supposed to be ... - s->gb= s->last_resync_gb; - align_get_bits(&s->gb); - left= get_bits_left(&s->gb); + h->gb = h->last_resync_gb; + align_get_bits(&h->gb); + left = get_bits_left(&h->gb); for(;left>16+1+5+5; left-=8){ - if(show_bits(&s->gb, 16)==0){ - GetBitContext bak= s->gb; + if (show_bits(&h->gb, 16) == 0){ + GetBitContext bak = h->gb; - pos= get_bits_count(&s->gb); - if(CONFIG_MPEG4_DECODER && s->codec_id==AV_CODEC_ID_MPEG4) - ret= ff_mpeg4_decode_video_packet_header(s->avctx->priv_data); + pos = get_bits_count(&h->gb); + if(CONFIG_MPEG4_DECODER && h->c.codec_id==AV_CODEC_ID_MPEG4) + ret = ff_mpeg4_decode_video_packet_header(h); else - ret= h263_decode_gob_header(s); + ret = h263_decode_gob_header(h); if(ret>=0) return pos; - s->gb= bak; + h->gb = bak; } - skip_bits(&s->gb, 8); + skip_bits(&h->gb, 8); } return -1; } -int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) +int ff_h263_decode_motion(H263DecContext *const h, int pred, int f_code) { int code, val, sign, shift; - code = get_vlc2(&s->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); + code = get_vlc2(&h->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); if (code == 0) return pred; if (code < 0) return 0xffff; - sign = get_bits1(&s->gb); + sign = get_bits1(&h->gb); shift = f_code - 1; val = code; if (shift) { val = (val - 1) << shift; - val |= get_bits(&s->gb, shift); + val |= get_bits(&h->gb, shift); val++; } if (sign) @@ -294,7 +295,7 @@ int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) val += pred; /* modulo decoding */ - if (!s->h263_long_vectors) { + if (!h->h263_long_vectors) { val = sign_extend(val, 5 + f_code); } else { /* horrible H.263 long vector mode */ @@ -309,21 +310,21 @@ int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code) /* Decode RVLC of H.263+ UMV */ -static int h263p_decode_umotion(MpegEncContext * s, int pred) +static int h263p_decode_umotion(H263DecContext *const h, int pred) { int code = 0, sign; - if (get_bits1(&s->gb)) /* Motion difference = 0 */ + if (get_bits1(&h->gb)) /* Motion difference = 0 */ return pred; - code = 2 + get_bits1(&s->gb); + code = 2 + get_bits1(&h->gb); - while (get_bits1(&s->gb)) + while (get_bits1(&h->gb)) { code <<= 1; - code += get_bits1(&s->gb); + code += get_bits1(&h->gb); if (code >= 32768) { - avpriv_request_sample(s->avctx, "Huge DMV"); + avpriv_request_sample(h->c.avctx, "Huge DMV"); return 0xffff; } } @@ -331,7 +332,7 @@ static int h263p_decode_umotion(MpegEncContext * s, int pred) code >>= 1; code = (sign) ? (pred - code) : (pred + code); - ff_tlog(s->avctx,"H.263+ UMV Motion = %d\n", code); + ff_tlog(h->c.avctx,"H.263+ UMV Motion = %d\n", code); return code; } @@ -339,82 +340,79 @@ static int h263p_decode_umotion(MpegEncContext * s, int pred) /** * read the next MVs for OBMC. yes this is an ugly hack, feel free to send a patch :) */ -static void preview_obmc(MpegEncContext *s){ - GetBitContext gb= s->gb; +static void preview_obmc(H263DecContext *const h) +{ + GetBitContext gb = h->gb; int cbpc, i, pred_x, pred_y, mx, my; int16_t *mot_val; - const int xy= s->mb_x + 1 + s->mb_y * s->mb_stride; - const int stride= s->b8_stride*2; + const int xy = h->c.mb_x + 1 + h->c.mb_y * h->c.mb_stride; + const int stride = h->c.b8_stride * 2; for(i=0; i<4; i++) - s->block_index[i]+= 2; + h->c.block_index[i] += 2; for(i=4; i<6; i++) - s->block_index[i]+= 1; - s->mb_x++; + h->c.block_index[i] += 1; + h->c.mb_x++; - av_assert2(s->pict_type == AV_PICTURE_TYPE_P); + av_assert2(h->c.pict_type == AV_PICTURE_TYPE_P); do{ - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - mot_val = s->cur_pic.motion_val[0][s->block_index[0]]; + mot_val = h->c.cur_pic.motion_val[0][h->c.block_index[0]]; mot_val[0 ]= mot_val[2 ]= mot_val[0+stride]= mot_val[2+stride]= 0; mot_val[1 ]= mot_val[3 ]= mot_val[1+stride]= mot_val[3+stride]= 0; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); }while(cbpc == 20); if(cbpc & 4){ - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; }else{ - get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpc & 8) { - if(s->modified_quant){ - if(get_bits1(&s->gb)) skip_bits(&s->gb, 1); - else skip_bits(&s->gb, 5); - }else - skip_bits(&s->gb, 2); + skip_bits(&h->gb, h->modified_quant ? (get_bits1(&h->gb) ? 1 : 5) : 2); } if ((cbpc & 16) == 0) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - mot_val= ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val= ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); mot_val[0 ]= mot_val[2 ]= mot_val[0+stride]= mot_val[2+stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+stride]= mot_val[3+stride]= my; } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; for(i=0;i<4;i++) { - mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + my = ff_h263_decode_motion(h, pred_y, 1); + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ mot_val[0] = mx; mot_val[1] = my; } @@ -423,57 +421,50 @@ static void preview_obmc(MpegEncContext *s){ end: for(i=0; i<4; i++) - s->block_index[i]-= 2; + h->c.block_index[i] -= 2; for(i=4; i<6; i++) - s->block_index[i]-= 1; - s->mb_x--; + h->c.block_index[i] -= 1; + h->c.mb_x--; - s->gb= gb; + h->gb = gb; } -static void h263_decode_dquant(MpegEncContext *s){ +static void h263_decode_dquant(H263DecContext *const h) +{ static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; + int qscale; - if(s->modified_quant){ - if(get_bits1(&s->gb)) - s->qscale= ff_modified_quant_tab[get_bits1(&s->gb)][ s->qscale ]; + if (h->modified_quant) { + if (get_bits1(&h->gb)) + qscale = ff_modified_quant_tab[get_bits1(&h->gb)][h->c.qscale]; else - s->qscale= get_bits(&s->gb, 5); + qscale = get_bits(&h->gb, 5); }else - s->qscale += quant_tab[get_bits(&s->gb, 2)]; - ff_set_qscale(s, s->qscale); + qscale = h->c.qscale + quant_tab[get_bits(&h->gb, 2)]; + ff_set_qscale(&h->c, qscale); } static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) { - int x, y, wrap, a, c, pred_dc, scale; - int16_t *dc_val, *ac_val, *ac_val1; + int wrap, a, c, pred_dc, scale; + const int xy = s->block_index[n]; + int16_t *const dc_val = s->dc_val + xy; + int16_t *const ac_val = (s->ac_val + xy)[0]; /* find prediction */ if (n < 4) { - x = 2 * s->mb_x + (n & 1); - y = 2 * s->mb_y + (n>> 1); wrap = s->b8_stride; - dc_val = s->dc_val[0]; - ac_val = s->ac_val[0][0]; scale = s->y_dc_scale; } else { - x = s->mb_x; - y = s->mb_y; wrap = s->mb_stride; - dc_val = s->dc_val[n - 4 + 1]; - ac_val = s->ac_val[n - 4 + 1][0]; scale = s->c_dc_scale; } - ac_val += ((y) * wrap + (x)) * 16; - ac_val1 = ac_val; - /* B C * A X */ - a = dc_val[(x - 1) + (y) * wrap]; - c = dc_val[(x) + (y - 1) * wrap]; + a = dc_val[-1]; + c = dc_val[-wrap]; /* No prediction outside GOB boundary */ if (s->first_slice_line && n != 3) { @@ -486,18 +477,18 @@ static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) if (s->h263_aic_dir) { /* left prediction */ if (a != 1024) { - ac_val -= 16; + int16_t *const ac_val2 = ac_val - 16; for (int i = 1; i < 8; i++) { - block[s->idsp.idct_permutation[i << 3]] += ac_val[i]; + block[s->idsp.idct_permutation[i << 3]] += ac_val2[i]; } pred_dc = a; } } else { /* top prediction */ if (c != 1024) { - ac_val -= 16 * wrap; + int16_t *const ac_val2 = ac_val - 16 * wrap; for (int i = 1; i < 8; i++) { - block[s->idsp.idct_permutation[i]] += ac_val[i + 8]; + block[s->idsp.idct_permutation[i]] += ac_val2[i + 8]; } pred_dc = c; } @@ -521,61 +512,63 @@ static void h263_pred_acdc(MpegEncContext * s, int16_t *block, int n) block[0] |= 1; /* Update AC/DC tables */ - dc_val[(x) + (y) * wrap] = block[0]; + *dc_val = block[0]; /* left copy */ for (int i = 1; i < 8; i++) - ac_val1[i] = block[s->idsp.idct_permutation[i << 3]]; + ac_val[i] = block[s->idsp.idct_permutation[i << 3]]; /* top copy */ for (int i = 1; i < 8; i++) - ac_val1[8 + i] = block[s->idsp.idct_permutation[i]]; + ac_val[8 + i] = block[s->idsp.idct_permutation[i]]; } -static int h263_decode_block(MpegEncContext * s, int16_t * block, +static int h263_decode_block(H263DecContext *const h, int16_t block[64], int n, int coded) { int level, i, j, run; const RLTable *rl = &ff_h263_rl_inter; const uint8_t *scan_table; - GetBitContext gb= s->gb; + GetBitContext gb = h->gb; - scan_table = s->intra_scantable.permutated; - if (s->h263_aic && s->mb_intra) { - rl = &ff_rl_intra_aic; + scan_table = h->c.intra_scantable.permutated; + if (h->c.h263_aic && h->c.mb_intra) { i = 0; - if (s->ac_pred) { - if (s->h263_aic_dir) - scan_table = s->permutated_intra_v_scantable; /* left */ + if (!coded) + goto not_coded; + rl = &ff_rl_intra_aic; + if (h->c.ac_pred) { + if (h->c.h263_aic_dir) + scan_table = h->c.permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->c.permutated_intra_h_scantable; /* top */ } - } else if (s->mb_intra) { + } else if (h->c.mb_intra) { /* DC coef */ - if (CONFIG_RV10_DECODER && s->codec_id == AV_CODEC_ID_RV10) { - if (s->rv10_version == 3 && s->pict_type == AV_PICTURE_TYPE_I) { - int component, diff; - component = (n <= 3 ? 0 : n - 4 + 1); - level = s->last_dc[component]; - if (s->rv10_first_dc_coded[component]) { - diff = ff_rv_decode_dc(s, n); - if (diff < 0) - return -1; - level += diff; - level = level & 0xff; /* handle wrap round */ - s->last_dc[component] = level; + if (CONFIG_RV10_DECODER && h->c.codec_id == AV_CODEC_ID_RV10) { + if (h->rv10_version == 3 && h->c.pict_type == AV_PICTURE_TYPE_I) { + int component = (n <= 3 ? 0 : n - 4 + 1); + level = h->c.last_dc[component]; + if (h->rv10_first_dc_coded[component]) { + int diff = ff_rv_decode_dc(h, n); + if (diff < 0) + return -1; + level += diff; + level = level & 0xff; /* handle wrap round */ + h->c.last_dc[component] = level; + } else { + h->rv10_first_dc_coded[component] = 1; + } } else { - s->rv10_first_dc_coded[component] = 1; - } - } else { - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); if (level == 255) level = 128; - } + } }else{ - level = get_bits(&s->gb, 8); + level = get_bits(&h->gb, 8); if((level&0x7F) == 0){ - av_log(s->avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", level, s->mb_x, s->mb_y); - if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", + level, h->c.mb_x, h->c.mb_y); + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) return -1; } if (level == 255) @@ -587,66 +580,65 @@ static int h263_decode_block(MpegEncContext * s, int16_t * block, i = 0; } if (!coded) { - if (s->mb_intra && s->h263_aic) - goto not_coded; - s->block_last_index[n] = i - 1; + h->c.block_last_index[n] = i - 1; return 0; } retry: { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); i--; // offset by -1 to allow direct indexing of scan_table for(;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0); if (run == 66) { if (level){ - CLOSE_READER(re, &s->gb); - av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y); + CLOSE_READER(re, &h->gb); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", + h->c.mb_x, h->c.mb_y); return -1; } /* escape */ - if (CONFIG_FLV_DECODER && s->h263_flv > 1) { - int is11 = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 7) + 1; + if (CONFIG_FLV_DECODER && h->flv) { + int is11 = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 7) + 1; if (is11) { - SKIP_COUNTER(re, &s->gb, 1 + 7); - UPDATE_CACHE(re, &s->gb); - level = SHOW_SBITS(re, &s->gb, 11); - SKIP_COUNTER(re, &s->gb, 11); + SKIP_COUNTER(re, &h->gb, 1 + 7); + UPDATE_CACHE(re, &h->gb); + level = SHOW_SBITS(re, &h->gb, 11); + SKIP_COUNTER(re, &h->gb, 11); } else { - SKIP_CACHE(re, &s->gb, 7); - level = SHOW_SBITS(re, &s->gb, 7); - SKIP_COUNTER(re, &s->gb, 1 + 7 + 7); + SKIP_CACHE(re, &h->gb, 7); + level = SHOW_SBITS(re, &h->gb, 7); + SKIP_COUNTER(re, &h->gb, 1 + 7 + 7); } } else { - run = SHOW_UBITS(re, &s->gb, 7) + 1; - SKIP_CACHE(re, &s->gb, 7); - level = (int8_t)SHOW_UBITS(re, &s->gb, 8); - SKIP_COUNTER(re, &s->gb, 7 + 8); + run = SHOW_UBITS(re, &h->gb, 7) + 1; + SKIP_CACHE(re, &h->gb, 7); + level = (int8_t)SHOW_UBITS(re, &h->gb, 8); + SKIP_COUNTER(re, &h->gb, 7 + 8); if(level == -128){ - UPDATE_CACHE(re, &s->gb); - if (s->codec_id == AV_CODEC_ID_RV10) { + UPDATE_CACHE(re, &h->gb); + if (h->c.codec_id == AV_CODEC_ID_RV10) { /* XXX: should patch encoder too */ - level = SHOW_SBITS(re, &s->gb, 12); - SKIP_COUNTER(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + SKIP_COUNTER(re, &h->gb, 12); }else{ - level = SHOW_UBITS(re, &s->gb, 5); - SKIP_CACHE(re, &s->gb, 5); - level |= SHOW_SBITS(re, &s->gb, 6) * (1<<5); - SKIP_COUNTER(re, &s->gb, 5 + 6); + level = SHOW_UBITS(re, &h->gb, 5); + SKIP_CACHE(re, &h->gb, 5); + level |= SHOW_SBITS(re, &h->gb, 6) * (1<<5); + SKIP_COUNTER(re, &h->gb, 5 + 6); } } } } else { - if (SHOW_UBITS(re, &s->gb, 1)) + if (SHOW_UBITS(re, &h->gb, 1)) level = -level; - SKIP_COUNTER(re, &s->gb, 1); + SKIP_COUNTER(re, &h->gb, 1); } i += run; if (i >= 64){ - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); // redo update without last flag, revert -1 offset i = i - run + ((run-1)&63) + 1; if (i < 64) { @@ -654,49 +646,49 @@ retry: block[scan_table[i]] = level; break; } - if(s->alt_inter_vlc && rl == &ff_h263_rl_inter && !s->mb_intra){ + if(h->alt_inter_vlc && rl == &ff_h263_rl_inter && !h->c.mb_intra){ //Looks like a hack but no, it's the way it is supposed to work ... rl = &ff_rl_intra_aic; i = 0; - s->gb= gb; - s->bdsp.clear_block(block); + h->gb = gb; + h->c.bdsp.clear_block(block); goto retry; } - av_log(s->avctx, AV_LOG_ERROR, "run overflow at %dx%d i:%d\n", s->mb_x, s->mb_y, s->mb_intra); + av_log(h->c.avctx, AV_LOG_ERROR, "run overflow at %dx%d i:%d\n", + h->c.mb_x, h->c.mb_y, h->c.mb_intra); return -1; } j = scan_table[i]; block[j] = level; } } + if (h->c.mb_intra && h->c.h263_aic) { not_coded: - if (s->mb_intra && s->h263_aic) { - h263_pred_acdc(s, block, n); - i = 63; + h263_pred_acdc(&h->c, block, n); } - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } -static int h263_skip_b_part(MpegEncContext *s, int cbp) +static int h263_skip_b_part(H263DecContext *const h, int cbp) { LOCAL_ALIGNED_32(int16_t, dblock, [64]); int i, mbi; int bli[6]; - /* we have to set s->mb_intra to zero to decode B-part of PB-frame correctly + /* we have to set h->c.mb_intra to zero to decode B-part of PB-frame correctly * but real value should be restored in order to be used later (in OBMC condition) */ - mbi = s->mb_intra; - memcpy(bli, s->block_last_index, sizeof(bli)); - s->mb_intra = 0; + mbi = h->c.mb_intra; + memcpy(bli, h->c.block_last_index, sizeof(bli)); + h->c.mb_intra = 0; for (i = 0; i < 6; i++) { - if (h263_decode_block(s, dblock, i, cbp&32) < 0) + if (h263_decode_block(h, dblock, i, cbp&32) < 0) return -1; cbp+=cbp; } - s->mb_intra = mbi; - memcpy(s->block_last_index, bli, sizeof(bli)); + h->c.mb_intra = mbi; + memcpy(h->c.block_last_index, bli, sizeof(bli)); return 0; } @@ -785,119 +777,121 @@ static int set_direct_mv(MpegEncContext *s) } } -int ff_h263_decode_mb(MpegEncContext *s, - int16_t block[6][64]) +int ff_h263_decode_mb(H263DecContext *const h) { int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; int16_t *mot_val; - const int xy= s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int cbpb = 0, pb_mv_count = 0; - av_assert2(!s->h263_pred); + av_assert2(!h->c.h263_pred); - if (s->pict_type == AV_PICTURE_TYPE_P) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { do{ - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = !(s->obmc | s->loop_filter); + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = !(h->c.obmc | h->loop_filter); goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(cbpc == 20); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); dquant = cbpc & 8; - s->mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) goto intra; + h->c.mb_intra = ((cbpc & 4) != 0); + if (h->c.mb_intra) + goto intra; - if(s->pb_frame && get_bits1(&s->gb)) - pb_mv_count = h263_get_modb(&s->gb, s->pb_frame, &cbpb); - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->pb_frame && get_bits1(&h->gb)) + pb_mv_count = h263_get_modb(&h->gb, h->pb_frame, &cbpb); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } - if(s->alt_inter_vlc==0 || (cbpc & 3)!=3) + if (!h->alt_inter_vlc|| (cbpc & 3)!=3) cbpy ^= 0xF; cbp = (cbpc & 3) | (cbpy << 2); if (dquant) { - h263_decode_dquant(s); + h263_decode_dquant(h); } - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - s->mv_type = MV_TYPE_16X16; - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + h->c.mv_type = MV_TYPE_16X16; + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; - s->mv_type = MV_TYPE_8X8; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.mv_type = MV_TYPE_8X8; for(i=0;i<4;i++) { - mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ mot_val[0] = mx; mot_val[1] = my; } } - } else if(s->pict_type==AV_PICTURE_TYPE_B) { + } else if (h->c.pict_type==AV_PICTURE_TYPE_B) { int mb_type; - const int stride= s->b8_stride; - int16_t *mot_val0 = s->cur_pic.motion_val[0][2 * (s->mb_x + s->mb_y * stride)]; - int16_t *mot_val1 = s->cur_pic.motion_val[1][2 * (s->mb_x + s->mb_y * stride)]; -// const int mv_xy= s->mb_x + 1 + s->mb_y * s->mb_stride; + const int stride = h->c.b8_stride; + int16_t *mot_val0 = h->c.cur_pic.motion_val[0][2 * (h->c.mb_x + h->c.mb_y * stride)]; + int16_t *mot_val1 = h->c.cur_pic.motion_val[1][2 * (h->c.mb_x + h->c.mb_y * stride)]; +// const int mv_xy = h->c.mb_x + 1 + h->c.mb_y * h->c.mb_stride; //FIXME ugly mot_val0[0 ]= mot_val0[2 ]= mot_val0[0+2*stride]= mot_val0[2+2*stride]= @@ -906,176 +900,181 @@ int ff_h263_decode_mb(MpegEncContext *s, mot_val1[1 ]= mot_val1[3 ]= mot_val1[1+2*stride]= mot_val1[3+2*stride]= 0; do{ - mb_type = get_vlc2(&s->gb, h263_mbtype_b_vlc, + mb_type = get_vlc2(&h->gb, h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 2); if (mb_type < 0){ - av_log(s->avctx, AV_LOG_ERROR, "b mb_type damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "b mb_type damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(!mb_type); - s->mb_intra = IS_INTRA(mb_type); + h->c.mb_intra = IS_INTRA(mb_type); if(HAS_CBP(mb_type)){ - s->bdsp.clear_blocks(s->block[0]); - cbpc = get_vlc2(&s->gb, cbpc_b_vlc, CBPC_B_VLC_BITS, 1); - if(s->mb_intra){ + h->c.bdsp.clear_blocks(h->block[0]); + cbpc = get_vlc2(&h->gb, cbpc_b_vlc, CBPC_B_VLC_BITS, 1); + if (h->c.mb_intra) { dquant = IS_QUANT(mb_type); goto intra; } - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0){ - av_log(s->avctx, AV_LOG_ERROR, "b cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "b cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } - if(s->alt_inter_vlc==0 || (cbpc & 3)!=3) + if (!h->alt_inter_vlc || (cbpc & 3)!=3) cbpy ^= 0xF; cbp = (cbpc & 3) | (cbpy << 2); }else cbp=0; - av_assert2(!s->mb_intra); + av_assert2(!h->c.mb_intra); if(IS_QUANT(mb_type)){ - h263_decode_dquant(s); + h263_decode_dquant(h); } if(IS_DIRECT(mb_type)){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - mb_type |= set_direct_mv(s); + h->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + mb_type |= set_direct_mv(&h->c); }else{ - s->mv_dir = 0; - s->mv_type= MV_TYPE_16X16; + h->c.mv_dir = 0; + h->c.mv_type = MV_TYPE_16X16; //FIXME UMV if (HAS_FORWARD_MV(mb_type)) { - int16_t *mot_val= ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - s->mv_dir = MV_DIR_FORWARD; + int16_t *mot_val = ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + h->c.mv_dir = MV_DIR_FORWARD; - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; mot_val[0 ]= mot_val[2 ]= mot_val[0+2*stride]= mot_val[2+2*stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+2*stride]= mot_val[3+2*stride]= my; } if (HAS_BACKWARD_MV(mb_type)) { - int16_t *mot_val= ff_h263_pred_motion(s, 0, 1, &pred_x, &pred_y); - s->mv_dir |= MV_DIR_BACKWARD; + int16_t *mot_val = ff_h263_pred_motion(&h->c, 0, 1, &pred_x, &pred_y); + h->c.mv_dir |= MV_DIR_BACKWARD; - if (s->umvplus) - mx = h263p_decode_umotion(s, pred_x); + if (h->umvplus) + mx = h263p_decode_umotion(h, pred_x); else - mx = ff_h263_decode_motion(s, pred_x, 1); + mx = ff_h263_decode_motion(h, pred_x, 1); if (mx >= 0xffff) return SLICE_ERROR; - if (s->umvplus) - my = h263p_decode_umotion(s, pred_y); + if (h->umvplus) + my = h263p_decode_umotion(h, pred_y); else - my = ff_h263_decode_motion(s, pred_y, 1); + my = ff_h263_decode_motion(h, pred_y, 1); if (my >= 0xffff) return SLICE_ERROR; - if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) - skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ + if (h->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) + skip_bits1(&h->gb); /* Bit stuffing to prevent PSC */ - s->mv[1][0][0] = mx; - s->mv[1][0][1] = my; + h->c.mv[1][0][0] = mx; + h->c.mv[1][0][1] = my; mot_val[0 ]= mot_val[2 ]= mot_val[0+2*stride]= mot_val[2+2*stride]= mx; mot_val[1 ]= mot_val[3 ]= mot_val[1+2*stride]= mot_val[3+2*stride]= my; } } - s->cur_pic.mb_type[xy] = mb_type; + h->c.cur_pic.mb_type[xy] = mb_type; } else { /* I-Frame */ do{ - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0){ - av_log(s->avctx, AV_LOG_ERROR, "I cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "I cbpc damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } }while(cbpc == 8); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); dquant = cbpc & 4; - s->mb_intra = 1; + h->c.mb_intra = 1; intra: - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - if (s->h263_aic) { - s->ac_pred = get_bits1(&s->gb); - if(s->ac_pred){ - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + if (h->c.h263_aic) { + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.ac_pred) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; - s->h263_aic_dir = get_bits1(&s->gb); + h->c.h263_aic_dir = get_bits1(&h->gb); } }else - s->ac_pred = 0; + h->c.ac_pred = 0; - if(s->pb_frame && get_bits1(&s->gb)) - pb_mv_count = h263_get_modb(&s->gb, s->pb_frame, &cbpb); - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->pb_frame && get_bits1(&h->gb)) + pb_mv_count = h263_get_modb(&h->gb, h->pb_frame, &cbpb); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if(cbpy<0){ - av_log(s->avctx, AV_LOG_ERROR, "I cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "I cbpy damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return SLICE_ERROR; } cbp = (cbpc & 3) | (cbpy << 2); if (dquant) { - h263_decode_dquant(s); + h263_decode_dquant(h); } - pb_mv_count += !!s->pb_frame; + pb_mv_count += !!h->pb_frame; } while(pb_mv_count--){ - ff_h263_decode_motion(s, 0, 1); - ff_h263_decode_motion(s, 0, 1); + ff_h263_decode_motion(h, 0, 1); + ff_h263_decode_motion(h, 0, 1); } /* decode each block */ for (i = 0; i < 6; i++) { - if (h263_decode_block(s, block[i], i, cbp&32) < 0) + if (h263_decode_block(h, h->block[i], i, cbp&32) < 0) return -1; cbp+=cbp; } - if(s->pb_frame && h263_skip_b_part(s, cbpb) < 0) + if (h->pb_frame && h263_skip_b_part(h, cbpb) < 0) return -1; - if(s->obmc && !s->mb_intra){ - if(s->pict_type == AV_PICTURE_TYPE_P && s->mb_x+1mb_width && s->mb_num_left != 1) - preview_obmc(s); + if (h->c.obmc && !h->c.mb_intra) { + if (h->c.pict_type == AV_PICTURE_TYPE_P && + h->c.mb_x + 1 < h->c.mb_width && h->mb_num_left != 1) + preview_obmc(h); } end: - if (get_bits_left(&s->gb) < 0) + if (get_bits_left(&h->gb) < 0) return AVERROR_INVALIDDATA; /* per-MB end of slice check */ { - int v= show_bits(&s->gb, 16); + int v = show_bits(&h->gb, 16); - if (get_bits_left(&s->gb) < 16) { - v >>= 16 - get_bits_left(&s->gb); + if (get_bits_left(&h->gb) < 16) { + v >>= 16 - get_bits_left(&h->gb); } if(v==0) @@ -1086,50 +1085,50 @@ end: } /* Most is hardcoded; should extend to handle all H.263 streams. */ -int ff_h263_decode_picture_header(MpegEncContext *s) +int ff_h263_decode_picture_header(H263DecContext *const h) { - int format, width, height, i, ret; - uint32_t startcode; + int width, height, i, ret; + int h263_plus; - align_get_bits(&s->gb); + align_get_bits(&h->gb); - if (show_bits(&s->gb, 2) == 2 && s->avctx->frame_num == 0) { - av_log(s->avctx, AV_LOG_WARNING, "Header looks like RTP instead of H.263\n"); + if (show_bits(&h->gb, 2) == 2 && h->c.avctx->frame_num == 0) { + av_log(h->c.avctx, AV_LOG_WARNING, "Header looks like RTP instead of H.263\n"); } - startcode= get_bits(&s->gb, 22-8); + uint32_t startcode = get_bits(&h->gb, 22-8); - for(i= get_bits_left(&s->gb); i>24; i-=8) { - startcode = ((startcode << 8) | get_bits(&s->gb, 8)) & 0x003FFFFF; + for (i = get_bits_left(&h->gb); i>24; i -= 8) { + startcode = ((startcode << 8) | get_bits(&h->gb, 8)) & 0x003FFFFF; if(startcode == 0x20) break; } if (startcode != 0x20) { - av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad picture start code\n"); return -1; } /* temporal reference */ - i = get_bits(&s->gb, 8); /* picture timestamp */ + i = get_bits(&h->gb, 8); /* picture timestamp */ - i -= (i - (s->picture_number & 0xFF) + 128) & ~0xFF; + i -= (i - (h->picture_number & 0xFF) + 128) & ~0xFF; - s->picture_number= (s->picture_number&~0xFF) + i; + h->picture_number = (h->picture_number&~0xFF) + i; /* PTYPE starts here */ - if (check_marker(s->avctx, &s->gb, "in PTYPE") != 1) { + if (check_marker(h->c.avctx, &h->gb, "in PTYPE") != 1) { return -1; } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad H.263 id\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Bad H.263 id\n"); return -1; /* H.263 id */ } - skip_bits1(&s->gb); /* split screen off */ - skip_bits1(&s->gb); /* camera off */ - skip_bits1(&s->gb); /* freeze picture release off */ + skip_bits1(&h->gb); /* split screen off */ + skip_bits1(&h->gb); /* camera off */ + skip_bits1(&h->gb); /* freeze picture release off */ - format = get_bits(&s->gb, 3); + int format = get_bits(&h->gb, 3); /* 0 forbidden 1 sub-QCIF @@ -1138,95 +1137,95 @@ int ff_h263_decode_picture_header(MpegEncContext *s) */ if (format != 7 && format != 6) { - s->h263_plus = 0; + h263_plus = 0; /* H.263v1 */ width = ff_h263_format[format][0]; height = ff_h263_format[format][1]; if (!width) return -1; - s->pict_type = AV_PICTURE_TYPE_I + get_bits1(&s->gb); + h->c.pict_type = AV_PICTURE_TYPE_I + get_bits1(&h->gb); - s->h263_long_vectors = get_bits1(&s->gb); + h->h263_long_vectors = get_bits1(&h->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "H.263 SAC not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "H.263 SAC not supported\n"); return -1; /* SAC: off */ } - s->obmc= get_bits1(&s->gb); /* Advanced prediction mode */ + h->c.obmc = get_bits1(&h->gb); /* Advanced prediction mode */ - s->pb_frame = get_bits1(&s->gb); - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - skip_bits1(&s->gb); /* Continuous Presence Multipoint mode: off */ + h->pb_frame = get_bits1(&h->gb); + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + skip_bits1(&h->gb); /* Continuous Presence Multipoint mode: off */ - s->width = width; - s->height = height; - s->avctx->sample_aspect_ratio= (AVRational){12,11}; - s->avctx->framerate = (AVRational){ 30000, 1001 }; + h->c.width = width; + h->c.height = height; + h->c.avctx->sample_aspect_ratio= (AVRational){12,11}; + h->c.avctx->framerate = (AVRational){ 30000, 1001 }; } else { int ufep; /* H.263v2 */ - s->h263_plus = 1; - ufep = get_bits(&s->gb, 3); /* Update Full Extended PTYPE */ + h263_plus = 1; + ufep = get_bits(&h->gb, 3); /* Update Full Extended PTYPE */ /* ufep other than 0 and 1 are reserved */ if (ufep == 1) { /* OPPTYPE */ - format = get_bits(&s->gb, 3); - ff_dlog(s->avctx, "ufep=1, format: %d\n", format); - s->custom_pcf= get_bits1(&s->gb); - s->umvplus = get_bits1(&s->gb); /* Unrestricted Motion Vector */ - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Syntax-based Arithmetic Coding (SAC) not supported\n"); + format = get_bits(&h->gb, 3); + ff_dlog(h->c.avctx, "ufep=1, format: %d\n", format); + h->custom_pcf = get_bits1(&h->gb); + h->umvplus = get_bits1(&h->gb); /* Unrestricted Motion Vector */ + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Syntax-based Arithmetic Coding (SAC) not supported\n"); } - s->obmc= get_bits1(&s->gb); /* Advanced prediction mode */ - s->h263_aic = get_bits1(&s->gb); /* Advanced Intra Coding (AIC) */ - s->loop_filter= get_bits1(&s->gb); - if(s->avctx->lowres) - s->loop_filter = 0; + h->c.obmc = get_bits1(&h->gb); /* Advanced prediction mode */ + h->c.h263_aic = get_bits1(&h->gb); /* Advanced Intra Coding (AIC) */ + h->loop_filter = get_bits1(&h->gb); + if (h->c.avctx->lowres) + h->loop_filter = 0; - s->h263_slice_structured= get_bits1(&s->gb); - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Reference Picture Selection not supported\n"); + h->h263_slice_structured = get_bits1(&h->gb); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Reference Picture Selection not supported\n"); } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Independent Segment Decoding not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Independent Segment Decoding not supported\n"); } - s->alt_inter_vlc= get_bits1(&s->gb); - s->modified_quant= get_bits1(&s->gb); - if(s->modified_quant) - s->chroma_qscale_table= ff_h263_chroma_qscale_table; + h->alt_inter_vlc = get_bits1(&h->gb); + h->modified_quant = get_bits1(&h->gb); + if (h->modified_quant) + h->c.chroma_qscale_table= ff_h263_chroma_qscale_table; - skip_bits(&s->gb, 1); /* Prevent start code emulation */ + skip_bits(&h->gb, 1); /* Prevent start code emulation */ - skip_bits(&s->gb, 3); /* Reserved */ + skip_bits(&h->gb, 3); /* Reserved */ } else if (ufep != 0) { - av_log(s->avctx, AV_LOG_ERROR, "Bad UFEP type (%d)\n", ufep); + av_log(h->c.avctx, AV_LOG_ERROR, "Bad UFEP type (%d)\n", ufep); return -1; } /* MPPTYPE */ - s->pict_type = get_bits(&s->gb, 3); - switch(s->pict_type){ - case 0: s->pict_type= AV_PICTURE_TYPE_I;break; - case 1: s->pict_type= AV_PICTURE_TYPE_P;break; - case 2: s->pict_type= AV_PICTURE_TYPE_P;s->pb_frame = 3;break; - case 3: s->pict_type= AV_PICTURE_TYPE_B;break; - case 7: s->pict_type= AV_PICTURE_TYPE_I;break; //ZYGO + h->c.pict_type = get_bits(&h->gb, 3); + switch (h->c.pict_type) { + case 0: h->c.pict_type = AV_PICTURE_TYPE_I; break; + case 1: h->c.pict_type = AV_PICTURE_TYPE_P; break; + case 2: h->c.pict_type = AV_PICTURE_TYPE_P; h->pb_frame = 3; break; + case 3: h->c.pict_type = AV_PICTURE_TYPE_B; break; + case 7: h->c.pict_type = AV_PICTURE_TYPE_I; break; //ZYGO default: return -1; } - skip_bits(&s->gb, 2); - s->no_rounding = get_bits1(&s->gb); - skip_bits(&s->gb, 4); + skip_bits(&h->gb, 2); + h->c.no_rounding = get_bits1(&h->gb); + skip_bits(&h->gb, 4); /* Get the picture dimensions */ if (ufep) { if (format == 6) { /* Custom Picture Format (CPFMT) */ - int aspect_ratio_info = get_bits(&s->gb, 4); - ff_dlog(s->avctx, "aspect: %d\n", aspect_ratio_info); + int aspect_ratio_info = get_bits(&h->gb, 4); + ff_dlog(h->c.avctx, "aspect: %d\n", aspect_ratio_info); /* aspect ratios: 0 - forbidden 1 - 1:1 @@ -1236,150 +1235,151 @@ int ff_h263_decode_picture_header(MpegEncContext *s) 5 - 40:33 (525-type 16:9) 6-14 - reserved */ - width = (get_bits(&s->gb, 9) + 1) * 4; - check_marker(s->avctx, &s->gb, "in dimensions"); - height = get_bits(&s->gb, 9) * 4; - ff_dlog(s->avctx, "\nH.263+ Custom picture: %dx%d\n",width,height); + width = (get_bits(&h->gb, 9) + 1) * 4; + check_marker(h->c.avctx, &h->gb, "in dimensions"); + height = get_bits(&h->gb, 9) * 4; + ff_dlog(h->c.avctx, "\nH.263+ Custom picture: %dx%d\n",width,height); if (aspect_ratio_info == FF_ASPECT_EXTENDED) { /* expected dimensions */ - s->avctx->sample_aspect_ratio.num= get_bits(&s->gb, 8); - s->avctx->sample_aspect_ratio.den= get_bits(&s->gb, 8); + h->c.avctx->sample_aspect_ratio.num = get_bits(&h->gb, 8); + h->c.avctx->sample_aspect_ratio.den = get_bits(&h->gb, 8); }else{ - s->avctx->sample_aspect_ratio= ff_h263_pixel_aspect[aspect_ratio_info]; + h->c.avctx->sample_aspect_ratio= ff_h263_pixel_aspect[aspect_ratio_info]; } } else { width = ff_h263_format[format][0]; height = ff_h263_format[format][1]; - s->avctx->sample_aspect_ratio= (AVRational){12,11}; + h->c.avctx->sample_aspect_ratio = (AVRational){12,11}; } - s->avctx->sample_aspect_ratio.den <<= s->ehc_mode; + h->c.avctx->sample_aspect_ratio.den <<= h->ehc_mode; if ((width == 0) || (height == 0)) return -1; - s->width = width; - s->height = height; + h->c.width = width; + h->c.height = height; - if(s->custom_pcf){ - int gcd; - s->avctx->framerate.num = 1800000; - s->avctx->framerate.den = 1000 + get_bits1(&s->gb); - s->avctx->framerate.den *= get_bits(&s->gb, 7); - if(s->avctx->framerate.den == 0){ - av_log(s, AV_LOG_ERROR, "zero framerate\n"); + if (h->custom_pcf) { + h->c.avctx->framerate.num = 1800000; + h->c.avctx->framerate.den = 1000 + get_bits1(&h->gb); + h->c.avctx->framerate.den *= get_bits(&h->gb, 7); + if (h->c.avctx->framerate.den == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "zero framerate\n"); return -1; } - gcd= av_gcd(s->avctx->framerate.den, s->avctx->framerate.num); - s->avctx->framerate.den /= gcd; - s->avctx->framerate.num /= gcd; + int gcd = av_gcd(h->c.avctx->framerate.den, h->c.avctx->framerate.num); + h->c.avctx->framerate.den /= gcd; + h->c.avctx->framerate.num /= gcd; }else{ - s->avctx->framerate = (AVRational){ 30000, 1001 }; + h->c.avctx->framerate = (AVRational){ 30000, 1001 }; } } - if(s->custom_pcf){ - skip_bits(&s->gb, 2); //extended Temporal reference - } + if (h->custom_pcf) + skip_bits(&h->gb, 2); //extended Temporal reference if (ufep) { - if (s->umvplus) { - if(get_bits1(&s->gb)==0) /* Unlimited Unrestricted Motion Vectors Indicator (UUI) */ - skip_bits1(&s->gb); + if (h->umvplus) { + if (get_bits1(&h->gb)==0) /* Unlimited Unrestricted Motion Vectors Indicator (UUI) */ + skip_bits1(&h->gb); } - if(s->h263_slice_structured){ - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "rectangular slices not supported\n"); + if (h->h263_slice_structured) { + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "rectangular slices not supported\n"); } - if (get_bits1(&s->gb) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "unordered slices not supported\n"); + if (get_bits1(&h->gb) != 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "unordered slices not supported\n"); } } - if (s->pict_type == AV_PICTURE_TYPE_B) { - skip_bits(&s->gb, 4); //ELNUM + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + skip_bits(&h->gb, 4); //ELNUM if (ufep == 1) { - skip_bits(&s->gb, 4); // RLNUM + skip_bits(&h->gb, 4); // RLNUM } } } - s->qscale = get_bits(&s->gb, 5); + h->c.qscale = get_bits(&h->gb, 5); } - if ((ret = av_image_check_size(s->width, s->height, 0, s)) < 0) + ret = av_image_check_size(h->c.width, h->c.height, 0, h->c.avctx); + if (ret < 0) return ret; - if (!(s->avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { - if ((s->width * s->height / 256 / 8) > get_bits_left(&s->gb)) + if (!(h->c.avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { + if ((h->c.width * h->c.height / 256 / 8) > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; } - s->mb_width = (s->width + 15) / 16; - s->mb_height = (s->height + 15) / 16; - s->mb_num = s->mb_width * s->mb_height; + h->c.mb_width = (h->c.width + 15U) / 16; + h->c.mb_height = (h->c.height + 15U) / 16; + h->c.mb_num = h->c.mb_width * h->c.mb_height; - if (s->pb_frame) { - skip_bits(&s->gb, 3); /* Temporal reference for B-pictures */ - if (s->custom_pcf) - skip_bits(&s->gb, 2); //extended Temporal reference - skip_bits(&s->gb, 2); /* Quantization information for B-pictures */ + h->gob_index = H263_GOB_HEIGHT(h->c.height); + + if (h->pb_frame) { + skip_bits(&h->gb, 3); /* Temporal reference for B-pictures */ + if (h->custom_pcf) + skip_bits(&h->gb, 2); //extended Temporal reference + skip_bits(&h->gb, 2); /* Quantization information for B-pictures */ } - if (s->pict_type!=AV_PICTURE_TYPE_B) { - s->time = s->picture_number; - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + if (h->c.pict_type!=AV_PICTURE_TYPE_B) { + h->c.time = h->picture_number; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; }else{ - s->time = s->picture_number; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); - if (s->pp_time <=s->pb_time || - s->pp_time <= s->pp_time - s->pb_time || - s->pp_time <= 0){ - s->pp_time = 2; - s->pb_time = 1; + h->c.time = h->picture_number; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); + if (h->c.pp_time <= h->c.pb_time || + h->c.pp_time <= h->c.pp_time - h->c.pb_time || + h->c.pp_time <= 0) { + h->c.pp_time = 2; + h->c.pb_time = 1; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); } /* PEI */ - if (skip_1stop_8data_bits(&s->gb) < 0) + if (skip_1stop_8data_bits(&h->gb) < 0) return AVERROR_INVALIDDATA; - if(s->h263_slice_structured){ - if (check_marker(s->avctx, &s->gb, "SEPB1") != 1) { + if (h->h263_slice_structured) { + if (check_marker(h->c.avctx, &h->gb, "SEPB1") != 1) { return -1; } - ff_h263_decode_mba(s); + ff_h263_decode_mba(h); - if (check_marker(s->avctx, &s->gb, "SEPB2") != 1) { + if (check_marker(h->c.avctx, &h->gb, "SEPB2") != 1) { return -1; } } - s->f_code = 1; - if (s->pict_type == AV_PICTURE_TYPE_B) - s->low_delay = 0; + if (h->c.pict_type == AV_PICTURE_TYPE_B) + h->c.low_delay = 0; - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; + if (h->c.h263_aic) { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_aic_dc_scale_table; }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; } - ff_h263_show_pict_info(s); - if (s->pict_type == AV_PICTURE_TYPE_I && s->codec_tag == AV_RL32("ZYGO") && get_bits_left(&s->gb) >= 85 + 13*3*16 + 50){ + ff_h263_show_pict_info(h, h263_plus); + + if (h->c.pict_type == AV_PICTURE_TYPE_I && h->c.codec_tag == AV_RL32("ZYGO") && get_bits_left(&h->gb) >= 85 + 13*3*16 + 50){ int i,j; - for(i=0; i<85; i++) av_log(s->avctx, AV_LOG_DEBUG, "%d", get_bits1(&s->gb)); - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + for(i=0; i<85; i++) av_log(h->c.avctx, AV_LOG_DEBUG, "%d", get_bits1(&h->gb)); + av_log(h->c.avctx, AV_LOG_DEBUG, "\n"); for(i=0; i<13; i++){ for(j=0; j<3; j++){ - int v= get_bits(&s->gb, 8); - v |= get_sbits(&s->gb, 8) * (1 << 8); - av_log(s->avctx, AV_LOG_DEBUG, " %5d", v); + int v= get_bits(&h->gb, 8); + v |= get_sbits(&h->gb, 8) * (1 << 8); + av_log(h->c.avctx, AV_LOG_DEBUG, " %5d", v); } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + av_log(h->c.avctx, AV_LOG_DEBUG, "\n"); } - for(i=0; i<50; i++) av_log(s->avctx, AV_LOG_DEBUG, "%d", get_bits1(&s->gb)); + for(i=0; i<50; i++) av_log(h->c.avctx, AV_LOG_DEBUG, "%d", get_bits1(&h->gb)); } return 0; diff --git a/libavcodec/ituh263enc.c b/libavcodec/ituh263enc.c index 8c41e45ab2..85008443da 100644 --- a/libavcodec/ituh263enc.c +++ b/libavcodec/ituh263enc.c @@ -30,13 +30,13 @@ #include "config_components.h" #include +#include #include "libavutil/attributes.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" #include "mpegvideo.h" -#include "mpegvideodata.h" #include "flvenc.h" #include "mpegvideoenc.h" #include "h263.h" @@ -46,17 +46,43 @@ #include "mathops.h" #include "mpegutils.h" #include "internal.h" +#include "put_bits.h" /** * Table of number of bits a motion vector component needs. */ static uint8_t mv_penalty[MAX_FCODE+1][MAX_DMV*2+1]; -/** - * Minimal fcode that a motion vector component would need. - */ -static uint8_t fcode_tab[MAX_MV*2+1]; +static av_cold void init_mv_penalty(void) +{ + for (int f_code = 1; f_code <= MAX_FCODE; f_code++) { + for (int mv = -MAX_DMV; mv <= MAX_DMV; mv++) { + int len; + if (mv == 0) len = 1; // ff_mvtab[0][1] + else { + int val, bit_size, code; + + bit_size = f_code - 1; + + val = mv; + if (val < 0) + val = -val; + val--; + code = (val >> bit_size) + 1; + if (code < 33) { + len = ff_mvtab[code][1] + 1 + bit_size; + } else { + len = 12 /* ff_mvtab[32][1] */ + av_log2(code>>5) + 2 + bit_size; + } + } + + mv_penalty[f_code][mv + MAX_DMV] = len; + } + } +} + +#if CONFIG_H263_ENCODER /** * Minimal fcode that a motion vector component would need in umv. * All entries in this table are 1. @@ -71,6 +97,89 @@ static uint8_t uni_h263_inter_rl_len [64*64*2*2]; //#define UNI_MPEG4_ENC_INDEX(last,run,level) ((last)*128*64 + (run) + (level)*64) #define UNI_MPEG4_ENC_INDEX(last,run,level) ((last)*128*64 + (run)*128 + (level)) +static av_cold void init_uni_h263_rl_tab(const RLTable *rl, uint8_t *len_tab) +{ + const uint16_t (*table_vlc)[2] = rl->table_vlc; + const uint8_t *table_run = rl->table_run; + const uint8_t *table_level = rl->table_level; + + av_assert0(MAX_LEVEL >= 64); + av_assert0(MAX_RUN >= 63); + + // Note: The LUT only covers level values for which the escape value + // is eight bits (not 8 + 5 + 6) + memset(len_tab, H263_ESCAPE_CODE_LENGTH + 1 + 6 + 8, + sizeof(uni_h263_intra_aic_rl_len)); + + len_tab += 64; // simplifies addressing + for (int i = 0; i < H263_RL_NB_ELEMS; ++i) { + int run = table_run[i]; + int level = table_level[i]; + int last = i >= H263_RL_NON_LAST_CODES; + int len = table_vlc[i][1]; + + len_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = + len_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = len + 1 /* sign */; + } + for (int run = 0; run < MAX_RUN; ++run) { + len_tab[UNI_MPEG4_ENC_INDEX(0, run, 0)] = + len_tab[UNI_MPEG4_ENC_INDEX(1, run, 0)] = 0; // is this necessary? + } +} +#endif + +static av_cold void h263_encode_init_static(void) +{ +#if CONFIG_H263_ENCODER + static uint8_t rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; + ff_rl_init(&ff_rl_intra_aic, rl_intra_table); + ff_h263_init_rl_inter(); + + init_uni_h263_rl_tab(&ff_rl_intra_aic, uni_h263_intra_aic_rl_len); + init_uni_h263_rl_tab(&ff_h263_rl_inter, uni_h263_inter_rl_len); + + memset(umv_fcode_tab, 1, sizeof(umv_fcode_tab)); +#endif + + init_mv_penalty(); +} + +av_cold const uint8_t (*ff_h263_get_mv_penalty(void))[MAX_DMV*2+1] +{ + static AVOnce init_static_once = AV_ONCE_INIT; + + ff_thread_once(&init_static_once, h263_encode_init_static); + + return mv_penalty; +} + +void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code) +{ + if (val == 0) { + /* zero vector -- corresponds to ff_mvtab[0] */ + put_bits(pb, 1, 1); + } else { + int sign, code, bits; + int bit_size = f_code - 1; + int range = 1 << bit_size; + /* modulo encoding */ + val = sign_extend(val, 6 + bit_size); + sign = val>>31; + val= (val^sign)-sign; + sign&=1; + + val--; + code = (val >> bit_size) + 1; + bits = val & (range - 1); + + put_bits(pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign); + if (bit_size > 0) { + put_bits(pb, bit_size, bits); + } + } +} + +#if CONFIG_H263_ENCODER // Snow and SVQ1 need the above static const uint8_t wrong_run[102] = { 1, 2, 3, 5, 4, 10, 9, 8, 11, 15, 17, 16, 23, 22, 21, 20, @@ -106,20 +215,23 @@ av_const int ff_h263_aspect_to_info(AVRational aspect){ return FF_ASPECT_EXTENDED; } -void ff_h263_encode_picture_header(MpegEncContext * s) +static int h263_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int format, coded_frame_rate, coded_frame_rate_base, i, temp_ref; int best_clock_code=1; int best_divisor=60; int best_error= INT_MAX; int custom_pcf; - if(s->h263_plus){ + put_bits_assume_flushed(&s->pb); + + if (s->c.codec_id == AV_CODEC_ID_H263P) { for(i=0; i<2; i++){ int div, error; - div= (s->avctx->time_base.num*1800000LL + 500LL*s->avctx->time_base.den) / ((1000LL+i)*s->avctx->time_base.den); + div= (s->c.avctx->time_base.num*1800000LL + 500LL*s->c.avctx->time_base.den) / ((1000LL+i)*s->c.avctx->time_base.den); div= av_clip(div, 1, 127); - error= FFABS(s->avctx->time_base.num*1800000LL - (1000LL+i)*s->avctx->time_base.den*div); + error= FFABS(s->c.avctx->time_base.num*1800000LL - (1000LL+i)*s->c.avctx->time_base.den*div); if(error < best_error){ best_error= error; best_divisor= div; @@ -131,13 +243,9 @@ void ff_h263_encode_picture_header(MpegEncContext * s) coded_frame_rate= 1800000; coded_frame_rate_base= (1000+best_clock_code)*best_divisor; - align_put_bits(&s->pb); - - /* Update the pointer to last GOB */ - s->ptr_lastgob = put_bits_ptr(&s->pb); put_bits(&s->pb, 22, 0x20); /* PSC */ - temp_ref= s->picture_number * (int64_t)coded_frame_rate * s->avctx->time_base.num / //FIXME use timestamp - (coded_frame_rate_base * (int64_t)s->avctx->time_base.den); + temp_ref = s->picture_number * (int64_t)coded_frame_rate * s->c.avctx->time_base.num / //FIXME use timestamp + (coded_frame_rate_base * (int64_t)s->c.avctx->time_base.den); put_sbits(&s->pb, 8, temp_ref); /* TemporalReference */ put_bits(&s->pb, 1, 1); /* marker */ @@ -146,19 +254,19 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb, 1, 0); /* camera off */ put_bits(&s->pb, 1, 0); /* freeze picture release off */ - format = ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), s->width, s->height); - if (!s->h263_plus) { + format = ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), s->c.width, s->c.height); + if (s->c.codec_id != AV_CODEC_ID_H263P) { /* H.263v1 */ put_bits(&s->pb, 3, format); - put_bits(&s->pb, 1, (s->pict_type == AV_PICTURE_TYPE_P)); + put_bits(&s->pb, 1, (s->c.pict_type == AV_PICTURE_TYPE_P)); /* By now UMV IS DISABLED ON H.263v1, since the restrictions of H.263v1 UMV implies to check the predicted MV after calculation of the current MB to see if we're on the limits */ put_bits(&s->pb, 1, 0); /* Unrestricted Motion Vector: off */ put_bits(&s->pb, 1, 0); /* SAC: off */ - put_bits(&s->pb, 1, s->obmc); /* Advanced Prediction */ + put_bits(&s->pb, 1, s->c.obmc); /* Advanced Prediction */ put_bits(&s->pb, 1, 0); /* only I/P-frames, no PB-frame */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); put_bits(&s->pb, 1, 0); /* Continuous Presence Multipoint mode: off */ } else { int ufep=1; @@ -175,8 +283,8 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb,1, custom_pcf); put_bits(&s->pb,1, s->umvplus); /* Unrestricted Motion Vector */ put_bits(&s->pb,1,0); /* SAC: off */ - put_bits(&s->pb,1,s->obmc); /* Advanced Prediction Mode */ - put_bits(&s->pb,1,s->h263_aic); /* Advanced Intra Coding */ + put_bits(&s->pb,1,s->c.obmc); /* Advanced Prediction Mode */ + put_bits(&s->pb,1,s->c.h263_aic); /* Advanced Intra Coding */ put_bits(&s->pb,1,s->loop_filter); /* Deblocking Filter */ put_bits(&s->pb,1,s->h263_slice_structured); /* Slice Structured */ put_bits(&s->pb,1,0); /* Reference Picture Selection: off */ @@ -186,11 +294,11 @@ void ff_h263_encode_picture_header(MpegEncContext * s) put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ put_bits(&s->pb,3,0); /* Reserved */ - put_bits(&s->pb, 3, s->pict_type == AV_PICTURE_TYPE_P); + put_bits(&s->pb, 3, s->c.pict_type == AV_PICTURE_TYPE_P); put_bits(&s->pb,1,0); /* Reference Picture Resampling: off */ put_bits(&s->pb,1,0); /* Reduced-Resolution Update: off */ - put_bits(&s->pb,1,s->no_rounding); /* Rounding Type */ + put_bits(&s->pb,1,s->c.no_rounding); /* Rounding Type */ put_bits(&s->pb,2,0); /* Reserved */ put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ @@ -199,15 +307,15 @@ void ff_h263_encode_picture_header(MpegEncContext * s) if (format == 8) { /* Custom Picture Format (CPFMT) */ - unsigned aspect_ratio_info = ff_h263_aspect_to_info(s->avctx->sample_aspect_ratio); + unsigned aspect_ratio_info = ff_h263_aspect_to_info(s->c.avctx->sample_aspect_ratio); put_bits(&s->pb,4, aspect_ratio_info); - put_bits(&s->pb,9,(s->width >> 2) - 1); + put_bits(&s->pb,9,(s->c.width >> 2) - 1); put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */ - put_bits(&s->pb,9,(s->height >> 2)); + put_bits(&s->pb,9,(s->c.height >> 2)); if (aspect_ratio_info == FF_ASPECT_EXTENDED){ - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.num); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.den); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.num); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.den); } } if (custom_pcf) { @@ -223,71 +331,90 @@ void ff_h263_encode_picture_header(MpegEncContext * s) // put_bits(&s->pb,1,1); /* Limited according tables of Annex D */ //FIXME check actual requested range put_bits(&s->pb,2,1); /* unlimited */ - if(s->h263_slice_structured) + if (s->h263_slice_structured) put_bits(&s->pb,2,0); /* no weird submodes */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); } put_bits(&s->pb, 1, 0); /* no PEI */ - if(s->h263_slice_structured){ + if (s->h263_slice_structured) { put_bits(&s->pb, 1, 1); - av_assert1(s->mb_x == 0 && s->mb_y == 0); + av_assert1(s->c.mb_x == 0 && s->c.mb_y == 0); ff_h263_encode_mba(s); put_bits(&s->pb, 1, 1); } + + return 0; +} + +void ff_h263_mpeg4_reset_dc(MPVEncContext *s) +{ + int16_t *dc = s->c.dc_val; + + // The "- 1" is for the top-left entry + const int l_xy = s->c.block_index[2]; + for (int i = l_xy - 2 * s->c.b8_stride - 1; i < l_xy; i += 2) + AV_WN32A(dc + i, 1024 << 16 | 1024); + + const int u_xy = s->c.block_index[4]; + const int v_xy = s->c.block_index[5]; + int16_t *dc2 = dc + v_xy - u_xy; + for (int i = u_xy - s->c.mb_stride - 1; i < u_xy; ++i) + dc[i] = dc2[i] = 1024; } /** * Encode a group of blocks header. */ -void ff_h263_encode_gob_header(MpegEncContext * s, int mb_line) +void ff_h263_encode_gob_header(MPVEncContext *const s, int mb_line) { put_bits(&s->pb, 17, 1); /* GBSC */ - if(s->h263_slice_structured){ + if (s->h263_slice_structured) { put_bits(&s->pb, 1, 1); ff_h263_encode_mba(s); - if(s->mb_num > 1583) + if(s->c.mb_num > 1583) put_bits(&s->pb, 1, 1); - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ put_bits(&s->pb, 1, 1); - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_I); /* GFID */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_I); /* GFID */ }else{ - int gob_number= mb_line / s->gob_index; + int gob_number = mb_line / s->gob_index; put_bits(&s->pb, 5, gob_number); /* GN */ - put_bits(&s->pb, 2, s->pict_type == AV_PICTURE_TYPE_I); /* GFID */ - put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + put_bits(&s->pb, 2, s->c.pict_type == AV_PICTURE_TYPE_I); /* GFID */ + put_bits(&s->pb, 5, s->c.qscale); /* GQUANT */ } } /** * modify qscale so that encoding is actually possible in H.263 (limit difference to -2..2) */ -void ff_clean_h263_qscales(MpegEncContext *s){ - int i; - int8_t * const qscale_table = s->cur_pic.qscale_table; +void ff_clean_h263_qscales(MPVEncContext *const s) +{ + int8_t * const qscale_table = s->c.cur_pic.qscale_table; - for(i=1; imb_num; i++){ - if(qscale_table[ s->mb_index2xy[i] ] - qscale_table[ s->mb_index2xy[i-1] ] >2) - qscale_table[ s->mb_index2xy[i] ]= qscale_table[ s->mb_index2xy[i-1] ]+2; + for (int i = 1; i < s->c.mb_num; i++) { + if (qscale_table[ s->c.mb_index2xy[i] ] - qscale_table[ s->c.mb_index2xy[i-1] ] > 2) + qscale_table[ s->c.mb_index2xy[i] ] = qscale_table[ s->c.mb_index2xy[i-1] ] + 2; } - for(i=s->mb_num-2; i>=0; i--){ - if(qscale_table[ s->mb_index2xy[i] ] - qscale_table[ s->mb_index2xy[i+1] ] >2) - qscale_table[ s->mb_index2xy[i] ]= qscale_table[ s->mb_index2xy[i+1] ]+2; + for(int i = s->c.mb_num - 2; i >= 0; i--) { + if (qscale_table[ s->c.mb_index2xy[i] ] - qscale_table[ s->c.mb_index2xy[i+1] ] > 2) + qscale_table[ s->c.mb_index2xy[i] ] = qscale_table[ s->c.mb_index2xy[i+1] ] + 2; } - if(s->codec_id != AV_CODEC_ID_H263P){ - for(i=1; imb_num; i++){ - int mb_xy= s->mb_index2xy[i]; + if (s->c.codec_id != AV_CODEC_ID_H263P) { + for (int i = 1; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; - if(qscale_table[mb_xy] != qscale_table[s->mb_index2xy[i-1]] && (s->mb_type[mb_xy]&CANDIDATE_MB_TYPE_INTER4V)){ + if (qscale_table[mb_xy] != qscale_table[s->c.mb_index2xy[i - 1]] && + (s->mb_type[mb_xy] & CANDIDATE_MB_TYPE_INTER4V)) { s->mb_type[mb_xy]|= CANDIDATE_MB_TYPE_INTER; } } @@ -296,18 +423,40 @@ void ff_clean_h263_qscales(MpegEncContext *s){ static const int dquant_code[5]= {1,0,9,2,3}; +static void flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, + int run, int last) +{ + unsigned code; + int bits; + if (level < 64) { // 7-bit level + bits = 1 + 1 + 6 + 7; + code = (0 << (1 + 6 + 7)) | + (last << (6 + 7)) | + (run << 7) | + (slevel & 0x7f); + } else { + /* 11-bit level */ + bits = 1 + 1 + 6 + 11; + code = (1 << (1 + 6 + 11)) | + (last << (6 + 11)) | + (run << 11) | + (slevel & 0x7ff); + } + put_bits(pb, bits, code); +} + /** * Encode an 8x8 block. * @param block the 8x8 block * @param n block index (0-3 are luma, 4-5 are chroma) */ -static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) +static void h263_encode_block(MPVEncContext *const s, int16_t block[], int n) { int level, run, last, i, j, last_index, last_non_zero, sign, slevel, code; const RLTable *rl; rl = &ff_h263_rl_inter; - if (s->mb_intra && !s->h263_aic) { + if (s->c.mb_intra && !s->c.h263_aic) { /* DC coef */ level = block[0]; /* 255 cannot be represented, so we clamp */ @@ -327,19 +476,19 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) i = 1; } else { i = 0; - if (s->h263_aic && s->mb_intra) + if (s->c.h263_aic && s->c.mb_intra) rl = &ff_rl_intra_aic; - if(s->alt_inter_vlc && !s->mb_intra){ + if (s->alt_inter_vlc && !s->c.mb_intra) { int aic_vlc_bits=0; int inter_vlc_bits=0; int wrong_pos=-1; int aic_code; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -370,10 +519,10 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) } /* AC coefs */ - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; if (level) { run = i - last_non_zero - 1; @@ -387,22 +536,22 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) code = get_rl_index(rl, last, run, level); put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); if (code == rl->n) { - if(!CONFIG_FLV_ENCODER || s->h263_flv <= 1){ - put_bits(&s->pb, 1, last); - put_bits(&s->pb, 6, run); + if (!CONFIG_FLV_ENCODER || s->c.codec_id != AV_CODEC_ID_FLV1) { + put_bits(&s->pb, 1, last); + put_bits(&s->pb, 6, run); - av_assert2(slevel != 0); + av_assert2(slevel != 0); - if(level < 128) - put_sbits(&s->pb, 8, slevel); - else{ - put_bits(&s->pb, 8, 128); - put_sbits(&s->pb, 5, slevel); - put_sbits(&s->pb, 6, slevel>>5); + if (level < 128) { + put_sbits(&s->pb, 8, slevel); + } else { + put_bits(&s->pb, 8, 128); + put_sbits(&s->pb, 5, slevel); + put_sbits(&s->pb, 6, slevel>>5); + } + } else { + flv2_encode_ac_esc(&s->pb, slevel, level, run, last); } - }else{ - ff_flv2_encode_ac_esc(&s->pb, slevel, level, run, last); - } } else { put_bits(&s->pb, 1, sign); } @@ -414,69 +563,37 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) /* Encode MV differences on H.263+ with Unrestricted MV mode */ static void h263p_encode_umotion(PutBitContext *pb, int val) { - short sval = 0; - short i = 0; - short n_bits = 0; - short temp_val; - int code = 0; - int tcode; - if ( val == 0) put_bits(pb, 1, 1); - else if (val == 1) - put_bits(pb, 3, 0); - else if (val == -1) - put_bits(pb, 3, 2); else { + unsigned code = (val < 0) << 1; + unsigned aval = val < 0 ? -val : val; + unsigned n_bits = 2; - sval = ((val < 0) ? (short)(-val):(short)val); - temp_val = sval; - - while (temp_val != 0) { - temp_val = temp_val >> 1; - n_bits++; + while (aval != 1) { // The leading digit is implicitly coded via length + unsigned tmp = (aval & 1) << 1 | 1; + aval >>= 1; + code |= tmp << n_bits; + n_bits += 2; } - - i = n_bits - 1; - while (i > 0) { - tcode = (sval & (1 << (i-1))) >> (i-1); - tcode = (tcode << 1) | 1; - code = (code << 2) | tcode; - i--; - } - code = ((code << 1) | (val < 0)) << 1; - put_bits(pb, (2*n_bits)+1, code); + put_bits(pb, n_bits + 1, code); } } -static int h263_pred_dc(MpegEncContext * s, int n, int16_t **dc_val_ptr) +static int h263_pred_dc(MPVEncContext *const s, int n, int16_t **dc_val_ptr) { - int x, y, wrap, a, c, pred_dc; - int16_t *dc_val; + const int wrap = s->c.block_wrap[n]; + const int xy = s->c.block_index[n]; + int16_t *const dc_val = s->c.dc_val + xy; + int pred_dc; /* find prediction */ - if (n < 4) { - x = 2 * s->mb_x + (n & 1); - y = 2 * s->mb_y + ((n & 2) >> 1); - wrap = s->b8_stride; - dc_val = s->dc_val[0]; - } else { - x = s->mb_x; - y = s->mb_y; - wrap = s->mb_stride; - dc_val = s->dc_val[n - 4 + 1]; - } /* B C * A X */ - a = dc_val[(x - 1) + (y) * wrap]; - c = dc_val[(x) + (y - 1) * wrap]; + int a = dc_val[-1]; + int c = dc_val[-wrap]; - /* No prediction outside GOB boundary */ - if (s->first_slice_line && n != 3) { - if (n != 2) c = 1024; - if (n != 1 && s->mb_x == s->resync_mb_x) a = 1024; - } /* just DC prediction */ if (a != 1024 && c != 1024) pred_dc = (a + c) >> 1; @@ -486,25 +603,24 @@ static int h263_pred_dc(MpegEncContext * s, int n, int16_t **dc_val_ptr) pred_dc = c; /* we assume pred is positive */ - *dc_val_ptr = &dc_val[x + y * wrap]; + *dc_val_ptr = dc_val; return pred_dc; } -void ff_h263_encode_mb(MpegEncContext * s, - int16_t block[6][64], - int motion_x, int motion_y) +static void h263_encode_mb(MPVEncContext *const s, + int16_t block[][64], + int motion_x, int motion_y) { int cbpc, cbpy, i, cbp, pred_x, pred_y; int16_t pred_dc; int16_t rec_intradc[6]; - int16_t *dc_ptr[6]; - const int interleaved_stats = s->avctx->flags & AV_CODEC_FLAG_PASS1; + const int interleaved_stats = s->c.avctx->flags & AV_CODEC_FLAG_PASS1; - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ cbp= get_p_cbp(s, block, motion_x, motion_y); - if ((cbp | motion_x | motion_y | s->dquant | (s->mv_type - MV_TYPE_16X16)) == 0) { + if ((cbp | motion_x | motion_y | s->dquant | (s->c.mv_type - MV_TYPE_16X16)) == 0) { /* skip macroblock */ put_bits(&s->pb, 1, 1); if(interleaved_stats){ @@ -518,10 +634,10 @@ void ff_h263_encode_mb(MpegEncContext * s, cbpc = cbp & 3; cbpy = cbp >> 2; - if(s->alt_inter_vlc==0 || cbpc!=3) + if (!s->alt_inter_vlc || cbpc!=3) cbpy ^= 0xF; if(s->dquant) cbpc+= 8; - if(s->mv_type==MV_TYPE_16X16){ + if(s->c.mv_type==MV_TYPE_16X16){ put_bits(&s->pb, ff_h263_inter_MCBPC_bits[cbpc], ff_h263_inter_MCBPC_code[cbpc]); @@ -535,7 +651,7 @@ void ff_h263_encode_mb(MpegEncContext * s, } /* motion vectors: 16x16 mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); if (!s->umvplus) { ff_h263_encode_motion_vector(s, motion_x - pred_x, @@ -562,10 +678,10 @@ void ff_h263_encode_mb(MpegEncContext * s, for(i=0; i<4; i++){ /* motion vectors: 8x8 mode*/ - ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, i, 0, &pred_x, &pred_y); - motion_x = s->cur_pic.motion_val[0][s->block_index[i]][0]; - motion_y = s->cur_pic.motion_val[0][s->block_index[i]][1]; + motion_x = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + motion_y = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; if (!s->umvplus) { ff_h263_encode_motion_vector(s, motion_x - pred_x, motion_y - pred_y, 1); @@ -584,19 +700,17 @@ void ff_h263_encode_mb(MpegEncContext * s, s->mv_bits+= get_bits_diff(s); } } else { - av_assert2(s->mb_intra); + av_assert2(s->c.mb_intra); cbp = 0; - if (s->h263_aic) { + if (s->c.h263_aic) { /* Predict DC */ for(i=0; i<6; i++) { int16_t level = block[i][0]; - int scale; + int16_t *dc_ptr; + int scale = i < 4 ? s->c.y_dc_scale : s->c.c_dc_scale; - if(i<4) scale= s->y_dc_scale; - else scale= s->c_dc_scale; - - pred_dc = h263_pred_dc(s, i, &dc_ptr[i]); + pred_dc = h263_pred_dc(s, i, &dc_ptr); level -= pred_dc; /* Quant */ if (level >= 0) @@ -604,7 +718,7 @@ void ff_h263_encode_mb(MpegEncContext * s, else level = (level - (scale>>1))/scale; - if(!s->modified_quant){ + if (!s->modified_quant) { if (level < -127) level = -127; else if (level > 127) @@ -625,22 +739,22 @@ void ff_h263_encode_mb(MpegEncContext * s, rec_intradc[i] = 2047; /* Update AC/DC tables */ - *dc_ptr[i] = rec_intradc[i]; + *dc_ptr = rec_intradc[i]; /* AIC can change CBP */ - if (s->block_last_index[i] > 0 || - (s->block_last_index[i] == 0 && level !=0)) + if (s->c.block_last_index[i] > 0 || + (s->c.block_last_index[i] == 0 && level !=0)) cbp |= 1 << (5 - i); } }else{ for(i=0; i<6; i++) { /* compute cbp */ - if (s->block_last_index[i] >= 1) + if (s->c.block_last_index[i] >= 1) cbp |= 1 << (5 - i); } } cbpc = cbp & 3; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if(s->dquant) cbpc+=4; put_bits(&s->pb, ff_h263_intra_MCBPC_bits[cbpc], @@ -652,7 +766,7 @@ void ff_h263_encode_mb(MpegEncContext * s, ff_h263_inter_MCBPC_bits[cbpc + 4], ff_h263_inter_MCBPC_code[cbpc + 4]); } - if (s->h263_aic) { + if (s->c.h263_aic) { /* XXX: currently, we do not try to use ac prediction */ put_bits(&s->pb, 1, 0); /* no AC prediction */ } @@ -671,14 +785,12 @@ void ff_h263_encode_mb(MpegEncContext * s, h263_encode_block(s, block[i], i); /* Update INTRADC for decoding */ - if (s->h263_aic && s->mb_intra) { + if (s->c.h263_aic && s->c.mb_intra) block[i][0] = rec_intradc[i]; - - } } if(interleaved_stats){ - if (!s->mb_intra) { + if (!s->c.mb_intra) { s->p_tex_bits+= get_bits_diff(s); }else{ s->i_tex_bits+= get_bits_diff(s); @@ -687,169 +799,57 @@ void ff_h263_encode_mb(MpegEncContext * s, } } -void ff_h263_update_mb(MpegEncContext *s) +void ff_h263_update_mb(MPVEncContext *const s) { - const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + const int mb_xy = s->c.mb_y * s->c.mb_stride + s->c.mb_x; - if (s->cur_pic.mbskip_table) - s->cur_pic.mbskip_table[mb_xy] = s->mb_skipped; + if (s->c.cur_pic.mbskip_table) + s->c.cur_pic.mbskip_table[mb_xy] = s->c.mb_skipped; - if (s->mv_type == MV_TYPE_8X8) - s->cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_8x8; - else if(s->mb_intra) - s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA; + if (s->c.mv_type == MV_TYPE_8X8) + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_8x8; + else if(s->c.mb_intra) + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA; else - s->cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; + s->c.cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; - ff_h263_update_motion_val(s); + ff_h263_update_motion_val(&s->c); } -void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code) +av_cold void ff_h263_encode_init(MPVMainEncContext *const m) { - int range, bit_size, sign, code, bits; + MPVEncContext *const s = &m->s; - if (val == 0) { - /* zero vector -- corresponds to ff_mvtab[0] */ - put_bits(pb, 1, 1); - } else { - bit_size = f_code - 1; - range = 1 << bit_size; - /* modulo encoding */ - val = sign_extend(val, 6 + bit_size); - sign = val>>31; - val= (val^sign)-sign; - sign&=1; + s->me.mv_penalty = ff_h263_get_mv_penalty(); // FIXME exact table for MSMPEG4 & H.263+ - val--; - code = (val >> bit_size) + 1; - bits = val & (range - 1); + ff_h263dsp_init(&s->c.h263dsp); - put_bits(pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign); - if (bit_size > 0) { - put_bits(pb, bit_size, bits); - } - } -} - -static av_cold void init_mv_penalty_and_fcode(void) -{ - int f_code; - int mv; - - for(f_code=1; f_code<=MAX_FCODE; f_code++){ - for(mv=-MAX_DMV; mv<=MAX_DMV; mv++){ - int len; - - if (mv==0) len = 1; // ff_mvtab[0][1] - else{ - int val, bit_size, code; - - bit_size = f_code - 1; - - val=mv; - if (val < 0) - val = -val; - val--; - code = (val >> bit_size) + 1; - if(code<33){ - len= ff_mvtab[code][1] + 1 + bit_size; - }else{ - len = 12 /* ff_mvtab[32][1] */ + av_log2(code>>5) + 2 + bit_size; - } - } - - mv_penalty[f_code][mv+MAX_DMV]= len; - } - } - - for(f_code=MAX_FCODE; f_code>0; f_code--){ - for(mv=-(16<= 64); - av_assert0(MAX_RUN >= 63); - - for(slevel=-64; slevel<64; slevel++){ - if(slevel==0) continue; - for(run=0; run<64; run++){ - for(last=0; last<=1; last++){ - const int index= UNI_MPEG4_ENC_INDEX(last, run, slevel+64); - int level= slevel < 0 ? -slevel : slevel; - int sign= slevel < 0 ? 1 : 0; - int bits, len, code; - - len_tab[index]= 100; - - /* ESC0 */ - code= get_rl_index(rl, last, run, level); - bits= rl->table_vlc[code][0]; - len= rl->table_vlc[code][1]; - bits=bits*2+sign; len++; - - if (code != rl->n && len < len_tab[index]) - len_tab [index]= len; - - /* ESC */ - bits= rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits=bits*2+last; len++; - bits=bits*64+run; len+=6; - bits=bits*256+(level&0xff); len+=8; - - if (len < len_tab[index]) - len_tab [index]= len; - } - } - } -} - -static av_cold void h263_encode_init_static(void) -{ - static uint8_t rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; - - ff_rl_init(&ff_rl_intra_aic, rl_intra_table); - ff_h263_init_rl_inter(); - - init_uni_h263_rl_tab(&ff_rl_intra_aic, uni_h263_intra_aic_rl_len); - init_uni_h263_rl_tab(&ff_h263_rl_inter, uni_h263_inter_rl_len); - - init_mv_penalty_and_fcode(); -} - -av_cold void ff_h263_encode_init(MpegEncContext *s) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - - s->me.mv_penalty= mv_penalty; // FIXME exact table for MSMPEG4 & H.263+ + if (s->c.codec_id == AV_CODEC_ID_MPEG4) + return; s->intra_ac_vlc_length =s->inter_ac_vlc_length = uni_h263_inter_rl_len; s->intra_ac_vlc_last_length=s->inter_ac_vlc_last_length= uni_h263_inter_rl_len + 128*64; - if(s->h263_aic){ + if (s->c.h263_aic) { s->intra_ac_vlc_length = uni_h263_intra_aic_rl_len; s->intra_ac_vlc_last_length= uni_h263_intra_aic_rl_len + 128*64; + + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_aic_dc_scale_table; } s->ac_esc_length= 7+1+6+8; + if (s->modified_quant) + s->c.chroma_qscale_table = ff_h263_chroma_qscale_table; + + // Only used for H.263 and H.263+ + s->gob_index = H263_GOB_HEIGHT(s->c.height); + // use fcodes >1 only for MPEG-4 & H.263 & H.263+ FIXME - switch(s->codec_id){ - case AV_CODEC_ID_MPEG4: - s->fcode_tab= fcode_tab; - break; + switch(s->c.codec_id){ case AV_CODEC_ID_H263P: - if(s->umvplus) - s->fcode_tab= umv_fcode_tab; - if(s->modified_quant){ + if (s->umvplus) + m->fcode_tab = umv_fcode_tab + MAX_MV; + if (s->modified_quant) { s->min_qcoeff= -2047; s->max_qcoeff= 2047; }else{ @@ -858,42 +858,33 @@ av_cold void ff_h263_encode_init(MpegEncContext *s) } break; // Note for MPEG-4 & H.263 the dc-scale table will be set per frame as needed later +#if CONFIG_FLV_ENCODER case AV_CODEC_ID_FLV1: - if (s->h263_flv > 1) { - s->min_qcoeff= -1023; - s->max_qcoeff= 1023; - } else { - s->min_qcoeff= -127; - s->max_qcoeff= 127; - } + m->encode_picture_header = ff_flv_encode_picture_header; + /* format = 1; 11-bit codes */ + s->min_qcoeff = -1023; + s->max_qcoeff = 1023; break; +#endif default: //nothing needed - default table already set in mpegvideo.c s->min_qcoeff= -127; s->max_qcoeff= 127; } - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; - }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; - } - -#if CONFIG_H263_ENCODER // Snow and SVQ1 call this - ff_h263dsp_init(&s->h263dsp); -#endif - - ff_thread_once(&init_static_once, h263_encode_init_static); + // H.263, H.263+; will be overwritten for MSMPEG-4 later + if (!m->encode_picture_header) + m->encode_picture_header = h263_encode_picture_header; + if (!s->encode_mb) + s->encode_mb = h263_encode_mb; } -void ff_h263_encode_mba(MpegEncContext *s) +void ff_h263_encode_mba(MPVEncContext *const s) { int i, mb_pos; for(i=0; i<6; i++){ - if(s->mb_num-1 <= ff_mba_max[i]) break; + if(s->c.mb_num-1 <= ff_mba_max[i]) break; } - mb_pos= s->mb_x + s->mb_width*s->mb_y; + mb_pos= s->c.mb_x + s->c.mb_width*s->c.mb_y; put_bits(&s->pb, ff_mba_length[i], mb_pos); } @@ -901,7 +892,7 @@ void ff_h263_encode_mba(MpegEncContext *s) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption h263_options[] = { { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "mb_info", "emit macroblock info for RFC 2190 packetization, the parameter value is the maximum payload size", OFFSET(mb_info), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "mb_info", "emit macroblock info for RFC 2190 packetization, the parameter value is the maximum payload size", FF_MPV_OFFSET(mb_info), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, FF_MPV_COMMON_OPTS FF_MPV_COMMON_MOTION_EST_OPTS { NULL }, @@ -919,22 +910,22 @@ const FFCodec ff_h263_encoder = { CODEC_LONG_NAME("H.263 / H.263-1996"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263, - .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, }; static const AVOption h263p_options[] = { - { "umv", "Use unlimited motion vectors.", OFFSET(umvplus), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "aiv", "Use alternative inter VLC.", OFFSET(alt_inter_vlc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "umv", "Use unlimited motion vectors.", FF_MPV_OFFSET(umvplus), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "aiv", "Use alternative inter VLC.", FF_MPV_OFFSET(alt_inter_vlc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "structured_slices", "Write slice start position at every GOB header instead of just GOB number.", OFFSET(h263_slice_structured), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "structured_slices", "Write slice start position at every GOB header instead of just GOB number.", FF_MPV_OFFSET(h263_slice_structured), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, FF_MPV_COMMON_OPTS FF_MPV_COMMON_MOTION_EST_OPTS { NULL }, @@ -951,13 +942,15 @@ const FFCodec ff_h263p_encoder = { CODEC_LONG_NAME("H.263+ / H.263-1998 / H.263 version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_H263P, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263p_class, - .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, }; +#endif diff --git a/libavcodec/itut35.h b/libavcodec/itut35.h index a75ef37929..b8987d0b01 100644 --- a/libavcodec/itut35.h +++ b/libavcodec/itut35.h @@ -23,10 +23,21 @@ #define ITU_T_T35_COUNTRY_CODE_UK 0xB4 #define ITU_T_T35_COUNTRY_CODE_US 0xB5 -#define ITU_T_T35_PROVIDER_CODE_ATSC 0x31 -#define ITU_T_T35_PROVIDER_CODE_CUVA 0x04 -#define ITU_T_T35_PROVIDER_CODE_DOLBY 0x3B -#define ITU_T_T35_PROVIDER_CODE_LCEVC 0x50 -#define ITU_T_T35_PROVIDER_CODE_SMTPE 0x3C +// The Terminal Provider Code (or "Manufacturer Code") identifies the +// manufacturer within a country. An Assignment Authority appointed by the +// national body assigns this code nationally. The manufacturer code is always +// used in conjunction with a country code. +// - CN providers +#define ITU_T_T35_PROVIDER_CODE_HDR_VIVID 0x0004 +// - UK providers +// V-Nova should be 0x5000 according to UK Register of Manufacturer Codes +// https://www.cix.co.uk/~bpechey/H221/h221code.htm +// but FFmpeg has been using 0x0050 +#define ITU_T_T35_PROVIDER_CODE_VNOVA 0x0050 +// - US providers +#define ITU_T_T35_PROVIDER_CODE_ATSC 0x0031 +#define ITU_T_T35_PROVIDER_CODE_DOLBY 0x003B +#define ITU_T_T35_PROVIDER_CODE_AOM 0x5890 +#define ITU_T_T35_PROVIDER_CODE_SAMSUNG 0x003C #endif /* AVCODEC_ITUT35_H */ diff --git a/libavcodec/ivi.c b/libavcodec/ivi.c index e7d8d10c3e..a38f382d5f 100644 --- a/libavcodec/ivi.c +++ b/libavcodec/ivi.c @@ -994,9 +994,11 @@ static int decode_band(IVI45DecContext *ctx, for (t = 0; t < band->num_tiles; t++) { tile = &band->tiles[t]; - if (tile->mb_size != band->mb_size) { - av_log(avctx, AV_LOG_ERROR, "MB sizes mismatch: %d vs. %d\n", - band->mb_size, tile->mb_size); + if (tile->mb_size != band->mb_size || + ctx->planes[0].bands[0].mb_size < band->mb_size + ) { + av_log(avctx, AV_LOG_ERROR, "MB sizes mismatch: %d vs. %d vs. %d\n", + band->mb_size, tile->mb_size, ctx->planes[0].bands[0].mb_size); return AVERROR_INVALIDDATA; } tile->is_empty = get_bits1(&ctx->gb); diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 60cc0f3093..847358dc7b 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -1268,7 +1268,7 @@ static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2 static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) { - int precno, compno, reslevelno, bandno, cblkno, lev, passno, layno; + int precno, compno, reslevelno, bandno, cblkno, passno, layno; int i; double min = DBL_MAX; double max = 0; @@ -1279,7 +1279,7 @@ static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) for (compno = 0; compno < s->ncomponents; compno++){ Jpeg2000Component *comp = tile->comp + compno; - for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){ + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){ Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ @@ -1726,7 +1726,7 @@ static av_cold int j2kenc_init(AVCodecContext *avctx) s->avctx = avctx; av_log(s->avctx, AV_LOG_DEBUG, "init\n"); if (parse_layer_rates(s)) { - av_log(s, AV_LOG_WARNING, "Layer rates invalid. Encoding with 1 layer based on quality metric.\n"); + av_log(avctx, AV_LOG_WARNING, "Layer rates invalid. Encoding with 1 layer based on quality metric.\n"); s->nlayers = 1; s->layer_rates[0] = 0; s->compression_rate_enc = 0; @@ -1802,7 +1802,7 @@ static int j2kenc_destroy(AVCodecContext *avctx) return 0; } -// taken from the libopenjpeg wraper so it matches +// taken from the libopenjpeg wrapper so it matches #define OFFSET(x) offsetof(Jpeg2000EncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM @@ -1845,7 +1845,7 @@ const FFCodec ff_jpeg2000_encoder = { .init = j2kenc_init, FF_CODEC_ENCODE_CB(encode_frame), .close = j2kenc_destroy, - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48, AV_PIX_FMT_GBR24P,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_GRAY14, AV_PIX_FMT_GRAY16, @@ -1862,9 +1862,7 @@ const FFCodec ff_jpeg2000_encoder = { AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P16, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_PAL8), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &j2k_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index d6ffb02319..6433e13892 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" @@ -260,9 +261,7 @@ static void init_band_stepsize(AVCodecContext *avctx, band->f_stepsize *= F_LFTG_X * F_LFTG_X * 4; break; } - if (codsty->transform == FF_DWT97) { - band->f_stepsize *= pow(F_LFTG_K, 2*(codsty->nreslevels2decode - reslevelno) + lband - 2); - } + band->f_stepsize *= pow(F_LFTG_K, 2*(codsty->nreslevels2decode - reslevelno) + lband - 2); } if (band->f_stepsize > (INT_MAX >> 15)) { @@ -270,12 +269,7 @@ static void init_band_stepsize(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "stepsize out of range\n"); } - band->i_stepsize = band->f_stepsize * (1 << 15); - - /* FIXME: In OpenJPEG code stepsize = stepsize * 0.5. Why? - * If not set output of entropic decoder is not correct. */ - if (!av_codec_is_encoder(avctx->codec)) - band->f_stepsize *= 0.5; + band->i_stepsize = (int)floorf(band->f_stepsize * (1 << 15)); } static int init_prec(AVCodecContext *avctx, diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 2e09b279dc..221ba87305 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -271,6 +271,25 @@ static int get_siz(Jpeg2000DecoderContext *s) return AVERROR_INVALIDDATA; } + for (i = 0; i < s->ncomponents; i++) { + if (s->cdef[i] < 0) { + for (i = 0; i < s->ncomponents; i++) { + s->cdef[i] = i + 1; + } + if ((s->ncomponents & 1) == 0) + s->cdef[s->ncomponents-1] = 0; + } + } + // after here we no longer have to consider negative cdef + + int cdef_used = 0; + for (i = 0; i < s->ncomponents; i++) + cdef_used |= 1<cdef[i]; + + // Check that the channels we have are what we expect for the number of components + if (cdef_used != ((int[]){0,2,3,14,15})[s->ncomponents]) + return AVERROR_INVALIDDATA; + for (i = 0; i < s->ncomponents; i++) { // Ssiz_i XRsiz_i, YRsiz_i uint8_t x = bytestream2_get_byteu(&s->g); s->cbps[i] = (x & 0x7f) + 1; @@ -283,7 +302,9 @@ static int get_siz(Jpeg2000DecoderContext *s) av_log(s->avctx, AV_LOG_ERROR, "Invalid sample separation %d/%d\n", s->cdx[i], s->cdy[i]); return AVERROR_INVALIDDATA; } - log2_chroma_wh |= s->cdy[i] >> 1 << i * 4 | s->cdx[i] >> 1 << i * 4 + 2; + int i_remapped = s->cdef[i] ? s->cdef[i]-1 : (s->ncomponents-1); + + log2_chroma_wh |= s->cdy[i] >> 1 << i_remapped * 4 | s->cdx[i] >> 1 << i_remapped * 4 + 2; } s->numXtiles = ff_jpeg2000_ceildiv(s->width - s->tile_offset_x, s->tile_width); @@ -542,9 +563,13 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) /* set integer 9/7 DWT in case of BITEXACT flag */ if ((s->avctx->flags & AV_CODEC_FLAG_BITEXACT) && (c->transform == FF_DWT97)) c->transform = FF_DWT97_INT; +#if FF_API_CODEC_PROPS else if (c->transform == FF_DWT53) { +FF_DISABLE_DEPRECATION_WARNINGS s->avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS } +#endif if (c->csty & JPEG2000_CSTY_PREC) { int i; @@ -1358,7 +1383,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } bits_to_read = (uint8_t) (bits_to_read + cblk->lblock); segment_bytes = get_bits(s, bits_to_read); - // Write length information for HT Refinment segment + // Write length information for HT Refinement segment cblk->pass_lengths[1] += segment_bytes; } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) { // Common case for non-HT code-blocks; we have only one segment @@ -1507,6 +1532,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc[cwsno]); cblk->length += cblk->lengthinc[cwsno]; + memset(cblk->data + cblk->length, 0, 4); cblk->lengthinc[cwsno] = 0; if (cblk->nb_terminationsinc) { cblk->nb_terminationsinc--; @@ -1517,6 +1543,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, } } av_freep(&cblk->lengthinc); + cblk->nb_lengthinc = 0; } } // Save state of stream @@ -1885,14 +1912,15 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, && !(t1->flags[(y+1) * t1->stride + x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))) { if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_jpeg2000_getsigctxno(t1->flags[(y+1) * t1->stride + x+1] & flags_mask, bandno))) { int xorbit, ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y+1) * t1->stride + x+1] & flags_mask, &xorbit); - if (t1->mqc.raw) - t1->data[(y) * t1->stride + x] = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? -mask : mask; - else - t1->data[(y) * t1->stride + x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? - -mask : mask; - + if (t1->mqc.raw) { + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno)) << 31; + t1->data[(y) * t1->stride + x] |= mask; + } else { + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) << 31; + t1->data[(y) * t1->stride + x] |= mask; + } ff_jpeg2000_set_significance(t1, x, y, - t1->data[(y) * t1->stride + x] < 0); + t1->data[(y) * t1->stride + x] & INT32_MIN); } t1->flags[(y + 1) * t1->stride + x + 1] |= JPEG2000_T1_VIS; } @@ -1902,11 +1930,10 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, static void decode_refpass(Jpeg2000T1Context *t1, int width, int height, int bpno, int vert_causal_ctx_csty_symbol) { - int phalf, nhalf; + int phalf; int y0, x, y; phalf = 1 << (bpno - 1); - nhalf = -phalf; for (y0 = 0; y0 < height; y0 += 4) for (x = 0; x < width; x++) @@ -1915,10 +1942,13 @@ static void decode_refpass(Jpeg2000T1Context *t1, int width, int height, int flags_mask = (vert_causal_ctx_csty_symbol && y == y0 + 3) ? ~(JPEG2000_T1_SIG_S | JPEG2000_T1_SIG_SW | JPEG2000_T1_SIG_SE | JPEG2000_T1_SGN_S) : -1; int ctxno = ff_jpeg2000_getrefctxno(t1->flags[(y + 1) * t1->stride + x + 1] & flags_mask); - int r = ff_mqc_decode(&t1->mqc, - t1->mqc.cx_states + ctxno) - ? phalf : nhalf; - t1->data[(y) * t1->stride + x] += t1->data[(y) * t1->stride + x] < 0 ? -r : r; + t1->data[(y) * t1->stride + x] |= phalf; + if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno)) + t1->data[(y) * t1->stride + x] |= phalf << 1; + else { + t1->data[(y) * t1->stride + x] &= ~(phalf << 1); + + } t1->flags[(y + 1) * t1->stride + x + 1] |= JPEG2000_T1_REF; } } @@ -1966,11 +1996,9 @@ static void decode_clnpass(const Jpeg2000DecoderContext *s, Jpeg2000T1Context *t int xorbit; int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[(y + 1) * t1->stride + x + 1] & flags_mask, &xorbit); - t1->data[(y) * t1->stride + x] = (ff_mqc_decode(&t1->mqc, - t1->mqc.cx_states + ctxno) ^ - xorbit) - ? -mask : mask; - ff_jpeg2000_set_significance(t1, x, y, t1->data[(y) * t1->stride + x] < 0); + t1->data[(y) * t1->stride + x] |= (uint32_t)(ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) << 31; + t1->data[(y) * t1->stride + x] |= mask; + ff_jpeg2000_set_significance(t1, x, y, t1->data[(y) * t1->stride + x] & INT32_MIN); } dec = 0; t1->flags[(y + 1) * t1->stride + x + 1] &= ~JPEG2000_T1_VIS; @@ -1991,9 +2019,9 @@ static void decode_clnpass(const Jpeg2000DecoderContext *s, Jpeg2000T1Context *t static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, - int width, int height, int bandpos, uint8_t roi_shift) + int width, int height, int bandpos, uint8_t roi_shift, const int M_b) { - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1; + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + 31 - M_b - 1 - roi_shift; int pass_cnt = 0; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; int term_cnt = 0; @@ -2068,22 +2096,25 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod av_log(s->avctx, AV_LOG_WARNING, "Synthetic End of Stream Marker Read.\n"); } + /* Reconstruct the sample values */ + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int32_t sign, n, val; + const uint32_t mask = UINT32_MAX >> (M_b + 1); // bit mask for ROI detection + + n = x + (y * t1->stride); + val = t1->data[n]; + sign = val & INT32_MIN; + val &= INT32_MAX; + /* ROI shift, if necessary */ + if (roi_shift && (((uint32_t)val & ~mask) == 0)) + val <<= roi_shift; + t1->data[n] = val | sign; /* NOTE: Binary point for reconstruction value is located in 31 - M_b */ + } + } return 1; } -static inline int roi_shift_param(Jpeg2000Component *comp, - int quan_parameter) -{ - uint8_t roi_shift; - int val; - roi_shift = comp->roi_shift; - val = (quan_parameter < 0)?-quan_parameter:quan_parameter; - - if (val > (1 << roi_shift)) - return (quan_parameter < 0)?-(val >> roi_shift):(val >> roi_shift); - return quan_parameter; -} - /* TODO: Verify dequantization for lossless case * comp->data can be float or int * band->stepsize can be float or int @@ -2093,50 +2124,86 @@ static inline int roi_shift_param(Jpeg2000Component *comp, /* Float dequantization of a codeblock.*/ static void dequantization_float(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; int w = cblk->coord[0][1] - cblk->coord[0][0]; + const int downshift = 31 - M_b; + float fscale = band->f_stepsize; + fscale /= (float)(1 << downshift); for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { float *datap = &comp->f_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - datap[i] = src[i] * band->f_stepsize; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -(val & INT32_MAX); + datap[i] = (float)val * fscale; + } } } /* Integer dequantization of a codeblock.*/ static void dequantization_int(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; + const int downshift = 31 - M_b; int w = cblk->coord[0][1] - cblk->coord[0][0]; for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; if (band->i_stepsize == 32768) { - for (i = 0; i < w; ++i) - datap[i] = src[i] / 2; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -((val & INT32_MAX) >> downshift); + else + val >>= downshift; + datap[i] = val; + } } else { // This should be VERY uncommon - for (i = 0; i < w; ++i) - datap[i] = (src[i] * (int64_t)band->i_stepsize) / 65536; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -((val & INT32_MAX) >> downshift); + else + val >>= downshift; + datap[i] = (val * (int64_t)band->i_stepsize) / 65536; + } } } } static void dequantization_int_97(int x, int y, Jpeg2000Cblk *cblk, Jpeg2000Component *comp, - Jpeg2000T1Context *t1, Jpeg2000Band *band) + Jpeg2000T1Context *t1, Jpeg2000Band *band, const int M_b) { int i, j; int w = cblk->coord[0][1] - cblk->coord[0][0]; + float fscale = band->f_stepsize; + const int downshift = 31 - M_b; + const int PRESCALE = 6; // At least 6 is required to pass the conformance tests in ISO/IEC 15444-4 + int scale; + + fscale /= (float)(1 << downshift); + fscale *= (float)(1 << PRESCALE); + fscale *= (float)(1 << (16 + I_PRESHIFT)); + scale = (int)(fscale + 0.5); + band->i_stepsize = scale; for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - datap[i] = (src[i] * (int64_t)band->i_stepsize + (1<<15)) >> 16; + for (i = 0; i < w; ++i) { + int val = src[i]; + if (val < 0) // Convert sign-magnitude to two's complement + val = -(val & INT32_MAX); + // Shifting down to prevent overflow in dequantization + val = (val + (1 << (PRESCALE - 1))) >> PRESCALE; + datap[i] = RSHIFT(val * (int64_t)band->i_stepsize, 16); + } } } @@ -2168,18 +2235,6 @@ static inline void mct_decode(const Jpeg2000DecoderContext *s, Jpeg2000Tile *til s->dsp.mct_decode[tile->codsty[0].transform](src[0], src[1], src[2], csize); } -static inline void roi_scale_cblk(Jpeg2000Cblk *cblk, - Jpeg2000Component *comp, - Jpeg2000T1Context *t1) -{ - int i, j; - int w = cblk->coord[0][1] - cblk->coord[0][0]; - for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) { - int *src = t1->data + j*t1->stride; - for (i = 0; i < w; ++i) - src[i] = roi_shift_param(comp, src[i]); - } -} static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) { @@ -2242,7 +2297,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile ret = decode_cblk(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], - bandpos, comp->roi_shift); + bandpos, comp->roi_shift, M_b); if (ret) coded = 1; @@ -2251,14 +2306,12 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile x = cblk->coord[0][0] - band->coord[0][0]; y = cblk->coord[1][0] - band->coord[1][0]; - if (comp->roi_shift) - roi_scale_cblk(cblk, comp, &t1); if (codsty->transform == FF_DWT97) - dequantization_float(x, y, cblk, comp, &t1, band); + dequantization_float(x, y, cblk, comp, &t1, band, M_b); else if (codsty->transform == FF_DWT97_INT) - dequantization_int_97(x, y, cblk, comp, &t1, band); + dequantization_int_97(x, y, cblk, comp, &t1, band, M_b); else - dequantization_int(x, y, cblk, comp, &t1, band); + dequantization_int(x, y, cblk, comp, &t1, band, M_b); } /* end cblk */ } /*end prec */ } /* end band */ @@ -2402,6 +2455,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) Jpeg2000QuantStyle *qntsty = s->qntsty; Jpeg2000POC *poc = &s->poc; uint8_t *properties = s->properties; + uint8_t in_tile_headers = 0; for (;;) { int len, ret = 0; @@ -2484,7 +2538,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_cap(s, codsty); break; case JPEG2000_COC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "COC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2492,7 +2546,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_coc(s, codsty, properties); break; case JPEG2000_COD: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "COD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2500,7 +2554,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_cod(s, codsty, properties); break; case JPEG2000_RGN: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "RGN marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2512,7 +2566,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) } break; case JPEG2000_QCC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "QCC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2520,7 +2574,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_qcc(s, len, qntsty, properties); break; case JPEG2000_QCD: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "QCD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2528,7 +2582,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_qcd(s, len, qntsty, properties); break; case JPEG2000_POC: - if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + if (in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { av_log(s->avctx, AV_LOG_ERROR, "POC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); return AVERROR_INVALIDDATA; @@ -2536,8 +2590,8 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) ret = get_poc(s, len, poc); break; case JPEG2000_SOT: - if (!s->in_tile_headers) { - s->in_tile_headers = 1; + if (!in_tile_headers) { + in_tile_headers = 1; if (s->has_ppm) { bytestream2_init(&s->packed_headers_stream, s->packed_headers, s->packed_headers_size); } @@ -2569,7 +2623,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) break; case JPEG2000_PPM: // Packed headers, main header - if (s->in_tile_headers) { + if (in_tile_headers) { av_log(s->avctx, AV_LOG_ERROR, "PPM Marker can only be in Main header\n"); return AVERROR_INVALIDDATA; } @@ -2782,7 +2836,7 @@ static av_cold int jpeg2000_decode_init(AVCodecContext *avctx) Jpeg2000DecoderContext *s = avctx->priv_data; if (avctx->lowres) - av_log(avctx, AV_LOG_WARNING, "lowres is overriden by reduction_factor but set anyway\n"); + av_log(avctx, AV_LOG_WARNING, "lowres is overridden by reduction_factor but set anyway\n"); if (!s->reduction_factor && avctx->lowres < JPEG2000_MAX_RESLEVELS) { s->reduction_factor = avctx->lowres; } @@ -2853,16 +2907,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, if (ret = jpeg2000_read_bitstream_packets(s)) goto end; - for (int x = 0; x < s->ncomponents; x++) { - if (s->cdef[x] < 0) { - for (x = 0; x < s->ncomponents; x++) { - s->cdef[x] = x + 1; - } - if ((s->ncomponents & 1) == 0) - s->cdef[s->ncomponents-1] = 0; - break; - } - } + for (int x = 0; x < s->ncomponents && s->codsty[x].transform == FF_DWT53;) + if (++x == s->ncomponents) + picture->flags |= AV_FRAME_FLAG_LOSSLESS; avctx->execute2(avctx, jpeg2000_decode_tile, picture, NULL, s->numXtiles * s->numYtiles); diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h index 78eba27ed9..fce3823164 100644 --- a/libavcodec/jpeg2000dec.h +++ b/libavcodec/jpeg2000dec.h @@ -86,7 +86,6 @@ typedef struct Jpeg2000DecoderContext { uint8_t *packed_headers; // contains packed headers. Used only along with PPM marker int packed_headers_size; GetByteContext packed_headers_stream; - uint8_t in_tile_headers; int cdx[4], cdy[4]; int precision; diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c index 34e33553f7..9ee8122658 100644 --- a/libavcodec/jpeg2000dwt.c +++ b/libavcodec/jpeg2000dwt.c @@ -39,13 +39,12 @@ /* Lifting parameters in integer format. * Computed as param = (float param) * (1 << 16) */ -#define I_LFTG_ALPHA 103949ll -#define I_LFTG_BETA 3472ll -#define I_LFTG_GAMMA 57862ll -#define I_LFTG_DELTA 29066ll -#define I_LFTG_K 80621ll -#define I_LFTG_X 53274ll -#define I_PRESHIFT 8 +#define I_LFTG_ALPHA_PRIME 38413ll // = 103949 - 65536, (= alpha - 1.0) +#define I_LFTG_BETA 3472ll +#define I_LFTG_GAMMA 57862ll +#define I_LFTG_DELTA 29066ll +#define I_LFTG_K 80621ll +#define I_LFTG_X 53274ll static inline void extend53(int *p, int i0, int i1) { @@ -234,8 +233,11 @@ static void sd_1d97_int(int *p, int i0, int i1) extend97_int(p, i0, i1); i0++; i1++; - for (i = (i0>>1) - 2; i < (i1>>1) + 1; i++) - p[2 * i + 1] -= (I_LFTG_ALPHA * (p[2 * i] + p[2 * i + 2]) + (1 << 15)) >> 16; + for (i = (i0>>1) - 2; i < (i1>>1) + 1; i++) { + const int64_t sum = p[2 * i] + p[2 * i + 2]; + p[2 * i + 1] -= sum; + p[2 * i + 1] -= (I_LFTG_ALPHA_PRIME * sum + (1 << 15)) >> 16; + } for (i = (i0>>1) - 1; i < (i1>>1) + 1; i++) p[2 * i] -= (I_LFTG_BETA * (p[2 * i - 1] + p[2 * i + 1]) + (1 << 15)) >> 16; for (i = (i0>>1) - 1; i < (i1>>1); i++) @@ -276,7 +278,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) // copy back and deinterleave for (i = mv; i < lv; i+=2, j++) - t[w*j + lp] = ((l[i] * I_LFTG_X) + (1 << 15)) >> 16; + t[w*j + lp] = l[i]; for (i = 1-mv; i < lv; i+=2, j++) t[w*j + lp] = l[i]; } @@ -293,7 +295,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) // copy back and deinterleave for (i = mh; i < lh; i+=2, j++) - t[w*lp + j] = ((l[i] * I_LFTG_X) + (1 << 15)) >> 16; + t[w*lp + j] = l[i]; for (i = 1-mh; i < lh; i+=2, j++) t[w*lp + j] = l[i]; } @@ -301,7 +303,7 @@ static void dwt_encode97_int(DWTContext *s, int *t) } for (i = 0; i < w * h; i++) - t[i] = (t[i] + ((1<>1)) >> I_PRESHIFT; + t[i] = (t[i] + ((1<<(I_PRESHIFT))>>1)) >> (I_PRESHIFT); } static void sr_1d53(unsigned *p, int i0, int i1) @@ -471,8 +473,11 @@ static void sr_1d97_int(int32_t *p, int i0, int i1) for (i = (i0 >> 1); i < (i1 >> 1) + 1; i++) p[2 * i] += (I_LFTG_BETA * (p[2 * i - 1] + (int64_t)p[2 * i + 1]) + (1 << 15)) >> 16; /* step 6 */ - for (i = (i0 >> 1); i < (i1 >> 1); i++) - p[2 * i + 1] += (I_LFTG_ALPHA * (p[2 * i] + (int64_t)p[2 * i + 2]) + (1 << 15)) >> 16; + for (i = (i0 >> 1); i < (i1 >> 1); i++) { + const int64_t sum = p[2 * i] + (int64_t) p[2 * i + 2]; + p[2 * i + 1] += sum; + p[2 * i + 1] += (I_LFTG_ALPHA_PRIME * sum + (1 << 15)) >> 16; + } } static void dwt_decode97_int(DWTContext *s, int32_t *t) @@ -486,9 +491,6 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) /* position at index O of line range [0-5,w+5] cf. extend function */ line += 5; - for (i = 0; i < w * h; i++) - data[i] *= 1LL << I_PRESHIFT; - for (lev = 0; lev < s->ndeclevels; lev++) { int lh = s->linelen[lev][0], lv = s->linelen[lev][1], @@ -500,9 +502,9 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) l = line + mh; for (lp = 0; lp < lv; lp++) { int i, j = 0; - // rescale with interleaving + // interleaving for (i = mh; i < lh; i += 2, j++) - l[i] = ((data[w * lp + j] * I_LFTG_K) + (1 << 15)) >> 16; + l[i] = data[w * lp + j]; for (i = 1 - mh; i < lh; i += 2, j++) l[i] = data[w * lp + j]; @@ -516,9 +518,9 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) l = line + mv; for (lp = 0; lp < lh; lp++) { int i, j = 0; - // rescale with interleaving + // interleaving for (i = mv; i < lv; i += 2, j++) - l[i] = ((data[w * j + lp] * I_LFTG_K) + (1 << 15)) >> 16; + l[i] = data[w * j + lp]; for (i = 1 - mv; i < lv; i += 2, j++) l[i] = data[w * j + lp]; @@ -530,7 +532,8 @@ static void dwt_decode97_int(DWTContext *s, int32_t *t) } for (i = 0; i < w * h; i++) - data[i] = (data[i] + ((1LL<>1)) >> I_PRESHIFT; + // We shift down by `I_PRESHIFT` because the input coefficients `datap[]` were shifted up by `I_PRESHIFT` to secure the precision + data[i] = (int32_t)(data[i] + ((1LL<<(I_PRESHIFT))>>1)) >> (I_PRESHIFT); } int ff_jpeg2000_dwt_init(DWTContext *s, int border[2][2], diff --git a/libavcodec/jpeg2000dwt.h b/libavcodec/jpeg2000dwt.h index 718d183ac1..62f0548ac8 100644 --- a/libavcodec/jpeg2000dwt.h +++ b/libavcodec/jpeg2000dwt.h @@ -32,6 +32,7 @@ #define FF_DWT_MAX_DECLVLS 32 ///< max number of decomposition levels #define F_LFTG_K 1.230174104914001f #define F_LFTG_X 0.812893066115961f +#define I_PRESHIFT 8 enum DWTType { FF_DWT97, diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c index c47c8d61fe..08140e06a9 100644 --- a/libavcodec/jpeg2000htdec.c +++ b/libavcodec/jpeg2000htdec.c @@ -1070,7 +1070,7 @@ static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s uint8_t *state_p = block_states + (i + 1) * stride + (j + 1); if ((state_p[0] >> HT_SHIFT_REF) & 1) { bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); - *sp |= (int32_t)bit << 31; + *sp |= (uint32_t)bit << 31; } } } @@ -1160,7 +1160,7 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); tmp = 0xFFFFFFFE | (uint32_t)bit; - tmp <<= pLSB; + tmp = (uint32_t)tmp << pLSB; sp[0] &= tmp; sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } @@ -1176,7 +1176,7 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); tmp = 0xFFFFFFFE | (uint32_t)bit; - tmp <<= pLSB; + tmp = (uint32_t)tmp << pLSB; sp[0] &= tmp; sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } @@ -1314,8 +1314,6 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref, pLSB - 1, sample_buf, block_states); - pLSB = 31 - M_b; - /* Reconstruct the sample values */ for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -1328,12 +1326,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c /* ROI shift, if necessary */ if (roi_shift && (((uint32_t)val & ~mask) == 0)) val <<= roi_shift; - /* Convert sign-magnitude to two's complement. */ - if (sign) - val = -val; - /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */ - val >>= (pLSB - 1); - t1->data[n] = val; + t1->data[n] = val | sign; /* NOTE: Binary point for reconstruction value is located in 31 - M_b */ } } free: diff --git a/libavcodec/jpeglsenc.c b/libavcodec/jpeglsenc.c index d2f4a52f24..edc3fa600c 100644 --- a/libavcodec/jpeglsenc.c +++ b/libavcodec/jpeglsenc.c @@ -484,10 +484,7 @@ const FFCodec ff_jpegls_encoder = { .init = encode_jpegls_init, FF_CODEC_ENCODE_CB(encode_picture_ls), .close = encode_jpegls_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/jpegxl_parse.c b/libavcodec/jpegxl_parse.c index 7cfdd3e7d5..022eed322d 100644 --- a/libavcodec/jpegxl_parse.c +++ b/libavcodec/jpegxl_parse.c @@ -450,7 +450,8 @@ int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_l uint8_t *buffer, int buflen, int *copied) { GetByteContext gb; - int pos = 0, last_box = 0; + int64_t pos = 0; + int last_box = 0; bytestream2_init(&gb, input_buffer, input_len); while (1) { @@ -516,5 +517,5 @@ int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_l break; } - return pos; + return FFMIN(pos, INT_MAX); } diff --git a/libavcodec/jpegxl_parser.c b/libavcodec/jpegxl_parser.c index 8c45e1a1b7..75acc53708 100644 --- a/libavcodec/jpegxl_parser.c +++ b/libavcodec/jpegxl_parser.c @@ -155,12 +155,12 @@ typedef struct JXLParseContext { /* using ISOBMFF-based container */ int container; - int skip; + int64_t skip; int copied; - int collected_size; - int codestream_length; + int64_t collected_size; + int64_t codestream_length; int skipped_icc; - int next; + int64_t next; uint8_t cs_buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE]; } JXLParseContext; @@ -352,6 +352,8 @@ static int decode_hybrid_varlen_uint(GetBitContext *gb, JXLEntropyDecoder *dec, if (bundle->lz77_enabled && token >= bundle->lz77_min_symbol) { const JXLSymbolDistribution *lz77dist = &bundle->dists[bundle->cluster_map[bundle->num_dist - 1]]; + if (!dec->num_decoded) + return AVERROR_INVALIDDATA; ret = read_hybrid_uint(gb, &bundle->lz_len_conf, token - bundle->lz77_min_symbol, &dec->num_to_copy); if (ret < 0) return ret; @@ -531,6 +533,7 @@ static int read_dist_clustering(GetBitContext *gb, JXLEntropyDecoder *dec, JXLDi dec->state = -1; /* it's not going to necessarily be zero after reading */ dec->num_to_copy = 0; + dec->num_decoded = 0; dist_bundle_close(&nested); if (use_mtf) { uint8_t mtf[256]; @@ -1311,7 +1314,14 @@ static int parse_frame_header(void *avctx, JXLParseContext *ctx, GetBitContext * // permuted toc if (get_bits1(gb)) { JXLEntropyDecoder dec; - uint32_t end, lehmer = 0; + int64_t end, lehmer = 0; + /* parser sanity check to prevent TOC perm from spinning cpu */ + if (width > meta->coded_width * 8 || height > meta->coded_height * 8) { + av_log(avctx, AV_LOG_WARNING, "frame of size %" PRIu32 "x%" PRIu32 + " exceeds max size of %" PRIu32 "x%" PRIu32 ", aborting parser\n", + width, height, meta->coded_width * 8, meta->coded_height * 8); + return AVERROR_INVALIDDATA; + } ret = entropy_decoder_init(avctx, gb, &dec, 8); if (ret < 0) return ret; @@ -1320,15 +1330,15 @@ static int parse_frame_header(void *avctx, JXLParseContext *ctx, GetBitContext * return AVERROR_BUFFER_TOO_SMALL; } end = entropy_decoder_read_symbol(gb, &dec, toc_context(toc_count)); - if (end > toc_count) { + if (end < 0 || end > toc_count) { entropy_decoder_close(&dec); return AVERROR_INVALIDDATA; } for (uint32_t i = 0; i < end; i++) { lehmer = entropy_decoder_read_symbol(gb, &dec, toc_context(lehmer)); - if (get_bits_left(gb) < 0) { + if (lehmer < 0 || get_bits_left(gb) < 0) { entropy_decoder_close(&dec); - return AVERROR_BUFFER_TOO_SMALL; + return lehmer < 0 ? lehmer : AVERROR_BUFFER_TOO_SMALL; } } entropy_decoder_close(&dec); @@ -1393,7 +1403,7 @@ static int skip_boxes(JXLParseContext *ctx, const uint8_t *buf, int buf_size) return 0; } -static int try_parse(AVCodecParserContext *s, AVCodecContext *avctx, JXLParseContext *ctx, +static int64_t try_parse(AVCodecParserContext *s, AVCodecContext *avctx, JXLParseContext *ctx, const uint8_t *buf, int buf_size) { int ret, cs_buflen, header_skip; @@ -1486,10 +1496,10 @@ static int jpegxl_parse(AVCodecParserContext *s, AVCodecContext *avctx, } if ((!ctx->container || !ctx->codestream_length) && !ctx->next) { - ret = try_parse(s, avctx, ctx, pbuf, pindex); - if (ret < 0) + int64_t ret64 = try_parse(s, avctx, ctx, pbuf, pindex); + if (ret64 < 0) goto flush; - ctx->next = ret; + ctx->next = ret64; if (ctx->container) ctx->skip += ctx->next; } @@ -1531,7 +1541,7 @@ flush: } const AVCodecParser ff_jpegxl_parser = { - .codec_ids = { AV_CODEC_ID_JPEGXL }, + .codec_ids = { AV_CODEC_ID_JPEGXL, AV_CODEC_ID_JPEGXL_ANIM }, .priv_data_size = sizeof(JXLParseContext), .parser_parse = jpegxl_parse, .parser_close = ff_parse_close, diff --git a/libavcodec/jrevdct.c b/libavcodec/jrevdct.c index 7f1863515f..531deee3a9 100644 --- a/libavcodec/jrevdct.c +++ b/libavcodec/jrevdct.c @@ -1159,13 +1159,13 @@ void ff_j_rev_dct1(DCTBLOCK data){ #undef FIX #undef CONST_BITS -void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]) { ff_j_rev_dct(block); ff_put_pixels_clamped_c(block, dest, line_size); } -void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t block[64]) { ff_j_rev_dct(block); ff_add_pixels_clamped_c(block, dest, line_size); diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c index 2b7c9f0d29..d8c78cd18f 100644 --- a/libavcodec/jvdec.c +++ b/libavcodec/jvdec.c @@ -37,9 +37,6 @@ typedef struct JvContext { BlockDSPContext bdsp; AVFrame *frame; uint32_t palette[AVPALETTE_COUNT]; -#if FF_API_PALETTE_HAS_CHANGED - int palette_has_changed; -#endif } JvContext; static av_cold int decode_init(AVCodecContext *avctx) @@ -209,18 +206,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, s->palette[i] = 0xFFU << 24 | pal << 2 | ((pal >> 4) & 0x30303); buf += 3; } -#if FF_API_PALETTE_HAS_CHANGED - s->palette_has_changed = 1; -#endif } if (video_size) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = s->palette_has_changed; - s->palette_has_changed = 0; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); if ((ret = av_frame_ref(rframe, s->frame)) < 0) diff --git a/libavcodec/kmvc.c b/libavcodec/kmvc.c index 83aba4b252..15a0bc59ef 100644 --- a/libavcodec/kmvc.c +++ b/libavcodec/kmvc.c @@ -273,14 +273,7 @@ static int decode_frame(AVCodecContext * avctx, AVFrame *frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(ctx->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif header = bytestream2_get_byte(&ctx->g); @@ -303,11 +296,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (header & KMVC_PALETTE) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif // palette starts from index 1 and has 127 entries for (i = 1; i <= ctx->palsize; i++) { ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g); @@ -316,11 +304,6 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->setpal) { ctx->setpal = 0; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } /* make the palette available on the way out */ diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c index ceeece3aa9..102f6f32e9 100644 --- a/libavcodec/lcevcdec.c +++ b/libavcodec/lcevcdec.c @@ -23,6 +23,8 @@ #include "libavutil/imgutils.h" #include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/refstruct.h" + #include "decode.h" #include "lcevcdec.h" @@ -45,7 +47,7 @@ static LCEVC_ColorFormat map_format(int format) return LCEVC_ColorFormat_Unknown; } -static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder, +static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *frame, LCEVC_PictureHandle *picture) { LCEVC_PictureDesc desc; @@ -68,22 +70,22 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder, desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den; /* Allocate LCEVC Picture */ - res = LCEVC_AllocPicture(decoder, &desc, picture); + res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture); if (res != LCEVC_Success) { return AVERROR_EXTERNAL; } - res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock); + res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock); if (res != LCEVC_Success) return AVERROR_EXTERNAL; - res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes); + res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes); if (res != LCEVC_Success) return AVERROR_EXTERNAL; for (unsigned i = 0; i < planes; i++) { LCEVC_PicturePlaneDesc plane; - res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane); + res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane); if (res != LCEVC_Success) return AVERROR_EXTERNAL; @@ -94,43 +96,43 @@ static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder, av_image_copy2(data, linesizes, frame->data, frame->linesize, frame->format, frame->width, frame->height); - res = LCEVC_UnlockPicture(decoder, lock); + res = LCEVC_UnlockPicture(lcevc->decoder, lock); if (res != LCEVC_Success) return AVERROR_EXTERNAL; return 0; } -static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder, - const AVFrame *frame, LCEVC_PictureHandle *picture) +static int alloc_enhanced_frame(void *logctx, FFLCEVCFrame *frame_ctx, + LCEVC_PictureHandle *picture) { + FFLCEVCContext *lcevc = frame_ctx->lcevc; LCEVC_PictureDesc desc ; - LCEVC_ColorFormat fmt = map_format(frame->format); + LCEVC_ColorFormat fmt = map_format(frame_ctx->frame->format); LCEVC_PicturePlaneDesc planes[4] = { 0 }; - int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1); - int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1); LCEVC_ReturnCode res; - res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height); + res = LCEVC_DefaultPictureDesc(&desc, fmt, frame_ctx->frame->width, frame_ctx->frame->height); if (res != LCEVC_Success) return AVERROR_EXTERNAL; /* Set plane description */ for (int i = 0; i < 4; i++) { - planes[i].firstSample = frame->data[i]; - planes[i].rowByteStride = frame->linesize[i]; + planes[i].firstSample = frame_ctx->frame->data[i]; + planes[i].rowByteStride = frame_ctx->frame->linesize[i]; } /* Allocate LCEVC Picture */ - res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture); + res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture); if (res != LCEVC_Success) { return AVERROR_EXTERNAL; } return 0; } -static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in) +static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame *in) { + FFLCEVCContext *lcevc = frame_ctx->lcevc; const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC); LCEVC_PictureHandle picture; LCEVC_ReturnCode res; @@ -143,7 +145,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame * if (res != LCEVC_Success) return AVERROR_EXTERNAL; - ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture); + ret = alloc_base_frame(logctx, lcevc, in, &picture); if (ret < 0) return ret; @@ -152,7 +154,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame * return AVERROR_EXTERNAL; memset(&picture, 0, sizeof(picture)); - ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture); + ret = alloc_enhanced_frame(logctx, frame_ctx, &picture); if (ret < 0) return ret; @@ -163,8 +165,9 @@ static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame * return 0; } -static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) +static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out) { + FFLCEVCContext *lcevc = frame_ctx->lcevc; LCEVC_PictureDesc desc; LCEVC_DecodeInformation info; LCEVC_PictureHandle picture; @@ -184,6 +187,11 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) out->crop_right = desc.cropRight; out->sample_aspect_ratio.num = desc.sampleAspectRatioNum; out->sample_aspect_ratio.den = desc.sampleAspectRatioDen; + + av_frame_copy_props(frame_ctx->frame, out); + av_frame_unref(out); + av_frame_move_ref(out, frame_ctx->frame); + out->width = desc.width + out->crop_left + out->crop_right; out->height = desc.height + out->crop_top + out->crop_bottom; @@ -194,13 +202,14 @@ static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) return 0; } -static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) +static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out) { + FFLCEVCContext *lcevc = frame_ctx->lcevc; LCEVC_PictureHandle picture; LCEVC_ReturnCode res; int ret; - ret = generate_output(logctx, lcevc, out); + ret = generate_output(logctx, frame_ctx, out); if (ret < 0) return ret; @@ -233,7 +242,7 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event, } } -static void lcevc_free(FFRefStructOpaque unused, void *obj) +static void lcevc_free(AVRefStructOpaque unused, void *obj) { FFLCEVCContext *lcevc = obj; if (lcevc->initialized) @@ -247,12 +256,7 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx) #if CONFIG_LIBLCEVC_DEC LCEVC_AccelContextHandle dummy = { 0 }; const int32_t event = LCEVC_Log; -#endif - if (lcevc->initialized) - return 0; - -#if CONFIG_LIBLCEVC_DEC if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) { av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n"); return AVERROR_EXTERNAL; @@ -276,8 +280,9 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx) int ff_lcevc_process(void *logctx, AVFrame *frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; - FFLCEVCContext *lcevc = fdd->post_process_opaque; + FrameDecodeData *fdd = frame->private_ref; + FFLCEVCFrame *frame_ctx = fdd->post_process_opaque; + FFLCEVCContext *lcevc = frame_ctx->lcevc; int ret; if (!lcevc->initialized) { @@ -287,11 +292,14 @@ int ff_lcevc_process(void *logctx, AVFrame *frame) } #if CONFIG_LIBLCEVC_DEC - ret = lcevc_send_frame(logctx, lcevc, frame); + av_assert0(frame_ctx->frame); + + + ret = lcevc_send_frame(logctx, frame_ctx, frame); if (ret) return ret < 0 ? ret : 0; - lcevc_receive_frame(logctx, lcevc, frame); + lcevc_receive_frame(logctx, frame_ctx, frame); if (ret < 0) return ret; @@ -305,7 +313,7 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc) { FFLCEVCContext *lcevc = NULL; #if CONFIG_LIBLCEVC_DEC - lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); + lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); if (!lcevc) return AVERROR(ENOMEM); #endif @@ -315,5 +323,8 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc) void ff_lcevc_unref(void *opaque) { - ff_refstruct_unref(&opaque); + FFLCEVCFrame *lcevc = opaque; + av_refstruct_unref(&lcevc->lcevc); + av_frame_free(&lcevc->frame); + av_free(opaque); } diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h index 7334d3a645..62014132d9 100644 --- a/libavcodec/lcevcdec.h +++ b/libavcodec/lcevcdec.h @@ -19,7 +19,7 @@ #ifndef AVCODEC_LCEVCDEC_H #define AVCODEC_LCEVCDEC_H -#include "config_components.h" +#include "config.h" #include #if CONFIG_LIBLCEVC_DEC @@ -27,7 +27,6 @@ #else typedef uintptr_t LCEVC_DecoderHandle; #endif -#include "refstruct.h" typedef struct FFLCEVCContext { LCEVC_DecoderHandle decoder; @@ -36,6 +35,11 @@ typedef struct FFLCEVCContext { struct AVFrame; +typedef struct FFLCEVCFrame { + FFLCEVCContext *lcevc; + struct AVFrame *frame; +} FFLCEVCFrame; + int ff_lcevc_alloc(FFLCEVCContext **plcevc); int ff_lcevc_process(void *logctx, struct AVFrame *frame); void ff_lcevc_unref(void *opaque); diff --git a/libavcodec/lclenc.c b/libavcodec/lclenc.c index dd5eed9d63..f328e12627 100644 --- a/libavcodec/lclenc.c +++ b/libavcodec/lclenc.c @@ -162,6 +162,6 @@ const FFCodec ff_zlib_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/leaddec.c b/libavcodec/leaddec.c index 2f5152c226..e6a91faabc 100644 --- a/libavcodec/leaddec.c +++ b/libavcodec/leaddec.c @@ -157,12 +157,17 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, zero = 1; avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x6: case 0x8000: yuv20p_half = 1; // fall-through case 0x1000: avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x1006: + fields = 2; + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + break; case 0x2000: avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; @@ -236,7 +241,8 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, return ret; } } else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - for (int mb_y = 0; mb_y < (avctx->height + 15) / 16; mb_y++) + for (int f = 0; f < fields; f++) + for (int mb_y = 0; mb_y < (avctx->height + 15) / 16 / fields; mb_y++) for (int mb_x = 0; mb_x < (avctx->width + 15) / 16; mb_x++) for (int b = 0; b < (yuv20p_half ? 4 : 6); b++) { int luma_block = yuv20p_half ? 2 : 4; @@ -257,8 +263,8 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, ret = decode_block(s, &gb, dc_vlc, dc_bits, ac_vlc, ac_bits, dc_pred + plane, dequant[!(b < 4)], - frame->data[plane] + y*frame->linesize[plane] + x, - (yuv20p_half && b < 2 ? 2 : 1) * frame->linesize[plane]); + frame->data[plane] + (f + y*fields)*frame->linesize[plane] + x, + (yuv20p_half && b < 2 ? 2 : 1) * fields * frame->linesize[plane]); if (ret < 0) return ret; diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c index 0f7571ee7a..46f8d60e46 100644 --- a/libavcodec/libaomenc.c +++ b/libavcodec/libaomenc.c @@ -140,6 +140,8 @@ typedef struct AOMEncoderContext { AVDictionary *aom_params; } AOMContext; +#define OFFSET(x) offsetof(AOMContext, x) + static const char *const ctlidstr[] = { [AOME_SET_CPUUSED] = "AOME_SET_CPUUSED", [AOME_SET_CQ_LEVEL] = "AOME_SET_CQ_LEVEL", @@ -673,6 +675,46 @@ static int choose_tiling(AVCodecContext *avctx, return 0; } + +static const struct { + int aom_enum; + unsigned offset; +} option_map[] = { + { AOME_SET_ENABLEAUTOALTREF, OFFSET(auto_alt_ref) }, + { AOME_SET_ARNR_MAXFRAMES, OFFSET(arnr_max_frames) }, + { AOME_SET_ARNR_STRENGTH, OFFSET(arnr_strength) }, + { AV1E_SET_ENABLE_CDEF, OFFSET(enable_cdef) }, + { AV1E_SET_ENABLE_RESTORATION, OFFSET(enable_restoration) }, + { AV1E_SET_ENABLE_RECT_PARTITIONS, OFFSET(enable_rect_partitions) }, + { AV1E_SET_ENABLE_1TO4_PARTITIONS, OFFSET(enable_1to4_partitions) }, + { AV1E_SET_ENABLE_AB_PARTITIONS, OFFSET(enable_ab_partitions) }, + { AV1E_SET_ENABLE_ANGLE_DELTA, OFFSET(enable_angle_delta) }, + { AV1E_SET_ENABLE_CFL_INTRA, OFFSET(enable_cfl_intra) }, + { AV1E_SET_ENABLE_FILTER_INTRA, OFFSET(enable_filter_intra) }, + { AV1E_SET_ENABLE_INTRA_EDGE_FILTER, OFFSET(enable_intra_edge_filter) }, + { AV1E_SET_ENABLE_PAETH_INTRA, OFFSET(enable_paeth_intra) }, + { AV1E_SET_ENABLE_SMOOTH_INTRA, OFFSET(enable_smooth_intra) }, + { AV1E_SET_ENABLE_PALETTE, OFFSET(enable_palette) }, + { AV1E_SET_ENABLE_TX64, OFFSET(enable_tx64) }, + { AV1E_SET_ENABLE_FLIP_IDTX, OFFSET(enable_flip_idtx) }, + { AV1E_SET_INTRA_DCT_ONLY, OFFSET(use_intra_dct_only) }, + { AV1E_SET_INTER_DCT_ONLY, OFFSET(use_inter_dct_only) }, + { AV1E_SET_INTRA_DEFAULT_TX_ONLY, OFFSET(use_intra_default_tx_only) }, + { AV1E_SET_REDUCED_TX_TYPE_SET, OFFSET(reduced_tx_type_set) }, + { AV1E_SET_ENABLE_REF_FRAME_MVS, OFFSET(enable_ref_frame_mvs) }, + { AV1E_SET_REDUCED_REFERENCE_SET, OFFSET(enable_reduced_reference_set) }, + { AV1E_SET_ENABLE_DIFF_WTD_COMP, OFFSET(enable_diff_wtd_comp) }, + { AV1E_SET_ENABLE_DIST_WTD_COMP, OFFSET(enable_dist_wtd_comp) }, + { AV1E_SET_ENABLE_DUAL_FILTER, OFFSET(enable_dual_filter) }, + { AV1E_SET_ENABLE_INTERINTER_WEDGE, OFFSET(enable_interinter_wedge) }, + { AV1E_SET_ENABLE_MASKED_COMP, OFFSET(enable_masked_comp) }, + { AV1E_SET_ENABLE_INTERINTRA_COMP, OFFSET(enable_interintra_comp) }, + { AV1E_SET_ENABLE_INTERINTRA_WEDGE, OFFSET(enable_interintra_wedge) }, + { AV1E_SET_ENABLE_OBMC, OFFSET(enable_obmc) }, + { AV1E_SET_ENABLE_ONESIDED_COMP, OFFSET(enable_onesided_comp) }, + { AV1E_SET_ENABLE_SMOOTH_INTERINTRA, OFFSET(enable_smooth_interintra) }, +}; + static av_cold int aom_init(AVCodecContext *avctx, const struct aom_codec_iface *iface) { @@ -681,7 +723,6 @@ static av_cold int aom_init(AVCodecContext *avctx, struct aom_codec_enc_cfg enccfg = { 0 }; aom_codec_flags_t flags = (avctx->flags & AV_CODEC_FLAG_PSNR) ? AOM_CODEC_USE_PSNR : 0; - AVCPBProperties *cpb_props; int res; aom_img_fmt_t img_fmt; aom_codec_caps_t codec_caps = aom_codec_get_caps(iface); @@ -860,73 +901,12 @@ static av_cold int aom_init(AVCodecContext *avctx, // 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); - if (ctx->arnr_max_frames >= 0) - codecctl_int(avctx, AOME_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames); - if (ctx->arnr_strength >= 0) - codecctl_int(avctx, AOME_SET_ARNR_STRENGTH, ctx->arnr_strength); - if (ctx->enable_cdef >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_CDEF, ctx->enable_cdef); - if (ctx->enable_restoration >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_RESTORATION, ctx->enable_restoration); - if (ctx->enable_rect_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_RECT_PARTITIONS, ctx->enable_rect_partitions); - if (ctx->enable_1to4_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_1TO4_PARTITIONS, ctx->enable_1to4_partitions); - if (ctx->enable_ab_partitions >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_AB_PARTITIONS, ctx->enable_ab_partitions); - if (ctx->enable_angle_delta >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_ANGLE_DELTA, ctx->enable_angle_delta); - if (ctx->enable_cfl_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_CFL_INTRA, ctx->enable_cfl_intra); - if (ctx->enable_filter_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_FILTER_INTRA, ctx->enable_filter_intra); - if (ctx->enable_intra_edge_filter >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, ctx->enable_intra_edge_filter); - if (ctx->enable_paeth_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_PAETH_INTRA, ctx->enable_paeth_intra); - if (ctx->enable_smooth_intra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTRA, ctx->enable_smooth_intra); - if (ctx->enable_palette >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_PALETTE, ctx->enable_palette); - if (ctx->enable_tx64 >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_TX64, ctx->enable_tx64); - if (ctx->enable_flip_idtx >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_FLIP_IDTX, ctx->enable_flip_idtx); - if (ctx->use_intra_dct_only >= 0) - codecctl_int(avctx, AV1E_SET_INTRA_DCT_ONLY, ctx->use_intra_dct_only); - if (ctx->use_inter_dct_only >= 0) - codecctl_int(avctx, AV1E_SET_INTER_DCT_ONLY, ctx->use_inter_dct_only); - if (ctx->use_intra_default_tx_only >= 0) - codecctl_int(avctx, AV1E_SET_INTRA_DEFAULT_TX_ONLY, ctx->use_intra_default_tx_only); - if (ctx->reduced_tx_type_set >= 0) - codecctl_int(avctx, AV1E_SET_REDUCED_TX_TYPE_SET, ctx->reduced_tx_type_set); - if (ctx->enable_ref_frame_mvs >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_REF_FRAME_MVS, ctx->enable_ref_frame_mvs); - if (ctx->enable_reduced_reference_set >= 0) - codecctl_int(avctx, AV1E_SET_REDUCED_REFERENCE_SET, ctx->enable_reduced_reference_set); - if (ctx->enable_diff_wtd_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DIFF_WTD_COMP, ctx->enable_diff_wtd_comp); - if (ctx->enable_dist_wtd_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DIST_WTD_COMP, ctx->enable_dist_wtd_comp); - if (ctx->enable_dual_filter >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_DUAL_FILTER, ctx->enable_dual_filter); - if (ctx->enable_interinter_wedge >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTER_WEDGE, ctx->enable_interinter_wedge); - if (ctx->enable_masked_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_MASKED_COMP, ctx->enable_masked_comp); - if (ctx->enable_interintra_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_COMP, ctx->enable_interintra_comp); - if (ctx->enable_interintra_wedge >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_WEDGE, ctx->enable_interintra_wedge); - if (ctx->enable_obmc >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_OBMC, ctx->enable_obmc); - if (ctx->enable_onesided_comp >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_ONESIDED_COMP, ctx->enable_onesided_comp); - if (ctx->enable_smooth_interintra >= 0) - codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, ctx->enable_smooth_interintra); + for (size_t i = 0; i < FF_ARRAY_ELEMS(option_map); ++i) { + int val = *(int*)((char*)ctx + option_map[i].offset); + if (val >= 0) + codecctl_int(avctx, option_map[i].aom_enum, val); + } codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) codecctl_int(avctx, AOME_SET_CQ_LEVEL, ctx->crf); @@ -989,10 +969,6 @@ static av_cold int aom_init(AVCodecContext *avctx, if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) ctx->rawimg.bit_depth = enccfg.g_bit_depth; - cpb_props = ff_encode_add_cpb_side_data(avctx); - if (!cpb_props) - return AVERROR(ENOMEM); - ctx->dovi.logctx = avctx; if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0) return res; @@ -1019,6 +995,10 @@ static av_cold int aom_init(AVCodecContext *avctx, return ret; } + AVCPBProperties *cpb_props = ff_encode_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; @@ -1270,13 +1250,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) duration = av_rescale_q(1, av_inv_q(avctx->framerate), avctx->time_base); else { -FF_DISABLE_DEPRECATION_WARNINGS - duration = -#if FF_API_TICKS_PER_FRAME - avctx->ticks_per_frame ? avctx->ticks_per_frame : -#endif - 1; -FF_ENABLE_DEPRECATION_WARNINGS + duration = 1; } switch (frame->color_range) { @@ -1464,7 +1438,6 @@ 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}, 0, 8, VE}, diff --git a/libavcodec/libaribb24.c b/libavcodec/libaribb24.c index 009c995ded..a26e456295 100644 --- a/libavcodec/libaribb24.c +++ b/libavcodec/libaribb24.c @@ -96,13 +96,13 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) font_size = get_profile_font_size(avctx); avctx->subtitle_header = av_asprintf( - "[Script Info]\r\n" - "; Script generated by FFmpeg/Lavc%s\r\n" - "ScriptType: v4.00+\r\n" - "PlayResX: %d\r\n" - "PlayResY: %d\r\n" - "\r\n" - "[V4+ Styles]\r\n" + "[Script Info]\n" + "; Script generated by FFmpeg/Lavc%s\n" + "ScriptType: v4.00+\n" + "PlayResX: %d\n" + "PlayResY: %d\n" + "\n" + "[V4+ Styles]\n" /* ASSv4 header */ "Format: Name, " @@ -113,7 +113,7 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) "Spacing, Angle, " "BorderStyle, Outline, Shadow, " "Alignment, MarginL, MarginR, MarginV, " - "Encoding\r\n" + "Encoding\n" "Style: " "Default," /* Name */ @@ -124,11 +124,11 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) "0,0," /* Spacing, Angle */ "%d,1,0," /* BorderStyle, Outline, Shadow */ "%d,10,10,10," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ + "0\n" /* Encoding */ - "\r\n" - "[Events]\r\n" - "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + "\n" + "[Events]\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n", !(avctx->flags & AV_CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "", plane_width, plane_height, ASS_DEFAULT_FONT, font_size, ASS_DEFAULT_COLOR, @@ -144,7 +144,7 @@ static int libaribb24_generate_ass_header(AVCodecContext *avctx) return 0; } -static int libaribb24_init(AVCodecContext *avctx) +static av_cold int libaribb24_init(AVCodecContext *avctx) { Libaribb24Context *b24 = avctx->priv_data; void(* arib_dec_init)(arib_decoder_t* decoder) = NULL; @@ -197,7 +197,7 @@ static int libaribb24_init(AVCodecContext *avctx) return 0; } -static int libaribb24_close(AVCodecContext *avctx) +static av_cold int libaribb24_close(AVCodecContext *avctx) { Libaribb24Context *b24 = avctx->priv_data; diff --git a/libavcodec/libaribcaption.c b/libavcodec/libaribcaption.c index 0b67d41772..66d18b9d38 100644 --- a/libavcodec/libaribcaption.c +++ b/libavcodec/libaribcaption.c @@ -250,7 +250,7 @@ static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, in return c; } -/* initialiaze CLUT with each character colors */ +/* initialize CLUT with each character colors */ static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region) { aribcc_color_t text_color, back_color, stroke_color; @@ -522,14 +522,14 @@ static int set_ass_header(ARIBCaptionContext *ctx) av_freep(&avctx->subtitle_header); avctx->subtitle_header = av_asprintf( - "[Script Info]\r\n" - "ScriptType: v4.00+\r\n" - "PlayResX: %d\r\n" - "PlayResY: %d\r\n" - "WrapStyle: 2\r\n" /* 2: no word wrapping */ - "\r\n" + "[Script Info]\n" + "ScriptType: v4.00+\n" + "PlayResX: %d\n" + "PlayResY: %d\n" + "WrapStyle: 2\n" /* 2: no word wrapping */ + "\n" - "[V4+ Styles]\r\n" + "[V4+ Styles]\n" "Format: Name, " "Fontname, Fontsize, " "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " @@ -538,7 +538,7 @@ static int set_ass_header(ARIBCaptionContext *ctx) "Spacing, Angle, " "BorderStyle, Outline, Shadow, " "Alignment, MarginL, MarginR, MarginV, " - "Encoding\r\n" + "Encoding\n" "Style: " "Default," /* Name */ @@ -549,11 +549,11 @@ static int set_ass_header(ARIBCaptionContext *ctx) "0,0," /* Spacing, Angle */ "%d,%d,%d," /* BorderStyle, Outline, Shadow */ "%d,10,10,10," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ - "\r\n" + "0\n" /* Encoding */ + "\n" - "[Events]\r\n" - "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + "[Events]\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n", ctx->plane_width, ctx->plane_height, font_name, ctx->font_size, ASS_DEFAULT_COLOR, ASS_DEFAULT_COLOR, @@ -939,7 +939,7 @@ static void aribcaption_flush(AVCodecContext *avctx) ctx->readorder = 0; } -static int aribcaption_close(AVCodecContext *avctx) +static av_cold int aribcaption_close(AVCodecContext *avctx) { ARIBCaptionContext *ctx = avctx->priv_data; @@ -954,7 +954,7 @@ static int aribcaption_close(AVCodecContext *avctx) return 0; } -static int aribcaption_init(AVCodecContext *avctx) +static av_cold int aribcaption_init(AVCodecContext *avctx) { ARIBCaptionContext *ctx = avctx->priv_data; aribcc_profile_t profile; diff --git a/libavcodec/libcodec2.c b/libavcodec/libcodec2.c index ebcd20c447..b0ba01bcb4 100644 --- a/libavcodec/libcodec2.c +++ b/libavcodec/libcodec2.c @@ -182,9 +182,9 @@ const FFCodec ff_libcodec2_decoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_CODEC2, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLERATES(8000), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibCodec2Context), .init = libcodec2_init_decoder, @@ -199,9 +199,9 @@ const FFCodec ff_libcodec2_encoder = { .p.id = AV_CODEC_ID_CODEC2, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLERATES(8000), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .p.priv_class = &libcodec2_enc_class, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibCodec2Context), diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index 546b42e9c6..a1158a23c4 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -162,10 +162,14 @@ static void libdav1d_init_params(AVCodecContext *c, const Dav1dSequenceHeader *s (unsigned)seq->num_units_in_tick, (unsigned)seq->time_scale); +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (seq->film_grain_present) c->properties |= FF_CODEC_PROPERTY_FILM_GRAIN; else c->properties &= ~FF_CODEC_PROPERTY_FILM_GRAIN; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static av_cold int libdav1d_parse_extradata(AVCodecContext *c) @@ -372,15 +376,90 @@ static int libdav1d_receive_frame_internal(AVCodecContext *c, Dav1dPicture *p) res = dav1d_get_picture(dav1d->c, p); if (res < 0) { - if (res == AVERROR(EINVAL)) + if (res == AVERROR(EINVAL)) { + dav1d_data_unref(data); res = AVERROR_INVALIDDATA; - else if (res == AVERROR(EAGAIN)) + } else if (res == AVERROR(EAGAIN)) res = c->internal->draining ? AVERROR_EOF : 1; } return res; } +static int parse_itut_t35_metadata(Libdav1dContext *dav1d, Dav1dPicture *p, + const Dav1dITUTT35 *itut_t35, AVCodecContext *c, + AVFrame *frame) { + GetByteContext gb; + int provider_code, country_code; + int res; + + bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); + + provider_code = bytestream2_get_be16(&gb); + country_code = itut_t35->country_code; + if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_ATSC) { + uint32_t user_identifier = bytestream2_get_be32(&gb); + switch (user_identifier) { + case MKBETAG('G', 'A', '9', '4'): { // closed captions + AVBufferRef *buf = NULL; + + res = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb)); + if (res < 0) + return res; + if (!res) + return 0; // no cc found, ignore + + res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf); + if (res < 0) + return res; + +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS + c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + break; + } + default: // ignore unsupported identifiers + break; + } + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG) { + AVDynamicHDRPlus *hdrplus; + int provider_oriented_code = bytestream2_get_be16(&gb); + int application_identifier = bytestream2_get_byte(&gb); + + if (provider_oriented_code != 1 || application_identifier != 4) + return 0; // ignore + + hdrplus = av_dynamic_hdr_plus_create_side_data(frame); + if (!hdrplus) + return AVERROR(ENOMEM); + + res = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer, + bytestream2_get_bytes_left(&gb)); + if (res < 0) + return res; + } else if (country_code == ITU_T_T35_COUNTRY_CODE_US && provider_code == ITU_T_T35_PROVIDER_CODE_DOLBY) { + int provider_oriented_code = bytestream2_get_be32(&gb); + if (provider_oriented_code != 0x800) + return 0; // ignore + + res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, gb.buffer_end - gb.buffer, + c->err_recognition); + if (res < 0) { + av_log(c, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); + return 0; // ignore + } + + res = ff_dovi_attach_side_data(&dav1d->dovi, frame); + if (res < 0) + return res; + } else { + // ignore unsupported provider codes + } + return 0; +} + static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) { Libdav1dContext *dav1d = c->priv_data; @@ -509,79 +588,9 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) #else const Dav1dITUTT35 *itut_t35 = p->itut_t35; #endif - GetByteContext gb; - int provider_code; - - bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size); - - provider_code = bytestream2_get_be16(&gb); - switch (provider_code) { - case ITU_T_T35_PROVIDER_CODE_ATSC: { - uint32_t user_identifier = bytestream2_get_be32(&gb); - switch (user_identifier) { - case MKBETAG('G', 'A', '9', '4'): { // closed captions - AVBufferRef *buf = NULL; - - res = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb)); - if (res < 0) - goto fail; - if (!res) - break; - - res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf); - if (res < 0) - goto fail; - - c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; - break; - } - default: // ignore unsupported identifiers - break; - } - break; - } - case ITU_T_T35_PROVIDER_CODE_SMTPE: { - AVDynamicHDRPlus *hdrplus; - int provider_oriented_code = bytestream2_get_be16(&gb); - int application_identifier = bytestream2_get_byte(&gb); - - if (itut_t35->country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 1 || application_identifier != 4) - break; - - hdrplus = av_dynamic_hdr_plus_create_side_data(frame); - if (!hdrplus) { - res = AVERROR(ENOMEM); - goto fail; - } - - res = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer, - bytestream2_get_bytes_left(&gb)); - if (res < 0) - goto fail; - break; - } - case ITU_T_T35_PROVIDER_CODE_DOLBY: { - int provider_oriented_code = bytestream2_get_be32(&gb); - if (itut_t35->country_code != ITU_T_T35_COUNTRY_CODE_US || - provider_oriented_code != 0x800) - break; - - res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, gb.buffer_end - gb.buffer, - c->err_recognition); - if (res < 0) { - av_log(c, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); - break; // ignore - } - - res = ff_dovi_attach_side_data(&dav1d->dovi, frame); - if (res < 0) - goto fail; - break; - } - default: // ignore unsupported provider codes - break; - } + res = parse_itut_t35_metadata(dav1d, p, itut_t35, c, frame); + if (res < 0) + goto fail; #if FF_DAV1D_VERSION_AT_LEAST(6,9) } #endif diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c index 1324377fb4..ac221645f0 100644 --- a/libavcodec/libfdk-aacdec.c +++ b/libavcodec/libfdk-aacdec.c @@ -111,7 +111,7 @@ static const AVClass fdk_aac_dec_class = { .version = LIBAVUTIL_VERSION_INT, }; -static int get_stream_info(AVCodecContext *avctx) +static int get_stream_info(AVCodecContext *avctx, AVFrame *frame) { FDKAACDecContext *s = avctx->priv_data; CStreamInfo *info = aacDecoder_GetStreamInfo(s->handle); @@ -130,6 +130,9 @@ static int get_stream_info(AVCodecContext *avctx) } avctx->sample_rate = info->sampleRate; avctx->frame_size = info->frameSize; + avctx->profile = info->aot - 1; + + frame->flags |= AV_FRAME_FLAG_KEY * !!(info->flags & AC_INDEP); #if FDKDEC_VER_AT_LEAST(2, 5) // 2.5.10 if (!s->output_delay_set && info->outputDelay) { // Set this only once. @@ -413,7 +416,7 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, AVFrame *frame, goto end; } - if ((ret = get_stream_info(avctx)) < 0) + if ((ret = get_stream_info(avctx, frame)) < 0) goto end; frame->nb_samples = avctx->frame_size; diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index 0f33cdb8c9..1a3f127d37 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -178,6 +178,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) AACContext *s = avctx->priv_data; int ret = AVERROR(EINVAL); AACENC_InfoStruct info = { 0 }; + AVCPBProperties *cpb_props; CHANNEL_MODE mode; AACENC_ERROR err; int aot = AV_PROFILE_AAC_LOW + 1; @@ -438,6 +439,14 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) memcpy(avctx->extradata, info.confBuf, info.confSize); } + + cpb_props = ff_encode_add_cpb_side_data(avctx); + if (!cpb_props) + return AVERROR(ENOMEM); + cpb_props->max_bitrate = + cpb_props->min_bitrate = + cpb_props->avg_bitrate = avctx->bit_rate; + return 0; error: aac_encode_close(avctx); @@ -540,6 +549,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } avpkt->size = out_args.numOutBytes; + avpkt->flags |= AV_PKT_FLAG_KEY; *got_packet_ptr = 1; return 0; } @@ -597,12 +607,11 @@ const FFCodec ff_libfdk_aac_encoder = { FF_CODEC_ENCODE_CB(aac_encode_frame), .flush = aac_encode_flush, .close = aac_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &aac_enc_class, .defaults = aac_encode_defaults, .p.profiles = profiles, - .p.supported_samplerates = aac_sample_rates, + CODEC_SAMPLERATES_ARRAY(aac_sample_rates), .p.wrapper_name = "libfdk", - .p.ch_layouts = aac_ch_layouts, + CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts), }; diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c index 505b6afb07..6b4786a8a5 100644 --- a/libavcodec/libgsmenc.c +++ b/libavcodec/libgsmenc.c @@ -127,9 +127,8 @@ const FFCodec ff_libgsm_encoder = { FF_CODEC_ENCODE_CB(libgsm_encode_frame), .close = libgsm_encode_close, .defaults = libgsm_defaults, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.wrapper_name = "libgsm", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; @@ -145,9 +144,8 @@ const FFCodec ff_libgsm_ms_encoder = { FF_CODEC_ENCODE_CB(libgsm_encode_frame), .close = libgsm_encode_close, .defaults = libgsm_defaults, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.wrapper_name = "libgsm", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c index 9ca90bf0c6..f496f16db9 100644 --- a/libavcodec/libilbc.c +++ b/libavcodec/libilbc.c @@ -210,8 +210,7 @@ const FFCodec ff_libilbc_encoder = { .priv_data_size = sizeof(ILBCEncContext), .init = ilbc_encode_init, FF_CODEC_ENCODE_CB(ilbc_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .defaults = ilbc_encode_defaults, .p.priv_class = &ilbc_enc_class, .p.wrapper_name = "libbilbc", diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c index 9dfc261e3d..96c338d1b4 100644 --- a/libavcodec/libjxldec.c +++ b/libavcodec/libjxldec.c @@ -549,3 +549,19 @@ const FFCodec ff_libjxl_decoder = { FF_CODEC_CAP_ICC_PROFILES, .p.wrapper_name = "libjxl", }; + +const FFCodec ff_libjxl_anim_decoder = { + .p.name = "libjxl_anim", + CODEC_LONG_NAME("libjxl JPEG XL animated"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXL_ANIM, + .priv_data_size = sizeof(LibJxlDecodeContext), + .init = libjxl_decode_init, + FF_CODEC_RECEIVE_FRAME_CB(libjxl_receive_frame), + .close = libjxl_decode_close, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_OTHER_THREADS, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, + .p.wrapper_name = "libjxl", +}; diff --git a/libavcodec/libjxlenc.c b/libavcodec/libjxlenc.c index 8b0e60df6f..40d5f760b1 100644 --- a/libavcodec/libjxlenc.c +++ b/libavcodec/libjxlenc.c @@ -56,6 +56,12 @@ typedef struct LibJxlEncodeContext { int xyb; uint8_t *buffer; size_t buffer_size; + JxlPixelFormat jxl_fmt; + + /* animation stuff */ + AVFrame *frame; + AVFrame *prev; + int64_t duration; } LibJxlEncodeContext; /** @@ -87,9 +93,9 @@ static float quality_to_distance(float quality) } /** - * Initalize the encoder on a per-frame basis. All of these need to be set - * once each time the encoder is reset, which it must be each frame to make - * the image2 muxer work. + * Initialize the encoder on a per-file basis. All of these need to be set + * once each time the encoder is reset, which is each frame for still + * images, to make the image2 muxer work. For animation this is run once. * * @return 0 upon success, negative on failure. */ @@ -100,12 +106,6 @@ static int libjxl_init_jxl_encoder(AVCodecContext *avctx) /* reset the encoder every frame for image2 muxer */ JxlEncoderReset(ctx->encoder); - ctx->options = JxlEncoderFrameSettingsCreate(ctx->encoder, NULL); - if (!ctx->options) { - av_log(avctx, AV_LOG_ERROR, "Failed to create JxlEncoderOptions\n"); - return AVERROR_EXTERNAL; - } - /* This needs to be set each time the encoder is reset */ if (JxlEncoderSetParallelRunner(ctx->encoder, JxlThreadParallelRunner, ctx->runner) != JXL_ENC_SUCCESS) { @@ -113,42 +113,9 @@ static int libjxl_init_jxl_encoder(AVCodecContext *avctx) return AVERROR_EXTERNAL; } - /* these shouldn't fail, libjxl bug notwithstanding */ - if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_EFFORT, ctx->effort) - != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set effort to: %d\n", ctx->effort); - return AVERROR_EXTERNAL; - } - - /* check for negative, our default */ - if (ctx->distance < 0.0) { - /* use ffmpeg.c -q option if passed */ - if (avctx->flags & AV_CODEC_FLAG_QSCALE) - ctx->distance = quality_to_distance((float)avctx->global_quality / FF_QP2LAMBDA); - else - /* default 1.0 matches cjxl */ - ctx->distance = 1.0; - } - - /* - * 0.01 is the minimum distance accepted for lossy - * interpreting any positive value less than this as minimum - */ - if (ctx->distance > 0.0 && ctx->distance < 0.01) - ctx->distance = 0.01; - if (JxlEncoderSetFrameDistance(ctx->options, ctx->distance) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set distance: %f\n", ctx->distance); - return AVERROR_EXTERNAL; - } - - /* - * In theory the library should automatically enable modular if necessary, - * but it appears it won't at the moment due to a bug. This will still - * work even if that is patched. - */ - if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_MODULAR, - ctx->modular || ctx->distance <= 0.0 ? 1 : -1) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set modular\n"); + ctx->options = JxlEncoderFrameSettingsCreate(ctx->encoder, NULL); + if (!ctx->options) { + av_log(avctx, AV_LOG_ERROR, "Failed to create JxlEncoderOptions\n"); return AVERROR_EXTERNAL; } @@ -185,6 +152,47 @@ static av_cold int libjxl_encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } + /* check for negative, our default */ + if (ctx->distance < 0.0) { + /* use ffmpeg.c -q option if passed */ + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + ctx->distance = quality_to_distance((float)avctx->global_quality / FF_QP2LAMBDA); + else + /* default 1.0 matches cjxl */ + ctx->distance = 1.0; + } + /* + * 0.01 is the minimum distance accepted for lossy + * interpreting any positive value less than this as minimum + */ + if (ctx->distance > 0.0 && ctx->distance < 0.01) + ctx->distance = 0.01; + + return 0; +} + +/** + * Initializer for the animation encoder. This calls the other initializers + * to prevent code duplication and also allocates the prev-frame used in the + * encoder. + */ +static av_cold int libjxl_anim_encode_init(AVCodecContext *avctx) +{ + int ret; + LibJxlEncodeContext *ctx = avctx->priv_data; + + ret = libjxl_encode_init(avctx); + if (ret < 0) + return ret; + + ret = libjxl_init_jxl_encoder(avctx); + if (ret < 0) + return ret; + + ctx->frame = av_frame_alloc(); + if (!ctx->frame) + return AVERROR(ENOMEM); + return 0; } @@ -239,83 +247,12 @@ static int libjxl_populate_primaries(void *avctx, JxlColorEncoding *jxl_color, e return 0; } -/** - * Encode an entire frame. Currently animation, is not supported by - * this encoder, so this will always reinitialize a new still image - * and encode a one-frame image (for image2 and image2pipe). - */ -static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) +static int libjxl_populate_colorspace(AVCodecContext *avctx, const AVFrame *frame, + const AVPixFmtDescriptor *pix_desc, const JxlBasicInfo *info) { - LibJxlEncodeContext *ctx = avctx->priv_data; - AVFrameSideData *sd; - const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(frame->format); - JxlBasicInfo info; JxlColorEncoding jxl_color; - JxlPixelFormat jxl_fmt; - int bits_per_sample; -#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) - JxlBitDepth jxl_bit_depth; -#endif - JxlEncoderStatus jret; + LibJxlEncodeContext *ctx = avctx->priv_data; int ret; - size_t available = ctx->buffer_size; - size_t bytes_written = 0; - uint8_t *next_out = ctx->buffer; - const uint8_t *data; - - ret = libjxl_init_jxl_encoder(avctx); - if (ret) { - av_log(avctx, AV_LOG_ERROR, "Error frame-initializing JxlEncoder\n"); - return ret; - } - - /* populate the basic info settings */ - JxlEncoderInitBasicInfo(&info); - jxl_fmt.num_channels = pix_desc->nb_components; - info.xsize = frame->width; - info.ysize = frame->height; - info.num_extra_channels = (jxl_fmt.num_channels + 1) % 2; - info.num_color_channels = jxl_fmt.num_channels - info.num_extra_channels; - bits_per_sample = av_get_bits_per_pixel(pix_desc) / jxl_fmt.num_channels; - info.bits_per_sample = avctx->bits_per_raw_sample > 0 && !(pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) - ? avctx->bits_per_raw_sample : bits_per_sample; - info.alpha_bits = (info.num_extra_channels > 0) * info.bits_per_sample; - if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - info.exponent_bits_per_sample = info.bits_per_sample > 16 ? 8 : 5; - info.alpha_exponent_bits = info.alpha_bits ? info.exponent_bits_per_sample : 0; - jxl_fmt.data_type = info.bits_per_sample > 16 ? JXL_TYPE_FLOAT : JXL_TYPE_FLOAT16; - } else { - info.exponent_bits_per_sample = 0; - info.alpha_exponent_bits = 0; - jxl_fmt.data_type = info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16; - } - -#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) - jxl_bit_depth.bits_per_sample = bits_per_sample; - jxl_bit_depth.type = JXL_BIT_DEPTH_FROM_PIXEL_FORMAT; - jxl_bit_depth.exponent_bits_per_sample = pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT ? - info.exponent_bits_per_sample : 0; -#endif - - /* JPEG XL format itself does not support limited range */ - if (avctx->color_range == AVCOL_RANGE_MPEG || - avctx->color_range == AVCOL_RANGE_UNSPECIFIED && frame->color_range == AVCOL_RANGE_MPEG) - av_log(avctx, AV_LOG_WARNING, "This encoder does not support limited (tv) range, colors will be wrong!\n"); - else if (avctx->color_range != AVCOL_RANGE_JPEG && frame->color_range != AVCOL_RANGE_JPEG) - av_log(avctx, AV_LOG_WARNING, "Unknown color range, assuming full (pc)\n"); - - /* bitexact lossless requires there to be no XYB transform */ - info.uses_original_profile = ctx->distance == 0.0 || !ctx->xyb; - info.orientation = frame->linesize[0] >= 0 ? JXL_ORIENT_IDENTITY : JXL_ORIENT_FLIP_VERTICAL; - - if (JxlEncoderSetBasicInfo(ctx->encoder, &info) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set JxlBasicInfo\n"); - return AVERROR_EXTERNAL; - } - - /* rendering intent doesn't matter here - * but libjxl will whine if we don't set it */ - jxl_color.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; switch (frame->color_trc && frame->color_trc != AVCOL_TRC_UNSPECIFIED ? frame->color_trc : avctx->color_trc) { @@ -347,32 +284,115 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra break; default: if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { - av_log(avctx, AV_LOG_WARNING, "Unknown transfer function, assuming Linear Light. Colors may be wrong.\n"); + av_log(avctx, AV_LOG_WARNING, + "Unknown transfer function, assuming Linear Light. Colors may be wrong.\n"); jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR; } else { - av_log(avctx, AV_LOG_WARNING, "Unknown transfer function, assuming IEC61966-2-1/sRGB. Colors may be wrong.\n"); + av_log(avctx, AV_LOG_WARNING, + "Unknown transfer function, assuming IEC61966-2-1/sRGB. Colors may be wrong.\n"); jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; } } - /* This should be implied to be honest - * but a libjxl bug makes it fail otherwise */ - if (info.num_color_channels == 1) + jxl_color.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + if (info->num_color_channels == 1) jxl_color.color_space = JXL_COLOR_SPACE_GRAY; else jxl_color.color_space = JXL_COLOR_SPACE_RGB; ret = libjxl_populate_primaries(avctx, &jxl_color, - frame->color_primaries && frame->color_primaries != AVCOL_PRI_UNSPECIFIED - ? frame->color_primaries : avctx->color_primaries); + frame->color_primaries && frame->color_primaries != AVCOL_PRI_UNSPECIFIED + ? frame->color_primaries : avctx->color_primaries); if (ret < 0) return ret; - sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); - if (sd && sd->size && JxlEncoderSetICCProfile(ctx->encoder, sd->data, sd->size) != JXL_ENC_SUCCESS) - av_log(avctx, AV_LOG_WARNING, "Could not set ICC Profile\n"); - if (JxlEncoderSetColorEncoding(ctx->encoder, &jxl_color) != JXL_ENC_SUCCESS) + if (JxlEncoderSetColorEncoding(ctx->encoder, &jxl_color) != JXL_ENC_SUCCESS) { av_log(avctx, AV_LOG_WARNING, "Failed to set JxlColorEncoding\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +/** + * Sends metadata to libjxl based on the first frame of the stream, such as pixel format, + * orientation, bit depth, and that sort of thing. + */ +static int libjxl_preprocess_stream(AVCodecContext *avctx, const AVFrame *frame, int animated) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + AVFrameSideData *sd; + const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(frame->format); + JxlBasicInfo info; + JxlPixelFormat *jxl_fmt = &ctx->jxl_fmt; + int bits_per_sample; +#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) + JxlBitDepth jxl_bit_depth; +#endif + + /* populate the basic info settings */ + JxlEncoderInitBasicInfo(&info); + jxl_fmt->num_channels = pix_desc->nb_components; + info.xsize = frame->width; + info.ysize = frame->height; + info.num_extra_channels = (jxl_fmt->num_channels + 1) & 0x1; + info.num_color_channels = jxl_fmt->num_channels - info.num_extra_channels; + bits_per_sample = av_get_bits_per_pixel(pix_desc) / jxl_fmt->num_channels; + info.bits_per_sample = avctx->bits_per_raw_sample > 0 && !(pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) + ? avctx->bits_per_raw_sample : bits_per_sample; + info.alpha_bits = (info.num_extra_channels > 0) * info.bits_per_sample; + if (pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT) { + info.exponent_bits_per_sample = info.bits_per_sample > 16 ? 8 : 5; + info.alpha_exponent_bits = info.alpha_bits ? info.exponent_bits_per_sample : 0; + jxl_fmt->data_type = info.bits_per_sample > 16 ? JXL_TYPE_FLOAT : JXL_TYPE_FLOAT16; + } else { + info.exponent_bits_per_sample = 0; + info.alpha_exponent_bits = 0; + jxl_fmt->data_type = info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16; + } + +#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) + jxl_bit_depth.bits_per_sample = bits_per_sample; + jxl_bit_depth.type = JXL_BIT_DEPTH_FROM_PIXEL_FORMAT; + jxl_bit_depth.exponent_bits_per_sample = pix_desc->flags & AV_PIX_FMT_FLAG_FLOAT ? + info.exponent_bits_per_sample : 0; +#endif + + /* JPEG XL format itself does not support limited range */ + if (avctx->color_range == AVCOL_RANGE_MPEG || + avctx->color_range == AVCOL_RANGE_UNSPECIFIED && frame->color_range == AVCOL_RANGE_MPEG) + av_log(avctx, AV_LOG_WARNING, "This encoder does not support limited (tv) range, colors will be wrong!\n"); + else if (avctx->color_range != AVCOL_RANGE_JPEG && frame->color_range != AVCOL_RANGE_JPEG) + av_log(avctx, AV_LOG_WARNING, "Unknown color range, assuming full (pc)\n"); + + /* bitexact lossless requires there to be no XYB transform */ + info.uses_original_profile = ctx->distance == 0.0 || !ctx->xyb; + + /* libjxl doesn't support negative linesizes so we use orientation to work around this */ + info.orientation = frame->linesize[0] >= 0 ? JXL_ORIENT_IDENTITY : JXL_ORIENT_FLIP_VERTICAL; + + if (animated) { + info.have_animation = 1; + info.animation.have_timecodes = 0; + info.animation.num_loops = 0; + /* avctx->timebase is in seconds per tick, so we take the reciprocol */ + info.animation.tps_numerator = avctx->time_base.den; + info.animation.tps_denominator = avctx->time_base.num; + } + + if (JxlEncoderSetBasicInfo(ctx->encoder, &info) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set JxlBasicInfo\n"); + return AVERROR_EXTERNAL; + } + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); + if (sd && sd->size && JxlEncoderSetICCProfile(ctx->encoder, sd->data, sd->size) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_WARNING, "Could not set ICC Profile\n"); + sd = NULL; + } + + if (!sd || !sd->size) + libjxl_populate_colorspace(avctx, frame, pix_desc, &info); #if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0) if (JxlEncoderSetFrameBitDepth(ctx->options, &jxl_bit_depth) != JXL_ENC_SUCCESS) @@ -386,25 +406,70 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra av_log(avctx, AV_LOG_WARNING, "Could not increase codestream level\n"); } - jxl_fmt.endianness = JXL_NATIVE_ENDIAN; - if (frame->linesize[0] >= 0) { - jxl_fmt.align = frame->linesize[0]; - data = frame->data[0]; - } else { - jxl_fmt.align = -frame->linesize[0]; - data = frame->data[0] + frame->linesize[0] * (info.ysize - 1); + return 0; +} + +/** + * Sends frame information to libjxl on a per-frame basis. If this is a still image, + * this is evaluated once per output file. If this is an animated JPEG XL encode, it + * is called once per frame. + * + * This returns a buffer to the data that should be passed to libjxl (via the + * argument **data). If the linesize is nonnegative, this will be frame->data[0], + * although if the linesize is negative, it will be the start of the buffer + * instead. *data is just a pointer to a location in frame->data so it should not be + * freed directly. + */ +static int libjxl_preprocess_frame(AVCodecContext *avctx, const AVFrame *frame, const uint8_t **data) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + JxlPixelFormat *jxl_fmt = &ctx->jxl_fmt; + + /* these shouldn't fail, libjxl bug notwithstanding */ + if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_EFFORT, ctx->effort) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set effort to: %d\n", ctx->effort); + return AVERROR_EXTERNAL; } - if (JxlEncoderAddImageFrame(ctx->options, &jxl_fmt, data, jxl_fmt.align * info.ysize) != JXL_ENC_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + if (JxlEncoderSetFrameDistance(ctx->options, ctx->distance) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set distance: %f\n", ctx->distance); return AVERROR_EXTERNAL; } /* - * Run this after the last frame in the image has been passed. - * TODO support animation + * In theory the library should automatically enable modular if necessary, + * but it appears it won't at the moment due to a bug. This will still + * work even if that is patched. */ - JxlEncoderCloseInput(ctx->encoder); + if (JxlEncoderFrameSettingsSetOption(ctx->options, JXL_ENC_FRAME_SETTING_MODULAR, + ctx->modular || ctx->distance <= 0.0 ? 1 : -1) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set modular\n"); + return AVERROR_EXTERNAL; + } + + jxl_fmt->endianness = JXL_NATIVE_ENDIAN; + if (frame->linesize[0] >= 0) { + jxl_fmt->align = frame->linesize[0]; + *data = frame->data[0]; + } else { + jxl_fmt->align = -frame->linesize[0]; + *data = frame->data[0] + frame->linesize[0] * (frame->height - 1); + } + + return 0; +} + +/** + * Run libjxl's output processing loop, reallocating the packet as necessary + * if libjxl needs more space to work with. + */ +static int libjxl_process_output(AVCodecContext *avctx, size_t *bytes_written) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + JxlEncoderStatus jret; + size_t available = ctx->buffer_size; + uint8_t *next_out = ctx->buffer; while (1) { jret = JxlEncoderProcessOutput(ctx->encoder, &next_out, &available); @@ -412,7 +477,7 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra av_log(avctx, AV_LOG_ERROR, "Unspecified libjxl error occurred\n"); return AVERROR_EXTERNAL; } - bytes_written = ctx->buffer_size - available; + *bytes_written = ctx->buffer_size - available; /* all data passed has been encoded */ if (jret == JXL_ENC_SUCCESS) break; @@ -429,14 +494,58 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra return AVERROR(ENOMEM); ctx->buffer = temp; ctx->buffer_size = new_size; - next_out = ctx->buffer + bytes_written; - available = new_size - bytes_written; + next_out = ctx->buffer + *bytes_written; + available = new_size - *bytes_written; continue; } av_log(avctx, AV_LOG_ERROR, "Bad libjxl event: %d\n", jret); return AVERROR_EXTERNAL; } + return 0; +} + +/** + * Encode an entire frame. This will always reinitialize a new still image + * and encode a one-frame image (for image2 and image2pipe). + */ +static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) +{ + + LibJxlEncodeContext *ctx = avctx->priv_data; + int ret; + size_t bytes_written = 0; + const uint8_t *data; + + ret = libjxl_init_jxl_encoder(avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error frame-initializing JxlEncoder\n"); + return ret; + } + + ret = libjxl_preprocess_stream(avctx, frame, 0); + if (ret < 0) + return ret; + + ret = libjxl_preprocess_frame(avctx, frame, &data); + if (ret < 0) + return ret; + + if (JxlEncoderAddImageFrame(ctx->options, &ctx->jxl_fmt, data, ctx->jxl_fmt.align * frame->height) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + return AVERROR_EXTERNAL; + } + + /* + * Run this after the last frame in the image has been passed. + */ + JxlEncoderCloseInput(ctx->encoder); + + ret = libjxl_process_output(avctx, &bytes_written); + if (ret < 0) + return ret; + ret = ff_get_encode_buffer(avctx, pkt, bytes_written, 0); if (ret < 0) return ret; @@ -447,6 +556,94 @@ static int libjxl_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFra return 0; } +/** + * Encode one frame of the animation. libjxl requires us to set duration of the frame + * but we're only promised the PTS, not the duration. As a result we have to buffer + * a frame and subtract the PTS from the last PTS. The last frame uses the previous + * frame's calculated duration as a fallback if its duration field is unset. + * + * We also need to tell libjxl if our frame is the last one, which we won't know upon + * receiving a single frame, so we have to buffer a frame as well and send the "last frame" + * upon receiving the special EOF frame. + */ +static int libjxl_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt) +{ + LibJxlEncodeContext *ctx = avctx->priv_data; + int ret = 0; + JxlFrameHeader frame_header; + size_t bytes_written = 0; + const uint8_t *data; + + if (!ctx->prev) { + ctx->prev = av_frame_alloc(); + if (!ctx->prev) + return AVERROR(ENOMEM); + ret = ff_encode_get_frame(avctx, ctx->prev); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return ret; + ret = libjxl_preprocess_stream(avctx, ctx->prev, 1); + if (ret < 0) + return ret; + } + + ret = ff_encode_get_frame(avctx, ctx->frame); + if (ret == AVERROR_EOF) { + av_frame_free(&ctx->frame); + ret = 0; + } + if (ret == AVERROR(EAGAIN)) + return ret; + + JxlEncoderInitFrameHeader(&frame_header); + + ctx->duration = ctx->prev->duration ? ctx->prev->duration : + ctx->frame ? ctx->frame->pts - ctx->prev->pts : + ctx->duration ? ctx->duration : + 1; + + frame_header.duration = ctx->duration; + pkt->duration = ctx->duration; + pkt->pts = ctx->prev->pts; + pkt->dts = pkt->pts; + + if (JxlEncoderSetFrameHeader(ctx->options, &frame_header) != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set JxlFrameHeader\n"); + return AVERROR_EXTERNAL; + } + + ret = libjxl_preprocess_frame(avctx, ctx->prev, &data); + if (ret < 0) + return ret; + + if (JxlEncoderAddImageFrame(ctx->options, &ctx->jxl_fmt, data, ctx->jxl_fmt.align * ctx->prev->height) + != JXL_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to add Image Frame\n"); + return AVERROR_EXTERNAL; + } + + if (!ctx->frame) + JxlEncoderCloseInput(ctx->encoder); + + ret = libjxl_process_output(avctx, &bytes_written); + if (ret < 0) + return ret; + + ret = ff_get_encode_buffer(avctx, pkt, bytes_written, 0); + if (ret < 0) + return ret; + + memcpy(pkt->data, ctx->buffer, bytes_written); + + if (ctx->frame) { + av_frame_unref(ctx->prev); + av_frame_move_ref(ctx->prev, ctx->frame); + } else { + av_frame_free(&ctx->prev); + } + + return ret; +} + static av_cold int libjxl_encode_close(AVCodecContext *avctx) { LibJxlEncodeContext *ctx = avctx->priv_data; @@ -464,6 +661,8 @@ static av_cold int libjxl_encode_close(AVCodecContext *avctx) ctx->encoder = NULL; av_freep(&ctx->buffer); + av_frame_free(&ctx->prev); + av_frame_free(&ctx->frame); return 0; } @@ -488,6 +687,16 @@ static const AVClass libjxl_encode_class = { .version = LIBAVUTIL_VERSION_INT, }; +static const enum AVPixelFormat libjxl_supported_pixfmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, + AV_PIX_FMT_RGBF32, AV_PIX_FMT_RGBAF32, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, + AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16, + AV_PIX_FMT_GRAYF32, + AV_PIX_FMT_NONE, +}; + const FFCodec ff_libjxl_encoder = { .p.name = "libjxl", CODEC_LONG_NAME("libjxl JPEG XL"), @@ -503,15 +712,27 @@ const FFCodec ff_libjxl_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, - AV_PIX_FMT_RGBF32, AV_PIX_FMT_RGBAF32, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, - AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16, - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS_ARRAY(libjxl_supported_pixfmts), + .p.priv_class = &libjxl_encode_class, + .p.wrapper_name = "libjxl", +}; + +const FFCodec ff_libjxl_anim_encoder = { + .p.name = "libjxl_anim", + CODEC_LONG_NAME("libjxl JPEG XL animated"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_JPEGXL_ANIM, + .priv_data_size = sizeof(LibJxlEncodeContext), + .init = libjxl_anim_encode_init, + FF_CODEC_RECEIVE_PACKET_CB(libjxl_anim_encode_frame), + .close = libjxl_encode_close, + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, + CODEC_PIXFMTS_ARRAY(libjxl_supported_pixfmts), .p.priv_class = &libjxl_encode_class, .p.wrapper_name = "libjxl", }; diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index e82be2a35f..78f0a94321 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -86,13 +86,7 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx) cfg->framerate_denom = avctx->framerate.den; } else { cfg->framerate_num = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - cfg->framerate_denom = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + cfg->framerate_denom = avctx->time_base.num; } cfg->target_bitrate = avctx->bit_rate; cfg->vui.sar_width = avctx->sample_aspect_ratio.num; @@ -333,7 +327,7 @@ const FFCodec ff_libkvazaar_encoder = { .p.id = AV_CODEC_ID_HEVC, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, diff --git a/libavcodec/liblc3enc.c b/libavcodec/liblc3enc.c index 3c0bcc6840..66007a90f3 100644 --- a/libavcodec/liblc3enc.c +++ b/libavcodec/liblc3enc.c @@ -201,12 +201,10 @@ const FFCodec ff_liblc3_encoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_LC3, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.supported_samplerates = (const int []) - { 96000, 48000, 32000, 24000, 16000, 8000, 0 }, - .p.sample_fmts = (const enum AVSampleFormat[]) - { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, .p.priv_class = &class, .p.wrapper_name = "liblc3", + CODEC_SAMPLERATES(96000, 48000, 32000, 24000, 16000, 8000), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .priv_data_size = sizeof(LibLC3EncContext), .init = liblc3_encode_init, .close = liblc3_encode_close, diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index 42558178e8..01b8985b8c 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -348,15 +348,9 @@ const FFCodec ff_libmp3lame_encoder = { .init = mp3lame_encode_init, FF_CODEC_ENCODE_CB(mp3lame_encode_frame), .close = mp3lame_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libmp3lame_sample_rates, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16P), + CODEC_SAMPLERATES_ARRAY(libmp3lame_sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), .p.priv_class = &libmp3lame_class, .defaults = libmp3lame_defaults, .p.wrapper_name = "libmp3lame", diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c new file mode 100644 index 0000000000..8e71fb54fe --- /dev/null +++ b/libavcodec/liboapvenc.c @@ -0,0 +1,511 @@ +/* + * liboapv encoder + * Advanced Professional Video codec library + * + * Copyright (C) 2025 Dawid Kozinski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +#include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/pixfmt.h" + +#include "avcodec.h" +#include "apv.h" +#include "codec_internal.h" +#include "encode.h" +#include "packet_internal.h" +#include "profiles.h" + +#define MAX_BS_BUF (128 * 1024 * 1024) +#define MAX_NUM_FRMS (1) // supports only 1-frame in an access unit +#define FRM_IDX (0) // supports only 1-frame in an access unit +#define MAX_NUM_CC (OAPV_MAX_CC) // Max number of color components (upto 4:4:4:4) + +/** + * The structure stores all the states associated with the instance of APV encoder + */ +typedef struct ApvEncContext { + const AVClass *class; + + oapve_t id; // APV instance identifier + oapvm_t mid; + oapve_cdesc_t cdsc; // coding parameters i.e profile, width & height of input frame, num of therads, frame rate ... + oapv_bitb_t bitb; // bitstream buffer (output) + oapve_stat_t stat; // encoding status (output) + + oapv_frms_t ifrms; // frames for input + + int num_frames; // number of frames in an access unit + + int preset_id; // preset of apv ( fastest, fast, medium, slow, placebo) + + int qp; // quantization parameter (QP) [0,63] + + AVDictionary *oapv_params; +} ApvEncContext; + +static int apv_imgb_release(oapv_imgb_t *imgb) +{ + int refcnt = --imgb->refcnt; + if (refcnt == 0) { + for (int i = 0; i < imgb->np; i++) + av_freep(&imgb->baddr[i]); + av_free(imgb); + } + + return refcnt; +} + +static int apv_imgb_addref(oapv_imgb_t * imgb) +{ + int refcnt = ++imgb->refcnt; + return refcnt; +} + +static int apv_imgb_getref(oapv_imgb_t * imgb) +{ + return imgb->refcnt; +} + +/** + * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined color format + * + * @return APV pre-defined color format (@see oapv.h) on success, OAPV_CF_UNKNOWN on failure + */ +static inline int get_color_format(enum AVPixelFormat pix_fmt) +{ + int cf = OAPV_CF_UNKNOWN; + + switch (pix_fmt) { + case AV_PIX_FMT_GRAY10: + cf = OAPV_CF_YCBCR400; + break; + case AV_PIX_FMT_YUV422P10: + cf = OAPV_CF_YCBCR422; + break; + case AV_PIX_FMT_YUV422P12: + cf = OAPV_CF_YCBCR422; + break; + case AV_PIX_FMT_YUV444P10: + cf = OAPV_CF_YCBCR444; + break; + case AV_PIX_FMT_YUV444P12: + cf = OAPV_CF_YCBCR444; + break; + case AV_PIX_FMT_YUVA444P10: + cf = OAPV_CF_YCBCR4444; + break; + case AV_PIX_FMT_YUVA444P12: + cf = OAPV_CF_YCBCR4444; + break; + default: + av_assert0(cf != OAPV_CF_UNKNOWN); + } + + return cf; +} + +static oapv_imgb_t *apv_imgb_create(AVCodecContext *avctx) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + oapv_imgb_t *imgb; + int input_depth; + int cfmt; // color format + int cs; + + av_assert0(desc); + + imgb = av_mallocz(sizeof(oapv_imgb_t)); + if (!imgb) + goto fail; + + input_depth = desc->comp[0].depth; + cfmt = get_color_format(avctx->pix_fmt); + cs = OAPV_CS_SET(cfmt, input_depth, AV_HAVE_BIGENDIAN); + + imgb->np = desc->nb_components; + + for (int i = 0; i < imgb->np; i++) { + imgb->w[i] = avctx->width >> ((i == 1 || i == 2) ? desc->log2_chroma_w : 0); + imgb->h[i] = avctx->height; + imgb->aw[i] = FFALIGN(imgb->w[i], OAPV_MB_W); + imgb->ah[i] = FFALIGN(imgb->h[i], OAPV_MB_H); + imgb->s[i] = imgb->aw[i] * OAPV_CS_GET_BYTE_DEPTH(cs); + + imgb->bsize[i] = imgb->e[i] = imgb->s[i] * imgb->ah[i]; + imgb->a[i] = imgb->baddr[i] = av_mallocz(imgb->bsize[i]); + if (imgb->a[i] == NULL) + goto fail; + } + + imgb->cs = cs; + imgb->addref = apv_imgb_addref; + imgb->getref = apv_imgb_getref; + imgb->release = apv_imgb_release; + imgb->refcnt = 1; + + return imgb; +fail: + av_log(avctx, AV_LOG_ERROR, "cannot create image buffer\n"); + if (imgb) { + for (int i = 0; i < imgb->np; i++) + av_freep(&imgb->a[i]); + av_freep(&imgb); + } + return NULL; +} + +/** + * The function returns a pointer to the object of the oapve_cdesc_t type. + * oapve_cdesc_t contains all encoder parameters that should be initialized before the encoder is used. + * + * The field values of the oapve_cdesc_t structure are populated based on: + * - the corresponding field values of the AvCodecConetxt structure, + * - the apv encoder specific option values, + * + * The order of processing input data and populating the apve_cdsc structure + * 1) first, the fields of the AVCodecContext structure corresponding to the provided input options are processed, + * (i.e -pix_fmt yuv422p -s:v 1920x1080 -r 30 -profile:v 0) + * 2) then apve-specific options added as AVOption to the apv AVCodec implementation + * (i.e -preset 0) + * + * Keep in mind that, there are options that can be set in different ways. + * In this case, please follow the above-mentioned order of processing. + * The most recent assignments overwrite the previous values. + * + * @param[in] avctx codec context (AVCodecContext) + * @param[out] cdsc contains all APV encoder encoder parameters that should be initialized before the encoder is use + * + * @return 0 on success, negative error code on failure + */ +static int get_conf(AVCodecContext *avctx, oapve_cdesc_t *cdsc) +{ + ApvEncContext *apv = avctx->priv_data; + + /* initialize apv_param struct with default values */ + int ret = oapve_param_default(&cdsc->param[FRM_IDX]); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "Cannot set default parameter\n"); + return AVERROR_EXTERNAL; + } + + /* read options from AVCodecContext */ + if (avctx->width > 0) + cdsc->param[FRM_IDX].w = avctx->width; + + if (avctx->height > 0) + cdsc->param[FRM_IDX].h = avctx->height; + + if (avctx->framerate.num > 0) { + cdsc->param[FRM_IDX].fps_num = avctx->framerate.num; + cdsc->param[FRM_IDX].fps_den = avctx->framerate.den; + } else if (avctx->time_base.num > 0) { + cdsc->param[FRM_IDX].fps_num = avctx->time_base.den; + cdsc->param[FRM_IDX].fps_den = avctx->time_base.num; + } + + cdsc->param[FRM_IDX].preset = apv->preset_id; + cdsc->param[FRM_IDX].qp = apv->qp; + if (avctx->bit_rate / 1000 > INT_MAX || avctx->rc_max_rate / 1000 > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "bit_rate and rc_max_rate > %d000 is not supported\n", INT_MAX); + return AVERROR(EINVAL); + } + cdsc->param[FRM_IDX].bitrate = (int)(avctx->bit_rate / 1000); + if (cdsc->param[FRM_IDX].bitrate) { + if (cdsc->param[FRM_IDX].qp) { + av_log(avctx, AV_LOG_WARNING, "You cannot set both the bitrate and the QP parameter at the same time.\n" + "If the bitrate is set, the rate control type is set to ABR, which means that the QP value is ignored.\n"); + } + cdsc->param[FRM_IDX].rc_type = OAPV_RC_ABR; + } + + cdsc->threads = avctx->thread_count; + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) { + cdsc->param[FRM_IDX].color_primaries = avctx->color_primaries; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) { + cdsc->param[FRM_IDX].transfer_characteristics = avctx->color_trc; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + cdsc->param[FRM_IDX].matrix_coefficients = avctx->colorspace; + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) { + cdsc->param[FRM_IDX].full_range_flag = (avctx->color_range == AVCOL_RANGE_JPEG); + cdsc->param[FRM_IDX].color_description_present_flag = 1; + } + + cdsc->max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size */ + cdsc->max_num_frms = MAX_NUM_FRMS; + + const AVDictionaryEntry *en = NULL; + while (en = av_dict_iterate(apv->oapv_params, en)) { + ret = oapve_param_parse(&cdsc->param[FRM_IDX], en->key, en->value); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = %s'.\n", en->key, en->value); + } + + return 0; +} + +/** + * @brief Initialize APV codec + * Create an encoder instance and allocate all the needed resources + * + * @param avctx codec context + * @return 0 on success, negative error code on failure + */ +static av_cold int liboapve_init(AVCodecContext *avctx) +{ + ApvEncContext *apv = avctx->priv_data; + oapve_cdesc_t *cdsc = &apv->cdsc; + unsigned char *bs_buf; + int ret; + + /* allocate bitstream buffer */ + bs_buf = (unsigned char *)av_malloc(MAX_BS_BUF); + if (bs_buf == NULL) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate bitstream buffer, size=%d\n", MAX_BS_BUF); + return AVERROR(ENOMEM); + } + apv->bitb.addr = bs_buf; + apv->bitb.bsize = MAX_BS_BUF; + + /* read configurations and set values for created descriptor (APV_CDSC) */ + ret = get_conf(avctx, cdsc); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot get OAPV configuration\n"); + return ret; + } + + /* create encoder */ + apv->id = oapve_create(cdsc, &ret); + if (apv->id == NULL) { + av_log(avctx, AV_LOG_ERROR, "Cannot create OAPV encoder\n"); + if (ret == OAPV_ERR_INVALID_LEVEL) + av_log(avctx, AV_LOG_ERROR, "Invalid level idc: %d\n", cdsc->param[0].level_idc); + return AVERROR_EXTERNAL; + } + + /* create metadata handler */ + apv->mid = oapvm_create(&ret); + if (apv->mid == NULL || OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "cannot create OAPV metadata handler\n"); + return AVERROR_EXTERNAL; + } + + int value = OAPV_CFG_VAL_AU_BS_FMT_NONE; + int size = 4; + ret = oapve_config(apv->id, OAPV_CFG_SET_AU_BS_FMT, &value, &size); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "Failed to set config for using encoder output format\n"); + return AVERROR_EXTERNAL; + } + + apv->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx); + if (apv->ifrms.frm[FRM_IDX].imgb == NULL) + return AVERROR(ENOMEM); + apv->ifrms.num_frms++; + + /* color description values */ + if (cdsc->param[FRM_IDX].color_description_present_flag) { + avctx->color_primaries = cdsc->param[FRM_IDX].color_primaries; + avctx->color_trc = cdsc->param[FRM_IDX].transfer_characteristics; + avctx->colorspace = cdsc->param[FRM_IDX].matrix_coefficients; + avctx->color_range = (cdsc->param[FRM_IDX].full_range_flag) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + } + + return 0; +} + +/** + * Encode raw data frame into APV packet + * + * @param[in] avctx codec context + * @param[out] avpkt output AVPacket containing encoded data + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in pkt + * + * @return 0 on success, negative error code on failure + */ +static int liboapve_encode(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet) +{ + ApvEncContext *apv = avctx->priv_data; + const oapve_cdesc_t *cdsc = &apv->cdsc; + oapv_frm_t *frm = &apv->ifrms.frm[FRM_IDX]; + oapv_imgb_t *imgb = frm->imgb; + int ret; + + if (avctx->width != frame->width || avctx->height != frame->height || avctx->pix_fmt != frame->format) { + av_log(avctx, AV_LOG_ERROR, "Dimension changes are not supported\n"); + return AVERROR(EINVAL); + } + + av_image_copy((uint8_t **)imgb->a, imgb->s, (const uint8_t **)frame->data, frame->linesize, + frame->format, frame->width, frame->height); + + imgb->ts[0] = frame->pts; + + frm->group_id = 1; // @todo FIX-ME : need to set properly in case of multi-frame + frm->pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME; + + ret = oapve_encode(apv->id, &apv->ifrms, apv->mid, &apv->bitb, &apv->stat, NULL); + if (OAPV_FAILED(ret)) { + av_log(avctx, AV_LOG_ERROR, "oapve_encode() failed\n"); + return AVERROR_EXTERNAL; + } + + /* store bitstream */ + if (OAPV_SUCCEEDED(ret) && apv->stat.write > 0) { + uint8_t *data = apv->bitb.addr; + int size = apv->stat.write; + + // The encoder may return a "Raw bitstream" formatted AU, including au_size. + // Discard it as we only need the access_unit() structure. + if (size > 4 && AV_RB32(data) != APV_SIGNATURE) { + data += 4; + size -= 4; + } + + ret = ff_get_encode_buffer(avctx, avpkt, size, 0); + if (ret < 0) + return ret; + + memcpy(avpkt->data, data, size); + avpkt->pts = avpkt->dts = frame->pts; + avpkt->flags |= AV_PKT_FLAG_KEY; + + if (cdsc->param[FRM_IDX].qp) + ff_side_data_set_encoder_stats(avpkt, cdsc->param[FRM_IDX].qp * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I); + + *got_packet = 1; + } + + return 0; +} + +/** + * Destroy the encoder and release all the allocated resources + * + * @param avctx codec context + * @return 0 on success, negative error code on failure + */ +static av_cold int liboapve_close(AVCodecContext *avctx) +{ + ApvEncContext *apv = avctx->priv_data; + + for (int i = 0; i < apv->num_frames; i++) { + if (apv->ifrms.frm[i].imgb != NULL) + apv->ifrms.frm[i].imgb->release(apv->ifrms.frm[i].imgb); + apv->ifrms.frm[i].imgb = NULL; + } + + if (apv->mid) { + oapvm_rem_all(apv->mid); + } + + if (apv->id) { + oapve_delete(apv->id); + apv->id = NULL; + } + + if (apv->mid) { + oapvm_delete(apv->mid); + apv->mid = NULL; + } + + av_freep(&apv->bitb.addr); /* release bitstream buffer */ + + return 0; +} + +#define OFFSET(x) offsetof(ApvEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const enum AVPixelFormat supported_pixel_formats[] = { + AV_PIX_FMT_GRAY10, + AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV422P12, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, + AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA444P12, + AV_PIX_FMT_NONE +}; + +static const AVOption liboapv_options[] = { + { "preset", "Encoding preset for setting encoding speed (optimization level control)", OFFSET(preset_id), AV_OPT_TYPE_INT, { .i64 = OAPV_PRESET_DEFAULT }, OAPV_PRESET_FASTEST, OAPV_PRESET_PLACEBO, VE, .unit = "preset" }, + { "fastest", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FASTEST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "fast", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FAST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "medium", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_MEDIUM }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_SLOW }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "placebo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_PLACEBO }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "preset" }, + + { "qp", "Quantization parameter value for CQP rate control mode", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 63, VE }, + { "oapv-params", "Override the apv configuration using a :-separated list of key=value parameters", OFFSET(oapv_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, + { NULL } +}; + +static const AVClass liboapve_class = { + .class_name = "liboapv", + .item_name = av_default_item_name, + .option = liboapv_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const FFCodecDefault liboapve_defaults[] = { + { "b", "0" }, // bitrate in terms of kilo-bits per second (support for bit-rates from a few hundred Mbps to a few Gbps for 2K, 4K and 8K resolution content) + { NULL }, +}; + +const FFCodec ff_liboapv_encoder = { + .p.name = "liboapv", + .p.long_name = NULL_IF_CONFIG_SMALL("liboapv APV"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_APV, + .init = liboapve_init, + FF_CODEC_ENCODE_CB(liboapve_encode), + .close = liboapve_close, + .priv_data_size = sizeof(ApvEncContext), + .p.priv_class = &liboapve_class, + .defaults = liboapve_defaults, + .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, + .p.wrapper_name = "liboapv", + .p.pix_fmts = supported_pixel_formats, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_apv_profiles), + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_NOT_INIT_THREADSAFE, +}; diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c index b127b33101..95c7b9b137 100644 --- a/libavcodec/libopencore-amr.c +++ b/libavcodec/libopencore-amr.c @@ -302,8 +302,7 @@ const FFCodec ff_libopencore_amrnb_encoder = { .init = amr_nb_encode_init, FF_CODEC_ENCODE_CB(amr_nb_encode_frame), .close = amr_nb_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .p.priv_class = &amrnb_class, }; #endif /* CONFIG_LIBOPENCORE_AMRNB_ENCODER */ diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 7107c1a679..6f6f264636 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -135,13 +135,7 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { param.fMaxFrameRate = av_q2d(avctx->framerate); } else { -FF_DISABLE_DEPRECATION_WARNINGS - param.fMaxFrameRate = 1.0 / av_q2d(avctx->time_base) -#if FF_API_TICKS_PER_FRAME - / FFMAX(avctx->ticks_per_frame, 1) -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + param.fMaxFrameRate = 1.0 / av_q2d(avctx->time_base); } param.iPicWidth = avctx->width; param.iPicHeight = avctx->height; @@ -442,9 +436,7 @@ const FFCodec ff_libopenh264_encoder = { .close = svc_encode_close, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUVJ420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .defaults = svc_enc_defaults, .p.priv_class = &class, diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 01b67dffda..b797d34e1c 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -765,7 +765,7 @@ const FFCodec ff_libopenjpeg_encoder = { FF_CODEC_ENCODE_CB(libopenjpeg_encode_frame), .p.capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_GBR24P, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, @@ -782,9 +782,7 @@ const FFCodec ff_libopenjpeg_encoder = { 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_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, - AV_PIX_FMT_XYZ12, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_XYZ12), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &openjpeg_class, .p.wrapper_name = "libopenjpeg", diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index 9b9a610343..c602499b7c 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -244,9 +244,7 @@ const FFCodec ff_libopus_decoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), .p.priv_class = &libopusdec_class, .p.wrapper_name = "libopus", }; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 6b8b2cda0e..131886c8ea 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -592,10 +592,8 @@ const FFCodec ff_libopus_encoder = { .init = libopus_encode_init, FF_CODEC_ENCODE_CB(libopus_encode), .close = libopus_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libopus_sample_rates, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), + CODEC_SAMPLERATES_ARRAY(libopus_sample_rates), .p.priv_class = &libopus_class, .defaults = libopus_defaults, .p.wrapper_name = "libopus", diff --git a/libavcodec/librav1e.c b/libavcodec/librav1e.c index 546d00297d..0db80830d8 100644 --- a/libavcodec/librav1e.c +++ b/libavcodec/librav1e.c @@ -217,15 +217,9 @@ static av_cold int librav1e_encode_init(AVCodecContext *avctx) avctx->framerate.den, avctx->framerate.num }); } else { -FF_DISABLE_DEPRECATION_WARNINGS rav1e_config_set_time_base(cfg, (RaRational) { - avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - , avctx->time_base.den + avctx->time_base.num, avctx->time_base.den }); -FF_ENABLE_DEPRECATION_WARNINGS } if ((avctx->flags & AV_CODEC_FLAG_PASS1 || avctx->flags & AV_CODEC_FLAG_PASS2) && !avctx->bit_rate) { @@ -667,7 +661,7 @@ const FFCodec ff_librav1e_encoder = { .priv_data_size = sizeof(librav1eContext), .p.priv_class = &class, .defaults = librav1e_defaults, - .p.pix_fmts = librav1e_pix_fmts, + CODEC_PIXFMTS_ARRAY(librav1e_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_RECON_FRAME | diff --git a/libavcodec/libshine.c b/libavcodec/libshine.c index 333d86f774..aa71383bfb 100644 --- a/libavcodec/libshine.c +++ b/libavcodec/libshine.c @@ -137,12 +137,8 @@ const FFCodec ff_libshine_encoder = { .init = libshine_encode_init, FF_CODEC_ENCODE_CB(libshine_encode_frame), .close = libshine_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = libshine_sample_rates, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), + CODEC_SAMPLERATES_ARRAY(libshine_sample_rates), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), .p.wrapper_name = "libshine", }; diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c index 84b308490a..46f65ab075 100644 --- a/libavcodec/libspeexdec.c +++ b/libavcodec/libspeexdec.c @@ -195,11 +195,7 @@ const FFCodec ff_libspeex_decoder = { CODEC_LONG_NAME("libspeex Speex"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_SPEEX, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .p.wrapper_name = "libspeex", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, .priv_data_size = sizeof(LibSpeexContext), diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index 7b19db5a2a..6f2d1ac7e9 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -353,13 +353,9 @@ const FFCodec ff_libspeex_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, - .p.supported_samplerates = (const int[]){ 8000, 16000, 32000, 0 }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLERATES(8000, 16000, 32000), .p.priv_class = &speex_class, .defaults = defaults, .p.wrapper_name = "libspeex", diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c index 79b28eb4df..c6a0ff90bc 100644 --- a/libavcodec/libsvtav1.c +++ b/libavcodec/libsvtav1.c @@ -311,13 +311,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param, param->frame_rate_denominator = avctx->framerate.den; } else { param->frame_rate_numerator = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - param->frame_rate_denominator = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + param->frame_rate_denominator = avctx->time_base.num; } /* 2 = IDR, closed GOP, 1 = CRA, open GOP */ @@ -435,7 +429,11 @@ static av_cold int eb_enc_init(AVCodecContext *avctx) svt_enc->eos_flag = EOS_NOT_REACHED; +#if SVT_AV1_CHECK_VERSION(3, 0, 0) + svt_ret = svt_av1_enc_init_handle(&svt_enc->svt_handle, &svt_enc->enc_params); +#else svt_ret = svt_av1_enc_init_handle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params); +#endif if (svt_ret != EB_ErrorNone) { return svt_print_error(avctx, svt_ret, "Error initializing encoder handle"); } @@ -766,9 +764,7 @@ const FFCodec ff_libsvtav1_encoder = { .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUV420P10, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = eb_enc_defaults, diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index 8844f4be6a..2b70ec06a6 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -37,6 +37,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/log.h" #include "libavutil/base64.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -45,6 +46,7 @@ #include typedef struct TheoraContext { + AVClass *av_class; /**< class for AVOptions */ th_enc_ctx *t_state; uint8_t *stats; int stats_size; @@ -52,8 +54,21 @@ typedef struct TheoraContext { int uv_hshift; int uv_vshift; int keyframe_mask; + int speed_level; } TheoraContext; +static const AVOption options[] = { + { "speed_level", "Sets the encoding speed level", offsetof(TheoraContext, speed_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { NULL } +}; + +static const AVClass theora_class = { + .class_name = "libtheora", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + /** Concatenate an ogg_packet into the extradata. */ static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, @@ -234,7 +249,7 @@ static av_cold int encode_init(AVCodecContext* avc_context) return AVERROR_EXTERNAL; } - h->keyframe_mask = (1 << t_info.keyframe_granule_shift) - 1; + h->keyframe_mask = (1 << av_ceil_log2(avc_context->gop_size)) - 1; /* Clear up theora_info struct */ th_info_clear(&t_info); @@ -244,6 +259,15 @@ static av_cold int encode_init(AVCodecContext* avc_context) return AVERROR_EXTERNAL; } + // Set encoding speed level + if (h->speed_level != -1) { + int max_speed_level; + int speed_level = h->speed_level; + th_encode_ctl(h->t_state, TH_ENCCTL_GET_SPLEVEL_MAX, &max_speed_level, sizeof(max_speed_level)); + speed_level = FFMIN(speed_level, max_speed_level); + th_encode_ctl(h->t_state, TH_ENCCTL_SET_SPLEVEL, &speed_level, sizeof(speed_level)); + } + // need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers if (avc_context->flags & AV_CODEC_FLAG_PASS1) { if ((ret = get_stats(avc_context, 0)) < 0) @@ -388,9 +412,8 @@ const FFCodec ff_libtheora_encoder = { .init = encode_init, .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), + .p.priv_class = &theora_class, .color_ranges = AVCOL_RANGE_MPEG, .p.wrapper_name = "libtheora", }; diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c index f3bd4771d7..18b40dafcc 100644 --- a/libavcodec/libtwolame.c +++ b/libavcodec/libtwolame.c @@ -221,18 +221,9 @@ const FFCodec ff_libtwolame_encoder = { .close = twolame_encode_close, .defaults = twolame_defaults, .p.priv_class = &twolame_class, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE - }, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 }, - }, - .p.supported_samplerates = twolame_samplerates, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLERATES_ARRAY(twolame_samplerates), .p.wrapper_name = "libtwolame", }; diff --git a/libavcodec/libuavs3d.c b/libavcodec/libuavs3d.c index 53b5faafc5..3eea2051b0 100644 --- a/libavcodec/libuavs3d.c +++ b/libavcodec/libuavs3d.c @@ -79,12 +79,6 @@ static void uavs3d_output_callback(uavs3d_io_frm_t *dec_frame) { frm->pts = dec_frame->pts; frm->pkt_dts = dec_frame->dts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frm->pkt_pos = dec_frame->pkt_pos; - frm->pkt_size = dec_frame->pkt_size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (dec_frame->type < 0 || dec_frame->type >= FF_ARRAY_ELEMS(ff_avs3_image_type)) { av_log(NULL, AV_LOG_WARNING, "Error frame type in uavs3d: %d.\n", dec_frame->type); @@ -106,6 +100,91 @@ FF_ENABLE_DEPRECATION_WARNINGS uavs3d_img_cpy_cvt(&frm_out, dec_frame, dec_frame->bit_depth); } +#define UAVS3D_CHECK_INVALID_RANGE(v, l, r) ((v)<(l)||(v)>(r)) + +static int libuavs3d_on_seq_header(AVCodecContext *avctx) +{ + uavs3d_context *h = avctx->priv_data; + uavs3d_io_frm_t *frm_dec = &h->dec_frame; + struct uavs3d_com_seqh_t *seqh = frm_dec->seqhdr; + int ret; + + if (UAVS3D_CHECK_INVALID_RANGE(seqh->frame_rate_code, 0, 15)) { + av_log(avctx, AV_LOG_ERROR, "Invalid frame rate code: %d.\n", seqh->frame_rate_code); + seqh->frame_rate_code = 3; // default 25 fps + } else { + avctx->framerate.num = ff_avs3_frame_rate_tab[seqh->frame_rate_code].num; + avctx->framerate.den = ff_avs3_frame_rate_tab[seqh->frame_rate_code].den; + } + avctx->has_b_frames = seqh->output_reorder_delay; + avctx->pix_fmt = seqh->bit_depth_internal == 8 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV420P10; + ret = ff_set_dimensions(avctx, seqh->horizontal_size, seqh->vertical_size); + if (ret < 0) + return ret; + h->got_seqhdr = 1; + + if (seqh->colour_description) { + if (UAVS3D_CHECK_INVALID_RANGE(seqh->colour_primaries, 0, 9) || + UAVS3D_CHECK_INVALID_RANGE(seqh->transfer_characteristics, 0, 14) || + UAVS3D_CHECK_INVALID_RANGE(seqh->matrix_coefficients, 0, 11)) { + av_log(avctx, AV_LOG_ERROR, + "Invalid colour description: primaries: %d" + "transfer characteristics: %d" + "matrix coefficients: %d.\n", + seqh->colour_primaries, + seqh->transfer_characteristics, + seqh->matrix_coefficients); + } else { + avctx->color_primaries = ff_avs3_color_primaries_tab[seqh->colour_primaries]; + avctx->color_trc = ff_avs3_color_transfer_tab [seqh->transfer_characteristics]; + avctx->colorspace = ff_avs3_color_matrix_tab [seqh->matrix_coefficients]; + } + } + + return 0; +} + +static int libuavs3d_decode_extradata(AVCodecContext *avctx) +{ + uavs3d_context *h = avctx->priv_data; + uint8_t *header = avctx->extradata; + int header_size = avctx->extradata_size; + uavs3d_io_frm_t *frm_dec = &h->dec_frame; + + if (avctx->extradata_size < 4) { + av_log(avctx, AV_LOG_WARNING, "Invalid extradata size %d\n", + avctx->extradata_size); + return 0; + } + + if (header[0] == 1) { + // Skip configurationVersion and sequence_header_length + header += 3; + // Also remove library_dependency_idc at the end + header_size -= 4; + } + + frm_dec->nal_type = 0; + frm_dec->pkt_pos = 0; + frm_dec->pkt_size = header_size; + frm_dec->bs = header; + frm_dec->bs_len = header_size; + frm_dec->pts = 0; + frm_dec->dts = 0; + uavs3d_decode(h->dec_handle, frm_dec); + if (frm_dec->nal_type == NAL_SEQ_HEADER) { + int ret = libuavs3d_on_seq_header(avctx); + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, + "Process sequence header failed, %s\n", av_err2str(ret)); + } else { + av_log(avctx, AV_LOG_WARNING, + "Missing sequence header in extradata\n"); + } + + return 0; +} + static av_cold int libuavs3d_init(AVCodecContext *avctx) { uavs3d_context *h = avctx->priv_data; @@ -120,6 +199,9 @@ static av_cold int libuavs3d_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } + if (avctx->extradata) + return libuavs3d_decode_extradata(avctx); + return 0; } @@ -146,7 +228,6 @@ static void libuavs3d_flush(AVCodecContext * avctx) } } -#define UAVS3D_CHECK_INVALID_RANGE(v, l, r) ((v)<(l)||(v)>(r)) static int libuavs3d_decode_frame(AVCodecContext *avctx, AVFrame *frm, int *got_frame, AVPacket *avpkt) { @@ -176,12 +257,6 @@ static int libuavs3d_decode_frame(AVCodecContext *avctx, AVFrame *frm, uavs3d_io_frm_t *frm_dec = &h->dec_frame; buf_end = buf + buf_size; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - frm_dec->pkt_pos = avpkt->pos; - frm_dec->pkt_size = avpkt->size; -FF_ENABLE_DEPRECATION_WARNINGS -#endif while (!finish) { int bs_len; @@ -207,38 +282,9 @@ FF_ENABLE_DEPRECATION_WARNINGS buf_ptr += bs_len; if (frm_dec->nal_type == NAL_SEQ_HEADER) { - struct uavs3d_com_seqh_t *seqh = frm_dec->seqhdr; - if (UAVS3D_CHECK_INVALID_RANGE(seqh->frame_rate_code, 0, 15)) { - av_log(avctx, AV_LOG_ERROR, "Invalid frame rate code: %d.\n", seqh->frame_rate_code); - seqh->frame_rate_code = 3; // default 25 fps - } else { - avctx->framerate.num = ff_avs3_frame_rate_tab[seqh->frame_rate_code].num; - avctx->framerate.den = ff_avs3_frame_rate_tab[seqh->frame_rate_code].den; - } - avctx->has_b_frames = seqh->output_reorder_delay; - avctx->pix_fmt = seqh->bit_depth_internal == 8 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV420P10LE; - ret = ff_set_dimensions(avctx, seqh->horizontal_size, seqh->vertical_size); + ret = libuavs3d_on_seq_header(avctx); if (ret < 0) return ret; - h->got_seqhdr = 1; - - if (seqh->colour_description) { - if (UAVS3D_CHECK_INVALID_RANGE(seqh->colour_primaries, 0, 9) || - UAVS3D_CHECK_INVALID_RANGE(seqh->transfer_characteristics, 0, 14) || - UAVS3D_CHECK_INVALID_RANGE(seqh->matrix_coefficients, 0, 11)) { - av_log(avctx, AV_LOG_ERROR, - "Invalid colour description: primaries: %d" - "transfer characteristics: %d" - "matrix coefficients: %d.\n", - seqh->colour_primaries, - seqh->transfer_characteristics, - seqh->matrix_coefficients); - } else { - avctx->color_primaries = ff_avs3_color_primaries_tab[seqh->colour_primaries]; - avctx->color_trc = ff_avs3_color_transfer_tab [seqh->transfer_characteristics]; - avctx->colorspace = ff_avs3_color_matrix_tab [seqh->matrix_coefficients]; - } - } } if (frm_dec->got_pic) { break; diff --git a/libavcodec/libvo-amrwbenc.c b/libavcodec/libvo-amrwbenc.c index 02b8941a6d..c68b66fc43 100644 --- a/libavcodec/libvo-amrwbenc.c +++ b/libavcodec/libvo-amrwbenc.c @@ -153,6 +153,5 @@ const FFCodec ff_libvo_amrwbenc_encoder = { .init = amr_wb_encode_init, FF_CODEC_ENCODE_CB(amr_wb_encode_frame), .close = amr_wb_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c index a5e7a691d6..326ed4b4fe 100644 --- a/libavcodec/libvorbisdec.c +++ b/libavcodec/libvorbisdec.c @@ -35,7 +35,8 @@ typedef struct OggVorbisDecContext { static int oggvorbis_decode_close(AVCodecContext *avccontext); -static int oggvorbis_decode_init(AVCodecContext *avccontext) { +static av_cold int oggvorbis_decode_init(AVCodecContext *avccontext) +{ OggVorbisDecContext *context = avccontext->priv_data ; uint8_t *p= avccontext->extradata; int i, hsizes[3], ret; @@ -113,6 +114,12 @@ static int oggvorbis_decode_init(AVCodecContext *avccontext) { } } + if (context->vi.rate <= 0 || context->vi.rate > INT_MAX) { + av_log(avccontext, AV_LOG_ERROR, "vorbis rate is invalid\n"); + ret = AVERROR_INVALIDDATA; + goto error; + } + av_channel_layout_uninit(&avccontext->ch_layout); avccontext->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; avccontext->ch_layout.nb_channels = context->vi.channels; @@ -198,7 +205,8 @@ static int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame, } -static int oggvorbis_decode_close(AVCodecContext *avccontext) { +static av_cold int oggvorbis_decode_close(AVCodecContext *avccontext) +{ OggVorbisDecContext *context = avccontext->priv_data ; vorbis_block_clear(&context->vb); diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c index e4f8cb67ef..6aa1ec3b3c 100644 --- a/libavcodec/libvorbisenc.c +++ b/libavcodec/libvorbisenc.c @@ -386,8 +386,7 @@ const FFCodec ff_libvorbis_encoder = { .init = libvorbis_encode_init, FF_CODEC_ENCODE_CB(libvorbis_encode_frame), .close = libvorbis_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .p.priv_class = &vorbis_class, .defaults = defaults, .p.wrapper_name = "libvorbis", diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 228ede7c84..406333d45f 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -1831,13 +1831,7 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) duration = av_rescale_q(1, av_inv_q(avctx->framerate), avctx->time_base); else { -FF_DISABLE_DEPRECATION_WARNINGS - duration = -#if FF_API_TICKS_PER_FRAME - avctx->ticks_per_frame ? avctx->ticks_per_frame : -#endif - 1; -FF_ENABLE_DEPRECATION_WARNINGS + duration = 1; } res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, @@ -2044,7 +2038,7 @@ const FFCodec ff_libvpx_vp8_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class_vp8, .defaults = defaults, diff --git a/libavcodec/libvvenc.c b/libavcodec/libvvenc.c index ece9badb19..29a49ba091 100644 --- a/libavcodec/libvvenc.c +++ b/libavcodec/libvvenc.c @@ -128,20 +128,7 @@ static void vvenc_set_framerate(AVCodecContext *avctx, vvenc_config *params) params->m_FrameScale = avctx->time_base.num; } -FF_DISABLE_DEPRECATION_WARNINGS - -#if FF_API_TICKS_PER_FRAME - if (avctx->ticks_per_frame == 1) { -#endif - params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */ -#if FF_API_TICKS_PER_FRAME - } else { - params->m_TicksPerSecond = - ceil((avctx->time_base.den / (double) avctx->time_base.num) * - (double) avctx->ticks_per_frame); - } -#endif -FF_ENABLE_DEPRECATION_WARNINGS + params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */ } static int vvenc_parse_vvenc_params(AVCodecContext *avctx, vvenc_config *params) @@ -482,7 +469,7 @@ const FFCodec ff_libvvenc_encoder = { .p.priv_class = &class, .p.wrapper_name = "libvvenc", .priv_data_size = sizeof(VVenCContext), - .p.pix_fmts = pix_fmts_vvenc, + CODEC_PIXFMTS_ARRAY(pix_fmts_vvenc), .init = vvenc_init, FF_CODEC_ENCODE_CB(vvenc_frame), .close = vvenc_close, diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index 670412cc6e..8ea1bc8803 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -94,7 +94,7 @@ const FFCodec ff_libwebp_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WEBP, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = ff_libwebpenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_libwebpenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c index c5361d7f92..15592fbd14 100644 --- a/libavcodec/libwebpenc_animencoder.c +++ b/libavcodec/libwebpenc_animencoder.c @@ -167,7 +167,7 @@ const FFCodec ff_libwebp_anim_encoder = { .p.id = AV_CODEC_ID_WEBP, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = ff_libwebpenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_libwebpenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index 409f45fc7d..58c03a77ad 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -22,7 +22,6 @@ #include "config_components.h" #include "libavutil/buffer.h" -#include "libavutil/eval.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" @@ -30,7 +29,6 @@ #include "libavutil/pixdesc.h" #include "libavutil/stereo3d.h" #include "libavutil/time.h" -#include "libavutil/intreadwrite.h" #include "libavutil/video_hint.h" #include "avcodec.h" #include "codec_internal.h" @@ -1317,13 +1315,7 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.i_fps_den = avctx->framerate.den; } else { x4->params.i_fps_num = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - x4->params.i_fps_den = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + x4->params.i_fps_den = avctx->time_base.num; } x4->params.analyse.b_psnr = avctx->flags & AV_CODEC_FLAG_PSNR; @@ -1633,7 +1625,7 @@ const FFCodec ff_libx264_encoder = { .flush = X264_flush, .close = X264_close, .defaults = x264_defaults, - .p.pix_fmts = pix_fmts_all, + CODEC_PIXFMTS_ARRAY(pix_fmts_all), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS #if X264_BUILD < 158 @@ -1659,7 +1651,7 @@ const FFCodec ff_libx264rgb_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts_8bit_rgb, + CODEC_PIXFMTS_ARRAY(pix_fmts_8bit_rgb), .p.priv_class = &rgbclass, .p.wrapper_name = "libx264", .priv_data_size = sizeof(X264Context), @@ -1691,7 +1683,7 @@ const FFCodec ff_libx262_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts_8bit, + CODEC_PIXFMTS_ARRAY(pix_fmts_8bit), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &X262_class, .p.wrapper_name = "libx264", diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index 513f473307..d897707dd7 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -42,6 +42,14 @@ #include "atsc_a53.h" #include "sei.h" +#if defined(X265_ENABLE_ALPHA) && MAX_LAYERS > 2 +#define FF_X265_MAX_LAYERS MAX_LAYERS +#elif X265_BUILD >= 210 +#define FF_X265_MAX_LAYERS 2 +#else +#define FF_X265_MAX_LAYERS 1 +#endif + typedef struct ReorderedData { int64_t duration; @@ -284,12 +292,7 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) ctx->params->fpsDenom = avctx->framerate.den; } else { ctx->params->fpsNum = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - ctx->params->fpsDenom = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; + ctx->params->fpsDenom = avctx->time_base.num; FF_ENABLE_DEPRECATION_WARNINGS } ctx->params->sourceWidth = avctx->width; @@ -497,8 +500,22 @@ FF_ENABLE_DEPRECATION_WARNINGS { const AVDictionaryEntry *en = NULL; while ((en = av_dict_iterate(ctx->x265_opts, en))) { - int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value); + int parse_ret; + // ignore forced alpha option. The pixel format is all we need. + if (!strncmp(en->key, "alpha", 5)) { + if (desc->nb_components == 4) { + av_log(avctx, AV_LOG_WARNING, + "Ignoring redundant \"alpha\" option.\n"); + continue; + } + av_log(avctx, AV_LOG_ERROR, + "Alpha encoding was requested through an unsupported " + "option when no alpha plane is present\n"); + return AVERROR(EINVAL); + } + + parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value); switch (parse_ret) { case X265_PARAM_BAD_NAME: av_log(avctx, AV_LOG_WARNING, @@ -539,6 +556,15 @@ FF_ENABLE_DEPRECATION_WARNINGS ctx->dovi.cfg.dv_bl_signal_compatibility_id; #endif +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) { + if (ctx->api->param_parse(ctx->params, "alpha", "1") < 0) { + av_log(avctx, AV_LOG_ERROR, "Loaded libx265 does not support alpha layer encoding.\n"); + return AVERROR(ENOTSUP); + } + } +#endif + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -659,15 +685,13 @@ static void free_picture(libx265Context *ctx, x265_picture *pic) static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); libx265Context *ctx = avctx->priv_data; x265_picture x265pic; -#if X265_BUILD >= 210 - x265_picture x265pic_layers_out[MAX_SCALABLE_LAYERS]; - x265_picture* x265pic_lyrptr_out[MAX_SCALABLE_LAYERS]; -#else - x265_picture x265pic_solo_out = { 0 }; + x265_picture x265pic_out[FF_X265_MAX_LAYERS] = { 0 }; +#if (X265_BUILD >= 210) && (X265_BUILD < 213) + x265_picture *x265pic_lyrptr_out[FF_X265_MAX_LAYERS]; #endif - x265_picture* x265pic_out; x265_nal *nal; x265_sei *sei; uint8_t *dst; @@ -687,7 +711,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ReorderedData *rd; int rd_idx; - for (i = 0; i < 3; i++) { + for (i = 0; i < desc->nb_components; i++) { x265pic.planes[i] = pic->data[i]; x265pic.stride[i] = pic->linesize[i]; } @@ -805,15 +829,15 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, #endif } -#if X265_BUILD >= 210 - for (i = 0; i < MAX_SCALABLE_LAYERS; i++) - x265pic_lyrptr_out[i] = &x265pic_layers_out[i]; +#if (X265_BUILD >= 210) && (X265_BUILD < 213) + for (i = 0; i < FF_ARRAY_ELEMS(x265pic_out); i++) + x265pic_lyrptr_out[i] = &x265pic_out[i]; ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, pic ? &x265pic : NULL, x265pic_lyrptr_out); #else ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, - pic ? &x265pic : NULL, &x265pic_solo_out); + pic ? &x265pic : NULL, x265pic_out); #endif for (i = 0; i < sei->numPayloads; i++) @@ -844,12 +868,6 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pkt->flags |= AV_PKT_FLAG_KEY; } -#if X265_BUILD >= 210 - x265pic_out = x265pic_lyrptr_out[0]; -#else - x265pic_out = &x265pic_solo_out; -#endif - pkt->pts = x265pic_out->pts; pkt->dts = x265pic_out->dts; @@ -907,6 +925,9 @@ static const enum AVPixelFormat x265_csp_eight[] = { AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, +#endif AV_PIX_FMT_NONE }; @@ -924,6 +945,10 @@ static const enum AVPixelFormat x265_csp_ten[] = { AV_PIX_FMT_GBRP10, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA420P10, +#endif AV_PIX_FMT_NONE }; @@ -946,6 +971,10 @@ static const enum AVPixelFormat x265_csp_twelve[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, +#if X265_BUILD >= 210 && FF_X265_MAX_LAYERS > 1 + AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA420P10, +#endif AV_PIX_FMT_NONE }; diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index d0f6e141c7..2fb87dc7a4 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -434,7 +434,7 @@ const FFCodec ff_libxavs_encoder = { .close = XAVS_close, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xavs_class, .defaults = xavs_defaults, diff --git a/libavcodec/libxavs2.c b/libavcodec/libxavs2.c index 1021d2ae2f..d7583e8b67 100644 --- a/libavcodec/libxavs2.c +++ b/libavcodec/libxavs2.c @@ -299,8 +299,7 @@ const FFCodec ff_libxavs2_encoder = { .close = xavs2_close, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_AUTO_THREADS, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &libxavs2, .defaults = xavs2_defaults, diff --git a/libavcodec/libxeve.c b/libavcodec/libxeve.c index 61376f3e65..63c2e1981b 100644 --- a/libavcodec/libxeve.c +++ b/libavcodec/libxeve.c @@ -613,7 +613,7 @@ const FFCodec ff_libxeve_encoder = { .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, .p.profiles = NULL_IF_CONFIG_SMALL(ff_evc_profiles), .p.wrapper_name = "libxeve", - .p.pix_fmts = supported_pixel_formats, + CODEC_PIXFMTS_ARRAY(supported_pixel_formats), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_NOT_INIT_THREADSAFE, }; diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index fbd33b7065..b85bb425c1 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -617,6 +617,10 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) x->intra_matrix = x->inter_matrix = NULL; + ret = ff_check_codec_matrices(avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_INTER, 1, 255); + if (ret < 0) + return ret; + if (x->mpeg_quant) x->vol_flags |= XVID_VOL_MPEGQUANT; if ((avctx->intra_matrix || avctx->inter_matrix)) { @@ -907,7 +911,7 @@ const FFCodec ff_libxvid_encoder = { .init = xvid_encode_init, FF_CODEC_ENCODE_CB(xvid_encode_frame), .close = xvid_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xvid_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c index 68ffe1f76c..e02ecb8b3a 100644 --- a/libavcodec/libzvbi-teletextdec.c +++ b/libavcodec/libzvbi-teletextdec.c @@ -91,7 +91,7 @@ static int my_ass_subtitle_header(AVCodecContext *avctx) if (ret < 0) return ret; - event_pos = strstr(avctx->subtitle_header, "\r\n[Events]\r\n"); + event_pos = strstr(avctx->subtitle_header, "\n[Events]\n"); if (!event_pos) return AVERROR_BUG; @@ -106,7 +106,7 @@ static int my_ass_subtitle_header(AVCodecContext *avctx) "0,0," /* Spacing, Angle */ "3,0.1,0," /* BorderStyle, Outline, Shadow */ "5,1,1,1," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ + "0\n" /* Encoding */ "Style: " "Subtitle," /* Name */ "Monospace,16," /* Font{name,size} */ @@ -116,7 +116,7 @@ static int my_ass_subtitle_header(AVCodecContext *avctx) "0,0," /* Spacing, Angle */ "1,1,1," /* BorderStyle, Outline, Shadow */ "8,48,48,20," /* Alignment, Margin[LRV] */ - "0\r\n" /* Encoding */ + "0\n" /* Encoding */ , event_pos); if (!new_header) diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c index 927420c2d4..ab37ab0d5c 100644 --- a/libavcodec/ljpegenc.c +++ b/libavcodec/ljpegenc.c @@ -252,7 +252,7 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ff_mjpeg_encode_picture_trailer(&pb, header_bits); flush_put_bits(&pb); - pkt->size = put_bits_ptr(&pb) - pb.buf; + pkt->size = put_bytes_output(&pb); *got_packet = 1; return 0; @@ -323,10 +323,8 @@ const FFCodec ff_ljpeg_encoder = { .init = ljpeg_encode_init, FF_CODEC_ENCODE_CB(ljpeg_encode_frame), .close = ljpeg_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGR24 , AV_PIX_FMT_BGRA , AV_PIX_FMT_BGR0, - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUV420P , AV_PIX_FMT_YUV444P , AV_PIX_FMT_YUV422P, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/loongarch/hevc_mc.S b/libavcodec/loongarch/hevc_mc.S index 12d92e32e9..b0eca55e68 100644 --- a/libavcodec/loongarch/hevc_mc.S +++ b/libavcodec/loongarch/hevc_mc.S @@ -674,7 +674,7 @@ endfunc vdp2.h.bu.b \out1, \in1, vr5 vdp2.h.bu.b vr12, \in2, vr5 vdp2.h.bu.b vr20, \in3, vr5 - vbsrl.v \in0, \in0, 1 //Back up previous 7 loaded datas, + vbsrl.v \in0, \in0, 1 //Back up previous 7 loaded data, vbsrl.v \in1, \in1, 1 //so just need to insert the 8th vbsrl.v \in2, \in2, 1 //load in the next loop. vbsrl.v \in3, \in3, 1 @@ -903,7 +903,7 @@ endfunc xvhaddw.d.h xr7 xvhaddw.d.h xr8 xvhaddw.d.h xr9 - xvbsrl.v xr14, xr14, 1 //Back up previous 7 loaded datas, + xvbsrl.v xr14, xr14, 1 //Back up previous 7 loaded data, xvbsrl.v xr15, xr15, 1 //so just need to insert the 8th xvbsrl.v xr16, xr16, 1 //load in next loop. xvbsrl.v xr17, xr17, 1 diff --git a/libavcodec/loongarch/hevc_mc_bi_lsx.c b/libavcodec/loongarch/hevc_mc_bi_lsx.c index d7ddd1c246..feb85956ac 100644 --- a/libavcodec/loongarch/hevc_mc_bi_lsx.c +++ b/libavcodec/loongarch/hevc_mc_bi_lsx.c @@ -227,7 +227,7 @@ void hevc_bi_copy_8w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - int32_t loop_cnt = height >> 3; + uint32_t loop_cnt; int32_t res = (height & 7) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); @@ -312,7 +312,8 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t src_stride_4x = (src_stride << 2); @@ -328,10 +329,9 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __m128i in0, in1, in2, in3, in4, in5, in6, in7; __m128i dst0, dst1, dst2, dst3, dst4, dst5; - for (loop_cnt = 4; loop_cnt--;) { + for (; loop_cnt--;) { src0 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, src1, src2); src3 = __lsx_vldx(src0_ptr, src_stride_3x); src0_ptr += src_stride_4x; in0 = __lsx_vld(src1_ptr, 0); @@ -340,8 +340,7 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, in3 = __lsx_vldx(src1_ptr, src2_stride_3x); src1_ptr += src2_stride_2x; in4 = __lsx_vld(_src1, 0); - DUP2_ARG2(__lsx_vldx, _src1, src2_stride_x, _src1, src2_stride_2x, - in5, in6); + DUP2_ARG2(__lsx_vldx, _src1, src2_stride_x, _src1, src2_stride_2x, in5, in6); in7 = __lsx_vldx(_src1, src2_stride_3x); _src1 += src2_stride_2x; @@ -363,6 +362,31 @@ void hevc_bi_copy_12w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstelm_w(out2, dst + dst_stride_3x, 8, 3); dst += dst_stride_4x; } + for (;res--;) { + src0 = __lsx_vld(src0_ptr, 0); + src1 = __lsx_vld(src0_ptr + src_stride, 0); + in0 = __lsx_vld(src1_ptr, 0); + in1 = __lsx_vldx(src1_ptr, src2_stride_x); + dst0 = __lsx_vsllwil_hu_bu(src0, 6); + dst1 = __lsx_vsllwil_hu_bu(src1, 6); + out0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + __lsx_vstelm_d(out0, dst, 0, 0); + __lsx_vstelm_d(out0, dst + dst_stride, 0, 1); + + in0 = __lsx_vldrepl_d(_src1, 0); + in1 = __lsx_vldrepl_d(_src1 + src2_stride, 0); + src0 = __lsx_vilvh_w(src1, src0); + in0 = __lsx_vilvl_d(in1, in0); + dst0 = __lsx_vsllwil_hu_bu(src0, 6); + dst0 = __lsx_vsadd_h(dst0, in0); + dst0 = __lsx_vssrarni_bu_h(dst0, dst0, 7); + __lsx_vstelm_w(dst0, dst, 8, 0); + __lsx_vstelm_w(dst0, dst + dst_stride, 8, 1); + src0_ptr += src_stride_2x; + _src1 += src2_stride_x; + src1_ptr += src2_stride_x; + dst += dst_stride_2x; + } } static @@ -370,7 +394,8 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, int32_t height) { - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t src_stride_4x = (src_stride << 2); @@ -387,7 +412,7 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __m128i dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; __m128i zero = {0}; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { src0 = __lsx_vld(src0_ptr, 0); DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, src1, src2); @@ -420,6 +445,27 @@ void hevc_bi_copy_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstx(out3, dst, dst_stride_3x); dst += dst_stride_4x; } + for (;res--;) { + src0 = __lsx_vld(src0_ptr, 0); + src1 = __lsx_vldx(src0_ptr, src_stride); + in0 = __lsx_vld(src1_ptr, 0); + in1 = __lsx_vldx(src1_ptr, src2_stride_x); + in4 = __lsx_vld(_src1, 0); + in5 = __lsx_vldx(_src1, src2_stride_x); + + DUP2_ARG2(__lsx_vsllwil_hu_bu, src0, 6, src1, 6, dst0_r, dst1_r); + DUP2_ARG2(__lsx_vilvh_b, zero, src0, zero, src1, dst0_l, dst1_l); + DUP2_ARG2(__lsx_vslli_h, dst0_l, 6, dst1_l, 6, dst0_l, dst1_l); + out0 = hevc_bi_rnd_clip(in0, dst0_r, in4, dst0_l); + out1 = hevc_bi_rnd_clip(in1, dst1_r, in5, dst1_l); + __lsx_vst(out0, dst, 0); + __lsx_vstx(out1, dst, dst_stride); + + src0_ptr += src_stride_2x; + _src1 += src2_stride_x; + src1_ptr += src2_stride_x; + dst += dst_stride_2x; + } } static @@ -1061,7 +1107,8 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, { const int16_t *src1_ptr_tmp; uint8_t *dst_tmp; - uint32_t loop_cnt; + uint32_t loop_cnt = height >> 2; + uint32_t res = (height & 3) >> 1; int32_t dst_stride_2x = (dst_stride << 1); int32_t dst_stride_4x = (dst_stride << 2); int32_t dst_stride_3x = dst_stride_2x + dst_stride; @@ -1086,7 +1133,7 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, dst_tmp = dst + 16; src1_ptr_tmp = src1_ptr + 16; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src0, src1); src0_ptr += src_stride; DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src2, src3); @@ -1155,6 +1202,42 @@ static void hevc_hz_4t_24w_lsx(const uint8_t *src0_ptr, int32_t src_stride, __lsx_vstelm_d(dst1, dst_tmp + dst_stride_3x, 0, 1); dst_tmp += dst_stride_4x; } + for (; res--;) { + DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + DUP2_ARG2(__lsx_vld, src0_ptr, 0, src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + DUP2_ARG2(__lsx_vld, src1_ptr, 0, src1_ptr, 16, in0, in1); + src1_ptr += src2_stride; + DUP2_ARG2(__lsx_vld, src1_ptr, 0, src1_ptr, 16, in2, in3); + src1_ptr += src2_stride; + + DUP4_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src0, mask2, src2, + src2, mask0, src3, src2, mask2, vec0, vec1, vec2, vec3); + DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, vec2, filt0, + vec3, filt0, dst0, dst1, dst2, dst3); + DUP4_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src0, mask3, src2, + src2, mask1, src3, src2, mask3, vec0, vec1, vec2, vec3); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, + dst2, vec2, filt1, dst3, vec3, filt1, dst0, dst1, dst2, dst3); + dst0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + dst1 = hevc_bi_rnd_clip(in2, dst2, in3, dst3); + __lsx_vst(dst0, dst, 0); + __lsx_vstx(dst1, dst, dst_stride); + dst += dst_stride_2x; + + in0 = __lsx_vld(src1_ptr_tmp, 0); + in1 = __lsx_vldx(src1_ptr_tmp, src2_stride_x); + src1_ptr_tmp += src2_stride_x; + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src3, src3, mask0, vec0, vec1); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, dst0, dst1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask1, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, dst0, dst1); + dst0 = hevc_bi_rnd_clip(in0, dst0, in1, dst1); + __lsx_vstelm_d(dst0, dst_tmp, 0, 0); + __lsx_vstelm_d(dst0, dst_tmp + dst_stride, 0, 1); + dst_tmp += dst_stride_2x; + } } static void hevc_hz_4t_32w_lsx(const uint8_t *src0_ptr, int32_t src_stride, @@ -1206,7 +1289,7 @@ static void hevc_vt_4t_12w_lsx(const uint8_t *src0_ptr, 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; int32_t src_stride_2x = (src_stride << 1); int32_t dst_stride_2x = (dst_stride << 1); int32_t dst_stride_4x = (dst_stride << 2); @@ -1295,7 +1378,7 @@ static void hevc_vt_4t_16w_lsx(const uint8_t *src0_ptr, 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 = height >> 2; const int32_t src_stride_2x = (src_stride << 1); const int32_t dst_stride_2x = (dst_stride << 1); const int32_t src_stride_3x = src_stride_2x + src_stride; @@ -1316,7 +1399,7 @@ static void hevc_vt_4t_16w_lsx(const uint8_t *src0_ptr, int32_t src_stride, DUP2_ARG2(__lsx_vilvl_b, src1, src0, src2, src1, src10_r, src21_r); DUP2_ARG2(__lsx_vilvh_b, src1, src0, src2, src1, src10_l, src21_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (; loop_cnt--;) { src3 = __lsx_vld(src0_ptr, 0); src4 = __lsx_vldx(src0_ptr, src_stride); src0_ptr += src_stride_2x; @@ -1480,193 +1563,6 @@ static void hevc_vt_4t_32w_lsx(const uint8_t *src0_ptr, int32_t src_stride, dst + 16, dst_stride, filter, height); } -static void hevc_hv_4t_6w_lsx(const uint8_t *src0_ptr, int32_t src_stride, - const 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 height) -{ - int32_t src_stride_2x = (src_stride << 1); - int32_t dst_stride_2x = (dst_stride << 1); - int32_t src_stride_4x = (src_stride << 2); - int32_t dst_stride_4x = (dst_stride << 2); - int32_t src2_stride_2x = (src2_stride << 1); - int32_t src2_stride_4x = (src2_stride << 2); - int32_t src_stride_3x = src_stride_2x + src_stride; - int32_t dst_stride_3x = dst_stride_2x + dst_stride; - int32_t src2_stride_3x = src2_stride_2x + src2_stride; - __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6; - __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, mask1; - __m128i filt0, filt1, filt_h0, filt_h1; - __m128i dsth0, dsth1, dsth2, dsth3, dsth4, dsth5; - __m128i dsth6, dsth7, dsth8, dsth9, dsth10; - __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst4_r, dst5_r, dst6_r, dst7_r; - __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; - __m128i reg0, reg1, reg2, reg3; - __m128i mask0 = __lsx_vld(ff_hevc_mask_arr, 0); - - src0_ptr -= (src_stride + 1); - DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); - - filt_h1 = __lsx_vld(filter_y, 0); - filt_h1 = __lsx_vsllwil_h_b(filt_h1, 0); - DUP2_ARG2(__lsx_vreplvei_w, filt_h1, 0, filt_h1, 1, filt_h0, filt_h1); - - mask1 = __lsx_vaddi_bu(mask0, 2); - - src0 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src1, src2); - src0_ptr += src_stride_3x; - - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); - dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, - dsth0, dsth1); - dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); - - DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, tmp0, tmp2); - DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, tmp1, tmp3); - - src3 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src4, src5); - src6 = __lsx_vldx(src0_ptr, src_stride_3x); - src0_ptr += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, - filt0, dsth3, dsth4, dsth5, dsth6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth3, vec1, filt1, dsth4, vec3, filt1, dsth5, - vec5, filt1, dsth6, vec7, filt1, dsth3, dsth4, dsth5, dsth6); - - src3 = __lsx_vld(src0_ptr, 0); - DUP2_ARG2(__lsx_vldx, src0_ptr, src_stride, src0_ptr, src_stride_2x, - src4, src5); - src6 = __lsx_vldx(src0_ptr, src_stride_3x); - - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, - filt0, dsth7, dsth8, dsth9, dsth10); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth7, vec1, filt1, dsth8, vec3, filt1, dsth9, - vec5, filt1, dsth10, vec7, filt1, dsth7, dsth8, dsth9, dsth10); - - DUP2_ARG2(__lsx_vilvl_h, dsth3, dsth2, dsth4, dsth3, tmp4, tmp6); - DUP2_ARG2(__lsx_vilvh_h, dsth3, dsth2, dsth4, dsth3, tmp5, tmp7); - DUP2_ARG2(__lsx_vilvl_h, dsth5, dsth4, dsth6, dsth5, dsth0, dsth2); - DUP2_ARG2(__lsx_vilvh_h, dsth5, dsth4, dsth6, dsth5, dsth1, dsth3); - DUP4_ARG2(__lsx_vdp2_w_h, tmp0, filt_h0, tmp2, filt_h0, tmp4, filt_h0, - tmp6, filt_h0, dst0_r, dst1_r, dst2_r, dst3_r); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, tmp4, filt_h1, dst1_r, tmp6, - filt_h1, dst2_r, dsth0, filt_h1, dst3_r, dsth2, filt_h1, - dst0_r, dst1_r, dst2_r, dst3_r); - DUP2_ARG2(__lsx_vpickev_d, tmp3, tmp1, tmp7, tmp5, tmp0, tmp8); - dst0_l = __lsx_vdp2_w_h(tmp0, filt_h0); - dst0_l = __lsx_vdp2add_w_h(dst0_l, tmp8, filt_h1); - - DUP2_ARG2(__lsx_vilvl_h, dsth7, dsth6, dsth8, dsth7, tmp0, tmp2); - DUP2_ARG2(__lsx_vilvh_h, dsth7, dsth6, dsth8, dsth7, tmp1, tmp3); - DUP2_ARG2(__lsx_vilvl_h, dsth9, dsth8, dsth10, dsth9, tmp4, tmp6); - DUP2_ARG2(__lsx_vilvh_h, dsth9, dsth8, dsth10, dsth9, tmp5, tmp7); - DUP4_ARG2(__lsx_vdp2_w_h, dsth0, filt_h0, dsth2, filt_h0, tmp0, filt_h0, - tmp2, filt_h0, dst4_r, dst5_r, dst6_r, dst7_r); - DUP4_ARG3(__lsx_vdp2add_w_h, dst4_r, tmp0, filt_h1, dst5_r, tmp2, - filt_h1, dst6_r, tmp4, filt_h1, dst7_r, tmp6, filt_h1, - dst4_r, dst5_r, dst6_r, dst7_r); - DUP2_ARG2(__lsx_vpickev_d, dsth3, dsth1, tmp3, tmp1, tmp0, tmp1); - tmp2 = __lsx_vpickev_d(tmp7, tmp5); - - DUP2_ARG2(__lsx_vdp2_w_h, tmp8, filt_h0, tmp0, filt_h0, dst1_l, dst2_l); - dst3_l = __lsx_vdp2_w_h(tmp1, filt_h0); - DUP2_ARG3(__lsx_vdp2add_w_h, dst1_l, tmp0, filt_h1, dst2_l, tmp1, filt_h1, - dst1_l, dst2_l); - dst3_l = __lsx_vdp2add_w_h(dst3_l, tmp2, filt_h1); - - DUP4_ARG2(__lsx_vsrai_d, dst0_r, 6, dst1_r, 6, dst2_r, 6, dst3_r, 6, - dst0_r, dst1_r, dst2_r, dst3_r); - DUP4_ARG2(__lsx_vsrai_d, dst4_r, 6, dst5_r, 6, dst6_r, 6, dst7_r, 6, - dst4_r, dst5_r, dst6_r, dst7_r); - DUP4_ARG2(__lsx_vsrai_d, dst0_l, 6, dst1_l, 6, dst2_l, 6, dst3_l, 6, - dst0_l, dst1_l, dst2_l, dst3_l); - DUP2_ARG2(__lsx_vpickev_h, dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); - DUP2_ARG2(__lsx_vpickev_h, dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); - DUP2_ARG2(__lsx_vpickev_h, dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); - - reg0 = __lsx_vldrepl_d(src1_ptr, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride, 0); - dsth0 = __lsx_vilvl_d(reg1, reg0); - reg0 = __lsx_vldrepl_d(src1_ptr + src2_stride_2x, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride_3x, 0); - dsth1 = __lsx_vilvl_d(reg1, reg0); - src1_ptr += src2_stride_4x; - reg0 = __lsx_vldrepl_d(src1_ptr, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride, 0); - dsth2 = __lsx_vilvl_d(reg1, reg0); - reg0 = __lsx_vldrepl_d(src1_ptr + src2_stride_2x, 0); - reg1 = __lsx_vldrepl_d(src1_ptr + src2_stride_3x, 0); - dsth3 = __lsx_vilvl_d(reg1, reg0); - - DUP4_ARG2(__lsx_vsadd_h, dsth0, tmp0, dsth1, tmp1, dsth2, tmp2, dsth3, - tmp3, tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vmaxi_h, tmp0, 0, tmp1, 0, tmp2, 0, tmp3, 0, - tmp0, tmp1, tmp2, tmp3); - DUP2_ARG3(__lsx_vssrlrni_bu_h, tmp1, tmp0, 7, tmp3, tmp2, 7, out0, out1); - - __lsx_vstelm_w(out0, dst, 0, 0); - __lsx_vstelm_w(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out0, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lsx_vstelm_w(out1, dst, 0, 0); - __lsx_vstelm_w(out1, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out1, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out1, dst + dst_stride_3x, 0, 3); - dst -= dst_stride_4x; - - src1_ptr -= src2_stride_4x; - - reg0 = __lsx_vldrepl_w(src1_ptr, 8); - reg1 = __lsx_vldrepl_w(src1_ptr + src2_stride, 8); - reg2 = __lsx_vldrepl_w(src1_ptr + src2_stride_2x, 8); - reg3 = __lsx_vldrepl_w(src1_ptr + src2_stride_3x, 8); - DUP2_ARG2(__lsx_vilvl_w, reg1, reg0, reg3, reg2, tmp0, tmp1); - dsth4 = __lsx_vilvl_d(tmp1, tmp0); - src1_ptr += src2_stride_4x; - - reg0 = __lsx_vldrepl_w(src1_ptr, 8); - reg1 = __lsx_vldrepl_w(src1_ptr + src2_stride, 8); - reg2 = __lsx_vldrepl_w(src1_ptr + src2_stride_2x, 8); - reg3 = __lsx_vldrepl_w(src1_ptr + src2_stride_3x, 8); - DUP2_ARG2(__lsx_vilvl_w, reg1, reg0, reg3, reg2, tmp0, tmp1); - dsth5 = __lsx_vilvl_d(tmp1, tmp0); - DUP2_ARG2(__lsx_vsadd_h, dsth4, tmp4, dsth5, tmp5, tmp4, tmp5); - DUP2_ARG2(__lsx_vmaxi_h, tmp4, 0, tmp5, 7, tmp4, tmp5); - out0 = __lsx_vssrlrni_bu_h(tmp5, tmp4, 7); - - __lsx_vstelm_h(out0, dst, 4, 0); - __lsx_vstelm_h(out0, dst + dst_stride, 4, 1); - __lsx_vstelm_h(out0, dst + dst_stride_2x, 4, 2); - __lsx_vstelm_h(out0, dst + dst_stride_3x, 4, 3); - dst += dst_stride_4x; - __lsx_vstelm_h(out0, dst, 4, 4); - __lsx_vstelm_h(out0, dst + dst_stride, 4, 5); - __lsx_vstelm_h(out0, dst + dst_stride_2x, 4, 6); - __lsx_vstelm_h(out0, dst + dst_stride_3x, 4, 7); -} - static av_always_inline void hevc_hv_4t_8x2_lsx(const uint8_t *src0_ptr, int32_t src_stride, const int16_t *src1_ptr, int32_t src2_stride, uint8_t *dst, int32_t dst_stride, @@ -2281,7 +2177,6 @@ BI_MC_HV(qpel, 48, 8); BI_MC_HV(qpel, 64, 8); BI_MC_HV(epel, 8, 4); -BI_MC_HV(epel, 6, 4); BI_MC_HV(epel, 16, 4); BI_MC_HV(epel, 24, 4); BI_MC_HV(epel, 32, 4); diff --git a/libavcodec/loongarch/hevc_mc_uni_lsx.c b/libavcodec/loongarch/hevc_mc_uni_lsx.c index 6bdc27a824..5ec115bab1 100644 --- a/libavcodec/loongarch/hevc_mc_uni_lsx.c +++ b/libavcodec/loongarch/hevc_mc_uni_lsx.c @@ -545,7 +545,7 @@ static void hevc_hv_8t_64w_lsx(const uint8_t *src, int32_t src_stride, uint8_t * } static av_always_inline -void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, +void common_vt_2t_24w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { @@ -554,8 +554,8 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, int32_t src_stride_3x = src_stride_2x + src_stride; const uint8_t *_src; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; - __m128i src11, filt0, filt1; + __m128i src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; + __m128i filt0, filt1; __m128i src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; __m128i src109_r, src10_l, src32_l, src21_l, src43_l; __m128i out0_r, out1_r, out2_r, out3_r, out0_l, out1_l; @@ -578,7 +578,7 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, _src += src_stride_3x; DUP2_ARG2(__lsx_vilvl_b, src7, src6, src8, src7, src76_r, src87_r); - for (loop_cnt = 8; loop_cnt--;) { + for (loop_cnt = height >> 1; loop_cnt--;) { /* 16 width */ DUP2_ARG2(__lsx_vld, src, 0, _src, 0, src3, src9); DUP2_ARG2(__lsx_vldx, src, src_stride, _src, src_stride, src4, src10); @@ -605,53 +605,27 @@ void common_vt_4t_24w_lsx(const uint8_t *src, int32_t src_stride, /* 16 + 8 width */ DUP4_ARG3(__lsx_vssrarni_bu_h, out0_l, out0_r, 6, out2_r, out2_r, 6, - out3_r, out3_r, 6, out1_l, out1_r, 6, out1, out2, out3, out4); - __lsx_vst(out1, dst, 0); - __lsx_vstelm_d(out2, dst, 16, 0); - dst += dst_stride; - __lsx_vst(out4, dst, 0); - __lsx_vstelm_d(out3, dst, 16, 0); - dst += dst_stride; - - /* 16 width */ - DUP2_ARG2(__lsx_vld, src, 0, _src, 0, src5, src11); - DUP2_ARG2(__lsx_vldx, src, src_stride, _src, src_stride, src2, src8); - DUP2_ARG2(__lsx_vilvl_b, src5, src4, src2, src5, src10_r, src21_r); - DUP2_ARG2(__lsx_vilvh_b, src5, src4, src2, src5, src10_l, src21_l); - - /* 8 width */ - src += src_stride_2x; - _src += src_stride_2x; - DUP2_ARG2(__lsx_vilvl_b, src11, src10, src8, src11, src76_r, src87_r); - - /* 16 width */ - DUP4_ARG2(__lsx_vdp2_h_bu_b, src32_r, filt0, src32_l, filt0, src43_r, - filt0, src43_l, filt0, out0_r, out0_l, out1_r, out1_l); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, out0_r, src10_r, filt1, out0_l, src10_l, - filt1, out1_r, src21_r, filt1, out1_l, src21_l, filt1, - out0_r, out0_l, out1_r, out1_l); - - /* 8 width */ - DUP2_ARG2(__lsx_vdp2_h_bu_b, src98_r, filt0, src109_r, filt0, - out2_r, out3_r); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, out2_r, src76_r, filt1, out3_r, - src87_r, filt1, out2_r, out3_r); - - /* 16 + 8 width */ - DUP4_ARG3(__lsx_vssrarni_bu_h, out0_l, out0_r, 6, out2_r, out2_r, 6, - out1_l, out1_r, 6, out3_r, out3_r, 6, out1, out2, out3, out4); - + out1_l, out1_r, 6, out3_r, out3_r, 6, out1, out2, out3, out4); __lsx_vst(out1, dst, 0); __lsx_vstelm_d(out2, dst, 16, 0); dst += dst_stride; __lsx_vst(out3, dst, 0); __lsx_vstelm_d(out4, dst, 16, 0); dst += dst_stride; + + src10_r = src32_r; + src21_r = src43_r; + src10_l = src32_l; + src21_l = src43_l; + src2 = src4; + src76_r = src98_r; + src87_r = src109_r; + src8 = src10; } } static av_always_inline -void common_vt_4t_32w_lsx(const uint8_t *src, int32_t src_stride, +void common_vt_2t_32w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { @@ -805,102 +779,6 @@ void hevc_hv_4t_8x2_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, __lsx_vstelm_d(out, dst + dst_stride, 0, 1); } -static av_always_inline -void hevc_hv_4t_8multx4_lsx(const 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; - const int32_t src_stride_2x = (src_stride << 1); - const int32_t dst_stride_2x = (dst_stride << 1); - const int32_t src_stride_4x = (src_stride << 2); - const int32_t src_stride_3x = src_stride_2x + src_stride; - const int32_t dst_stride_3x = dst_stride_2x + dst_stride; - - __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6, mask0, mask1; - __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i filt0, filt1, filt_h0, filt_h1, filter_vec; - __m128i dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; - __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; - __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; - - src -= (src_stride + 1); - DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); - - filter_vec = __lsx_vld(filter_y, 0); - filter_vec = __lsx_vsllwil_h_b(filter_vec, 0); - DUP2_ARG2(__lsx_vreplvei_w, filter_vec, 0, filter_vec, 1, filt_h0, filt_h1); - - mask0 = __lsx_vld(ff_hevc_mask_arr, 0); - mask1 = __lsx_vaddi_bu(mask0, 2); - - for (cnt = width8mult; cnt--;) { - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src3 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src4 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src5, src6); - src += (8 - src_stride_4x); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, - vec4, vec5); - - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); - dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, - dst0, dst1); - dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); - - DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); - DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); - - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, - vec6, vec7); - - DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst3, dst4, dst5, dst6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, - dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); - - DUP4_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst5, dst4, dst6, - dst5, dst32_r, dst43_r, dst54_r, dst65_r); - DUP4_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst5, dst4, dst6, - dst5, dst32_l, dst43_l, dst54_l, dst65_l); - - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, - filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, - filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, - filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, - dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, - filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, - dst2_r, dst2_l, dst3_r, dst3_l); - - DUP4_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, - dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, tmp0, tmp1, tmp2, tmp3); - DUP2_ARG3(__lsx_vssrarni_bu_h, tmp1, tmp0, 6, tmp3, tmp2, 6, out0, out1); - __lsx_vstelm_d(out0, dst, 0, 0); - __lsx_vstelm_d(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_d(out1, dst + dst_stride_2x, 0, 0); - __lsx_vstelm_d(out1, dst + dst_stride_3x, 0, 1); - dst += 8; - } -} - static av_always_inline void hevc_hv_4t_8x6_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, @@ -1009,10 +887,9 @@ void hevc_hv_4t_8x6_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, } static av_always_inline -void hevc_hv_4t_8multx4mult_lsx(const 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) +void hevc_hv_4t_8mult_lsx(const 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; const uint8_t *src_tmp; @@ -1134,14 +1011,10 @@ void hevc_hv_4t_8w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, { if (2 == height) { hevc_hv_4t_8x2_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y); - } else if (4 == height) { - hevc_hv_4t_8multx4_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_4t_8x6_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y); } else if (0 == (height & 0x03)) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 1); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 1); } } @@ -1160,17 +1033,14 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, const int32_t src_stride_3x = src_stride_2x + src_stride; const int32_t dst_stride_3x = dst_stride_2x + dst_stride; __m128i out0, out1; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + __m128i src0, src1, src2, src3, src4, src5, src6; __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i mask0, mask1, mask2, mask3; + __m128i mask0, mask1; __m128i filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; __m128i dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; - __m128i dst10, dst21, dst22, dst73, dst84, dst95, dst106; - __m128i dst76_r, dst98_r, dst87_r, dst109_r; __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; src -= (src_stride + 1); DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); @@ -1186,8 +1056,7 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, dst_tmp = dst; src0 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); src_tmp += src_stride_3x; DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); @@ -1196,17 +1065,15 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, - dsth0, dsth1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, dsth0, dsth1); dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, dst10_r, dst21_r); DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, dst10_l, dst21_l); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src3 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src4, src5); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); src6 = __lsx_vldx(src_tmp, src_stride_3x); src_tmp += src_stride_4x; @@ -1254,83 +1121,73 @@ void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride, uint8_t *dst, dsth2 = dsth6; } - src += 8; - dst += 8; + src_tmp = src + 8; + dst_tmp = dst + 8; - mask2 = __lsx_vld(ff_hevc_mask_arr, 16); - mask3 = __lsx_vaddi_bu(mask2, 2); + src0 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); + src_tmp += src_stride_3x; - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src += src_stride_3x; - DUP2_ARG3(__lsx_vshuf_b, src1, src0, mask2, src1, src0, mask3, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src1, mask2, src2, src1, mask3, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst10, dst21); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst10, vec1, filt1, dst21, vec3, filt1, - dst10, dst21); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dsth0, dsth1); + dsth2 = __lsx_vdp2_h_bu_b(vec4, filt0); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dsth0, vec1, filt1, dsth1, vec3, filt1, dsth0, dsth1); + dsth2 = __lsx_vdp2add_h_bu_b(dsth2, vec5, filt1); - dst10_r = __lsx_vilvl_h(dst21, dst10); - dst21_r = __lsx_vilvh_h(dst21, dst10); - dst22 = __lsx_vreplvei_d(dst21, 1); + DUP2_ARG2(__lsx_vilvl_h, dsth1, dsth0, dsth2, dsth1, dst10_r, dst21_r); + DUP2_ARG2(__lsx_vilvh_h, dsth1, dsth0, dsth2, dsth1, dst10_l, dst21_l); - for (loop_cnt = 2; loop_cnt--;) { - src3 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src4, src5); - src6 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src7 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src8, src9); - src10 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - DUP4_ARG3(__lsx_vshuf_b, src7, src3, mask2, src7, src3, mask3, src8, - src4, mask2, src8, src4, mask3, vec0, vec1, vec2, vec3); - DUP4_ARG3(__lsx_vshuf_b, src9, src5, mask2, src9, src5, mask3, src10, - src6, mask2, src10, src6, mask3, vec4, vec5, vec6, vec7); + for (loop_cnt = height >> 2; loop_cnt--;) { + src3 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); + src6 = __lsx_vldx(src_tmp, src_stride_3x); + src_tmp += src_stride_4x; + + DUP4_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, src4, + src4, mask0, src4, src4, mask1, vec0, vec1, vec2, vec3); + DUP4_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, src6, + src6, mask0, src6, src6, mask1, vec4, vec5, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst73, dst84, dst95, dst106); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst73, vec1, filt1, dst84, vec3, - filt1, dst95, vec5, filt1, dst106, vec7, filt1, - dst73, dst84, dst95, dst106); + vec6, filt0, dsth3, dsth4, dsth5, dsth6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dsth3, vec1, filt1, dsth4, + vec3, filt1, dsth5, vec5, filt1, dsth6, vec7, filt1, + dsth3, dsth4, dsth5, dsth6); - dst32_r = __lsx_vilvl_h(dst73, dst22); - DUP2_ARG2(__lsx_vilvl_h, dst84, dst73, dst95, dst84, dst43_r, dst54_r); - DUP2_ARG2(__lsx_vilvh_h, dst84, dst73, dst95, dst84, dst87_r, dst98_r); - dst65_r = __lsx_vilvl_h(dst106, dst95); - dst109_r = __lsx_vilvh_h(dst106, dst95); - dst22 = __lsx_vreplvei_d(dst73, 1); - dst76_r = __lsx_vilvl_h(dst22, dst106); + DUP4_ARG2(__lsx_vilvl_h, dsth3, dsth2, dsth4, dsth3, dsth5, dsth4, + dsth6, dsth5, dst32_r, dst43_r, dst54_r, dst65_r); + DUP4_ARG2(__lsx_vilvh_h, dsth3, dsth2, dsth4, dsth3, dsth5, dsth4, + dsth6, dsth5, dst32_l, dst43_l, dst54_l, dst65_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst21_r, filt_h0, dst32_r, - filt_h0, dst43_r, filt_h0, dst0, dst1, dst2, dst3); - DUP4_ARG2(__lsx_vdp2_w_h, dst54_r, filt_h0, dst65_r, filt_h0, dst76_r, - filt_h0, dst87_r, filt_h0, dst4, dst5, dst6, dst7); - DUP4_ARG3(__lsx_vdp2add_w_h, dst0, dst32_r, filt_h1, dst1, dst43_r, - filt_h1, dst2, dst54_r, filt_h1, dst3, dst65_r, filt_h1, - dst0, dst1, dst2, dst3); - DUP4_ARG3(__lsx_vdp2add_w_h, dst4, dst76_r, filt_h1, dst5, dst87_r, - filt_h1, dst6, dst98_r, filt_h1, dst7, dst109_r, filt_h1, - dst4, dst5, dst6, dst7); + DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, + filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, + filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, + filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, + dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, + filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, + dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG3(__lsx_vsrani_h_w, dst1, dst0, 6, dst3, dst2, 6, dst5, dst4, - 6, dst7, dst6, 6, tmp0, tmp1, tmp2, tmp3); + DUP4_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst2_l, + dst2_r, 6, dst3_l, dst3_r, 6, tmp0, tmp1, tmp2, tmp3); DUP2_ARG3(__lsx_vssrarni_bu_h, tmp1, tmp0, 6, tmp3, tmp2, 6, out0, out1); - __lsx_vstelm_w(out0, dst, 0, 0); - __lsx_vstelm_w(out0, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out0, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out0, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; - __lsx_vstelm_w(out1, dst, 0, 0); - __lsx_vstelm_w(out1, dst + dst_stride, 0, 1); - __lsx_vstelm_w(out1, dst + dst_stride_2x, 0, 2); - __lsx_vstelm_w(out1, dst + dst_stride_3x, 0, 3); - dst += dst_stride_4x; + __lsx_vstelm_w(out0, dst_tmp, 0, 0); + __lsx_vstelm_w(out0, dst_tmp + dst_stride, 0, 2); + __lsx_vstelm_w(out1, dst_tmp + dst_stride_2x, 0, 0); + __lsx_vstelm_w(out1, dst_tmp + dst_stride_3x, 0, 2); + dst_tmp += dst_stride_4x; - dst10_r = dst98_r; - dst21_r = dst109_r; - dst22 = __lsx_vreplvei_d(dst106, 1); + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; } } @@ -1338,29 +1195,21 @@ static void hevc_hv_4t_16w_lsx(const uint8_t *src, int32_t src_stride, uint8_t * int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - if (4 == height) { - hevc_hv_4t_8multx4_lsx(src, src_stride, dst, dst_stride, filter_x, - filter_y, 2); - } else { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 2); - } + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 2); } static void hevc_hv_4t_24w_lsx(const 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) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 3); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 3); } static void hevc_hv_4t_32w_lsx(const 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) { - hevc_hv_4t_8multx4mult_lsx(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 4); + hevc_hv_4t_8mult_lsx(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 4); } #define UNI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ @@ -1386,8 +1235,8 @@ UNI_MC(qpel, v, 32, 8, vt, my); UNI_MC(qpel, v, 48, 8, vt, my); UNI_MC(qpel, v, 64, 8, vt, my); -UNI_MC(epel, v, 24, 4, vt, my); -UNI_MC(epel, v, 32, 4, vt, my); +UNI_MC(epel, v, 24, 2, vt, my); +UNI_MC(epel, v, 32, 2, vt, my); #undef UNI_MC diff --git a/libavcodec/loongarch/hevcdsp_init_loongarch.c b/libavcodec/loongarch/hevcdsp_init_loongarch.c index 1585bda276..55fe6b15ad 100644 --- a/libavcodec/loongarch/hevcdsp_init_loongarch.c +++ b/libavcodec/loongarch/hevcdsp_init_loongarch.c @@ -139,7 +139,6 @@ void ff_hevc_dsp_init_loongarch(HEVCDSPContext *c, const int bit_depth) c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_8_lsx; c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_lsx; - c->put_hevc_epel_bi[2][1][1] = ff_hevc_put_hevc_bi_epel_hv6_8_lsx; c->put_hevc_epel_bi[3][1][1] = ff_hevc_put_hevc_bi_epel_hv8_8_lsx; c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_8_lsx; c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_8_lsx; diff --git a/libavcodec/loongarch/hevcdsp_lsx.c b/libavcodec/loongarch/hevcdsp_lsx.c index 5747925525..993944164d 100644 --- a/libavcodec/loongarch/hevcdsp_lsx.c +++ b/libavcodec/loongarch/hevcdsp_lsx.c @@ -772,56 +772,40 @@ static void hevc_hz_8t_12w_lsx(const uint8_t *src, int32_t src_stride, DUP2_ARG2(__lsx_vaddi_bu, mask4, 2, mask4, 4, mask5, mask6); mask7 = __lsx_vaddi_bu(mask4, 6); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src0 = __lsx_vld(src, 0); DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); src3 = __lsx_vldx(src, src_stride_3x); src4 = __lsx_vld(_src, 0); - DUP2_ARG2(__lsx_vldx, _src, src_stride, _src, src_stride_2x, - src5, src6); + DUP2_ARG2(__lsx_vldx, _src, src_stride, _src, src_stride_2x, src5, src6); src7 = __lsx_vldx(_src, src_stride_3x); src += src_stride_4x; _src += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src1, mask0, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src3, src3, mask0, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask4, src7, src6, mask4, - vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src1, src1, mask0, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src3, src3, mask0, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask4, src7, src6, mask4, vec4, vec5); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec1, filt0, vec2, filt0, vec3, filt0, dst0, dst1, dst2, dst3); DUP2_ARG2(__lsx_vdp2_h_bu_b, vec4, filt0, vec5, filt0, dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src1, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask1, src3, src3, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask5, src7, src6, mask5, - vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask1, src1, src1, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask1, src3, src3, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask5, src7, src6, mask5, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt1, dst1, vec1, filt1, dst2, vec2, filt1, dst3, vec3, filt1, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt1, dst5, vec5, filt1, - dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask2, src1, src1, mask2, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask2, src3, src3, mask2, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask6, src7, src6, mask6, - vec4, vec5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt1, dst5, vec5, filt1, dst4, dst5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask2, src1, src1, mask2, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask2, src3, src3, mask2, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask6, src7, src6, mask6, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt2, dst1, vec1, filt2, dst2, vec2, filt2, dst3, vec3, filt2, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt2, dst5, vec5, filt2, - dst4, dst5); - DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask3, src1, src1, mask3, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask3, src3, src3, mask3, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask7, src7, src6, mask7, - vec4, vec5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt2, dst5, vec5, filt2, dst4, dst5); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask3, src1, src1, mask3, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask3, src3, src3, mask3, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src4, mask7, src7, src6, mask7, vec4, vec5); DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec0, filt3, dst1, vec1, filt3, dst2, vec2, filt3, dst3, vec3, filt3, dst0, dst1, dst2, dst3); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt3, dst5, vec5, filt3, - dst4, dst5); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst4, vec4, filt3, dst5, vec5, filt3, dst4, dst5); __lsx_vst(dst0, dst, 0); __lsx_vstelm_d(dst4, dst, 16, 0); @@ -2972,16 +2956,14 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, int32_t src_stride_3x = src_stride_2x + src_stride; int32_t dst_stride_3x = dst_stride_2x + dst_stride_x; - __m128i src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + __m128i src0, src1, src2, src3, src4, src5, src6; __m128i vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - __m128i mask0, mask1, mask2, mask3; + __m128i mask0, mask1; __m128i filt0, filt1, filt_h0, filt_h1, filter_vec, dst0; - __m128i dst1, dst2, dst3, dst4, dst5, dst6, dst10, dst21, dst22, dst73; - __m128i dst84, dst95, dst106, dst76_r, dst98_r, dst87_r, dst109_r; + __m128i dst1, dst2, dst3, dst4, dst5, dst6; __m128i dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; __m128i dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; __m128i dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; src -= (src_stride + 1); DUP2_ARG2(__lsx_vldrepl_h, filter_x, 0, filter_x, 2, filt0, filt1); @@ -2997,8 +2979,7 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, dst_tmp = dst; src0 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src1, src2); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); src_tmp += src_stride_3x; DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); @@ -3007,34 +2988,27 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, - dst0, dst1); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, dst0, dst1); dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); - for (loop_cnt = 4; loop_cnt--;) { + for (loop_cnt = height >> 2; loop_cnt--;) { src3 = __lsx_vld(src_tmp, 0); - DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, - src4, src5); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); src6 = __lsx_vldx(src_tmp, src_stride_3x); src_tmp += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, - vec6, vec7); + DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, vec6, filt0, dst3, dst4, dst5, dst6); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, - filt1, dst5, vec5, filt1, dst6, vec7, filt1, dst3, - dst4, dst5, dst6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, + dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); DUP2_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst32_r, dst43_r); DUP2_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst32_l, dst43_l); @@ -3051,12 +3025,8 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG2(__lsx_vsrai_w, dst0_r, 6, dst0_l, 6, dst1_r, 6, dst1_l, 6, - dst0_r, dst0_l, dst1_r, dst1_l); - DUP4_ARG2(__lsx_vsrai_w, dst2_r, 6, dst2_l, 6, dst3_r, 6, dst3_l, 6, - dst2_r, dst2_l, dst3_r, dst3_l); - DUP4_ARG2(__lsx_vpickev_h, dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, - dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst0_r, dst1_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, dst2_r, dst3_r); __lsx_vst(dst0_r, dst_tmp, 0); __lsx_vstx(dst1_r, dst_tmp, dst_stride_x); __lsx_vstx(dst2_r, dst_tmp, dst_stride_2x); @@ -3070,93 +3040,74 @@ static void hevc_hv_4t_12w_lsx(const uint8_t *src, dst2 = dst6; } - src += 8; - dst += 8; + src_tmp = src + 8; + dst_tmp = dst + 8; - mask2 = __lsx_vld(ff_hevc_mask_arr, 16); - mask3 = __lsx_vaddi_bu(mask2, 2); + src0 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src1, src2); + src_tmp += src_stride_3x; - src0 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src1, src2); - src += src_stride_3x; - DUP2_ARG3(__lsx_vshuf_b, src1, src0, mask2, src1, src0, mask3, vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src2, src1, mask2, src2, src1, mask3, vec2, vec3); - DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst10, dst21); - DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst10, vec1, filt1, dst21, vec3, filt1, - dst10, dst21); - dst10_r = __lsx_vilvl_h(dst21, dst10); - dst21_r = __lsx_vilvh_h(dst21, dst10); - dst22 = __lsx_vreplvei_d(dst21, 1); + DUP2_ARG3(__lsx_vshuf_b, src0, src0, mask0, src0, src0, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src1, src1, mask0, src1, src1, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src2, src2, mask0, src2, src2, mask1, vec4, vec5); - for (loop_cnt = 2; loop_cnt--;) { - src3 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src4, src5); - src6 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - src7 = __lsx_vld(src, 0); - DUP2_ARG2(__lsx_vldx, src, src_stride, src, src_stride_2x, src8, src9); - src10 = __lsx_vldx(src, src_stride_3x); - src += src_stride_4x; - DUP2_ARG3(__lsx_vshuf_b, src7, src3, mask2, src7, src3, mask3, - vec0, vec1); - DUP2_ARG3(__lsx_vshuf_b, src8, src4, mask2, src8, src4, mask3, - vec2, vec3); - DUP2_ARG3(__lsx_vshuf_b, src9, src5, mask2, src9, src5, mask3, - vec4, vec5); - DUP2_ARG3(__lsx_vshuf_b, src10, src6, mask2, src10, src6, mask3, - vec6, vec7); + DUP2_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, dst0, dst1); + dst2 = __lsx_vdp2_h_bu_b(vec4, filt0); + DUP2_ARG3(__lsx_vdp2add_h_bu_b, dst0, vec1, filt1, dst1, vec3, filt1, dst0, dst1); + dst2 = __lsx_vdp2add_h_bu_b(dst2, vec5, filt1); + + DUP2_ARG2(__lsx_vilvl_h, dst1, dst0, dst2, dst1, dst10_r, dst21_r); + DUP2_ARG2(__lsx_vilvh_h, dst1, dst0, dst2, dst1, dst10_l, dst21_l); + + for (loop_cnt = height >> 2; loop_cnt--;) { + src3 = __lsx_vld(src_tmp, 0); + DUP2_ARG2(__lsx_vldx, src_tmp, src_stride, src_tmp, src_stride_2x, src4, src5); + src6 = __lsx_vldx(src_tmp, src_stride_3x); + src_tmp += src_stride_4x; + + DUP2_ARG3(__lsx_vshuf_b, src3, src3, mask0, src3, src3, mask1, vec0, vec1); + DUP2_ARG3(__lsx_vshuf_b, src4, src4, mask0, src4, src4, mask1, vec2, vec3); + DUP2_ARG3(__lsx_vshuf_b, src5, src5, mask0, src5, src5, mask1, vec4, vec5); + DUP2_ARG3(__lsx_vshuf_b, src6, src6, mask0, src6, src6, mask1, vec6, vec7); DUP4_ARG2(__lsx_vdp2_h_bu_b, vec0, filt0, vec2, filt0, vec4, filt0, - vec6, filt0, dst73, dst84, dst95, dst106); - DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst73, vec1, filt1, dst84, vec3, - filt1, dst95, vec5, filt1, dst106, vec7, filt1, dst73, - dst84, dst95, dst106); + vec6, filt0, dst3, dst4, dst5, dst6); + DUP4_ARG3(__lsx_vdp2add_h_bu_b, dst3, vec1, filt1, dst4, vec3, filt1, + dst5, vec5, filt1, dst6, vec7, filt1, dst3, dst4, dst5, dst6); - DUP2_ARG2(__lsx_vilvl_h, dst73, dst22, dst84, dst73, dst32_r, dst43_r); - DUP2_ARG2(__lsx_vilvh_h, dst84, dst73, dst95, dst84, dst87_r, dst98_r); - DUP2_ARG2(__lsx_vilvl_h, dst95, dst84, dst106, dst95, dst54_r, dst65_r); - dst109_r = __lsx_vilvh_h(dst106, dst95); - dst22 = __lsx_vreplvei_d(dst73, 1); - dst76_r = __lsx_vilvl_h(dst22, dst106); + DUP2_ARG2(__lsx_vilvl_h, dst3, dst2, dst4, dst3, dst32_r, dst43_r); + DUP2_ARG2(__lsx_vilvh_h, dst3, dst2, dst4, dst3, dst32_l, dst43_l); + DUP2_ARG2(__lsx_vilvl_h, dst5, dst4, dst6, dst5, dst54_r, dst65_r); + DUP2_ARG2(__lsx_vilvh_h, dst5, dst4, dst6, dst5, dst54_l, dst65_l); - DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst21_r, filt_h0, dst32_r, - filt_h0, dst43_r, filt_h0, tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vdp2_w_h, dst54_r, filt_h0, dst65_r, filt_h0, dst76_r, - filt_h0, dst87_r, filt_h0, tmp4, tmp5, tmp6, tmp7); - DUP4_ARG3(__lsx_vdp2add_w_h, tmp0, dst32_r, filt_h1, tmp1, dst43_r, - filt_h1, tmp2, dst54_r, filt_h1, tmp3, dst65_r, filt_h1, - tmp0, tmp1, tmp2, tmp3); - DUP4_ARG3(__lsx_vdp2add_w_h, tmp4, dst76_r, filt_h1, tmp5, dst87_r, - filt_h1, tmp6, dst98_r, filt_h1, tmp7, dst109_r, filt_h1, - tmp4, tmp5, tmp6, tmp7); - DUP4_ARG2(__lsx_vsrai_w, tmp0, 6, tmp1, 6, tmp2, 6, tmp3, 6, - tmp0, tmp1, tmp2, tmp3); - DUP4_ARG2(__lsx_vsrai_w, tmp4, 6, tmp5, 6, tmp6, 6, tmp7, 6, - tmp4, tmp5, tmp6, tmp7); - DUP4_ARG2(__lsx_vpickev_h, tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, - tmp7, tmp6, tmp0, tmp1, tmp2, tmp3); + DUP4_ARG2(__lsx_vdp2_w_h, dst10_r, filt_h0, dst10_l, filt_h0, dst21_r, + filt_h0, dst21_l, filt_h0, dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG2(__lsx_vdp2_w_h, dst32_r, filt_h0, dst32_l, filt_h0, dst43_r, + filt_h0, dst43_l, filt_h0, dst2_r, dst2_l, dst3_r, dst3_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst0_r, dst32_r, filt_h1, dst0_l, dst32_l, + filt_h1, dst1_r, dst43_r, filt_h1, dst1_l, dst43_l, filt_h1, + dst0_r, dst0_l, dst1_r, dst1_l); + DUP4_ARG3(__lsx_vdp2add_w_h, dst2_r, dst54_r, filt_h1, dst2_l, dst54_l, + filt_h1, dst3_r, dst65_r, filt_h1, dst3_l, dst65_l, filt_h1, + dst2_r, dst2_l, dst3_r, dst3_l); + DUP2_ARG3(__lsx_vsrani_h_w, dst0_l, dst0_r, 6, dst1_l, dst1_r, 6, dst0_r, dst1_r); + DUP2_ARG3(__lsx_vsrani_h_w, dst2_l, dst2_r, 6, dst3_l, dst3_r, 6, dst2_r, dst3_r); + __lsx_vstelm_d(dst0_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst1_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst2_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; + __lsx_vstelm_d(dst3_r, dst_tmp, 0, 0); + dst_tmp += dst_stride; - __lsx_vstelm_d(tmp0, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp0, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp1, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp1, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp2, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp2, dst, 0, 1); - dst += dst_stride; - __lsx_vstelm_d(tmp3, dst, 0, 0); - dst += dst_stride; - __lsx_vstelm_d(tmp3, dst, 0, 1); - dst += dst_stride; - - dst10_r = dst98_r; - dst21_r = dst109_r; - dst22 = __lsx_vreplvei_d(dst106, 1); + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } + } static void hevc_hv_4t_16w_lsx(const uint8_t *src, diff --git a/libavcodec/loongarch/hevcdsp_lsx.h b/libavcodec/loongarch/hevcdsp_lsx.h index cf2a519e94..8562a0d681 100644 --- a/libavcodec/loongarch/hevcdsp_lsx.h +++ b/libavcodec/loongarch/hevcdsp_lsx.h @@ -141,7 +141,6 @@ BI_MC(epel, v, 16); BI_MC(epel, v, 24); BI_MC(epel, v, 32); -BI_MC(epel, hv, 6); BI_MC(epel, hv, 8); BI_MC(epel, hv, 16); BI_MC(epel, hv, 24); diff --git a/libavcodec/loongarch/loongson_asm.S b/libavcodec/loongarch/loongson_asm.S index 0a649f51c7..5edec9b823 100644 --- a/libavcodec/loongarch/loongson_asm.S +++ b/libavcodec/loongarch/loongson_asm.S @@ -332,7 +332,7 @@ ASM_PREF\name: ; /* * Description : Store elements of vector - * vd : Data vector to be stroed + * vd : Data vector to be stored * rk : Address of data storage * ra : Offset of address * si : Index of data in vd diff --git a/libavcodec/loongarch/vc1dsp_loongarch.h b/libavcodec/loongarch/vc1dsp_loongarch.h index e5ccbcb768..30589e248a 100644 --- a/libavcodec/loongarch/vc1dsp_loongarch.h +++ b/libavcodec/loongarch/vc1dsp_loongarch.h @@ -30,7 +30,7 @@ void ff_vc1_inv_trans_8x8_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *bloc void ff_vc1_inv_trans_8x4_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_8x4_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x8_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); -void ff_vc1_inv_trans_4x8_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *blokc); +void ff_vc1_inv_trans_4x8_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x4_dc_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x4_lasx(uint8_t *dest, ptrdiff_t stride, int16_t *block); diff --git a/libavcodec/lpc.c b/libavcodec/lpc.c index e793e54038..38c78d9521 100644 --- a/libavcodec/lpc.c +++ b/libavcodec/lpc.c @@ -267,7 +267,7 @@ int ff_lpc_calc_coefs(LPCContext *s, s->lpc_compute_autocorr(s->windowed_samples, blocksize, max_order, autoc); - compute_lpc_coefs(autoc, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1); + compute_lpc_coefs(autoc, 0, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1, NULL); for(i=0; isize; } -static int lscr_decode_close(AVCodecContext *avctx) +static av_cold int lscr_decode_close(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; @@ -225,7 +225,7 @@ static int lscr_decode_close(AVCodecContext *avctx) return 0; } -static int lscr_decode_init(AVCodecContext *avctx) +static av_cold int lscr_decode_init(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; @@ -242,7 +242,7 @@ static int lscr_decode_init(AVCodecContext *avctx) return ff_inflate_init(&s->zstream, avctx); } -static void lscr_decode_flush(AVCodecContext *avctx) +static av_cold void lscr_decode_flush(AVCodecContext *avctx) { LSCRContext *s = avctx->priv_data; av_frame_unref(s->last_picture); diff --git a/libavcodec/lsp.c b/libavcodec/lsp.c index 275984097d..4eaeb2bfc2 100644 --- a/libavcodec/lsp.c +++ b/libavcodec/lsp.c @@ -150,7 +150,13 @@ static void lsp2polyf(const double *lsp, double *f, int lp_half_order) } #endif /* lsp2polyf */ -void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order) +/** + * @brief LSP to LP conversion (3.2.6 of G.729) + * @param[out] lp decoded LP coefficients (-0x8000 <= (3.12) < 0x8000) + * @param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000) + * @param lp_half_order LP filter order, divided by 2 + */ +static void acelp_lsp2lpc(int16_t lp[], const int16_t lsp[], int lp_half_order) { int i; int f1[MAX_LP_HALF_ORDER+1]; // (3.22) @@ -211,10 +217,10 @@ void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1; #endif - ff_acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1); + acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1); /* LSP values for second subframe (3.2.5 of G.729)*/ - ff_acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1); + acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1); } void ff_acelp_lspd2lpc(const double *lsp, float *lpc, int lp_half_order) diff --git a/libavcodec/lsp.h b/libavcodec/lsp.h index 26b1382eda..17126a43ce 100644 --- a/libavcodec/lsp.h +++ b/libavcodec/lsp.h @@ -67,14 +67,6 @@ void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf, int lp_order); */ void ff_acelp_lsf2lspd(double *lsp, const float *lsf, int lp_order); -/** - * @brief LSP to LP conversion (3.2.6 of G.729) - * @param[out] lp decoded LP coefficients (-0x8000 <= (3.12) < 0x8000) - * @param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000) - * @param lp_half_order LP filter order, divided by 2 - */ -void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order); - /** * LSP to LP conversion (5.2.4 of AMR-WB) */ diff --git a/libavcodec/lzf.c b/libavcodec/lzf.c index 1e3c86c88c..94b369dd59 100644 --- a/libavcodec/lzf.c +++ b/libavcodec/lzf.c @@ -56,7 +56,10 @@ int ff_lzf_uncompress(GetByteContext *gb, uint8_t **buf, int64_t *size) p = *buf + len; } - bytestream2_get_buffer(gb, p, s); + int s2 = bytestream2_get_buffer(gb, p, s); + if (s2 != s) + return AVERROR_INVALIDDATA; + p += s; len += s; } else { diff --git a/libavcodec/mace.c b/libavcodec/mace.c index a35291330e..2aa54fb548 100644 --- a/libavcodec/mace.c +++ b/libavcodec/mace.c @@ -293,8 +293,7 @@ const FFCodec ff_mace3_decoder = { .init = mace_decode_init, FF_CODEC_DECODE_CB(mace_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; const FFCodec ff_mace6_decoder = { @@ -306,6 +305,5 @@ const FFCodec ff_mace6_decoder = { .init = mace_decode_init, FF_CODEC_DECODE_CB(mace_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index b85505c428..e106228757 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -462,37 +462,22 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_PATCHWELCOME; } - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 0; - s->decorrelate = 0; - s->bps = 8; - format = bytestream2_get_byteu(&gb); switch (format) { case 0x65: avctx->pix_fmt = AV_PIX_FMT_GBRP; - s->decorrelate = 1; break; case 0x66: avctx->pix_fmt = AV_PIX_FMT_GBRAP; - s->decorrelate = 1; break; case 0x67: avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; case 0x68: avctx->pix_fmt = AV_PIX_FMT_YUV422P; - s->hshift[1] = - s->hshift[2] = 1; break; case 0x69: avctx->pix_fmt = AV_PIX_FMT_YUV420P; - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 1; break; case 0x6a: avctx->pix_fmt = AV_PIX_FMT_YUVA444P; @@ -502,60 +487,44 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, break; case 0x6c: avctx->pix_fmt = AV_PIX_FMT_YUV422P10; - s->hshift[1] = - s->hshift[2] = 1; - s->bps = 10; break; case 0x76: avctx->pix_fmt = AV_PIX_FMT_YUV444P10; - s->bps = 10; break; case 0x6d: avctx->pix_fmt = AV_PIX_FMT_GBRP10; - s->decorrelate = 1; - s->bps = 10; break; case 0x6e: avctx->pix_fmt = AV_PIX_FMT_GBRAP10; - s->decorrelate = 1; - s->bps = 10; break; case 0x6f: avctx->pix_fmt = AV_PIX_FMT_GBRP12; - s->decorrelate = 1; - s->bps = 12; break; case 0x70: avctx->pix_fmt = AV_PIX_FMT_GBRAP12; - s->decorrelate = 1; - s->bps = 12; break; case 0x71: avctx->pix_fmt = AV_PIX_FMT_GBRP14; - s->decorrelate = 1; - s->bps = 14; break; case 0x72: avctx->pix_fmt = AV_PIX_FMT_GBRAP14; - s->decorrelate = 1; - s->bps = 14; break; case 0x73: avctx->pix_fmt = AV_PIX_FMT_GRAY10; - s->bps = 10; break; case 0x7b: avctx->pix_fmt = AV_PIX_FMT_YUV420P10; - s->hshift[1] = - s->vshift[1] = - s->hshift[2] = - s->vshift[2] = 1; - s->bps = 10; break; default: avpriv_request_sample(avctx, "Format 0x%X", format); return AVERROR_PATCHWELCOME; } + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + av_assert1(desc); + int is_rgb = s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + s->hshift[1] = s->hshift[2] = desc->log2_chroma_w; + s->vshift[1] = s->vshift[2] = desc->log2_chroma_h; + s->bps = desc->comp[0].depth; s->max = 1 << s->bps; s->magy_decode_slice = s->bps == 8 ? magy_decode_slice : magy_decode_slice10; s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); @@ -659,14 +628,7 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, s->p = p; avctx->execute2(avctx, s->magy_decode_slice, NULL, NULL, s->nb_slices); - if (avctx->pix_fmt == AV_PIX_FMT_GBRP || - avctx->pix_fmt == AV_PIX_FMT_GBRAP || - avctx->pix_fmt == AV_PIX_FMT_GBRP10 || - avctx->pix_fmt == AV_PIX_FMT_GBRAP10|| - avctx->pix_fmt == AV_PIX_FMT_GBRAP12|| - avctx->pix_fmt == AV_PIX_FMT_GBRAP14|| - avctx->pix_fmt == AV_PIX_FMT_GBRP12|| - avctx->pix_fmt == AV_PIX_FMT_GBRP14) { + if (is_rgb) { FFSWAP(uint8_t*, p->data[0], p->data[1]); FFSWAP(int, p->linesize[0], p->linesize[1]); } else { diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c index 3364207f81..80a54638bc 100644 --- a/libavcodec/magicyuvenc.c +++ b/libavcodec/magicyuvenc.c @@ -50,15 +50,18 @@ typedef struct HuffEntry { typedef struct PTable { int value; ///< input value - int64_t prob; ///< number of occurences of this value in input + int64_t prob; ///< number of occurrences of this value in input } PTable; typedef struct Slice { + int width; + int height; + int encode_raw; unsigned pos; unsigned size; uint8_t *slice; - uint8_t *bitslice; - PTable counts[256]; + uint8_t *dst; + int64_t counts[256]; } Slice; typedef struct MagicYUVContext { @@ -71,7 +74,6 @@ typedef struct MagicYUVContext { int correlate; int hshift[4]; int vshift[4]; - unsigned bitslice_size; uint8_t *decorrelate_buf[2]; Slice *slices; HuffEntry he[4][256]; @@ -201,11 +203,12 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); - s->nb_slices = (avctx->slices <= 0) ? av_cpu_count() : avctx->slices; + s->nb_slices = avctx->slices > 0 ? avctx->slices : avctx->thread_count; s->nb_slices = FFMIN(s->nb_slices, avctx->height >> s->vshift[1]); s->nb_slices = FFMAX(1, s->nb_slices); s->slice_height = FFALIGN((avctx->height + s->nb_slices - 1) / s->nb_slices, 1 << s->vshift[1]); s->nb_slices = (avctx->height + s->slice_height - 1) / s->slice_height; + s->nb_slices = FFMIN(256U / s->planes, s->nb_slices); s->slices = av_calloc(s->nb_slices * s->planes, sizeof(*s->slices)); if (!s->slices) return AVERROR(ENOMEM); @@ -220,18 +223,18 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) s->decorrelate_buf[1] = s->decorrelate_buf[0] + (s->nb_slices * s->slice_height) * aligned_width; } - s->bitslice_size = avctx->width * s->slice_height + 2; for (int n = 0; n < s->nb_slices; n++) { for (int i = 0; i < s->planes; i++) { Slice *sl = &s->slices[n * s->planes + i]; - sl->bitslice = av_malloc(s->bitslice_size + AV_INPUT_BUFFER_PADDING_SIZE); + sl->height = n == s->nb_slices - 1 ? avctx->height - n * s->slice_height : s->slice_height; + sl->height = AV_CEIL_RSHIFT(sl->height, s->vshift[i]); + sl->width = AV_CEIL_RSHIFT(avctx->width, s->hshift[i]); + sl->slice = av_malloc(avctx->width * (s->slice_height + 2) + AV_INPUT_BUFFER_PADDING_SIZE); - if (!sl->slice || !sl->bitslice) { - av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer.\n"); + if (!sl->slice) return AVERROR(ENOMEM); - } } } @@ -245,29 +248,26 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - - if (!avctx->extradata) { - av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata.\n"); + if (!avctx->extradata) return AVERROR(ENOMEM); - } bytestream2_init_writer(&pb, avctx->extradata, MAGICYUV_EXTRADATA_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, 12); - bytestream2_put_byte(&pb, 0); + bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32u(&pb, 32); + bytestream2_put_byteu(&pb, 7); + bytestream2_put_byteu(&pb, s->format); + bytestream2_put_byteu(&pb, 12); + bytestream2_put_byteu(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 32); - bytestream2_put_byte(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 32); + bytestream2_put_byteu(&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_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); return 0; } @@ -287,11 +287,11 @@ static void calculate_codes(HuffEntry *he, uint16_t codes_count[33]) } static void count_usage(const uint8_t *src, int width, - int height, PTable *counts) + int height, int64_t *counts) { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) - counts[src[i]].prob++; + counts[src[i]]++; src += width; } } @@ -377,53 +377,51 @@ static int count_plane_slice(AVCodecContext *avctx, int n, int plane) MagicYUVContext *s = avctx->priv_data; Slice *sl = &s->slices[n * s->planes + plane]; const uint8_t *dst = sl->slice; - PTable *counts = sl->counts; - const int slice_height = s->slice_height; - const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); - const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height; + int64_t *counts = sl->counts; memset(counts, 0, sizeof(sl->counts)); - count_usage(dst, AV_CEIL_RSHIFT(avctx->width, s->hshift[plane]), - AV_CEIL_RSHIFT(height, s->vshift[plane]), counts); + count_usage(dst, sl->width, sl->height, counts); return 0; } -static int encode_table(AVCodecContext *avctx, - PutBitContext *pb, HuffEntry *he, int plane) +static void generate_codes(AVCodecContext *avctx, + HuffEntry *he, int plane) { MagicYUVContext *s = avctx->priv_data; - PTable counts[256] = { {0} }; + PTable counts[256]; uint16_t codes_counts[33] = { 0 }; + for (size_t i = 0; i < FF_ARRAY_ELEMS(counts); i++) { + counts[i].prob = 1; + counts[i].value = i; + } + for (int n = 0; n < s->nb_slices; n++) { Slice *sl = &s->slices[n * s->planes + plane]; - PTable *slice_counts = sl->counts; + int64_t *slice_counts = sl->counts; for (int i = 0; i < 256; i++) - counts[i].prob = slice_counts[i].prob; - } - - for (int i = 0; i < 256; i++) { - counts[i].prob++; - counts[i].value = i; + counts[i].prob += slice_counts[i]; } magy_huffman_compute_bits(counts, he, codes_counts, 256, 12); calculate_codes(he, codes_counts); - - for (int i = 0; i < 256; i++) { - put_bits(pb, 1, 0); - put_bits(pb, 7, he[i].len); - } - - return 0; } -static int encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, unsigned dst_size, - int width, int height, int prediction) +static void output_codes(PutByteContext *pb, const HuffEntry he[256]) +{ + for (int i = 0; i < 256; i++) { + // The seven low bits are len; the top bit means the run of + // codes of this length has length one. + bytestream2_put_byteu(pb, he[i].len); + } +} + +static void encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, + int width, int height, int prediction) { unsigned count = width * height; @@ -431,20 +429,12 @@ static int encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, unsigned dst dst[1] = prediction; memcpy(dst + 2, src, count); - count += 2; - AV_WN32(dst + count, 0); - if (count & 3) - count += 4 - (count & 3); - - return count; } -static int encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size, - int width, int height, HuffEntry *he, int prediction) +static void encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size, + int width, int height, HuffEntry *he, int prediction) { - const uint8_t *osrc = src; PutBitContext pb; - int count; init_put_bits(&pb, dst, dst_size); @@ -455,41 +445,35 @@ static int encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_siz for (int i = 0; i < width; i++) { const int idx = src[i]; const int len = he[idx].len; - if (put_bits_left(&pb) < len + 32) - return encode_plane_slice_raw(osrc, dst, dst_size, width, height, prediction); put_bits(&pb, len, he[idx].code); } src += width; } - count = put_bits_count(&pb) & 0x1F; - - if (count) - put_bits(&pb, 32 - count, 0); - flush_put_bits(&pb); - - return put_bytes_output(&pb); + av_assert1(put_bytes_left(&pb, 0) <= 3); } static int encode_slice(AVCodecContext *avctx, void *tdata, int n, int threadnr) { MagicYUVContext *s = avctx->priv_data; - const int slice_height = s->slice_height; - const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); - const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height; for (int i = 0; i < s->planes; i++) { Slice *sl = &s->slices[n * s->planes + i]; - sl->size = + // Zero the padding now + AV_WN32(sl->dst + sl->size - 4, 0); + + if (sl->encode_raw) + encode_plane_slice_raw(sl->slice, sl->dst, + sl->width, sl->height, s->frame_pred); + else encode_plane_slice(sl->slice, - sl->bitslice, - s->bitslice_size, - AV_CEIL_RSHIFT(avctx->width, s->hshift[i]), - AV_CEIL_RSHIFT(height, s->vshift[i]), + sl->dst, + sl->size, + sl->width, sl->height, s->he[i], s->frame_pred); } @@ -545,8 +529,7 @@ static int predict_slice(AVCodecContext *avctx, void *tdata, s->predict(s, frame->data[i] + n * (slice_height >> s->vshift[i]) * frame->linesize[i], sl->slice, frame->linesize[i], - AV_CEIL_RSHIFT(frame->width, s->hshift[i]), - AV_CEIL_RSHIFT(height, s->vshift[i])); + sl->width, sl->height); } } @@ -560,86 +543,79 @@ static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) { MagicYUVContext *s = avctx->priv_data; - const int width = avctx->width, height = avctx->height; - const int slice_height = s->slice_height; - unsigned tables_size; - PutBitContext pbit; PutByteContext pb; - int pos, ret = 0; + int header_size = 32 + (4 + 1) * (s->planes * s->nb_slices + 1) + + 256 * s->planes /* Hufftables */; + int64_t pkt_size = header_size; + int ret; - ret = ff_alloc_packet(avctx, pkt, (256 + 4 * s->nb_slices + width * height) * - s->planes + 256); + avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices); + + for (int i = 0; i < s->planes; i++) + generate_codes(avctx, s->he[i], i); + + for (int i = 0; i < s->nb_slices; ++i) { + for (int j = 0; j < s->planes; ++j) { + Slice *const sl = &s->slices[i * s->planes + j]; + int64_t size = 0; + + for (size_t k = 0; k < FF_ARRAY_ELEMS(sl->counts); ++k) + size += sl->counts[k] * s->he[j][k].len; + size = AV_CEIL_RSHIFT(size, 3); + sl->encode_raw = size >= sl->width * sl->height; + if (sl->encode_raw) + size = sl->width * sl->height; + sl->size = FFALIGN(size + 2, 4); + sl->pos = pkt_size; + pkt_size += sl->size; + } + } + + ret = ff_get_encode_buffer(avctx, pkt, pkt_size, 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); // header size - bytestream2_put_byte(&pb, 7); // version - bytestream2_put_byte(&pb, s->format); - bytestream2_put_byte(&pb, 12); // max huffman length - bytestream2_put_byte(&pb, 0); + bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32u(&pb, 32); // header size + bytestream2_put_byteu(&pb, 7); // version + bytestream2_put_byteu(&pb, s->format); + bytestream2_put_byteu(&pb, 12); // max huffman length + bytestream2_put_byteu(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 0); - bytestream2_put_byte(&pb, 32); // coder type - bytestream2_put_byte(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 0); + bytestream2_put_byteu(&pb, 32); // coder type + bytestream2_put_byteu(&pb, 0); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, avctx->height); - bytestream2_put_le32(&pb, avctx->width); - bytestream2_put_le32(&pb, slice_height); - bytestream2_put_le32(&pb, 0); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, avctx->height); + bytestream2_put_le32u(&pb, avctx->width); + bytestream2_put_le32u(&pb, s->slice_height); - for (int i = 0; i < s->planes; i++) { - bytestream2_put_le32(&pb, 0); - for (int j = 1; j < s->nb_slices; j++) - bytestream2_put_le32(&pb, 0); + // Slice position is relative to the current position (i.e. 32) + bytestream2_put_le32u(&pb, header_size - 32); + + for (int i = 0; i < s->planes; ++i) { + for (int j = 0; j < s->nb_slices; ++j) { + Slice *const sl = &s->slices[j * s->planes + i]; + bytestream2_put_le32u(&pb, sl->pos - 32); + sl->dst = pkt->data + sl->pos; + } } - bytestream2_put_byte(&pb, s->planes); + bytestream2_put_byteu(&pb, s->planes); for (int i = 0; i < s->planes; i++) { for (int n = 0; n < s->nb_slices; n++) - bytestream2_put_byte(&pb, n * s->planes + i); + bytestream2_put_byteu(&pb, n * s->planes + i); } - avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices); - - init_put_bits(&pbit, pkt->data + bytestream2_tell_p(&pb), bytestream2_get_bytes_left_p(&pb)); - - for (int i = 0; i < s->planes; i++) - encode_table(avctx, &pbit, s->he[i], i); - - tables_size = put_bytes_count(&pbit, 1); - bytestream2_skip_p(&pb, tables_size); + for (int i = 0; i < s->planes; ++i) + output_codes(&pb, s->he[i]); avctx->execute2(avctx, encode_slice, NULL, NULL, s->nb_slices); - for (int n = 0; n < s->nb_slices; n++) { - for (int i = 0; i < s->planes; i++) { - Slice *sl = &s->slices[n * s->planes + i]; - - sl->pos = bytestream2_tell_p(&pb); - - bytestream2_put_buffer(&pb, sl->bitslice, sl->size); - } - } - - pos = bytestream2_tell_p(&pb); - bytestream2_seek_p(&pb, 32, SEEK_SET); - bytestream2_put_le32(&pb, s->slices[0].pos - 32); - for (int i = 0; i < s->planes; i++) { - for (int n = 0; n < s->nb_slices; n++) { - Slice *sl = &s->slices[n * s->planes + i]; - - bytestream2_put_le32(&pb, sl->pos - 32); - } - } - bytestream2_seek_p(&pb, pos, SEEK_SET); - - pkt->size = bytestream2_tell_p(&pb); - *got_packet = 1; return 0; @@ -649,13 +625,14 @@ static av_cold int magy_encode_close(AVCodecContext *avctx) { MagicYUVContext *s = avctx->priv_data; - for (int i = 0; i < s->planes * s->nb_slices && s->slices; i++) { - Slice *sl = &s->slices[i]; + if (s->slices) { + for (int i = 0; i < s->planes * s->nb_slices; i++) { + Slice *sl = &s->slices[i]; - av_freep(&sl->slice); - av_freep(&sl->bitslice); + av_freep(&sl->slice); + } + av_freep(&s->slices); } - av_freep(&s->slices); av_freep(&s->decorrelate_buf); return 0; @@ -691,11 +668,9 @@ const FFCodec ff_magicyuv_encoder = { .init = magy_encode_init, .close = magy_encode_close, FF_CODEC_ENCODE_CB(magy_encode_frame), - .p.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 - }, + CODEC_PIXFMTS(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), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mathops.h b/libavcodec/mathops.h index 84a924f31b..aa0bdfe956 100644 --- a/libavcodec/mathops.h +++ b/libavcodec/mathops.h @@ -32,8 +32,9 @@ extern const uint32_t ff_inverse[257]; extern const uint8_t ff_log2_run[41]; +EXTERN const uint32_t ff_square_tab[512]; extern const uint8_t ff_sqrt_tab[256]; -extern const uint8_t attribute_visibility_hidden ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +EXTERN const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; extern const uint8_t ff_zigzag_direct[64]; extern const uint8_t ff_zigzag_scan[16+1]; diff --git a/libavcodec/mathtables.c b/libavcodec/mathtables.c index 8b0031eb00..9a25da4964 100644 --- a/libavcodec/mathtables.c +++ b/libavcodec/mathtables.c @@ -20,8 +20,47 @@ #include +#include "config.h" #include "mathops.h" +#if CONFIG_ME_CMP || CONFIG_MPEGVIDEOENCDSP +/* (i - 256) * (i - 256) */ +const uint32_t ff_square_tab[512] = { + 65536, 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, + 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, + 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, + 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, + 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, + 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, + 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, + 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, + 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, + 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, + 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, + 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, + 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, + 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, + 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, + 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, + 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, + 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, + 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, + 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, + 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, + 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, + 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, + 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, + 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, + 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, + 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, + 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, + 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, + 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, + 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, + 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025, +}; +#endif + /* a*inverse[b]>>32 == a/b for all 0<=a<=16909558 && 2<=b<=256 * for a>16909558, is an overestimate by less than 1 part in 1<<24 */ const uint32_t ff_inverse[257]={ @@ -72,10 +111,10 @@ const uint8_t ff_sqrt_tab[256]={ }; #define times4(x) x, x, x, x -#define times256(x) times4(times4(times4(times4(times4(x))))) +#define times1024(x) times4(times4(times4(times4(times4(x))))) const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP] = { -times256(0x00), +times1024(0x00), 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, @@ -92,7 +131,7 @@ times256(0x00), 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, -times256(0xFF) +times1024(0xFF) }; const uint8_t ff_zigzag_direct[64] = { diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c index 5ab40719ac..c8865d7c63 100644 --- a/libavcodec/mdec.c +++ b/libavcodec/mdec.c @@ -56,7 +56,6 @@ typedef struct MDECContext { DECLARE_ALIGNED(16, uint16_t, quant_matrix)[64]; uint8_t *bitstream_buffer; unsigned int bitstream_buffer_size; - int block_last_index[6]; } MDECContext; //very similar to MPEG-1 @@ -101,9 +100,10 @@ static inline int mdec_decode_block_intra(MDECContext *a, int16_t *block, int n) LAST_SKIP_BITS(re, &a->gb, 1); } else { /* escape */ - run = SHOW_UBITS(re, &a->gb, 6)+1; LAST_SKIP_BITS(re, &a->gb, 6); - UPDATE_CACHE(re, &a->gb); - level = SHOW_SBITS(re, &a->gb, 10); SKIP_BITS(re, &a->gb, 10); + run = SHOW_UBITS(re, &a->gb, 6) + 1; + SKIP_BITS(re, &a->gb, 6); + level = SHOW_SBITS(re, &a->gb, 10); + LAST_SKIP_BITS(re, &a->gb, 10); i += run; if (i > 63) { av_log(a->avctx, AV_LOG_ERROR, @@ -126,7 +126,6 @@ static inline int mdec_decode_block_intra(MDECContext *a, int16_t *block, int n) } CLOSE_READER(re, &a->gb); } - a->block_last_index[n] = i; return 0; } diff --git a/libavcodec/me_cmp.c b/libavcodec/me_cmp.c index f3e2f2482e..8e53f6d573 100644 --- a/libavcodec/me_cmp.c +++ b/libavcodec/me_cmp.c @@ -27,49 +27,14 @@ #include "libavutil/mem_internal.h" #include "avcodec.h" #include "copy_block.h" +#include "mathops.h" #include "simple_idct.h" #include "me_cmp.h" #include "mpegvideoenc.h" #include "config.h" #include "config_components.h" -/* (i - 256) * (i - 256) */ -const uint32_t ff_square_tab[512] = { - 65536, 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, - 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, - 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, - 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, - 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, - 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, - 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, - 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, - 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, - 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, - 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, - 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, - 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, - 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, - 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, - 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, - 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, - 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, - 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, - 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, - 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, - 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, - 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, - 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, - 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, - 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, - 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, - 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, - 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, - 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, - 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, - 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025, -}; - -static int sse4_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse4_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -86,7 +51,7 @@ static int sse4_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, return s; } -static int sse8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -107,7 +72,7 @@ static int sse8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, return s; } -static int sse16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -149,7 +114,7 @@ static int sum_abs_dctelem_c(const int16_t *block) #define avg2(a, b) (((a) + (b) + 1) >> 1) #define avg4(a, b, c, d) (((a) + (b) + (c) + (d) + 2) >> 2) -static inline int pix_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_abs16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -177,7 +142,7 @@ static inline int pix_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint return s; } -static inline int pix_median_abs16_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_median_abs16_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i, j; @@ -216,7 +181,7 @@ static inline int pix_median_abs16_c(MpegEncContext *v, const uint8_t *pix1, con return s; } -static int pix_abs16_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_x2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -244,7 +209,7 @@ static int pix_abs16_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int pix_abs16_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_y2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -274,7 +239,7 @@ static int pix_abs16_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int pix_abs16_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs16_xy2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -304,7 +269,7 @@ static int pix_abs16_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static inline int pix_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_abs8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -324,7 +289,7 @@ static inline int pix_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8 return s; } -static inline int pix_median_abs8_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static inline int pix_median_abs8_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i, j; @@ -355,7 +320,7 @@ static inline int pix_median_abs8_c(MpegEncContext *v, const uint8_t *pix1, cons return s; } -static int pix_abs8_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_x2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -375,7 +340,7 @@ static int pix_abs8_x2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int pix_abs8_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_y2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -397,7 +362,7 @@ static int pix_abs8_y2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int pix_abs8_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int pix_abs8_xy2_c(MPVEncContext *unused, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int s = 0, i; @@ -419,7 +384,7 @@ static int pix_abs8_xy2_c(MpegEncContext *v, const uint8_t *pix1, const uint8_t return s; } -static int nsse16_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse16_c(MPVEncContext *const c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { int score1 = 0, score2 = 0, x, y; @@ -439,12 +404,12 @@ static int nsse16_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, } if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int nsse8_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse8_c(MPVEncContext *const c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { int score1 = 0, score2 = 0, x, y; @@ -464,12 +429,12 @@ static int nsse8_c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, } if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, +static int zero_cmp(MPVEncContext *s, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h) { return 0; @@ -546,7 +511,7 @@ av_cold int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, int type, int mp #define BUTTERFLYA(x, y) (FFABS((x) + (y)) + FFABS((x) - (y))) -static int hadamard8_diff8x8_c(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff8x8_c(MPVEncContext *unused, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int i, temp[64], sum = 0; @@ -596,7 +561,7 @@ static int hadamard8_diff8x8_c(MpegEncContext *s, const uint8_t *dst, return sum; } -static int hadamard8_intra8x8_c(MpegEncContext *s, const uint8_t *src, +static int hadamard8_intra8x8_c(MPVEncContext *unused, const uint8_t *src, const uint8_t *dummy, ptrdiff_t stride, int h) { int i, temp[64], sum = 0; @@ -646,7 +611,7 @@ static int hadamard8_intra8x8_c(MpegEncContext *s, const uint8_t *src, return sum; } -static int dct_sad8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct_sad8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64]); @@ -685,7 +650,7 @@ static int dct_sad8x8_c(MpegEncContext *s, const uint8_t *src1, DST(7, (a4 >> 2) - a7); \ } -static int dct264_sad8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct264_sad8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { int16_t dct[8][8]; @@ -710,7 +675,7 @@ static int dct264_sad8x8_c(MpegEncContext *s, const uint8_t *src1, } #endif -static int dct_max8x8_c(MpegEncContext *s, const uint8_t *src1, +static int dct_max8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64]); @@ -725,22 +690,22 @@ static int dct_max8x8_c(MpegEncContext *s, const uint8_t *src1, return sum; } -static int quant_psnr8x8_c(MpegEncContext *s, const uint8_t *src1, +static int quant_psnr8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { LOCAL_ALIGNED_16(int16_t, temp, [64 * 2]); int16_t *const bak = temp + 64; int sum = 0, i; - s->mb_intra = 0; + s->c.mb_intra = 0; s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); memcpy(bak, temp, 64 * sizeof(int16_t)); - s->block_last_index[0 /* FIXME */] = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); - s->dct_unquantize_inter(s, temp, 0, s->qscale); + s->c.block_last_index[0 /* FIXME */] = + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); + s->c.dct_unquantize_inter(&s->c, temp, 0, s->c.qscale); ff_simple_idct_int16_8bit(temp); // FIXME for (i = 0; i < 64; i++) @@ -749,29 +714,29 @@ static int quant_psnr8x8_c(MpegEncContext *s, const uint8_t *src1, return sum; } -static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, +static int rd8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { - const uint8_t *scantable = s->intra_scantable.permutated; + const uint8_t *scantable = s->c.intra_scantable.permutated; LOCAL_ALIGNED_16(int16_t, temp, [64]); LOCAL_ALIGNED_16(uint8_t, lsrc1, [64]); LOCAL_ALIGNED_16(uint8_t, lsrc2, [64]); int i, last, run, bits, level, distortion, start_i; const int esc_length = s->ac_esc_length; - uint8_t *length, *last_length; + const uint8_t *length, *last_length; copy_block8(lsrc1, src1, 8, stride, 8); copy_block8(lsrc2, src2, 8, stride, 8); s->pdsp.diff_pixels(temp, lsrc1, lsrc2, 8); - s->block_last_index[0 /* FIXME */] = + s->c.block_last_index[0 /* FIXME */] = last = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); bits = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { start_i = 1; length = s->intra_ac_vlc_length; last_length = s->intra_ac_vlc_last_length; @@ -811,37 +776,37 @@ static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, } if (last >= 0) { - if (s->mb_intra) - s->dct_unquantize_intra(s, temp, 0, s->qscale); + if (s->c.mb_intra) + s->c.dct_unquantize_intra(&s->c, temp, 0, s->c.qscale); else - s->dct_unquantize_inter(s, temp, 0, s->qscale); + s->c.dct_unquantize_inter(&s->c, temp, 0, s->c.qscale); } - s->idsp.idct_add(lsrc2, 8, temp); + s->c.idsp.idct_add(lsrc2, 8, temp); distortion = s->sse_cmp[1](NULL, lsrc2, lsrc1, 8, 8); - return distortion + ((bits * s->qscale * s->qscale * 109 + 64) >> 7); + return distortion + ((bits * s->c.qscale * s->c.qscale * 109 + 64) >> 7); } -static int bit8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, +static int bit8x8_c(MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { - const uint8_t *scantable = s->intra_scantable.permutated; + const uint8_t *scantable = s->c.intra_scantable.permutated; LOCAL_ALIGNED_16(int16_t, temp, [64]); int i, last, run, bits, level, start_i; const int esc_length = s->ac_esc_length; - uint8_t *length, *last_length; + const uint8_t *length, *last_length; s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); - s->block_last_index[0 /* FIXME */] = + s->c.block_last_index[0 /* FIXME */] = last = - s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->c.qscale, &i); bits = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { start_i = 1; length = s->intra_ac_vlc_length; last_length = s->intra_ac_vlc_last_length; @@ -884,7 +849,7 @@ static int bit8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, } #define VSAD_INTRA(size) \ -static int vsad_intra ## size ## _c(MpegEncContext *c, \ +static int vsad_intra ## size ## _c(MPVEncContext *unused, \ const uint8_t *s, const uint8_t *dummy, \ ptrdiff_t stride, int h) \ { \ @@ -906,7 +871,7 @@ VSAD_INTRA(8) VSAD_INTRA(16) #define VSAD(size) \ -static int vsad ## size ## _c(MpegEncContext *c, \ +static int vsad ## size ## _c(MPVEncContext *unused, \ const uint8_t *s1, const uint8_t *s2, \ ptrdiff_t stride, int h) \ { \ @@ -926,7 +891,7 @@ VSAD(16) #define SQ(a) ((a) * (a)) #define VSSE_INTRA(size) \ -static int vsse_intra ## size ## _c(MpegEncContext *c, \ +static int vsse_intra ## size ## _c(MPVEncContext *unused, \ const uint8_t *s, const uint8_t *dummy, \ ptrdiff_t stride, int h) \ { \ @@ -948,8 +913,8 @@ VSSE_INTRA(8) VSSE_INTRA(16) #define VSSE(size) \ -static int vsse ## size ## _c(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, \ - ptrdiff_t stride, int h) \ +static int vsse ## size ## _c(MPVEncContext *unused, const uint8_t *s1, \ + const uint8_t *s2, ptrdiff_t stride, int h) \ { \ int score = 0, x, y; \ \ @@ -966,8 +931,8 @@ VSSE(8) VSSE(16) #define WRAPPER8_16_SQ(name8, name16) \ -static int name16(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, \ - ptrdiff_t stride, int h) \ +static int name16(MPVEncContext *const s, const uint8_t *dst, \ + const uint8_t *src, ptrdiff_t stride, int h) \ { \ int score = 0; \ \ diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h index 9053327c4c..49f81e1901 100644 --- a/libavcodec/me_cmp.h +++ b/libavcodec/me_cmp.h @@ -21,13 +21,8 @@ #include -#include "libavutil/attributes_internal.h" - #include "avcodec.h" -extern const uint32_t attribute_visibility_hidden ff_square_tab[512]; - - /* minimum alignment rules ;) * If you notice errors in the align stuff, need more alignment for some ASM code * for some CPU or need to use a function with less aligned data then send a mail @@ -41,13 +36,13 @@ extern const uint32_t attribute_visibility_hidden ff_square_tab[512]; * !future video codecs might need functions with less strict alignment */ -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; /* Motion estimation: * h is limited to { width / 2, width, 2 * width }, * but never larger than 16 and never smaller than 2. * Although currently h < 4 is not used as functions with * width < 8 are neither used nor implemented. */ -typedef int (*me_cmp_func)(struct MpegEncContext *c, +typedef int (*me_cmp_func)(MPVEncContext *c, const uint8_t *blk1 /* align width (8 or 16) */, const uint8_t *blk2 /* align 1 */, ptrdiff_t stride, int h); @@ -76,7 +71,6 @@ typedef struct MECmpContext { void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx); -void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_riscv(MECmpContext *c, AVCodecContext *avctx); @@ -87,7 +81,7 @@ void ff_me_cmp_init_mips(MECmpContext *c, AVCodecContext *avctx); * Fill the function pointer array cmp[6] with me_cmp_funcs from * c based upon type. If mpvenc is not set, an error is returned * if the type of comparison functions requires an initialized - * MpegEncContext. + * MPVEncContext. */ int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, int type, int mpvenc); diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index 96c886666a..283bbe72d6 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -1762,6 +1762,14 @@ static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } +static int mediacodec_jni_setAsyncNotifyCallback(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + av_log(codec, AV_LOG_ERROR, "Doesn't support aync mode with JNI, please try ndk_codec=1\n"); + return AVERROR(ENOSYS); +} + static const FFAMediaFormat media_format_jni = { .class = &amediaformat_class, @@ -1821,6 +1829,7 @@ static const FFAMediaCodec media_codec_jni = { .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream, + .setAsyncNotifyCallback = mediacodec_jni_setAsyncNotifyCallback, }; typedef struct FFAMediaFormatNdk { @@ -1842,6 +1851,9 @@ typedef struct FFAMediaCodecNdk { AMediaCodec *impl; ANativeWindow *window; + FFAMediaCodecOnAsyncNotifyCallback async_cb; + void *async_userdata; + // Available since API level 28. media_status_t (*getName)(AMediaCodec*, char** out_name); void (*releaseName)(AMediaCodec*, char* name); @@ -1849,6 +1861,8 @@ typedef struct FFAMediaCodecNdk { // Available since API level 26. media_status_t (*setInputSurface)(AMediaCodec*, ANativeWindow *); media_status_t (*signalEndOfInputStream)(AMediaCodec *); + media_status_t (*setAsyncNotifyCallback)(AMediaCodec *, + struct AMediaCodecOnAsyncNotifyCallback callback, void *userdata); } FFAMediaCodecNdk; static const FFAMediaFormat media_format_ndk; @@ -1866,6 +1880,32 @@ static const AVClass amediacodec_ndk_class = { .version = LIBAVUTIL_VERSION_INT, }; +static int media_status_to_error(media_status_t status) +{ + switch (status) { + case AMEDIA_OK: + return 0; + case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: + return AVERROR(ENOMEM); + case AMEDIA_ERROR_MALFORMED: + return AVERROR_INVALIDDATA; + case AMEDIA_ERROR_UNSUPPORTED: + return AVERROR(ENOTSUP); + case AMEDIA_ERROR_INVALID_PARAMETER: + return AVERROR(EINVAL); + case AMEDIA_ERROR_INVALID_OPERATION: + return AVERROR(EOPNOTSUPP); + case AMEDIA_ERROR_END_OF_STREAM: + return AVERROR_EOF; + case AMEDIA_ERROR_IO: + return AVERROR(EIO); + case AMEDIA_ERROR_WOULD_BLOCK: + return AVERROR(EWOULDBLOCK); + default: + return AVERROR_EXTERNAL; + } +} + static FFAMediaFormat *mediaformat_ndk_create(AMediaFormat *impl) { FFAMediaFormatNdk *format = av_mallocz(sizeof(*format)); @@ -2060,6 +2100,7 @@ static inline FFAMediaCodec *ndk_codec_create(int method, const char *arg) { GET_SYMBOL(setInputSurface) GET_SYMBOL(signalEndOfInputStream) + GET_SYMBOL(setAsyncNotifyCallback) #undef GET_SYMBOL @@ -2335,6 +2376,94 @@ static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } +static void mediacodec_ndk_onInputAvailable(AMediaCodec *impl, void *userdata, + int32_t index) +{ + FFAMediaCodecNdk *codec = userdata; + codec->async_cb.onAsyncInputAvailable((FFAMediaCodec *) codec, + codec->async_userdata, index); +} + +static void mediacodec_ndk_onOutputAvailable(AMediaCodec *impl, + void *userdata, + int32_t index, + AMediaCodecBufferInfo *buffer_info) +{ + FFAMediaCodecNdk *codec = userdata; + FFAMediaCodecBufferInfo info = { + .offset = buffer_info->offset, + .size = buffer_info->size, + .presentationTimeUs = buffer_info->presentationTimeUs, + .flags = buffer_info->flags, + }; + + codec->async_cb.onAsyncOutputAvailable(&codec->api, codec->async_userdata, + index, &info); +} + +static void mediacodec_ndk_onFormatChanged(AMediaCodec *impl, void *userdata, + AMediaFormat *format) +{ + FFAMediaCodecNdk *codec = userdata; + FFAMediaFormat *media_format = mediaformat_ndk_create(format); + if (!media_format) + return; + + codec->async_cb.onAsyncFormatChanged(&codec->api, codec->async_userdata, + media_format); + ff_AMediaFormat_delete(media_format); +} + +static void mediacodec_ndk_onError(AMediaCodec *impl, void *userdata, + media_status_t status, + int32_t actionCode, + const char *detail) +{ + FFAMediaCodecNdk *codec = userdata; + int error = media_status_to_error(status); + + codec->async_cb.onAsyncError(&codec->api, codec->async_userdata, error, + detail); +} + +static int mediacodec_ndk_setAsyncNotifyCallback(FFAMediaCodec *ctx, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; + struct AMediaCodecOnAsyncNotifyCallback cb = { + .onAsyncInputAvailable = mediacodec_ndk_onInputAvailable, + .onAsyncOutputAvailable = mediacodec_ndk_onOutputAvailable, + .onAsyncFormatChanged = mediacodec_ndk_onFormatChanged, + .onAsyncError = mediacodec_ndk_onError, + }; + media_status_t status; + + if (!codec->setAsyncNotifyCallback) { + av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback unavailable\n"); + return AVERROR(ENOSYS); + } + + if (!callback || + !callback->onAsyncInputAvailable || + !callback->onAsyncOutputAvailable || + !callback->onAsyncFormatChanged || + !callback->onAsyncError) + return AVERROR(EINVAL); + + codec->async_cb = *callback; + codec->async_userdata = userdata; + + status = codec->setAsyncNotifyCallback(codec->impl, cb, codec); + if (status != AMEDIA_OK) { + av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback failed, %d\n", + status); + return AVERROR_EXTERNAL; + } + + return 0; +} + static const FFAMediaFormat media_format_ndk = { .class = &amediaformat_ndk_class, @@ -2396,6 +2525,7 @@ static const FFAMediaCodec media_codec_ndk = { .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream, + .setAsyncNotifyCallback = mediacodec_ndk_setAsyncNotifyCallback, }; FFAMediaFormat *ff_AMediaFormat_new(int ndk) diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h index 11a4260497..18d0796445 100644 --- a/libavcodec/mediacodec_wrapper.h +++ b/libavcodec/mediacodec_wrapper.h @@ -178,6 +178,22 @@ struct FFAMediaCodecBufferInfo { typedef struct FFAMediaCodecBufferInfo FFAMediaCodecBufferInfo; typedef struct FFAMediaCodec FFAMediaCodec; + +typedef struct FFAMediaCodecOnAsyncNotifyCallback { + void (*onAsyncInputAvailable)(FFAMediaCodec *codec, void *userdata, + int32_t index); + + void (*onAsyncOutputAvailable)(FFAMediaCodec *codec, void *userdata, + int32_t index, + FFAMediaCodecBufferInfo *buffer_info); + + void (*onAsyncFormatChanged)(FFAMediaCodec *codec, void *userdata, + FFAMediaFormat *format); + + void (*onAsyncError)(FFAMediaCodec *codec, void *userdata, int error, + const char *detail); +} FFAMediaCodecOnAsyncNotifyCallback; + struct FFAMediaCodec { const AVClass *class; @@ -219,6 +235,11 @@ struct FFAMediaCodec { // For encoder with FFANativeWindow as input. int (*signalEndOfInputStream)(FFAMediaCodec *); + + // Introduced in Android API 28 + int (*setAsyncNotifyCallback)(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata); }; static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec) @@ -343,6 +364,13 @@ static inline int ff_AMediaCodec_signalEndOfInputStream(FFAMediaCodec *codec) return codec->signalEndOfInputStream(codec); } +static inline int ff_AMediaCodec_setAsyncNotifyCallback(FFAMediaCodec *codec, + const FFAMediaCodecOnAsyncNotifyCallback *callback, + void *userdata) +{ + return codec->setAsyncNotifyCallback(codec, callback, userdata); +} + int ff_Build_SDK_INT(AVCodecContext *avctx); enum FFAMediaFormatColorRange { diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index cc55b306bd..ea9362ba85 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -57,6 +57,8 @@ typedef struct MediaCodecH264DecContext { int amlogic_mpeg2_api23_workaround; int use_ndk_codec; + // Ref. MediaFormat KEY_OPERATING_RATE + int operating_rate; } MediaCodecH264DecContext; static av_cold int mediacodec_decode_close(AVCodecContext *avctx) @@ -131,14 +133,12 @@ static int h264_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int i; int ret; - H264ParamSets ps; + H264ParamSets ps = {0}; const PPS *pps = NULL; const SPS *sps = NULL; int is_avc = 0; int nal_length_size = 0; - memset(&ps, 0, sizeof(ps)); - ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, &ps, &is_avc, &nal_length_size, 0, avctx); if (ret < 0) { @@ -197,8 +197,8 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int i; int ret; - HEVCParamSets ps; - HEVCSEI sei; + HEVCParamSets ps = {0}; + HEVCSEI sei = {0}; const HEVCVPS *vps = NULL; const HEVCPPS *pps = NULL; @@ -213,9 +213,6 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int sps_data_size = 0; int pps_data_size = 0; - memset(&ps, 0, sizeof(ps)); - memset(&sei, 0, sizeof(sei)); - ret = ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, &ps, &sei, &is_nalff, &nal_length_size, 0, 1, avctx); if (ret < 0) { @@ -441,6 +438,8 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) ff_AMediaFormat_setInt32(format, "channel-count", avctx->ch_layout.nb_channels); ff_AMediaFormat_setInt32(format, "sample-rate", avctx->sample_rate); } + if (s->operating_rate > 0) + ff_AMediaFormat_setInt32(format, "operating-rate", s->operating_rate); s->ctx = av_mallocz(sizeof(*s->ctx)); if (!s->ctx) { @@ -599,6 +598,8 @@ static const AVOption ff_mediacodec_vdec_options[] = { OFFSET(delay_flush), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD }, { "ndk_codec", "Use MediaCodec from NDK", OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VD }, + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VD }, { NULL } }; @@ -662,6 +663,8 @@ DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL) static const AVOption ff_mediacodec_adec_options[] = { { "ndk_codec", "Use MediaCodec from NDK", OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AD }, + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AD }, { NULL } }; diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index b1ee8b609a..ae336ab835 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -416,6 +416,7 @@ static int mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx, frame->pts = info->presentationTimeUs; } frame->pkt_dts = AV_NOPTS_VALUE; + frame->flags |= AV_FRAME_FLAG_KEY; av_log(avctx, AV_LOG_TRACE, "Frame: format=%d channels=%d sample_rate=%d nb_samples=%d", @@ -536,6 +537,8 @@ static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", key, format); \ ret = AVERROR_EXTERNAL; \ goto fail; \ + } else { \ + (name) = 0; \ } \ } while (0) \ @@ -593,7 +596,8 @@ static int mediacodec_dec_parse_video_format(AVCodecContext *avctx, MediaCodecDe AMEDIAFORMAT_GET_INT32(s->crop_right, "crop-right", 0); // Try "crop" for NDK - if (!(s->crop_right && s->crop_bottom) && s->use_ndk_codec) + // MediaTek SOC return some default value like Rect(0, 0, 318, 238) + if (!(s->crop_right && s->crop_bottom) && s->use_ndk_codec && !strstr(s->codec_name, ".mtk.")) ff_AMediaFormat_getRect(s->format, "crop", &s->crop_left, &s->crop_top, &s->crop_right, &s->crop_bottom); if (s->crop_right && s->crop_bottom) { diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c index 6ca3968a24..507c48df9c 100644 --- a/libavcodec/mediacodecenc.c +++ b/libavcodec/mediacodecenc.c @@ -23,11 +23,13 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/fifo.h" #include "libavutil/avstring.h" #include "libavutil/hwcontext_mediacodec.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "bsf.h" @@ -54,6 +56,11 @@ enum BitrateMode { BITRATE_MODE_CBR_FD = 3, }; +typedef struct MediaCodecAsyncOutput { + int32_t index; + FFAMediaCodecBufferInfo buf_info; +} MediaCodecAsyncOutput; + typedef struct MediaCodecEncContext { AVClass *avclass; FFAMediaCodec *codec; @@ -76,6 +83,25 @@ typedef struct MediaCodecEncContext { int level; int pts_as_dts; int extract_extradata; + // Ref. MediaFormat KEY_OPERATING_RATE + int operating_rate; + int async_mode; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_index; + + AVMutex output_mutex; + AVCond output_cond; + int encode_status; + AVFifo *async_output; + + int qp_i_min; + int qp_p_min; + int qp_b_min; + int qp_i_max; + int qp_p_max; + int qp_b_max; } MediaCodecEncContext; enum { @@ -100,17 +126,26 @@ static const enum AVPixelFormat avc_pix_fmts[] = { AV_PIX_FMT_NONE }; -static void mediacodec_output_format(AVCodecContext *avctx) +static void mediacodec_dump_format(AVCodecContext *avctx, + FFAMediaFormat *out_format) { MediaCodecEncContext *s = avctx->priv_data; - char *name = ff_AMediaCodec_getName(s->codec); - FFAMediaFormat *out_format = ff_AMediaCodec_getOutputFormat(s->codec); + const char *name = s->name; char *str = ff_AMediaFormat_toString(out_format); av_log(avctx, AV_LOG_DEBUG, "MediaCodec encoder %s output format %s\n", name ? name : "unknown", str); - av_free(name); av_free(str); +} + +static void mediacodec_output_format(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + FFAMediaFormat *out_format = ff_AMediaCodec_getOutputFormat(s->codec); + + if (!s->name) + s->name = ff_AMediaCodec_getName(s->codec); + mediacodec_dump_format(avctx, out_format); ff_AMediaFormat_delete(out_format); } @@ -134,7 +169,7 @@ static int extract_extradata_support(AVCodecContext *avctx) static int mediacodec_init_bsf(AVCodecContext *avctx) { MediaCodecEncContext *s = avctx->priv_data; - char str[128]; + char str[128] = {0}; int ret; int crop_right = s->width - avctx->width; int crop_bottom = s->height - avctx->height; @@ -183,8 +218,179 @@ static int mediacodec_init_bsf(AVCodecContext *avctx) return ret; } +static void copy_frame_to_buffer(AVCodecContext *avctx, const AVFrame *frame, + uint8_t *dst, size_t size) +{ + MediaCodecEncContext *s = avctx->priv_data; + uint8_t *dst_data[4] = {}; + int dst_linesize[4] = {}; + + if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { + dst_data[0] = dst; + dst_data[1] = dst + s->width * s->height; + dst_data[2] = dst_data[1] + s->width * s->height / 4; + + dst_linesize[0] = s->width; + dst_linesize[1] = dst_linesize[2] = s->width / 2; + } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) { + dst_data[0] = dst; + dst_data[1] = dst + s->width * s->height; + + dst_linesize[0] = s->width; + dst_linesize[1] = s->width; + } else { + av_assert0(0); + } + + av_image_copy2(dst_data, dst_linesize, frame->data, frame->linesize, + avctx->pix_fmt, avctx->width, avctx->height); +} + + +static void on_error(FFAMediaCodec *codec, void *userdata, int error, + const char *detail) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + + if (error == AVERROR(EAGAIN)) + return; + + av_log(avctx, AV_LOG_ERROR, "On error, %s, %s\n", av_err2str(error), detail); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->encode_status = error; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void on_input_available(FFAMediaCodec *codec, void *userdata, + int32_t index) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + int ret; + + ff_mutex_lock(&s->input_mutex); + ret = av_fifo_write(s->input_index, &index, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + on_error(codec, userdata, ret, "av_fifo_write failed"); +} + +static void on_output_available(FFAMediaCodec *codec, void *userdata, + int32_t index, + FFAMediaCodecBufferInfo *out_info) +{ + AVCodecContext *avctx = userdata; + MediaCodecEncContext *s = avctx->priv_data; + MediaCodecAsyncOutput output = { + .index = index, + .buf_info = *out_info, + }; + int ret; + + ff_mutex_lock(&s->output_mutex); + ret = av_fifo_write(s->async_output, &output, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + on_error(codec, userdata, ret, "av_fifo_write failed"); +} + +static void on_format_changed(FFAMediaCodec *codec, void *userdata, + FFAMediaFormat *format) +{ + mediacodec_dump_format(userdata, format); +} + +static int mediacodec_init_async_state(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + size_t fifo_size = 16; + + if (!s->async_mode) + return 0; + + ff_mutex_init(&s->input_mutex, NULL); + ff_cond_init(&s->input_cond, NULL); + + ff_mutex_init(&s->output_mutex, NULL); + ff_cond_init(&s->output_cond, NULL); + + s->input_index = av_fifo_alloc2(fifo_size, sizeof(int32_t), AV_FIFO_FLAG_AUTO_GROW); + s->async_output = av_fifo_alloc2(fifo_size, sizeof(MediaCodecAsyncOutput), + AV_FIFO_FLAG_AUTO_GROW); + + if (!s->input_index || !s->async_output) + return AVERROR(ENOMEM); + + return 0; +} + +static void mediacodec_uninit_async_state(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + + if (!s->async_mode) + return; + + ff_mutex_destroy(&s->input_mutex); + ff_cond_destroy(&s->input_cond); + + ff_mutex_destroy(&s->output_mutex); + ff_cond_destroy(&s->output_cond); + + av_fifo_freep2(&s->input_index); + av_fifo_freep2(&s->async_output); + + s->async_mode = 0; +} + static int mediacodec_generate_extradata(AVCodecContext *avctx); +static void mediacodec_set_qp_range(AVCodecContext *avctx, + FFAMediaFormat *format) +{ + MediaCodecEncContext *s = avctx->priv_data; + + // Handle common options in AVCodecContext first. + if (avctx->qmin >= 0) { + ff_AMediaFormat_setInt32(format, "video-qp-i-min", avctx->qmin); + ff_AMediaFormat_setInt32(format, "video-qp-p-min", avctx->qmin); + ff_AMediaFormat_setInt32(format, "video-qp-b-min", avctx->qmin); + } + + if (avctx->qmax >= 0) { + ff_AMediaFormat_setInt32(format, "video-qp-i-max", avctx->qmax); + ff_AMediaFormat_setInt32(format, "video-qp-p-max", avctx->qmax); + ff_AMediaFormat_setInt32(format, "video-qp-b-max", avctx->qmax); + } + + if (s->qp_i_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-i-min", s->qp_i_min); + if (s->qp_p_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-p-min", s->qp_p_min); + if (s->qp_b_min >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-b-min", s->qp_b_min); + + if (s->qp_i_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-i-max", s->qp_i_max); + if (s->qp_p_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-p-max", s->qp_p_max); + if (s->qp_b_max >= 0) + ff_AMediaFormat_setInt32(format, "video-qp-b-max", s->qp_b_max); +} + static av_cold int mediacodec_init(AVCodecContext *avctx) { const char *codec_mime = NULL; @@ -193,6 +399,11 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) int ret; int gop; + // Init async state first, so we can do cleanup safely on error path. + ret = mediacodec_init_async_state(avctx); + if (ret < 0) + return ret; + if (s->use_ndk_codec < 0) s->use_ndk_codec = !av_jni_get_java_vm(avctx); @@ -313,6 +524,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) if (s->bitrate_mode == BITRATE_MODE_CQ && avctx->global_quality > 0) ff_AMediaFormat_setInt32(format, "quality", avctx->global_quality); } + mediacodec_set_qp_range(avctx, format); + // frame-rate and i-frame-interval are required to configure codec if (avctx->framerate.num >= avctx->framerate.den && avctx->framerate.den > 0) { s->fps = avctx->framerate.num / avctx->framerate.den; @@ -354,6 +567,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) } if (s->pts_as_dts == -1) s->pts_as_dts = avctx->max_b_frames <= 0; + if (s->operating_rate > 0) + ff_AMediaFormat_setInt32(format, "operating-rate", s->operating_rate); ret = ff_AMediaCodec_getConfigureFlagEncode(s->codec); ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL, ret); @@ -365,10 +580,21 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) goto bailout; } - ret = ff_AMediaCodec_start(s->codec); - if (ret) { - av_log(avctx, AV_LOG_ERROR, "MediaCodec failed to start, %s\n", av_err2str(ret)); - goto bailout; + if (s->async_mode) { + FFAMediaCodecOnAsyncNotifyCallback cb = { + .onAsyncInputAvailable = on_input_available, + .onAsyncOutputAvailable = on_output_available, + .onAsyncFormatChanged = on_format_changed, + .onAsyncError = on_error, + }; + + ret = ff_AMediaCodec_setAsyncNotifyCallback(s->codec, &cb, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, + "Try MediaCodec async mode failed, %s, switch to sync mode\n", + av_err2str(ret)); + mediacodec_uninit_async_state(avctx); + } } ret = mediacodec_init_bsf(avctx); @@ -383,6 +609,13 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) goto bailout; } + ret = ff_AMediaCodec_start(s->codec); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "MediaCodec failed to start, %s\n", + av_err2str(ret)); + goto bailout; + } + ret = mediacodec_generate_extradata(avctx); bailout: @@ -391,17 +624,60 @@ bailout: return ret; } +static int mediacodec_get_output_index(AVCodecContext *avctx, ssize_t *index, + FFAMediaCodecBufferInfo *out_info) +{ + MediaCodecEncContext *s = avctx->priv_data; + FFAMediaCodec *codec = s->codec; + int64_t timeout_us = s->eof_sent ? OUTPUT_DEQUEUE_TIMEOUT_US : 0; + MediaCodecAsyncOutput output = { .index = -1 }; + int ret; + + if (!s->async_mode) { + *index = ff_AMediaCodec_dequeueOutputBuffer(codec, out_info, timeout_us); + return 0; + } + + ff_mutex_lock(&s->output_mutex); + + while (!s->encode_status) { + if (av_fifo_read(s->async_output, &output, 1) >= 0) + break; + + // Only wait after signalEndOfInputStream + if (s->eof_sent && !s->encode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->encode_status; + ff_mutex_unlock(&s->output_mutex); + + // Get output index success + if (output.index >= 0) { + *index = output.index; + *out_info = output.buf_info; + return 0; + } + + return ret ? ret : AVERROR(EAGAIN); +} + static int mediacodec_receive(AVCodecContext *avctx, AVPacket *pkt) { MediaCodecEncContext *s = avctx->priv_data; FFAMediaCodec *codec = s->codec; + ssize_t index; FFAMediaCodecBufferInfo out_info = {0}; uint8_t *out_buf; size_t out_size = 0; int ret; int extradata_size = 0; - int64_t timeout_us = s->eof_sent ? OUTPUT_DEQUEUE_TIMEOUT_US : 0; - ssize_t index = ff_AMediaCodec_dequeueOutputBuffer(codec, &out_info, timeout_us); + + ret = mediacodec_get_output_index(avctx, &index, &out_info); + if (ret < 0) + return ret; if (ff_AMediaCodec_infoTryAgainLater(codec, index)) return AVERROR(EAGAIN); @@ -429,6 +705,16 @@ static int mediacodec_receive(AVCodecContext *avctx, AVPacket *pkt) } if (out_info.flags & ff_AMediaCodec_getBufferFlagCodecConfig(codec)) { + if (avctx->codec_id == AV_CODEC_ID_AV1) { + // Skip AV1CodecConfigurationRecord without configOBUs + if (out_info.size <= 4) { + ff_AMediaCodec_releaseOutputBuffer(codec, index, false); + return mediacodec_receive(avctx, pkt); + } + out_info.size -= 4; + out_info.offset += 4; + } + ret = av_reallocp(&s->extradata, out_info.size); if (ret) goto bailout; @@ -466,33 +752,39 @@ bailout: return ret; } -static void copy_frame_to_buffer(AVCodecContext *avctx, const AVFrame *frame, uint8_t *dst, size_t size) +static int mediacodec_get_input_index(AVCodecContext *avctx, ssize_t *index) { MediaCodecEncContext *s = avctx->priv_data; - uint8_t *dst_data[4] = {}; - int dst_linesize[4] = {}; + FFAMediaCodec *codec = s->codec; + int ret = 0; + int32_t n; - if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - dst_data[0] = dst; - dst_data[1] = dst + s->width * s->height; - dst_data[2] = dst_data[1] + s->width * s->height / 4; - - dst_linesize[0] = s->width; - dst_linesize[1] = dst_linesize[2] = s->width / 2; - } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) { - dst_data[0] = dst; - dst_data[1] = dst + s->width * s->height; - - dst_linesize[0] = s->width; - dst_linesize[1] = s->width; - } else { - av_assert0(0); + if (!s->async_mode) { + *index = ff_AMediaCodec_dequeueInputBuffer(codec, INPUT_DEQUEUE_TIMEOUT_US); + return 0; } - av_image_copy2(dst_data, dst_linesize, frame->data, frame->linesize, - avctx->pix_fmt, avctx->width, avctx->height); + ff_mutex_lock(&s->input_mutex); + + n = -1; + while (n < 0 && !s->encode_status) { + if (av_fifo_can_read(s->input_index) > 0) { + av_fifo_read(s->input_index, &n, 1); + break; + } + + if (n < 0 && !s->encode_status) + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->encode_status; + *index = n; + ff_mutex_unlock(&s->input_mutex); + + return ret; } + static int mediacodec_send(AVCodecContext *avctx, const AVFrame *frame) { MediaCodecEncContext *s = avctx->priv_data; @@ -502,7 +794,7 @@ static int mediacodec_send(AVCodecContext *avctx, size_t input_size = 0; int64_t pts = 0; uint32_t flags = 0; - int64_t timeout_us; + int ret; if (s->eof_sent) return 0; @@ -518,8 +810,10 @@ static int mediacodec_send(AVCodecContext *avctx, return 0; } - timeout_us = INPUT_DEQUEUE_TIMEOUT_US; - index = ff_AMediaCodec_dequeueInputBuffer(codec, timeout_us); + ret = mediacodec_get_input_index(avctx, &index); + if (ret < 0) + return ret; + if (ff_AMediaCodec_infoTryAgainLater(codec, index)) return AVERROR(EAGAIN); @@ -652,7 +946,8 @@ static int mediacodec_generate_extradata(AVCodecContext *avctx) if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) return 0; - if (!s->extract_extradata) { + // Send dummy frame and receive a packet doesn't work in async mode + if (s->async_mode || !s->extract_extradata) { av_log(avctx, AV_LOG_WARNING, "Mediacodec encoder doesn't support AV_CODEC_FLAG_GLOBAL_HEADER. " "Use extract_extradata bsf when necessary.\n"); @@ -709,6 +1004,8 @@ static av_cold int mediacodec_close(AVCodecContext *avctx) av_bsf_free(&s->bsf); av_frame_free(&s->frame); + mediacodec_uninit_async_state(avctx); + return 0; } @@ -734,11 +1031,19 @@ static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = { NULL }; +static const FFCodecDefault mediacodec_defaults[] = { + {"qmin", "-1"}, + {"qmax", "-1"}, + {NULL}, +}; + #define OFFSET(x) offsetof(MediaCodecEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM #define COMMON_OPTION \ { "ndk_codec", "Use MediaCodec from NDK", \ OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, \ + { "ndk_async", "Try NDK MediaCodec in async mode", \ + OFFSET(async_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE }, \ { "codec_name", "Select codec by name", \ OFFSET(name), AV_OPT_TYPE_STRING, {0}, 0, 0, VE }, \ { "bitrate_mode", "Bitrate control method", \ @@ -754,6 +1059,20 @@ static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = { { "pts_as_dts", "Use PTS as DTS. It is enabled automatically if avctx max_b_frames <= 0, " \ "since most of Android devices don't output B frames by default.", \ OFFSET(pts_as_dts), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, \ + { "operating_rate", "The desired operating rate that the codec will need to operate at, zero for unspecified", \ + OFFSET(operating_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE }, \ + { "qp_i_min", "minimum quantization parameter for I frame", \ + OFFSET(qp_i_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_p_min", "minimum quantization parameter for P frame", \ + OFFSET(qp_p_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_b_min", "minimum quantization parameter for B frame", \ + OFFSET(qp_b_min), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_i_max", "maximum quantization parameter for I frame", \ + OFFSET(qp_i_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_p_max", "maximum quantization parameter for P frame", \ + OFFSET(qp_p_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ + { "qp_b_max", "maximum quantization parameter for B frame", \ + OFFSET(qp_b_max), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE }, \ #define MEDIACODEC_ENCODER_CLASS(name) \ @@ -775,8 +1094,9 @@ const FFCodec ff_ ## short_name ## _mediacodec_encoder = { \ AV_CODEC_CAP_HARDWARE | \ AV_CODEC_CAP_ENCODER_FLUSH, \ .priv_data_size = sizeof(MediaCodecEncContext), \ - .p.pix_fmts = avc_pix_fmts, \ + CODEC_PIXFMTS_ARRAY(avc_pix_fmts), \ .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ + .defaults = mediacodec_defaults, \ .init = mediacodec_init, \ FF_CODEC_RECEIVE_PACKET_CB(mediacodec_encode), \ .close = mediacodec_close, \ @@ -1032,7 +1352,7 @@ static const AVOption vp9_options[] = { 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level52 }, 0, 0, VE, .unit = "level" }, { "6", "Level 6", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level6 }, 0, 0, VE, .unit = "level" }, - { "6.1", "Level 4.1", + { "6.1", "Level 6.1", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level61 }, 0, 0, VE, .unit = "level" }, { "6.2", "Level 6.2", 0, AV_OPT_TYPE_CONST, { .i64 = VP9Level62 }, 0, 0, VE, .unit = "level" }, diff --git a/libavcodec/metasound.c b/libavcodec/metasound.c index f332316831..0ea9088e8d 100644 --- a/libavcodec/metasound.c +++ b/libavcodec/metasound.c @@ -374,7 +374,6 @@ const FFCodec ff_metasound_decoder = { .close = ff_twinvq_decode_close, FF_CODEC_DECODE_CB(ff_twinvq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mf_utils.c b/libavcodec/mf_utils.c index 48e3a63efc..ff44130ca9 100644 --- a/libavcodec/mf_utils.c +++ b/libavcodec/mf_utils.c @@ -240,6 +240,7 @@ static struct GUID_Entry guid_names[] = { GUID_ENTRY(MFMediaType_Video), GUID_ENTRY(MFAudioFormat_PCM), GUID_ENTRY(MFAudioFormat_Float), + GUID_ENTRY(ff_MFVideoFormat_AV1), GUID_ENTRY(MFVideoFormat_H264), GUID_ENTRY(MFVideoFormat_H264_ES), GUID_ENTRY(ff_MFVideoFormat_HEVC), @@ -507,6 +508,7 @@ void ff_media_type_dump(void *log, IMFMediaType *type) const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec) { switch (codec) { + case AV_CODEC_ID_AV1: return &ff_MFVideoFormat_AV1; case AV_CODEC_ID_H264: return &MFVideoFormat_H264; case AV_CODEC_ID_HEVC: return &ff_MFVideoFormat_HEVC; case AV_CODEC_ID_AC3: return &MFAudioFormat_Dolby_AC3; diff --git a/libavcodec/mf_utils.h b/libavcodec/mf_utils.h index 387c005f38..ecebb6fcdf 100644 --- a/libavcodec/mf_utils.h +++ b/libavcodec/mf_utils.h @@ -53,6 +53,13 @@ typedef struct MFFunctions { IMFMediaBuffer **ppBuffer); HRESULT (WINAPI *MFCreateSample) (IMFSample **ppIMFSample); HRESULT (WINAPI *MFCreateMediaType) (IMFMediaType **ppMFType); + HRESULT (WINAPI *MFCreateDXGISurfaceBuffer) (REFIID riid, + IUnknown* punkSurface, + UINT uSubresourceIndex, + BOOL fBottomUpWhenLinear, + IMFMediaBuffer** ppBuffer); + HRESULT (WINAPI *MFCreateDXGIDeviceManager) (UINT* resetToken, + IMFDXGIDeviceManager** ppDeviceManager); // MFTEnumEx is missing in Windows Vista's mfplat.dll. HRESULT (WINAPI *MFTEnumEx)(GUID guidCategory, UINT32 Flags, const MFT_REGISTER_TYPE_INFO *pInputType, @@ -113,6 +120,7 @@ DEFINE_GUID(ff_MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE, 0xf5523a5, 0x1cb2, DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC, 0x43564548); // FCC('HEVC') DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC_ES, 0x53564548); // FCC('HEVS') +DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_AV1, 0x31305641); // FCC('AV01') // This enum is missing from mingw-w64's codecapi.h by v7.0.0. diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c index b8f8a25f43..942c75cb9d 100644 --- a/libavcodec/mfenc.c +++ b/libavcodec/mfenc.c @@ -31,10 +31,18 @@ #include "codec_internal.h" #include "internal.h" #include "compat/w32dlfcn.h" +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif typedef struct MFContext { AVClass *av_class; HMODULE library; + HMODULE d3d_dll; + ID3D11DeviceContext* d3d_context; + IMFDXGIDeviceManager *dxgiManager; + int resetToken; + MFFunctions functions; AVFrame *frame; int is_video, is_audio; @@ -47,6 +55,7 @@ typedef struct MFContext { int out_stream_provides_samples; int draining, draining_done; int sample_sent; + int stream_started; int async_need_input, async_have_output, async_marker; int64_t reorder_delay; ICodecAPI *codec_api; @@ -55,6 +64,7 @@ typedef struct MFContext { int opt_enc_quality; int opt_enc_scenario; int opt_enc_hw; + AVD3D11VADeviceContext* device_hwctx; } MFContext; static int mf_choose_output_type(AVCodecContext *avctx); @@ -138,6 +148,15 @@ static int64_t mf_sample_get_pts(AVCodecContext *avctx, IMFSample *sample) return mf_from_mf_time(avctx, pts); } +static int64_t mf_sample_get_duration(AVCodecContext *avctx, IMFSample *sample) +{ + LONGLONG duration; + HRESULT hr = IMFSample_GetSampleDuration(sample, &duration); + if (FAILED(hr)) + return 0; + return mf_from_mf_time(avctx, duration); +} + static int mf_enca_output_type_get(AVCodecContext *avctx, IMFMediaType *type) { MFContext *c = avctx->priv_data; @@ -265,6 +284,7 @@ static int mf_sample_to_avpacket(AVCodecContext *avctx, IMFSample *sample, AVPac IMFMediaBuffer_Release(buffer); avpkt->pts = avpkt->dts = mf_sample_get_pts(avctx, sample); + avpkt->duration = mf_sample_get_duration(avctx, sample); hr = IMFAttributes_GetUINT32(sample, &MFSampleExtension_CleanPoint, &t32); if (c->is_audio || (!FAILED(hr) && t32 != 0)) @@ -286,7 +306,7 @@ static int mf_sample_to_avpacket(AVCodecContext *avctx, IMFSample *sample, AVPac return 0; } -static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) { MFContext *c = avctx->priv_data; size_t len; @@ -298,41 +318,127 @@ static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f sample = ff_create_memory_sample(&c->functions, frame->data[0], len, c->in_info.cbAlignment); - if (sample) - IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples)); - return sample; + if (!sample) + return AVERROR(ENOMEM); + + IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples)); + + *out_sample = sample; + return 0; } -static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int initialize_dxgi_manager(AVCodecContext *avctx) { MFContext *c = avctx->priv_data; - IMFSample *sample; - IMFMediaBuffer *buffer; - BYTE *data; + MFFunctions *func = &c->functions; HRESULT hr; - int ret; - int size; + + hr = func->MFCreateDXGIDeviceManager(&c->resetToken, &c->dxgiManager); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create DXGI device manager: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = IMFDXGIDeviceManager_ResetDevice(c->dxgiManager, (IUnknown*)c->device_hwctx->device, c->resetToken); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to reset device: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)c->dxgiManager); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to set D3D manager: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int process_d3d11_frame(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + MFContext *c = avctx->priv_data; + MFFunctions *func = &c->functions; + AVHWFramesContext *frames_ctx = NULL; + ID3D11Texture2D *d3d11_texture = NULL; + IMFSample *sample = NULL; + IMFMediaBuffer *buffer = NULL; + int subIdx = 0; + HRESULT hr; + + frames_ctx = (AVHWFramesContext*)frame->hw_frames_ctx->data; + c->device_hwctx = (AVD3D11VADeviceContext*)frames_ctx->device_ctx->hwctx; + + if (!c->dxgiManager) { + hr = initialize_dxgi_manager(avctx); + if (FAILED(hr)) { + return AVERROR_EXTERNAL; + } + } + + d3d11_texture = (ID3D11Texture2D*)frame->data[0]; + subIdx = (int)(intptr_t)frame->data[1]; + + if (!d3d11_texture) { + av_log(avctx, AV_LOG_ERROR, "D3D11 texture not found\n"); + return AVERROR(EINVAL); + } + + hr = func->MFCreateSample(&sample); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create MF sample: %s\n", ff_hr_str(hr)); + return AVERROR_EXTERNAL; + } + + hr = func->MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown*)d3d11_texture, subIdx, 0, &buffer); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create DXGI surface buffer: %s\n", ff_hr_str(hr)); + IMFSample_Release(sample); + return AVERROR_EXTERNAL; + } + + hr = IMFSample_AddBuffer(sample, buffer); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to add buffer to sample: %s\n", ff_hr_str(hr)); + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); + return AVERROR_EXTERNAL; + } + + IMFMediaBuffer_Release(buffer); + + *out_sample = sample; + return 0; +} + +static int process_software_frame(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + MFContext *c = avctx->priv_data; + IMFSample *sample = NULL; + IMFMediaBuffer *buffer = NULL; + BYTE *data = NULL; + HRESULT hr; + int size, ret; size = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1); if (size < 0) - return NULL; + return size; sample = ff_create_memory_sample(&c->functions, NULL, size, c->in_info.cbAlignment); if (!sample) - return NULL; + return AVERROR_EXTERNAL; hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); if (FAILED(hr)) { IMFSample_Release(sample); - return NULL; + return AVERROR_EXTERNAL; } hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); if (FAILED(hr)) { IMFMediaBuffer_Release(buffer); IMFSample_Release(sample); - return NULL; + return AVERROR_EXTERNAL; } ret = av_image_copy_to_buffer((uint8_t *)data, size, (void *)frame->data, frame->linesize, @@ -342,29 +448,63 @@ static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f IMFMediaBuffer_Release(buffer); if (ret < 0) { IMFSample_Release(sample); - return NULL; + return ret; } IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->duration)); + *out_sample = sample; - return sample; + return 0; } -static IMFSample *mf_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame) +static int mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) +{ + IMFSample *sample = NULL; + HRESULT hr; + int ret; + + if (frame->format == AV_PIX_FMT_D3D11) { + // Handle D3D11 hardware frames + ret = process_d3d11_frame(avctx, frame, &sample); + if (ret < 0) { + return ret; + } + } else { + // Handle software frames + ret = process_software_frame(avctx, frame, &sample); + if (ret < 0) { + return ret; + } + } + + // Set sample duration + hr = IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->duration)); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_WARNING, "Failed to set sample duration: %s\n", ff_hr_str(hr)); + } + + *out_sample = sample; + return 0; +} + +static int mf_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame, IMFSample **out_sample) { MFContext *c = avctx->priv_data; IMFSample *sample; + int ret; if (c->is_audio) { - sample = mf_a_avframe_to_sample(avctx, frame); + ret = mf_a_avframe_to_sample(avctx, frame, &sample); } else { - sample = mf_v_avframe_to_sample(avctx, frame); + ret = mf_v_avframe_to_sample(avctx, frame, &sample); } - if (sample) - mf_sample_set_pts(avctx, sample, frame->pts); + if (ret < 0) + return ret; - return sample; + mf_sample_set_pts(avctx, sample, frame->pts); + *out_sample = sample; + return 0; } static int mf_send_sample(AVCodecContext *avctx, IMFSample *sample) @@ -500,10 +640,10 @@ static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } if (c->frame->buf[0]) { - sample = mf_avframe_to_sample(avctx, c->frame); - if (!sample) { + ret = mf_avframe_to_sample(avctx, c->frame, &sample); + if (ret < 0) { av_frame_unref(c->frame); - return AVERROR(ENOMEM); + return ret; } if (c->is_video && c->codec_api) { if (c->frame->pict_type == AV_PICTURE_TYPE_I || !c->sample_sent) @@ -511,6 +651,23 @@ static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } } + if(!c->stream_started) + { + HRESULT hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "could not start streaming (%s)\n", ff_hr_str(hr)); + return AVERROR(EBADMSG); + } + + hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "could not start stream (%s)\n", ff_hr_str(hr)); + return AVERROR(EBADMSG); + } + + c->stream_started = 1; + } + ret = mf_send_sample(avctx, sample); if (sample) IMFSample_Release(sample); @@ -660,11 +817,6 @@ static int mf_encv_output_adjust(AVCodecContext *avctx, IMFMediaType *type) framerate = avctx->framerate; } else { framerate = av_inv_q(avctx->time_base); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - framerate.den *= avctx->ticks_per_frame; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } ff_MFSetAttributeRatio((IMFAttributes *)type, &MF_MT_FRAME_RATE, framerate.num, framerate.den); @@ -732,8 +884,16 @@ FF_ENABLE_DEPRECATION_WARNINGS static int64_t mf_encv_input_score(AVCodecContext *avctx, IMFMediaType *type) { enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type); - if (pix_fmt != avctx->pix_fmt) - return -1; // can not use + + if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (pix_fmt != AV_PIX_FMT_NV12) { + return -1; // can not use + } + } + else { + if (pix_fmt != avctx->pix_fmt) + return -1; // can not use + } return 0; } @@ -741,9 +901,16 @@ static int64_t mf_encv_input_score(AVCodecContext *avctx, IMFMediaType *type) static int mf_encv_input_adjust(AVCodecContext *avctx, IMFMediaType *type) { enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type); - if (pix_fmt != avctx->pix_fmt) { - av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); - return AVERROR(EINVAL); + if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + if (pix_fmt != AV_PIX_FMT_NV12 && pix_fmt != AV_PIX_FMT_D3D11) { + av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); + return AVERROR(EINVAL); + } + } else { + if (pix_fmt != avctx->pix_fmt) { + av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n"); + return AVERROR(EINVAL); + } } //ff_MFSetAttributeSize((IMFAttributes *)type, &MF_MT_FRAME_SIZE, avctx->width, avctx->height); @@ -1111,18 +1278,6 @@ static int mf_init_encoder(AVCodecContext *avctx) if ((ret = mf_setup_context(avctx)) < 0) return ret; - hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "could not start streaming (%s)\n", ff_hr_str(hr)); - return AVERROR_EXTERNAL; - } - - hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "could not start stream (%s)\n", ff_hr_str(hr)); - return AVERROR_EXTERNAL; - } - if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER && c->async_events && c->is_video && !avctx->extradata) { int sleep = 10000, total = 0; @@ -1180,6 +1335,7 @@ static int mf_load_library(AVCodecContext *avctx) #if !HAVE_UWP c->library = dlopen("mfplat.dll", 0); + c->d3d_dll = dlopen("D3D11.dll", 0); if (!c->library) { av_log(c, AV_LOG_ERROR, "DLL mfplat.dll failed to open\n"); @@ -1192,6 +1348,8 @@ static int mf_load_library(AVCodecContext *avctx) LOAD_MF_FUNCTION(c, MFCreateAlignedMemoryBuffer); LOAD_MF_FUNCTION(c, MFCreateSample); LOAD_MF_FUNCTION(c, MFCreateMediaType); + LOAD_MF_FUNCTION(c, MFCreateDXGISurfaceBuffer); + LOAD_MF_FUNCTION(c, MFCreateDXGIDeviceManager); // MFTEnumEx is missing in Windows Vista's mfplat.dll. LOAD_MF_FUNCTION(c, MFTEnumEx); @@ -1213,6 +1371,7 @@ static int mf_close(AVCodecContext *avctx) ff_free_mf(&c->functions, &c->mft); dlclose(c->library); + dlclose(c->d3d_dll); c->library = NULL; #else ff_free_mf(&c->functions, &c->mft); @@ -1226,7 +1385,7 @@ static int mf_close(AVCodecContext *avctx) return 0; } -static int mf_init(AVCodecContext *avctx) +static av_cold int mf_init(AVCodecContext *avctx) { int ret; if ((ret = mf_load_library(avctx)) == 0) { @@ -1263,8 +1422,7 @@ static int mf_init(AVCodecContext *avctx) }; #define AFMTS \ - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, \ - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), #define ACAPS \ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE, @@ -1306,12 +1464,11 @@ static const FFCodecDefault defaults[] = { }; #define VFMTS \ - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_YUV420P, \ - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_D3D11), #define VCAPS \ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1, MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS, defaults); MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS, defaults); +MF_ENCODER(VIDEO, av1, AV1, venc_opts, VFMTS, VCAPS, defaults); diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c index 786a3845fd..a46a62e45f 100644 --- a/libavcodec/microdvddec.c +++ b/libavcodec/microdvddec.c @@ -319,7 +319,7 @@ static int microdvd_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, return avpkt->size; } -static int microdvd_init(AVCodecContext *avctx) +static av_cold int microdvd_init(AVCodecContext *avctx) { int i, sidx; AVBPrint font_buf; diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile index fc1bc6b03f..f1c1c796a2 100644 --- a/libavcodec/mips/Makefile +++ b/libavcodec/mips/Makefile @@ -1,20 +1,43 @@ ARCH_HEADERS = cabac.h compute_antialias_fixed.h \ compute_antialias_float.h \ +MIPSFPU-OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o MIPSFPU-OBJS-$(CONFIG_AMRNB_DECODER) += mips/acelp_filters_mips.o \ mips/celp_filters_mips.o \ - mips/celp_math_mips.o \ mips/acelp_vectors_mips.o MIPSFPU-OBJS-$(CONFIG_AMRWB_DECODER) += mips/acelp_filters_mips.o \ mips/celp_filters_mips.o \ mips/amrwbdec_mips.o \ - mips/celp_math_mips.o \ mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_COMFORTNOISE_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_EVRC_DECODER) += mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G723_1_DECODER) += mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G723_1_ENCODER) += mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_G728_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_G729_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_QCELP_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_144_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_144_ENCODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_RA_288_DECODER) += mips/celp_filters_mips.o +MIPSFPU-OBJS-$(CONFIG_SIPR_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_WMAVOICE_DECODER) += mips/acelp_filters_mips.o \ + mips/celp_filters_mips.o \ + mips/acelp_vectors_mips.o +MIPSFPU-OBJS-$(CONFIG_CELP_MATH) += mips/celp_math_mips.o MIPSFPU-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_float.o MIPSDSP-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_fixed.o MIPSFPU-OBJS-$(CONFIG_FMTCONVERT) += mips/fmtconvert_mips.o OBJS-$(CONFIG_AC3DSP) += mips/ac3dsp_mips.o -MIPSFPU-OBJS-$(CONFIG_AAC_ENCODER) += mips/iirfilter_mips.o OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_init_mips.o \ mips/hevcpred_init_mips.o OBJS-$(CONFIG_VP9_DECODER) += mips/vp9dsp_init_mips.o @@ -31,8 +54,8 @@ OBJS-$(CONFIG_BLOCKDSP) += mips/blockdsp_init_mips.o OBJS-$(CONFIG_PIXBLOCKDSP) += mips/pixblockdsp_init_mips.o OBJS-$(CONFIG_IDCTDSP) += mips/idctdsp_init_mips.o OBJS-$(CONFIG_MPEGVIDEO) += mips/mpegvideo_init_mips.o -OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoenc_init_mips.o \ - mips/mpegvideoencdsp_init_mips.o +OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoenc_init_mips.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mips/mpegvideoencdsp_init_mips.o OBJS-$(CONFIG_ME_CMP) += mips/me_cmp_init_mips.o OBJS-$(CONFIG_MPEG4_DECODER) += mips/xvididct_init_mips.o OBJS-$(CONFIG_VC1DSP) += mips/vc1dsp_init_mips.o @@ -68,7 +91,7 @@ MSA-OBJS-$(CONFIG_PIXBLOCKDSP) += mips/pixblockdsp_msa.o MSA-OBJS-$(CONFIG_IDCTDSP) += mips/idctdsp_msa.o \ mips/simple_idct_msa.o MSA-OBJS-$(CONFIG_MPEGVIDEO) += mips/mpegvideo_msa.o -MSA-OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoencdsp_msa.o +MSA-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += mips/mpegvideoencdsp_msa.o MSA-OBJS-$(CONFIG_ME_CMP) += mips/me_cmp_msa.o MSA-OBJS-$(CONFIG_VC1_DECODER) += mips/vc1dsp_msa.o diff --git a/libavcodec/mips/celp_math_mips.c b/libavcodec/mips/celp_math_mips.c index ce711bd63c..1c41ce56d3 100644 --- a/libavcodec/mips/celp_math_mips.c +++ b/libavcodec/mips/celp_math_mips.c @@ -53,6 +53,7 @@ */ #include "config.h" #include "libavcodec/celp_math.h" +#include "libavutil/attributes.h" #include "libavutil/mips/asmdefs.h" #if HAVE_INLINE_ASM @@ -84,7 +85,7 @@ static float ff_dot_productf_mips(const float* a, const float* b, #endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ #endif /* HAVE_INLINE_ASM */ -void ff_celp_math_init_mips(CELPMContext *c) +av_cold void ff_celp_math_init_mips(CELPMContext *c) { #if HAVE_INLINE_ASM #if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 diff --git a/libavcodec/mips/h264pred_mmi.c b/libavcodec/mips/h264pred_mmi.c index 480411f5b5..09d4ac1693 100644 --- a/libavcodec/mips/h264pred_mmi.c +++ b/libavcodec/mips/h264pred_mmi.c @@ -24,6 +24,7 @@ #include "h264pred_mips.h" #include "libavcodec/bit_depth_template.c" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #include "constants.h" diff --git a/libavcodec/mips/h264qpel_mmi.c b/libavcodec/mips/h264qpel_mmi.c index 3482956e13..37ab29a443 100644 --- a/libavcodec/mips/h264qpel_mmi.c +++ b/libavcodec/mips/h264qpel_mmi.c @@ -1258,7 +1258,6 @@ static void avg_h264_qpel16_v_lowpass_mmi(uint8_t *dst, const uint8_t *src, static void put_h264_qpel4_hv_lowpass_mmi(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride) { - INIT_CLIP int i; int16_t _tmp[36]; int16_t *tmp = _tmp; @@ -1822,7 +1821,6 @@ static void put_pixels16_l2_shift5_mmi(uint8_t *dst, int16_t *src16, static void avg_h264_qpel4_hv_lowpass_mmi(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride) { - INIT_CLIP int i; int16_t _tmp[36]; int16_t *tmp = _tmp; diff --git a/libavcodec/mips/hevcdsp_mmi.c b/libavcodec/mips/hevcdsp_mmi.c index 6ff52187e5..30a3030d00 100644 --- a/libavcodec/mips/hevcdsp_mmi.c +++ b/libavcodec/mips/hevcdsp_mmi.c @@ -21,6 +21,7 @@ #include "libavcodec/hevc/hevcdec.h" #include "libavcodec/bit_depth_template.c" #include "libavcodec/mips/hevcdsp_mips.h" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #define PUT_HEVC_QPEL_H(w, x_step, src_step, dst_step) \ diff --git a/libavcodec/mips/iirfilter_mips.c b/libavcodec/mips/iirfilter_mips.c deleted file mode 100644 index 3a1352a7e4..0000000000 --- a/libavcodec/mips/iirfilter_mips.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2012 - * MIPS Technologies, Inc., California. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Author: Bojan Zivkovic (bojan@mips.com) - * - * IIR filter optimized for MIPS floating-point architecture - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * Reference: libavcodec/iirfilter.c - */ - -#include "config.h" -#include "libavcodec/iirfilter.h" - -#if HAVE_INLINE_ASM -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -typedef struct FFIIRFilterCoeffs { - int order; - float gain; - int *cx; - float *cy; -} FFIIRFilterCoeffs; - -typedef struct FFIIRFilterState { - float x[1]; -} FFIIRFilterState; - -static void iir_filter_flt_mips(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - int i; - const float *src0 = src; - float *dst0 = dst; - for (i = 0; i < size; i++) { - float in = *src0 * c->gain + s->x[0] * c->cy[0] + s->x[1] * c->cy[1]; - *dst0 = s->x[0] + in + s->x[1] * c->cx[1]; - s->x[0] = s->x[1]; - s->x[1] = in; - src0 += sstep; - dst0 += dstep; - } - } else if (c->order == 4) { - int i; - const float *src0 = src; - float *dst0 = dst; - float four = 4.0; - float six = 6.0; - for (i = 0; i < size; i += 4) { - float in1, in2, in3, in4; - float res1, res2, res3, res4; - float *x = s->x; - float *cy = c->cy; - float gain = c->gain; - float src0_0 = src0[0 ]; - float src0_1 = src0[sstep ]; - float src0_2 = src0[2*sstep]; - float src0_3 = src0[3*sstep]; - - __asm__ volatile ( - "lwc1 $f0, 0(%[cy]) \n\t" - "lwc1 $f4, 0(%[x]) \n\t" - "lwc1 $f5, 4(%[x]) \n\t" - "lwc1 $f6, 8(%[x]) \n\t" - "lwc1 $f7, 12(%[x]) \n\t" - "mul.s %[in1], %[src0_0], %[gain] \n\t" - "mul.s %[in2], %[src0_1], %[gain] \n\t" - "mul.s %[in3], %[src0_2], %[gain] \n\t" - "mul.s %[in4], %[src0_3], %[gain] \n\t" - "lwc1 $f1, 4(%[cy]) \n\t" - "madd.s %[in1], %[in1], $f0, $f4 \n\t" - "madd.s %[in2], %[in2], $f0, $f5 \n\t" - "madd.s %[in3], %[in3], $f0, $f6 \n\t" - "madd.s %[in4], %[in4], $f0, $f7 \n\t" - "lwc1 $f2, 8(%[cy]) \n\t" - "madd.s %[in1], %[in1], $f1, $f5 \n\t" - "madd.s %[in2], %[in2], $f1, $f6 \n\t" - "madd.s %[in3], %[in3], $f1, $f7 \n\t" - "lwc1 $f3, 12(%[cy]) \n\t" - "add.s $f8, $f5, $f7 \n\t" - "madd.s %[in1], %[in1], $f2, $f6 \n\t" - "madd.s %[in2], %[in2], $f2, $f7 \n\t" - "mul.s $f9, $f6, %[six] \n\t" - "mul.s $f10, $f7, %[six] \n\t" - "madd.s %[in1], %[in1], $f3, $f7 \n\t" - "madd.s %[in2], %[in2], $f3, %[in1] \n\t" - "madd.s %[in3], %[in3], $f2, %[in1] \n\t" - "madd.s %[in4], %[in4], $f1, %[in1] \n\t" - "add.s %[res1], $f4, %[in1] \n\t" - "swc1 %[in1], 0(%[x]) \n\t" - "add.s $f0, $f6, %[in1] \n\t" - "madd.s %[in3], %[in3], $f3, %[in2] \n\t" - "madd.s %[in4], %[in4], $f2, %[in2] \n\t" - "add.s %[res2], $f5, %[in2] \n\t" - "madd.s %[res1], %[res1], $f8, %[four] \n\t" - "add.s $f8, $f7, %[in2] \n\t" - "swc1 %[in2], 4(%[x]) \n\t" - "madd.s %[in4], %[in4], $f3, %[in3] \n\t" - "add.s %[res3], $f6, %[in3] \n\t" - "add.s %[res1], %[res1], $f9 \n\t" - "madd.s %[res2], %[res2], $f0, %[four] \n\t" - "swc1 %[in3], 8(%[x]) \n\t" - "add.s %[res4], $f7, %[in4] \n\t" - "madd.s %[res3], %[res3], $f8, %[four] \n\t" - "swc1 %[in4], 12(%[x]) \n\t" - "add.s %[res2], %[res2], $f10 \n\t" - "add.s $f8, %[in1], %[in3] \n\t" - "madd.s %[res3], %[res3], %[in1], %[six] \n\t" - "madd.s %[res4], %[res4], $f8, %[four] \n\t" - "madd.s %[res4], %[res4], %[in2], %[six] \n\t" - - : [in1]"=&f"(in1), [in2]"=&f"(in2), - [in3]"=&f"(in3), [in4]"=&f"(in4), - [res1]"=&f"(res1), [res2]"=&f"(res2), - [res3]"=&f"(res3), [res4]"=&f"(res4) - : [src0_0]"f"(src0_0), [src0_1]"f"(src0_1), - [src0_2]"f"(src0_2), [src0_3]"f"(src0_3), - [gain]"f"(gain), [x]"r"(x), [cy]"r"(cy), - [four]"f"(four), [six]"f"(six) - : "$f0", "$f1", "$f2", "$f3", - "$f4", "$f5", "$f6", "$f7", - "$f8", "$f9", "$f10", - "memory" - ); - - dst0[0 ] = res1; - dst0[sstep ] = res2; - dst0[2*sstep] = res3; - dst0[3*sstep] = res4; - - src0 += 4*sstep; - dst0 += 4*dstep; - } - } else { - int i; - const float *src0 = src; - float *dst0 = dst; - for (i = 0; i < size; i++) { - int j; - float in, res; - in = *src0 * c->gain; - for(j = 0; j < c->order; j++) - in += c->cy[j] * s->x[j]; - res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; - for(j = 1; j < c->order >> 1; j++) - res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; - for(j = 0; j < c->order - 1; j++) - s->x[j] = s->x[j + 1]; - *dst0 = res; - s->x[c->order - 1] = in; - src0 += sstep; - dst0 += dstep; - } - } -} -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM */ - -void ff_iir_filter_init_mips(FFIIRFilterContext *f) { -#if HAVE_INLINE_ASM -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 - f->filter_flt = iir_filter_flt_mips; -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mips/me_cmp_mips.h b/libavcodec/mips/me_cmp_mips.h index 72b7de70b4..7e2c926d3a 100644 --- a/libavcodec/mips/me_cmp_mips.h +++ b/libavcodec/mips/me_cmp_mips.h @@ -21,38 +21,38 @@ #ifndef AVCODEC_MIPS_ME_CMP_MIPS_H #define AVCODEC_MIPS_ME_CMP_MIPS_H -#include "../mpegvideo.h" +#include "../mpegvideoenc.h" #include "libavcodec/bit_depth_template.c" -int ff_hadamard8_diff8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_intra8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_diff16_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff16_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_hadamard8_intra16_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_intra16_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h); -int ff_pix_abs16_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse16_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); -int ff_sse8_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse8_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); -int ff_sse4_msa(MpegEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, +int ff_sse4_msa(MPVEncContext *v, const uint8_t *pu8Src, const uint8_t *pu8Ref, ptrdiff_t stride, int i32Height); void ff_add_pixels8_msa(const uint8_t *restrict pixels, int16_t *block, ptrdiff_t stride); diff --git a/libavcodec/mips/me_cmp_msa.c b/libavcodec/mips/me_cmp_msa.c index 351494161f..8ecc6352e6 100644 --- a/libavcodec/mips/me_cmp_msa.c +++ b/libavcodec/mips/me_cmp_msa.c @@ -732,79 +732,79 @@ static int32_t hadamard_intra_8x8_msa(const uint8_t *src, int32_t src_stride, return sum_res; } -int ff_pix_abs16_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_pix_abs16_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sad_16width_msa(src, stride, ref, stride, height); } -int ff_pix_abs8_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_pix_abs8_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sad_8width_msa(src, stride, ref, stride, height); } -int ff_pix_abs16_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_horiz_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs16_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_vert_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs16_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_hv_bilinear_filter_16width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_x2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_horiz_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_y2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_vert_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_pix_abs8_xy2_msa(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_xy2_msa(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { return sad_hv_bilinear_filter_8width_msa(pix1, stride, pix2, stride, h); } -int ff_sse16_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse16_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_16width_msa(src, stride, ref, stride, height); } -int ff_sse8_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse8_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_8width_msa(src, stride, ref, stride, height); } -int ff_sse4_msa(MpegEncContext *v, const uint8_t *src, const uint8_t *ref, +int ff_sse4_msa(MPVEncContext *v, const uint8_t *src, const uint8_t *ref, ptrdiff_t stride, int height) { return sse_4width_msa(src, stride, ref, stride, height); } -int ff_hadamard8_diff8x8_msa(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, +int ff_hadamard8_diff8x8_msa(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { return hadamard_diff_8x8_msa(src, stride, dst, stride); } -int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *src, const uint8_t *dummy, +int ff_hadamard8_intra8x8_msa(MPVEncContext *s, const uint8_t *src, const uint8_t *dummy, ptrdiff_t stride, int h) { return hadamard_intra_8x8_msa(src, stride, dummy, stride); @@ -812,7 +812,7 @@ int ff_hadamard8_intra8x8_msa(MpegEncContext *s, const uint8_t *src, const uint8 /* Hadamard Transform functions */ #define WRAPPER8_16_SQ(name8, name16) \ -int name16(MpegEncContext *s, const uint8_t *dst, const uint8_t *src, \ +int name16(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, \ ptrdiff_t stride, int h) \ { \ int score = 0; \ diff --git a/libavcodec/mips/mpegvideo_init_mips.c b/libavcodec/mips/mpegvideo_init_mips.c index 1d02b0c937..75c88a1317 100644 --- a/libavcodec/mips/mpegvideo_init_mips.c +++ b/libavcodec/mips/mpegvideo_init_mips.c @@ -20,10 +20,12 @@ #include "libavutil/attributes.h" #include "libavutil/mips/cpu.h" +#include "libavcodec/mpegvideo_unquantize.h" #include "h263dsp_mips.h" #include "mpegvideo_mips.h" -av_cold void ff_mpv_common_init_mips(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_mips(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type) { int cpu_flags = av_get_cpu_flags(); @@ -33,15 +35,15 @@ av_cold void ff_mpv_common_init_mips(MpegEncContext *s) s->dct_unquantize_mpeg1_intra = ff_dct_unquantize_mpeg1_intra_mmi; s->dct_unquantize_mpeg1_inter = ff_dct_unquantize_mpeg1_inter_mmi; - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) - if (!s->q_scale_type) + if (!bitexact) + if (!q_scale_type) s->dct_unquantize_mpeg2_intra = ff_dct_unquantize_mpeg2_intra_mmi; } if (have_msa(cpu_flags)) { s->dct_unquantize_h263_intra = ff_dct_unquantize_h263_intra_msa; s->dct_unquantize_h263_inter = ff_dct_unquantize_h263_inter_msa; - if (!s->q_scale_type) + if (!q_scale_type) s->dct_unquantize_mpeg2_inter = ff_dct_unquantize_mpeg2_inter_msa; } } diff --git a/libavcodec/mips/mpegvideo_mips.h b/libavcodec/mips/mpegvideo_mips.h index 760d7b3295..72ffed6985 100644 --- a/libavcodec/mips/mpegvideo_mips.h +++ b/libavcodec/mips/mpegvideo_mips.h @@ -22,6 +22,7 @@ #define AVCODEC_MIPS_MPEGVIDEO_MIPS_H #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" void ff_dct_unquantize_h263_intra_mmi(MpegEncContext *s, int16_t *block, int n, int qscale); @@ -33,6 +34,6 @@ void ff_dct_unquantize_mpeg1_inter_mmi(MpegEncContext *s, int16_t *block, int n, int qscale); void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, int n, int qscale); -void ff_denoise_dct_mmi(MpegEncContext *s, int16_t *block); +void ff_denoise_dct_mmi(MPVEncContext *s, int16_t *block); #endif /* AVCODEC_MIPS_MPEGVIDEO_MIPS_H */ diff --git a/libavcodec/mips/mpegvideo_mmi.c b/libavcodec/mips/mpegvideo_mmi.c index 7af421db6b..87d4aafd8c 100644 --- a/libavcodec/mips/mpegvideo_mmi.c +++ b/libavcodec/mips/mpegvideo_mmi.c @@ -356,10 +356,7 @@ void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, assert(s->block_last_index[n]>=0); - if (s->alternate_scan) - nCoeffs = 63; - else - nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; + nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; if (n < 4) block0 = block[0] * s->y_dc_scale; diff --git a/libavcodec/mips/mpegvideo_msa.c b/libavcodec/mips/mpegvideo_msa.c index aa9ef770eb..cd4adc0f77 100644 --- a/libavcodec/mips/mpegvideo_msa.c +++ b/libavcodec/mips/mpegvideo_msa.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/mips/generic_macros_msa.h" #include "h263dsp_mips.h" diff --git a/libavcodec/mips/mpegvideoenc_init_mips.c b/libavcodec/mips/mpegvideoenc_init_mips.c index 5ef0664937..7831973eb8 100644 --- a/libavcodec/mips/mpegvideoenc_init_mips.c +++ b/libavcodec/mips/mpegvideoenc_init_mips.c @@ -23,7 +23,7 @@ #include "libavcodec/mpegvideoenc.h" #include "mpegvideo_mips.h" -av_cold void ff_mpvenc_dct_init_mips(MpegEncContext *s) +av_cold void ff_mpvenc_dct_init_mips(MPVEncContext *s) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/mips/mpegvideoenc_mmi.c b/libavcodec/mips/mpegvideoenc_mmi.c index 65da155e9f..085be3b0ec 100644 --- a/libavcodec/mips/mpegvideoenc_mmi.c +++ b/libavcodec/mips/mpegvideoenc_mmi.c @@ -25,9 +25,9 @@ #include "mpegvideo_mips.h" #include "libavutil/mips/mmiutils.h" -void ff_denoise_dct_mmi(MpegEncContext *s, int16_t *block) +void ff_denoise_dct_mmi(MPVEncContext *s, int16_t *block) { - const int intra = s->mb_intra; + const int intra = s->c.mb_intra; int *sum = s->dct_error_sum[intra]; uint16_t *offset = s->dct_offset[intra]; double ftmp[8]; diff --git a/libavcodec/mips/mpegvideoencdsp_init_mips.c b/libavcodec/mips/mpegvideoencdsp_init_mips.c index 3efbeec34a..24a17b91db 100644 --- a/libavcodec/mips/mpegvideoencdsp_init_mips.c +++ b/libavcodec/mips/mpegvideoencdsp_init_mips.c @@ -21,6 +21,7 @@ #include "libavutil/attributes.h" #include "libavutil/mips/cpu.h" #include "libavcodec/bit_depth_template.c" +#include "libavcodec/mpegvideoencdsp.h" #include "h263dsp_mips.h" av_cold void ff_mpegvideoencdsp_init_mips(MpegvideoEncDSPContext *c, diff --git a/libavcodec/mips/pixblockdsp_init_mips.c b/libavcodec/mips/pixblockdsp_init_mips.c index 2e2d70953b..acea95d36e 100644 --- a/libavcodec/mips/pixblockdsp_init_mips.c +++ b/libavcodec/mips/pixblockdsp_init_mips.c @@ -20,9 +20,10 @@ */ #include "libavutil/mips/cpu.h" +#include "libavcodec/pixblockdsp.h" #include "pixblockdsp_mips.h" -void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_mips(PixblockDSPContext *c, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); @@ -30,27 +31,13 @@ void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, if (have_mmi(cpu_flags)) { c->diff_pixels = ff_diff_pixels_mmi; - if (!high_bit_depth || avctx->codec_type != AVMEDIA_TYPE_VIDEO) { + if (!high_bit_depth) c->get_pixels = ff_get_pixels_8_mmi; - } } if (have_msa(cpu_flags)) { c->diff_pixels = ff_diff_pixels_msa; - switch (avctx->bits_per_raw_sample) { - case 9: - case 10: - case 12: - case 14: - c->get_pixels = ff_get_pixels_16_msa; - break; - default: - if (avctx->bits_per_raw_sample <= 8 || avctx->codec_type != - AVMEDIA_TYPE_VIDEO) { - c->get_pixels = ff_get_pixels_8_msa; - } - break; - } + c->get_pixels = high_bit_depth ? ff_get_pixels_16_msa : ff_get_pixels_8_msa; } } diff --git a/libavcodec/mips/pixblockdsp_mips.h b/libavcodec/mips/pixblockdsp_mips.h index 7fd137cd09..fc387ea427 100644 --- a/libavcodec/mips/pixblockdsp_mips.h +++ b/libavcodec/mips/pixblockdsp_mips.h @@ -22,7 +22,8 @@ #ifndef AVCODEC_MIPS_PIXBLOCKDSP_MIPS_H #define AVCODEC_MIPS_PIXBLOCKDSP_MIPS_H -#include "../mpegvideo.h" +#include +#include void ff_diff_pixels_msa(int16_t *restrict block, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride); diff --git a/libavcodec/mips/vp8dsp_mmi.c b/libavcodec/mips/vp8dsp_mmi.c index bc774aa365..8b518e9c49 100644 --- a/libavcodec/mips/vp8dsp_mmi.c +++ b/libavcodec/mips/vp8dsp_mmi.c @@ -24,6 +24,7 @@ #include "vp8dsp_mips.h" #include "constants.h" #include "libavutil/attributes.h" +#include "libavutil/intfloat.h" #include "libavutil/mips/mmiutils.h" #include "libavutil/mem_internal.h" diff --git a/libavcodec/mips/xvididct_init_mips.c b/libavcodec/mips/xvididct_init_mips.c index 658a5792e0..524cf8dcdf 100644 --- a/libavcodec/mips/xvididct_init_mips.c +++ b/libavcodec/mips/xvididct_init_mips.c @@ -22,20 +22,14 @@ #include "libavutil/mips/cpu.h" #include "xvididct_mips.h" -av_cold void ff_xvid_idct_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) +av_cold void ff_xvid_idct_init_mips(IDCTDSPContext *c) { int cpu_flags = av_get_cpu_flags(); if (have_mmi(cpu_flags)) { - if (!high_bit_depth) { - if (avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID) { - c->idct_put = ff_xvid_idct_put_mmi; - c->idct_add = ff_xvid_idct_add_mmi; - c->idct = ff_xvid_idct_mmi; - c->perm_type = FF_IDCT_PERM_NONE; - } - } + c->idct_put = ff_xvid_idct_put_mmi; + c->idct_add = ff_xvid_idct_add_mmi; + c->idct = ff_xvid_idct_mmi; + c->perm_type = FF_IDCT_PERM_NONE; } } diff --git a/libavcodec/misc4.c b/libavcodec/misc4.c index 72ac944e54..ba79b95efe 100644 --- a/libavcodec/misc4.c +++ b/libavcodec/misc4.c @@ -180,10 +180,6 @@ const FFCodec ff_misc4_decoder = { .init = misc4_init, FF_CODEC_DECODE_CB(misc4_decode), .p.capabilities = AV_CODEC_CAP_DR1 | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 86ec58713c..87d1d02077 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -468,6 +468,10 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (s->avctx->height <= 0) return AVERROR_INVALIDDATA; } + if (s->bayer && s->progressive) { + avpriv_request_sample(s->avctx, "progressively coded bayer picture"); + return AVERROR_INVALIDDATA; + } if (s->got_picture && s->interlaced && (s->bottom_field == !s->interlace_polarity)) { if (s->progressive) { @@ -804,7 +808,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (!s->hwaccel_picture_private) return AVERROR(ENOMEM); - ret = hwaccel->start_frame(s->avctx, s->raw_image_buffer, + ret = hwaccel->start_frame(s->avctx, NULL, s->raw_image_buffer, s->raw_image_buffer_size); if (ret < 0) return ret; @@ -2120,7 +2124,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) av_log(s->avctx, AV_LOG_WARNING, "Invalid number of markers coded in APP2\n"); goto out; } else if (s->iccnum != 0 && nummarkers != s->iccnum) { - av_log(s->avctx, AV_LOG_WARNING, "Mistmatch in coded number of ICC markers between markers\n"); + av_log(s->avctx, AV_LOG_WARNING, "Mismatch in coded number of ICC markers between markers\n"); goto out; } else if (seqno > nummarkers) { av_log(s->avctx, AV_LOG_WARNING, "Mismatching sequence number and coded number of ICC markers\n"); @@ -2459,9 +2463,6 @@ redo_for_pal8: case SOF2: case SOF3: case SOF48: - case SOI: - case SOS: - case EOI: break; default: goto skip; @@ -2504,7 +2505,11 @@ redo_for_pal8: break; case SOF3: avctx->profile = AV_PROFILE_MJPEG_HUFFMAN_LOSSLESS; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif s->lossless = 1; s->ls = 0; s->progressive = 0; @@ -2513,7 +2518,11 @@ redo_for_pal8: break; case SOF48: avctx->profile = AV_PROFILE_MJPEG_JPEG_LS; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif s->lossless = 1; s->ls = 1; s->progressive = 0; @@ -2529,7 +2538,7 @@ redo_for_pal8: break; case EOI: eoi_parser: - if (!avctx->hwaccel && avctx->skip_frame != AVDISCARD_ALL && + if (!avctx->hwaccel && s->progressive && s->cur_scan && s->got_picture) mjpeg_idct_scan_progressive_ac(s); s->cur_scan = 0; @@ -2544,10 +2553,6 @@ eoi_parser: if (s->bottom_field == !s->interlace_polarity) break; } - if (avctx->skip_frame == AVDISCARD_ALL) { - s->got_picture = 0; - goto the_end_no_picture; - } if (avctx->hwaccel) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); if (ret < 0) @@ -2557,6 +2562,8 @@ eoi_parser: } if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0) return ret; + if (s->lossless) + frame->flags |= AV_FRAME_FLAG_LOSSLESS; *got_frame = 1; s->got_picture = 0; @@ -2574,10 +2581,6 @@ eoi_parser: 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)); - break; - } if ((ret = ff_mjpeg_decode_sos(s, NULL, 0, NULL)) < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) @@ -2602,6 +2605,18 @@ eoi_parser: break; } + if (avctx->skip_frame == AVDISCARD_ALL) { + switch(start_code) { + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF48: + s->got_picture = 0; + goto the_end_no_picture; + } + } + skip: /* eof process start code */ buf_ptr += (get_bits_count(&s->gb) + 7) / 8; @@ -2940,11 +2955,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) av_log(avctx, AV_LOG_INFO, "Single field\n"); } - if (s->picture) { - av_frame_free(&s->picture); - s->picture_ptr = NULL; - } else if (s->picture_ptr) - av_frame_unref(s->picture_ptr); + av_frame_free(&s->picture); + s->picture_ptr = NULL; av_frame_free(&s->smv_frame); diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 40da602a6d..214e2b0ec1 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -45,12 +45,26 @@ #include "mpegvideoenc.h" #include "profiles.h" +/** + * Buffer of JPEG frame data. + * + * Optimal Huffman table generation requires the frame data to be loaded into + * a buffer so that the tables can be computed. + * There are at most mb_width*mb_height*12*64 of these per frame. + */ +typedef struct MJpegHuffmanCode { + // 0=DC lum, 1=DC chrom, 2=AC lum, 3=AC chrom + uint8_t table_id; ///< The Huffman table id associated with the data. + uint8_t code; ///< The exponent. + uint16_t mant; ///< The mantissa. +} MJpegHuffmanCode; + /* The following is the private context of MJPEG/AMV decoder. * Note that when using slice threading only the main thread's - * MpegEncContext is followed by a MjpegContext; the other threads - * can access this shared context via MpegEncContext.mjpeg. */ + * MPVEncContext is followed by a MjpegContext; the other threads + * can access this shared context via MPVEncContext.mjpeg. */ typedef struct MJPEGEncContext { - MpegEncContext mpeg; + MPVMainEncContext mpeg; MJpegContext mjpeg; } MJPEGEncContext; @@ -78,35 +92,39 @@ static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], } } -static void mjpeg_encode_picture_header(MpegEncContext *s) +static void mjpeg_encode_picture_header(MPVEncContext *const s) { - ff_mjpeg_encode_picture_header(s->avctx, &s->pb, s->cur_pic.ptr->f, s->mjpeg_ctx, - s->intra_scantable.permutated, 0, - s->intra_matrix, s->chroma_intra_matrix, - s->slice_context_count > 1); + ff_mjpeg_encode_picture_header(s->c.avctx, &s->pb, s->c.cur_pic.ptr->f, s->mjpeg_ctx, + s->c.intra_scantable.permutated, 0, + s->c.intra_matrix, s->c.chroma_intra_matrix, + s->c.slice_context_count > 1); s->esc_pos = put_bytes_count(&s->pb, 0); - for (int i = 1; i < s->slice_context_count; i++) - s->thread_context[i]->esc_pos = 0; + for (int i = 1; i < s->c.slice_context_count; i++) + s->c.enc_contexts[i]->esc_pos = 0; } -void ff_mjpeg_amv_encode_picture_header(MpegEncContext *s) +static int mjpeg_amv_encode_picture_header(MPVMainEncContext *const m) { - MJPEGEncContext *const m = (MJPEGEncContext*)s; - av_assert2(s->mjpeg_ctx == &m->mjpeg); + MJPEGEncContext *const m2 = (MJPEGEncContext*)m; + MPVEncContext *const s = &m->s; + av_assert2(s->mjpeg_ctx == &m2->mjpeg); /* s->huffman == HUFFMAN_TABLE_OPTIMAL can only be true for MJPEG. */ - if (!CONFIG_MJPEG_ENCODER || m->mjpeg.huffman != HUFFMAN_TABLE_OPTIMAL) + if (!CONFIG_MJPEG_ENCODER || m2->mjpeg.huffman != HUFFMAN_TABLE_OPTIMAL) mjpeg_encode_picture_header(s); + + return 0; } #if CONFIG_MJPEG_ENCODER /** * Encodes and outputs the entire frame in the JPEG format. * - * @param s The MpegEncContext. + * @param main The MPVMainEncContext. */ -static void mjpeg_encode_picture_frame(MpegEncContext *s) +static void mjpeg_encode_picture_frame(MPVMainEncContext *const main) { + MPVEncContext *const s = &main->s; int nbits, code, table_id; MJpegContext *m = s->mjpeg_ctx; uint8_t *huff_size[4] = { m->huff_size_dc_luminance, @@ -120,7 +138,7 @@ static void mjpeg_encode_picture_frame(MpegEncContext *s) size_t total_bits = 0; size_t bytes_needed; - s->header_bits = get_bits_diff(s); + main->header_bits = get_bits_diff(s); // Estimate the total size first for (int i = 0; i < m->huff_ncode; i++) { table_id = m->huff_buffer[i].table_id; @@ -214,18 +232,21 @@ static void mjpeg_build_optimal_huffman(MJpegContext *m) * * Header + values + stuffing. * - * @param s The MpegEncContext. + * @param s The MPVEncContext. * @return int Error code, 0 if successful. */ -int ff_mjpeg_encode_stuffing(MpegEncContext *s) +int ff_mjpeg_encode_stuffing(MPVEncContext *const s) { MJpegContext *const m = s->mjpeg_ctx; PutBitContext *pbc = &s->pb; - int mb_y = s->mb_y - !s->mb_x; + int mb_y = s->c.mb_y - !s->c.mb_x; int ret; #if CONFIG_MJPEG_ENCODER if (m->huffman == HUFFMAN_TABLE_OPTIMAL) { + /* HUFFMAN_TABLE_OPTIMAL is incompatible with slice threading, + * therefore the following cast is allowed. */ + MPVMainEncContext *const main = (MPVMainEncContext*)s; mjpeg_build_optimal_huffman(m); @@ -239,128 +260,49 @@ int ff_mjpeg_encode_stuffing(MpegEncContext *s) s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; mjpeg_encode_picture_header(s); - mjpeg_encode_picture_frame(s); + mjpeg_encode_picture_frame(main); } #endif ret = ff_mpv_reallocate_putbitbuffer(s, put_bits_count(&s->pb) / 8 + 100, put_bits_count(&s->pb) / 4 + 1000); if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Buffer reallocation failed\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "Buffer reallocation failed\n"); goto fail; } ff_mjpeg_escape_FF(pbc, s->esc_pos); - if (s->slice_context_count > 1 && mb_y < s->mb_height - 1) + if (s->c.slice_context_count > 1 && mb_y < s->c.mb_height - 1) put_marker(pbc, RST0 + (mb_y&7)); s->esc_pos = put_bytes_count(pbc, 0); fail: for (int i = 0; i < 3; i++) - s->last_dc[i] = 128 << s->intra_dc_precision; + s->c.last_dc[i] = 128 << s->c.intra_dc_precision; return ret; } -static int alloc_huffman(MpegEncContext *s) +static int alloc_huffman(MJPEGEncContext *const m2) { - MJpegContext *m = s->mjpeg_ctx; - size_t num_mbs, num_blocks, num_codes; - int blocks_per_mb; - - // We need to init this here as the mjpeg init is called before the common init, - s->mb_width = (s->width + 15) / 16; - s->mb_height = (s->height + 15) / 16; - - switch (s->chroma_format) { - case CHROMA_420: blocks_per_mb = 6; break; - case CHROMA_422: blocks_per_mb = 8; break; - case CHROMA_444: blocks_per_mb = 12; break; - default: av_assert0(0); + MJpegContext *const m = &m2->mjpeg; + MPVEncContext *const s = &m2->mpeg.s; + static const char blocks_per_mb[] = { + [CHROMA_420] = 6, [CHROMA_422] = 8, [CHROMA_444] = 12 }; + size_t num_blocks; // Make sure we have enough space to hold this frame. - num_mbs = s->mb_width * s->mb_height; - num_blocks = num_mbs * blocks_per_mb; - num_codes = num_blocks * 64; + num_blocks = s->c.mb_num * blocks_per_mb[s->c.chroma_format]; - m->huff_buffer = av_malloc_array(num_codes, sizeof(MJpegHuffmanCode)); + m->huff_buffer = av_malloc_array(num_blocks, + 64 /* codes per MB */ * sizeof(MJpegHuffmanCode)); if (!m->huff_buffer) return AVERROR(ENOMEM); return 0; } -av_cold int ff_mjpeg_encode_init(MpegEncContext *s) -{ - MJpegContext *const m = &((MJPEGEncContext*)s)->mjpeg; - int ret, use_slices; - - s->mjpeg_ctx = m; - use_slices = s->avctx->slices > 0 ? s->avctx->slices > 1 : - (s->avctx->active_thread_type & FF_THREAD_SLICE) && - s->avctx->thread_count > 1; - - if (s->codec_id == AV_CODEC_ID_AMV || use_slices) - m->huffman = HUFFMAN_TABLE_DEFAULT; - - if (s->mpv_flags & FF_MPV_FLAG_QP_RD) { - // Used to produce garbage with MJPEG. - av_log(s->avctx, AV_LOG_ERROR, - "QP RD is no longer compatible with MJPEG or AMV\n"); - return AVERROR(EINVAL); - } - - /* The following check is automatically true for AMV, - * but it doesn't hurt either. */ - ret = ff_mjpeg_encode_check_pix_fmt(s->avctx); - if (ret < 0) - return ret; - - if (s->width > 65500 || s->height > 65500) { - av_log(s, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n"); - return AVERROR(EINVAL); - } - - s->min_qcoeff=-1023; - s->max_qcoeff= 1023; - - // Build default Huffman tables. - // These may be overwritten later with more optimal Huffman tables, but - // they are needed at least right now for some processes like trellis. - ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance, - m->huff_code_dc_luminance, - ff_mjpeg_bits_dc_luminance, - ff_mjpeg_val_dc); - ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance, - m->huff_code_dc_chrominance, - ff_mjpeg_bits_dc_chrominance, - ff_mjpeg_val_dc); - ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance, - m->huff_code_ac_luminance, - ff_mjpeg_bits_ac_luminance, - ff_mjpeg_val_ac_luminance); - ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance, - m->huff_code_ac_chrominance, - ff_mjpeg_bits_ac_chrominance, - ff_mjpeg_val_ac_chrominance); - - init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); - init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); - s->intra_ac_vlc_length = - s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; - s->intra_chroma_ac_vlc_length = - s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; - - // Buffers start out empty. - m->huff_ncode = 0; - - if (m->huffman == HUFFMAN_TABLE_OPTIMAL) - return alloc_huffman(s); - - return 0; -} - static av_cold int mjpeg_encode_close(AVCodecContext *avctx) { MJPEGEncContext *const mjpeg = avctx->priv_data; @@ -376,7 +318,7 @@ static av_cold int mjpeg_encode_close(AVCodecContext *avctx) * @param table_id Which Huffman table the code belongs to. * @param code The encoded exponent of the coefficients and the run-bits. */ -static inline void ff_mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int code) +static inline void mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int code) { MJpegHuffmanCode *c = &s->huff_buffer[s->huff_ncode++]; c->table_id = table_id; @@ -391,13 +333,13 @@ static inline void ff_mjpeg_encode_code(MJpegContext *s, uint8_t table_id, int c * @param val The coefficient. * @param run The run-bits. */ -static void ff_mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int run) +static void mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int run) { int mant, code; if (val == 0) { av_assert0(run == 0); - ff_mjpeg_encode_code(s, table_id, 0); + mjpeg_encode_code(s, table_id, 0); } else { mant = val; if (val < 0) { @@ -408,18 +350,18 @@ static void ff_mjpeg_encode_coef(MJpegContext *s, uint8_t table_id, int val, int code = (run << 4) | (av_log2_16bit(val) + 1); s->huff_buffer[s->huff_ncode].mant = mant; - ff_mjpeg_encode_code(s, table_id, code); + mjpeg_encode_code(s, table_id, code); } } /** * Add the block's data into the JPEG buffer. * - * @param s The MpegEncContext that contains the JPEG buffer. + * @param s The MPVEncContext that contains the JPEG buffer. * @param block The block. * @param n The block's index or number. */ -static void record_block(MpegEncContext *s, int16_t *block, int n) +static void record_block(MPVEncContext *const s, int16_t block[], int n) { int i, j, table_id; int component, dc, last_index, val, run; @@ -429,51 +371,51 @@ static void record_block(MpegEncContext *s, int16_t *block, int n) component = (n <= 3 ? 0 : (n&1) + 1); table_id = (n <= 3 ? 0 : 1); dc = block[0]; /* overflow is impossible */ - val = dc - s->last_dc[component]; + val = dc - s->c.last_dc[component]; - ff_mjpeg_encode_coef(m, table_id, val, 0); + mjpeg_encode_coef(m, table_id, val, 0); - s->last_dc[component] = dc; + s->c.last_dc[component] = dc; /* AC coefs */ run = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; table_id |= 2; for(i=1;i<=last_index;i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; val = block[j]; if (val == 0) { run++; } else { while (run >= 16) { - ff_mjpeg_encode_code(m, table_id, 0xf0); + mjpeg_encode_code(m, table_id, 0xf0); run -= 16; } - ff_mjpeg_encode_coef(m, table_id, val, run); + mjpeg_encode_coef(m, table_id, val, run); run = 0; } } /* output EOB only if not already 64 values */ if (last_index < 63 || run != 0) - ff_mjpeg_encode_code(m, table_id, 0); + mjpeg_encode_code(m, table_id, 0); } -static void encode_block(MpegEncContext *s, int16_t *block, int n) +static void encode_block(MPVEncContext *const s, int16_t block[], int n) { int mant, nbits, code, i, j; int component, dc, run, last_index, val; - MJpegContext *m = s->mjpeg_ctx; - uint8_t *huff_size_ac; - uint16_t *huff_code_ac; + const MJpegContext *const m = s->mjpeg_ctx; + const uint16_t *huff_code_ac; + const uint8_t *huff_size_ac; /* DC coef */ component = (n <= 3 ? 0 : (n&1) + 1); dc = block[0]; /* overflow is impossible */ - val = dc - s->last_dc[component]; + val = dc - s->c.last_dc[component]; if (n < 4) { ff_mjpeg_encode_dc(&s->pb, val, m->huff_size_dc_luminance, m->huff_code_dc_luminance); huff_size_ac = m->huff_size_ac_luminance; @@ -483,14 +425,14 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) huff_size_ac = m->huff_size_ac_chrominance; huff_code_ac = m->huff_code_ac_chrominance; } - s->last_dc[component] = dc; + s->c.last_dc[component] = dc; /* AC coefs */ run = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; for(i=1;i<=last_index;i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; val = block[j]; if (val == 0) { run++; @@ -520,79 +462,159 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) put_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]); } -void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]) +static void mjpeg_record_mb(MPVEncContext *const s, int16_t block[][64], + int unused_x, int unused_y) { - int i; - if (s->mjpeg_ctx->huffman == HUFFMAN_TABLE_OPTIMAL) { - if (s->chroma_format == CHROMA_444) { - record_block(s, block[0], 0); - record_block(s, block[2], 2); - record_block(s, block[4], 4); - record_block(s, block[8], 8); - record_block(s, block[5], 5); - record_block(s, block[9], 9); + if (s->c.chroma_format == CHROMA_444) { + record_block(s, block[0], 0); + record_block(s, block[2], 2); + record_block(s, block[4], 4); + record_block(s, block[8], 8); + record_block(s, block[5], 5); + record_block(s, block[9], 9); - if (16*s->mb_x+8 < s->width) { - record_block(s, block[1], 1); - record_block(s, block[3], 3); - record_block(s, block[6], 6); - record_block(s, block[10], 10); - record_block(s, block[7], 7); - record_block(s, block[11], 11); - } - } else { - for(i=0;i<5;i++) { - record_block(s, block[i], i); - } - if (s->chroma_format == CHROMA_420) { - record_block(s, block[5], 5); - } else { - record_block(s, block[6], 6); - record_block(s, block[5], 5); - record_block(s, block[7], 7); - } + if (16*s->c.mb_x+8 < s->c.width) { + record_block(s, block[1], 1); + record_block(s, block[3], 3); + record_block(s, block[6], 6); + record_block(s, block[10], 10); + record_block(s, block[7], 7); + record_block(s, block[11], 11); } } else { - if (s->chroma_format == CHROMA_444) { - encode_block(s, block[0], 0); - encode_block(s, block[2], 2); - encode_block(s, block[4], 4); - encode_block(s, block[8], 8); - encode_block(s, block[5], 5); - encode_block(s, block[9], 9); - - if (16*s->mb_x+8 < s->width) { - encode_block(s, block[1], 1); - encode_block(s, block[3], 3); - encode_block(s, block[6], 6); - encode_block(s, block[10], 10); - encode_block(s, block[7], 7); - encode_block(s, block[11], 11); - } + for (int i = 0; i < 5; i++) + record_block(s, block[i], i); + if (s->c.chroma_format == CHROMA_420) { + record_block(s, block[5], 5); } else { - for(i=0;i<5;i++) { - encode_block(s, block[i], i); - } - if (s->chroma_format == CHROMA_420) { - encode_block(s, block[5], 5); - } else { - encode_block(s, block[6], 6); - encode_block(s, block[5], 5); - encode_block(s, block[7], 7); - } + record_block(s, block[6], 6); + record_block(s, block[5], 5); + record_block(s, block[7], 7); } - - s->i_tex_bits += get_bits_diff(s); } } +static void mjpeg_encode_mb(MPVEncContext *const s, int16_t block[][64], + int unused_x, int unused_y) +{ + if (s->c.chroma_format == CHROMA_444) { + encode_block(s, block[0], 0); + encode_block(s, block[2], 2); + encode_block(s, block[4], 4); + encode_block(s, block[8], 8); + encode_block(s, block[5], 5); + encode_block(s, block[9], 9); + + if (16 * s->c.mb_x + 8 < s->c.width) { + encode_block(s, block[1], 1); + encode_block(s, block[3], 3); + encode_block(s, block[6], 6); + encode_block(s, block[10], 10); + encode_block(s, block[7], 7); + encode_block(s, block[11], 11); + } + } else { + for (int i = 0; i < 5; i++) + encode_block(s, block[i], i); + if (s->c.chroma_format == CHROMA_420) { + encode_block(s, block[5], 5); + } else { + encode_block(s, block[6], 6); + encode_block(s, block[5], 5); + encode_block(s, block[7], 7); + } + } + + s->i_tex_bits += get_bits_diff(s); +} + +static av_cold int mjpeg_encode_init(AVCodecContext *avctx) +{ + MJPEGEncContext *const m2 = avctx->priv_data; + MJpegContext *const m = &m2->mjpeg; + MPVEncContext *const s = &m2->mpeg.s; + int ret; + + s->mjpeg_ctx = m; + m2->mpeg.encode_picture_header = mjpeg_amv_encode_picture_header; + // May be overridden below + s->encode_mb = mjpeg_encode_mb; + + if (s->mpv_flags & FF_MPV_FLAG_QP_RD) { + // Used to produce garbage with MJPEG. + av_log(avctx, AV_LOG_ERROR, + "QP RD is no longer compatible with MJPEG or AMV\n"); + return AVERROR(EINVAL); + } + + /* The following check is automatically true for AMV, + * but it doesn't hurt either. */ + ret = ff_mjpeg_encode_check_pix_fmt(avctx); + if (ret < 0) + return ret; + + if (avctx->width > 65500 || avctx->height > 65500) { + av_log(avctx, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n"); + return AVERROR(EINVAL); + } + + // Build default Huffman tables. + // These may be overwritten later with more optimal Huffman tables, but + // they are needed at least right now for some processes like trellis. + ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance, + m->huff_code_dc_luminance, + ff_mjpeg_bits_dc_luminance, + ff_mjpeg_val_dc); + ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance, + m->huff_code_dc_chrominance, + ff_mjpeg_bits_dc_chrominance, + ff_mjpeg_val_dc); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance, + m->huff_code_ac_luminance, + ff_mjpeg_bits_ac_luminance, + ff_mjpeg_val_ac_luminance); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance, + m->huff_code_ac_chrominance, + ff_mjpeg_bits_ac_chrominance, + ff_mjpeg_val_ac_chrominance); + + init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); + init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); + + s->min_qcoeff = -1023; + s->max_qcoeff = 1023; + + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; + + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + // Buffers start out empty. + m->huff_ncode = 0; + + if (s->c.slice_context_count > 1) + m->huffman = HUFFMAN_TABLE_DEFAULT; + + if (m->huffman == HUFFMAN_TABLE_OPTIMAL) { + // If we are here, we have only one slice_context. So no loop necessary. + s->encode_mb = mjpeg_record_mb; + return alloc_huffman(m2); + } + + return 0; +} + #if CONFIG_AMV_ENCODER // maximum over s->mjpeg_vsample[i] #define V_MAX 2 static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic_arg, int *got_packet) { - MpegEncContext *s = avctx->priv_data; + MPVEncContext *const s = avctx->priv_data; AVFrame *pic; int i, ret; int chroma_v_shift = 1; /* AMV is 420-only */ @@ -612,7 +634,7 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, //picture should be flipped upside-down for(i=0; i < 3; i++) { int vsample = i ? 2 >> chroma_v_shift : 2; - pic->data[i] += pic->linesize[i] * (vsample * s->height / V_MAX - 1); + pic->data[i] += pic->linesize[i] * (vsample * s->c.height / V_MAX - 1); pic->linesize[i] *= -1; } ret = ff_mpv_encode_picture(avctx, pkt, pic, got_packet); @@ -624,11 +646,12 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(MJPEGEncContext, mjpeg.x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { -FF_MPV_COMMON_OPTS +#define AMV_OPTIONS_OFFSET 4 { "huffman", "Huffman table strategy", OFFSET(huffman), AV_OPT_TYPE_INT, { .i64 = HUFFMAN_TABLE_OPTIMAL }, 0, NB_HUFFMAN_TABLE_OPTION - 1, VE, .unit = "huffman" }, { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = HUFFMAN_TABLE_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "huffman" }, { "optimal", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = HUFFMAN_TABLE_OPTIMAL }, INT_MIN, INT_MAX, VE, .unit = "huffman" }, { "force_duplicated_matrix", "Always write luma and chroma matrix for mjpeg, useful for rtp streaming.", OFFSET(force_duplicated_matrix), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, VE }, +FF_MPV_COMMON_OPTS { NULL}, }; @@ -660,23 +683,21 @@ static int mjpeg_get_supported_config(const AVCodecContext *avctx, return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } -FFCodec ff_mjpeg_encoder = { +const FFCodec ff_mjpeg_encoder = { .p.name = "mjpeg", CODEC_LONG_NAME("MJPEG (Motion JPEG)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MJPEG, .priv_data_size = sizeof(MJPEGEncContext), - .init = ff_mpv_encode_init, + .init = mjpeg_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = mjpeg_encode_close, - .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), .p.priv_class = &mjpeg_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), .get_supported_config = mjpeg_get_supported_config, @@ -687,7 +708,7 @@ FFCodec ff_mjpeg_encoder = { static const AVClass amv_class = { .class_name = "amv encoder", .item_name = av_default_item_name, - .option = options, + .option = options + AMV_OPTIONS_OFFSET, .version = LIBAVUTIL_VERSION_INT, }; @@ -696,16 +717,14 @@ const FFCodec ff_amv_encoder = { CODEC_LONG_NAME("AMV Video"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_AMV, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(MJPEGEncContext), - .init = ff_mpv_encode_init, + .init = mjpeg_encode_init, FF_CODEC_ENCODE_CB(amv_encode_picture), .close = mjpeg_encode_close, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ420P), .color_ranges = AVCOL_RANGE_JPEG, .p.priv_class = &amv_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; #endif diff --git a/libavcodec/mjpegenc.h b/libavcodec/mjpegenc.h index a593b67e96..92feed28b4 100644 --- a/libavcodec/mjpegenc.h +++ b/libavcodec/mjpegenc.h @@ -36,23 +36,8 @@ #include #include "mjpeg.h" -#include "mpegvideo.h" #include "put_bits.h" -/** - * Buffer of JPEG frame data. - * - * Optimal Huffman table generation requires the frame data to be loaded into - * a buffer so that the tables can be computed. - * There are at most mb_width*mb_height*12*64 of these per frame. - */ -typedef struct MJpegHuffmanCode { - // 0=DC lum, 1=DC chrom, 2=AC lum, 3=AC chrom - uint8_t table_id; ///< The Huffman table id associated with the data. - uint8_t code; ///< The exponent. - uint16_t mant; ///< The mantissa. -} MJpegHuffmanCode; - /** * Holds JPEG frame data and Huffman table data. */ @@ -71,9 +56,9 @@ typedef struct MJpegContext { uint8_t huff_size_ac_chrominance[256]; ///< AC chrominance Huffman table size. uint16_t huff_code_ac_chrominance[256]; ///< AC chrominance Huffman table codes. - /** Storage for AC luminance VLC (in MpegEncContext) */ + /** Storage for AC luminance VLC */ uint8_t uni_ac_vlc_len[64 * 64 * 2]; - /** Storage for AC chrominance VLC (in MpegEncContext) */ + /** Storage for AC chrominance VLC */ uint8_t uni_chroma_ac_vlc_len[64 * 64 * 2]; // Default DC tables have exactly 12 values @@ -89,7 +74,7 @@ typedef struct MJpegContext { uint8_t val_ac_chrominance[256]; ///< AC chrominance Huffman values. size_t huff_ncode; ///< Number of current entries in the buffer. - MJpegHuffmanCode *huff_buffer; ///< Buffer for Huffman code values. + struct MJpegHuffmanCode *huff_buffer; ///< Buffer for Huffman code values. } MJpegContext; /** @@ -107,9 +92,8 @@ static inline void put_marker(PutBitContext *p, enum JpegMarker code) put_bits(p, 8, code); } -int ff_mjpeg_encode_init(MpegEncContext *s); -void ff_mjpeg_amv_encode_picture_header(MpegEncContext *s); -void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]); -int ff_mjpeg_encode_stuffing(MpegEncContext *s); +typedef struct MPVEncContext MPVEncContext; + +int ff_mjpeg_encode_stuffing(MPVEncContext *s); #endif /* AVCODEC_MJPEGENC_H */ diff --git a/libavcodec/mjpegenc_common.c b/libavcodec/mjpegenc_common.c index 751e43fd3b..21b3b19b93 100644 --- a/libavcodec/mjpegenc_common.c +++ b/libavcodec/mjpegenc_common.c @@ -56,10 +56,10 @@ static int put_huffman_table(PutBitContext *p, int table_class, int table_id, } static void jpeg_table_header(AVCodecContext *avctx, PutBitContext *p, - MJpegContext *m, + const MJpegContext *m, const uint8_t intra_matrix_permutation[64], - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int hsample[3], int use_slices, int matrices_differ) { int size; @@ -246,7 +246,7 @@ static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p, } } -void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4]) +void ff_mjpeg_init_hvsample(const AVCodecContext *avctx, int hsample[4], int vsample[4]) { if (avctx->codec_id == AV_CODEC_ID_LJPEG && ( avctx->pix_fmt == AV_PIX_FMT_BGR0 @@ -273,10 +273,10 @@ void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4 } void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - const AVFrame *frame, struct MJpegContext *m, + const AVFrame *frame, const struct MJpegContext *m, const uint8_t intra_matrix_permutation[64], int pred, - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int use_slices) { const int lossless = !m; @@ -304,7 +304,8 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, switch (avctx->codec_id) { case AV_CODEC_ID_MJPEG: put_marker(pb, SOF0 ); break; case AV_CODEC_ID_LJPEG: put_marker(pb, SOF3 ); break; - default: av_assert0(0); + default: av_unreachable("ff_mjpeg_encode_picture_header only called by " + "AMV, LJPEG, MJPEG and the former has been ruled out"); } put_bits(pb, 16, 8 + 3 * components); @@ -375,7 +376,7 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, switch (avctx->codec_id) { case AV_CODEC_ID_MJPEG: put_bits(pb, 8, 63); break; /* Se (not used) */ case AV_CODEC_ID_LJPEG: put_bits(pb, 8, 0); break; /* not used */ - default: av_assert0(0); + default: av_unreachable("Only LJPEG, MJPEG possible here"); } put_bits(pb, 8, 0); /* Ah/Al (not used) */ @@ -465,7 +466,7 @@ void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits) } void ff_mjpeg_encode_dc(PutBitContext *pb, int val, - uint8_t *huff_size, uint16_t *huff_code) + const uint8_t huff_size[], const uint16_t huff_code[]) { int mant, nbits; diff --git a/libavcodec/mjpegenc_common.h b/libavcodec/mjpegenc_common.h index e9f0ea44a0..0cf5a72706 100644 --- a/libavcodec/mjpegenc_common.h +++ b/libavcodec/mjpegenc_common.h @@ -31,21 +31,21 @@ struct MJpegContext; int ff_mjpeg_add_icc_profile_size(AVCodecContext *avctx, const AVFrame *frame, size_t *max_pkt_size); void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - const AVFrame *frame, struct MJpegContext *m, + const AVFrame *frame, const struct MJpegContext *m, const uint8_t intra_matrix_permutation[64], int pred, - uint16_t luma_intra_matrix[64], - uint16_t chroma_intra_matrix[64], + const uint16_t luma_intra_matrix[64], + const uint16_t chroma_intra_matrix[64], int use_slices); void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits); void ff_mjpeg_escape_FF(PutBitContext *pb, int start); void ff_mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code, const uint8_t *bits_table, const uint8_t *val_table); -void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4]); +void ff_mjpeg_init_hvsample(const AVCodecContext *avctx, int hsample[4], int vsample[4]); void ff_mjpeg_encode_dc(PutBitContext *pb, int val, - uint8_t *huff_size, uint16_t *huff_code); + const uint8_t huff_size[], const uint16_t huff_code[]); int ff_mjpeg_encode_check_pix_fmt(AVCodecContext *avctx); diff --git a/libavcodec/mjpegenc_huffman.c b/libavcodec/mjpegenc_huffman.c index 9bfcb7e785..5a0d8b0b48 100644 --- a/libavcodec/mjpegenc_huffman.c +++ b/libavcodec/mjpegenc_huffman.c @@ -25,6 +25,24 @@ #include "libavutil/qsort.h" #include "mjpegenc_huffman.h" +/** + * Used to assign a occurrence count or "probability" to an input value + */ +typedef struct PTable { + int value; ///< input value + int prob; ///< number of occurrences of this value in input +} PTable; + +/** + * Used to store intermediate lists in the package merge algorithm + */ +typedef struct PackageMergerList { + int nitems; ///< number of items in the list and probability ex. 4 + int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 + int probability[514]; ///< probability of each item 3, 8, 18, 46 + int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E +} PackageMergerList; + /** * Comparison function for two PTables by prob * @@ -39,20 +57,6 @@ static int compare_by_prob(const void *a, const void *b) return a_val.prob - b_val.prob; } -/** - * Comparison function for two HuffTables by length - * - * @param a First HuffTable to compare - * @param b Second HuffTable to compare - * @return < 0 for less than, 0 for equals, > 0 for greater than - */ -static int compare_by_length(const void *a, const void *b) -{ - HuffTable a_val = *(HuffTable *) a; - HuffTable b_val = *(HuffTable *) b; - return a_val.length - b_val.length; -} - /** * Computes the length of the Huffman encoding for each distinct input value. * Uses package merge algorithm as follows: @@ -66,15 +70,17 @@ static int compare_by_length(const void *a, const void *b) * 8. the length of the huffman code for symbol s will be equal to the number of times the symbol occurs in the select elements * Go to guru.multimedia.cx/small-tasks-for-ffmpeg/ for more details * - * All probabilities should be positive integers. The output is sorted by code, - * not by length. + * All probabilities should be nonnegative integers. * - * @param prob_table input array of a PTable for each distinct input value - * @param distincts output array of a HuffTable that will be populated by this function - * @param size size of the prob_table array - * @param max_length max length of an encoding + * @param prob_table[in,out] array of a PTable for each distinct input value, + * will be sorted according to ascending probability + * @param counts[out] the number of values of a given length + * @param size number of elements of the prob_table array + * @param max_length max length of a code */ -void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, int size, int max_length) +static void mjpegenc_huffman_compute_bits(PTable *prob_table, + uint8_t counts[/* max_length + 1 */], + int size, int max_length) { PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp; @@ -132,14 +138,9 @@ void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, } // we don't want to return the 256 bit count (it was just in here to prevent // all 1s encoding) - j = 0; - for (i = 0; i < 256; i++) { - if (nbits[i] > 0) { - distincts[j].code = i; - distincts[j].length = nbits[i]; - j++; - } - } + memset(counts, 0, sizeof(counts[0]) * (max_length + 1)); + for (int i = 0; i < 256; ++i) + counts[nbits[i]]++; } void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s) @@ -158,32 +159,28 @@ void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s) void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17], uint8_t val[], int max_nval) { - int i, j; - int nval = 0; PTable val_counts[257]; - HuffTable distincts[256]; - for (i = 0; i < 256; i++) { - if (s->val_count[i]) nval++; - } - av_assert0 (nval <= max_nval); + av_assert1(max_nval <= FF_ARRAY_ELEMS(val_counts) - 1); - j = 0; - for (i = 0; i < 256; i++) { + int nval = 0; + for (int i = 0; i < 256; i++) { if (s->val_count[i]) { - val_counts[j].value = i; - val_counts[j].prob = s->val_count[i]; - j++; + val_counts[nval].value = i; + val_counts[nval].prob = s->val_count[i]; + nval++; + av_assert2(nval <= max_nval); } } - val_counts[j].value = 256; - val_counts[j].prob = 0; - ff_mjpegenc_huffman_compute_bits(val_counts, distincts, nval + 1, 16); - AV_QSORT(distincts, nval, HuffTable, compare_by_length); + val_counts[nval].value = 256; + val_counts[nval].prob = 0; - memset(bits, 0, sizeof(bits[0]) * 17); - for (i = 0; i < nval; i++) { - val[i] = distincts[i].code; - bits[distincts[i].length]++; - } + mjpegenc_huffman_compute_bits(val_counts, bits, nval + 1, 16); + + // val_counts[0] is the fake element we added earlier. + av_assert1(val_counts[0].prob == 0 && val_counts[0].value == 256); + // The following loop puts the values with higher occurrence first, + // ensuring that they get the shorter codes. + for (int i = 0; i < nval; ++i) + val[i] = val_counts[nval - i].value; } diff --git a/libavcodec/mjpegenc_huffman.h b/libavcodec/mjpegenc_huffman.h index 5fe65504e4..8822e468aa 100644 --- a/libavcodec/mjpegenc_huffman.h +++ b/libavcodec/mjpegenc_huffman.h @@ -44,33 +44,4 @@ void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17], uint8_t val[], int max_nval); - -/** - * Used to assign a occurrence count or "probability" to an input value - */ -typedef struct PTable { - int value; ///< input value - int prob; ///< number of occurences of this value in input -} PTable; - -/** - * Used to store intermediate lists in the package merge algorithm - */ -typedef struct PackageMergerList { - int nitems; ///< number of items in the list and probability ex. 4 - int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 - int probability[514]; ///< probability of each item 3, 8, 18, 46 - int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E -} PackageMergerList; - -/** - * Used to store optimal huffman encoding results - */ -typedef struct HuffTable { - int code; ///< code is the input value - int length; ///< length of the encoding -} HuffTable; - -void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, - int size, int max_length); #endif /* AVCODEC_MJPEGENC_HUFFMAN_H */ diff --git a/libavcodec/mlpenc.c b/libavcodec/mlpenc.c index 06670de456..475a70c225 100644 --- a/libavcodec/mlpenc.c +++ b/libavcodec/mlpenc.c @@ -2308,9 +2308,9 @@ const FFCodec ff_mlp_encoder = { FF_CODEC_ENCODE_CB(mlp_encode_frame), .close = mlp_encode_close, .p.priv_class = &mlp_class, - .p.sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE}, - .p.supported_samplerates = (const int[]) {44100, 48000, 88200, 96000, 176400, 192000, 0}, - .p.ch_layouts = ff_mlp_ch_layouts, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(44100, 48000, 88200, 96000, 176400, 192000), + CODEC_CH_LAYOUTS_ARRAY(ff_mlp_ch_layouts), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -2328,20 +2328,13 @@ const FFCodec ff_truehd_encoder = { FF_CODEC_ENCODE_CB(mlp_encode_frame), .close = mlp_encode_close, .p.priv_class = &mlp_class, - .p.sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE}, - .p.supported_samplerates = (const int[]) {44100, 48000, 88200, 96000, 176400, 192000, 0}, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_2POINT1, - AV_CHANNEL_LAYOUT_SURROUND, - AV_CHANNEL_LAYOUT_3POINT1, - AV_CHANNEL_LAYOUT_4POINT0, - AV_CHANNEL_LAYOUT_4POINT1, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - { 0 } - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), + CODEC_SAMPLERATES(44100, 48000, 88200, 96000, 176400, 192000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_2POINT1, AV_CHANNEL_LAYOUT_SURROUND, + AV_CHANNEL_LAYOUT_3POINT1, AV_CHANNEL_LAYOUT_4POINT0, + AV_CHANNEL_LAYOUT_4POINT1, AV_CHANNEL_LAYOUT_5POINT0, + AV_CHANNEL_LAYOUT_5POINT1), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mlz.h b/libavcodec/mlz.h index 24993126ca..666a8d0b24 100644 --- a/libavcodec/mlz.h +++ b/libavcodec/mlz.h @@ -42,7 +42,7 @@ typedef struct MLZDict { int match_len; } MLZDict; -/** MLZ data strucure +/** MLZ data structure */ typedef struct MLZ { int dic_code_bit; diff --git a/libavcodec/mmvideo.c b/libavcodec/mmvideo.c index 3038d9ea92..2a0c855992 100644 --- a/libavcodec/mmvideo.c +++ b/libavcodec/mmvideo.c @@ -39,6 +39,7 @@ #define MM_PREAMBLE_SIZE 6 +#define MM_TYPE_RAW 0x2 #define MM_TYPE_INTER 0x5 #define MM_TYPE_INTRA 0x8 #define MM_TYPE_INTRA_HH 0xc @@ -76,15 +77,21 @@ static av_cold int mm_decode_init(AVCodecContext *avctx) return 0; } +static int mm_decode_raw(MmContext * s) +{ + if (bytestream2_get_bytes_left(&s->gb) < s->avctx->width * s->avctx->height) + return AVERROR_INVALIDDATA; + for (int y = 0; y < s->avctx->height; y++) + bytestream2_get_buffer(&s->gb, s->frame->data[0] + y*s->frame->linesize[0], s->avctx->width); + return 0; +} + static void mm_decode_pal(MmContext *s) { - int i; - - bytestream2_skip(&s->gb, 4); - for (i = 0; i < 128; i++) { - s->palette[i] = 0xFFU << 24 | bytestream2_get_be24(&s->gb); - s->palette[i+128] = s->palette[i]<<2; - } + int start = bytestream2_get_le16(&s->gb); + int count = bytestream2_get_le16(&s->gb); + for (int i = 0; i < count; i++) + s->palette[(start+i)&0xFF] = 0xFFU << 24 | (bytestream2_get_be24(&s->gb) << 2); } /** @@ -164,7 +171,7 @@ static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert) for(j=0; j<8; j++) { int replace = (replace_array >> (7-j)) & 1; if (x + half_horiz >= s->avctx->width) - return AVERROR_INVALIDDATA; + break; if (replace) { int color = bytestream2_get_byte(&data_ptr); s->frame->data[0][y*s->frame->linesize[0] + x] = color; @@ -205,6 +212,7 @@ static int mm_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return res; switch(type) { + case MM_TYPE_RAW : res = mm_decode_raw(s); break; case MM_TYPE_PALETTE : mm_decode_pal(s); return avpkt->size; case MM_TYPE_INTRA : res = mm_decode_intra(s, 0, 0); break; case MM_TYPE_INTRA_HH : res = mm_decode_intra(s, 1, 0); break; diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index e4f17fb2d8..33166f2a90 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -32,6 +32,7 @@ #include #include "avcodec.h" +#include "h263.h" #include "mathops.h" #include "motion_est.h" #include "mpegutils.h" @@ -46,7 +47,7 @@ #define ME_MAP_SHIFT 3 #define ME_MAP_MV_BITS 11 -static int sad_hpel_motion_search(MpegEncContext * s, +static int sad_hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h); @@ -90,12 +91,12 @@ static inline void init_ref(MotionEstContext *c, uint8_t *const src[3], }; int i; for(i=0; i<3; i++){ - c->src[0][i]= src [i] + offset[i]; - c->ref[0][i]= ref [i] + offset[i]; + c->src[0][i]= src[i] ? src[i] + offset[i] : NULL; + c->ref[0][i]= ref[i] ? ref[i] + offset[i] : NULL; } if(ref_index){ for(i=0; i<3; i++){ - c->ref[ref_index][i]= ref2[i] + offset[i]; + c->ref[ref_index][i]= ref2[i] ? ref2[i] + offset[i] : NULL; } } } @@ -106,10 +107,10 @@ static int get_flags(MotionEstContext *c, int direct, int chroma){ + (chroma ? FLAG_CHROMA : 0); } -static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp_direct_inline(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int stride= c->stride; const int hx = subx + x * (1 << (1 + qpel)); const int hy = suby + y * (1 << (1 + qpel)); @@ -117,71 +118,71 @@ static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, co const uint8_t * const * const src = c->src[src_index]; int d; //FIXME check chroma 4mv, (no crashes ...) - av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); - if(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)){ - const int time_pp= s->pp_time; - const int time_pb= s->pb_time; - const int mask= 2*qpel+1; - if(s->mv_type==MV_TYPE_8X8){ - int i; - for(i=0; i<4; i++){ - int fx = c->direct_basis_mv[i][0] + hx; - int fy = c->direct_basis_mv[i][1] + hy; - int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); - int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1]*(time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); - int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); - int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); + av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); + if (x >= c->xmin && hx <= c->xmax << (qpel + 1) && + y >= c->ymin && hy <= c->ymax << (qpel + 1)) { + const int time_pp = s->c.pp_time; + const int time_pb = s->c.pb_time; + const int mask = 2 * qpel + 1; + if (s->c.mv_type == MV_TYPE_8X8) { + for(int i = 0; i < 4; ++i) { + int fx = c->direct_basis_mv[i][0] + hx; + int fy = c->direct_basis_mv[i][1] + hy; + int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0] * (time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); + int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1] * (time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); + int fxy = (fx & mask) + ((fy & mask) << (qpel + 1)); + int bxy = (bx & mask) + ((by & mask) << (qpel + 1)); - uint8_t *dst= c->temp + 8*(i&1) + 8*stride*(i>>1); - if(qpel){ - c->qpel_put[1][fxy](dst, ref[0] + (fx>>2) + (fy>>2)*stride, stride); - c->qpel_avg[1][bxy](dst, ref[8] + (bx>>2) + (by>>2)*stride, stride); - }else{ - c->hpel_put[1][fxy](dst, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 8); - c->hpel_avg[1][bxy](dst, ref[8] + (bx>>1) + (by>>1)*stride, stride, 8); - } - } - }else{ - int fx = c->direct_basis_mv[0][0] + hx; - int fy = c->direct_basis_mv[0][1] + hy; - int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0]*(time_pb - time_pp)/time_pp); - int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1]*(time_pb - time_pp)/time_pp); - int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); - int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); - - if(qpel){ - c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); - c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); - c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); - c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); - c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); - c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); - c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); - c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); - }else{ - av_assert2((fx>>1) + 16*s->mb_x >= -16); - av_assert2((fy>>1) + 16*s->mb_y >= -16); - av_assert2((fx>>1) + 16*s->mb_x <= s->width); - av_assert2((fy>>1) + 16*s->mb_y <= s->height); - av_assert2((bx>>1) + 16*s->mb_x >= -16); - av_assert2((by>>1) + 16*s->mb_y >= -16); - av_assert2((bx>>1) + 16*s->mb_x <= s->width); - av_assert2((by>>1) + 16*s->mb_y <= s->height); - - c->hpel_put[0][fxy](c->temp, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 16); - c->hpel_avg[0][bxy](c->temp, ref[8] + (bx>>1) + (by>>1)*stride, stride, 16); + uint8_t *dst = c->temp + 8 * (i & 1) + 8 * stride * (i >> 1); + if (qpel) { + c->qpel_put[1][fxy](dst, ref[0] + (fx >> 2) + (fy >> 2) * stride, stride); + c->qpel_avg[1][bxy](dst, ref[8] + (bx >> 2) + (by >> 2) * stride, stride); + } else { + c->hpel_put[1][fxy](dst, ref[0] + (fx >> 1) + (fy >> 1) * stride, stride, 8); + c->hpel_avg[1][bxy](dst, ref[8] + (bx >> 1) + (by >> 1) * stride, stride, 8); } } - d = cmp_func(s, c->temp, src[0], stride, 16); - }else - d= 256*256*256*32; + } else { + int fx = c->direct_basis_mv[0][0] + hx; + int fy = c->direct_basis_mv[0][1] + hy; + int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0] * (time_pb - time_pp)/time_pp); + int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1] * (time_pb - time_pp)/time_pp); + int fxy = (fx & mask) + ((fy & mask) << (qpel + 1)); + int bxy = (bx & mask) + ((by & mask) << (qpel + 1)); + + if (qpel) { + c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); + c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); + c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); + c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); + c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); + c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); + } else { + av_assert2((fx >> 1) + 16 * s->c.mb_x >= -16); + av_assert2((fy >> 1) + 16 * s->c.mb_y >= -16); + av_assert2((fx >> 1) + 16 * s->c.mb_x <= s->c.width); + av_assert2((fy >> 1) + 16 * s->c.mb_y <= s->c.height); + av_assert2((bx >> 1) + 16 * s->c.mb_x >= -16); + av_assert2((by >> 1) + 16 * s->c.mb_y >= -16); + av_assert2((bx >> 1) + 16 * s->c.mb_x <= s->c.width); + av_assert2((by >> 1) + 16 * s->c.mb_y <= s->c.height); + + c->hpel_put[0][fxy](c->temp, ref[0] + (fx >> 1) + (fy >> 1) * stride, stride, 16); + c->hpel_avg[0][bxy](c->temp, ref[8] + (bx >> 1) + (by >> 1) * stride, stride, 16); + } + } + d = cmp_func(s, c->temp, src[0], stride, 16); + } else + d = 256 * 256 * 256 * 32; return d; } -static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp_inline(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel, int chroma){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int stride= c->stride; const int uvstride= c->uvstride; const int dxy= subx + (suby<<(1+qpel)); //FIXME log2_subpel? @@ -191,52 +192,52 @@ static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int const uint8_t * const * const src = c->src[src_index]; int d; //FIXME check chroma 4mv, (no crashes ...) - int uvdxy; /* no, it might not be used uninitialized */ - if(dxy){ - if(qpel){ - if (h << size == 16) { - c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h) - } else if (size == 0 && h == 8) { - c->qpel_put[1][dxy](c->temp , ref[0] + x + y*stride , stride); - c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y*stride + 8, stride); - } else - av_assert2(0); - if(chroma){ - int cx= hx/2; - int cy= hy/2; - cx= (cx>>1)|(cx&1); - cy= (cy>>1)|(cy&1); - uvdxy= (cx&1) + 2*(cy&1); - // FIXME x/y wrong, but MPEG-4 qpel is sick anyway, we should drop as much of it as possible in favor for H.264 - } - }else{ - c->hpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride, h); - if(chroma) - uvdxy= dxy | (x&1) | (2*(y&1)); + int uvdxy; /* no, it might not be used uninitialized */ + if (dxy) { + if (qpel) { + if (h << size == 16) { + c->qpel_put[size][dxy](c->temp, ref[0] + x + y * stride, stride); //FIXME prototype (add h) + } else if (size == 0 && h == 8) { + c->qpel_put[1][dxy](c->temp , ref[0] + x + y * stride , stride); + c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y * stride + 8, stride); + } else + av_assert2(0); + if (chroma) { + int cx = hx / 2; + int cy = hy / 2; + cx = (cx >> 1) | (cx & 1); + cy = (cy >> 1) | (cy & 1); + uvdxy = (cx & 1) + 2 * (cy & 1); + // FIXME x/y wrong, but MPEG-4 qpel is sick anyway, we should drop as much of it as possible in favor for H.264 } - d = cmp_func(s, c->temp, src[0], stride, h); - }else{ - d = cmp_func(s, src[0], ref[0] + x + y*stride, stride, h); - if(chroma) - uvdxy= (x&1) + 2*(y&1); - } - if(chroma){ - uint8_t * const uvtemp= c->temp + 16*stride; - c->hpel_put[size+1][uvdxy](uvtemp , ref[1] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); - c->hpel_put[size+1][uvdxy](uvtemp+8, ref[2] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); - d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h>>1); - d += chroma_cmp_func(s, uvtemp+8, src[2], uvstride, h>>1); + } else { + c->hpel_put[size][dxy](c->temp, ref[0] + x + y * stride, stride, h); + if (chroma) + uvdxy = dxy | (x & 1) | (2 * (y & 1)); } + d = cmp_func(s, c->temp, src[0], stride, h); + } else { + d = cmp_func(s, src[0], ref[0] + x + y * stride, stride, h); + if (chroma) + uvdxy = (x & 1) + 2 * (y & 1); + } + if (chroma) { + uint8_t *const uvtemp = c->temp + 16 * stride; + c->hpel_put[size + 1][uvdxy](uvtemp , ref[1] + (x >> 1) + (y >> 1) * uvstride, uvstride, h >> 1); + c->hpel_put[size + 1][uvdxy](uvtemp + 8, ref[2] + (x >> 1) + (y >> 1) * uvstride, uvstride, h >> 1); + d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h >> 1); + d += chroma_cmp_func(s, uvtemp + 8, src[2], uvstride, h >> 1); + } return d; } -static int cmp_simple(MpegEncContext *s, const int x, const int y, +static int cmp_simple(MPVEncContext *const s, const int x, const int y, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func){ return cmp_inline(s,x,y,0,0,0,16,ref_index,src_index, cmp_func, chroma_cmp_func, 0, 0); } -static int cmp_fpel_internal(MpegEncContext *s, const int x, const int y, +static int cmp_fpel_internal(MPVEncContext *const s, const int x, const int y, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -246,7 +247,7 @@ static int cmp_fpel_internal(MpegEncContext *s, const int x, const int y, } } -static int cmp_internal(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_internal(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -259,7 +260,7 @@ static int cmp_internal(MpegEncContext *s, const int x, const int y, const int s /** @brief compares a block (either a full macroblock or a partition thereof) against a proposed motion-compensated prediction of that block */ -static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static av_always_inline int cmp(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(av_builtin_constant_p(flags) && av_builtin_constant_p(h) && av_builtin_constant_p(size) @@ -274,7 +275,7 @@ static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, con } } -static int cmp_hpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_hpel(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -284,7 +285,7 @@ static int cmp_hpel(MpegEncContext *s, const int x, const int y, const int subx, } } -static int cmp_qpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +static int cmp_qpel(MPVEncContext *const s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ if(flags&FLAG_DIRECT){ @@ -296,7 +297,7 @@ static int cmp_qpel(MpegEncContext *s, const int x, const int y, const int subx, #include "motion_est_template.c" -static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, +static int zero_cmp(MPVEncContext *const s, const uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h) { return 0; @@ -367,35 +368,39 @@ av_cold int ff_me_init(MotionEstContext *c, AVCodecContext *avctx, return 0; } -void ff_me_init_pic(MpegEncContext *s) +void ff_me_init_pic(MPVEncContext *const s) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; -/*FIXME s->no_rounding b_type*/ - if (s->avctx->flags & AV_CODEC_FLAG_QPEL) { - c->qpel_avg = s->qdsp.avg_qpel_pixels_tab; - if (s->no_rounding) - c->qpel_put = s->qdsp.put_no_rnd_qpel_pixels_tab; +/*FIXME s->c.no_rounding b_type*/ + if (c->avctx->flags & AV_CODEC_FLAG_QPEL) { + c->qpel_avg = s->c.qdsp.avg_qpel_pixels_tab; + if (s->c.no_rounding) + c->qpel_put = s->c.qdsp.put_no_rnd_qpel_pixels_tab; else - c->qpel_put = s->qdsp.put_qpel_pixels_tab; + c->qpel_put = s->c.qdsp.put_qpel_pixels_tab; } - c->hpel_avg = s->hdsp.avg_pixels_tab; - if (s->no_rounding) - c->hpel_put = s->hdsp.put_no_rnd_pixels_tab; + c->hpel_avg = s->c.hdsp.avg_pixels_tab; + if (s->c.no_rounding) + c->hpel_put = s->c.hdsp.put_no_rnd_pixels_tab; else - c->hpel_put = s->hdsp.put_pixels_tab; + c->hpel_put = s->c.hdsp.put_pixels_tab; - if(s->linesize){ - c->stride = s->linesize; - c->uvstride= s->uvlinesize; + if (s->c.linesize) { + c->stride = s->c.linesize; + c->uvstride = s->c.uvlinesize; }else{ - c->stride = 16*s->mb_width + 32; - c->uvstride= 8*s->mb_width + 16; + c->stride = 16*s->c.mb_width + 32; + c->uvstride = 8*s->c.mb_width + 16; } - if (s->codec_id != AV_CODEC_ID_SNOW) { + if (s->c.codec_id != AV_CODEC_ID_SNOW) { c->hpel_put[2][0]= c->hpel_put[2][1]= c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; } + /* Reset the average MB variance and scene change stats */ + c->scene_change_score = 0; + c->mb_var_sum_temp = + c->mc_mb_var_sum_temp = 0; } #define CHECK_SAD_HALF_MV(suffix, x, y) \ @@ -405,12 +410,12 @@ void ff_me_init_pic(MpegEncContext *s) COPY3_IF_LT(dminh, d, dx, x, dy, y)\ } -static int sad_hpel_motion_search(MpegEncContext * s, +static int sad_hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int penalty_factor= c->sub_penalty_factor; int mx, my, dminh; const uint8_t *pix, *ptr; @@ -510,58 +515,58 @@ static int sad_hpel_motion_search(MpegEncContext * s, return dminh; } -static inline void set_p_mv_tables(MpegEncContext * s, int mx, int my, int mv4) +static inline void set_p_mv_tables(MPVEncContext *const s, int mx, int my, int mv4) { - const int xy= s->mb_x + s->mb_y*s->mb_stride; + const int xy = s->c.mb_x + s->c.mb_y * s->c.mb_stride; s->p_mv_table[xy][0] = mx; s->p_mv_table[xy][1] = my; /* has already been set to the 4 MV if 4MV is done */ if(mv4){ - int mot_xy= s->block_index[0]; + int mot_xy = s->c.block_index[0]; - s->cur_pic.motion_val[0][mot_xy ][0] = mx; - s->cur_pic.motion_val[0][mot_xy ][1] = my; - s->cur_pic.motion_val[0][mot_xy + 1][0] = mx; - s->cur_pic.motion_val[0][mot_xy + 1][1] = my; + s->c.cur_pic.motion_val[0][mot_xy ][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy ][1] = my; + s->c.cur_pic.motion_val[0][mot_xy + 1][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy + 1][1] = my; - mot_xy += s->b8_stride; - s->cur_pic.motion_val[0][mot_xy ][0] = mx; - s->cur_pic.motion_val[0][mot_xy ][1] = my; - s->cur_pic.motion_val[0][mot_xy + 1][0] = mx; - s->cur_pic.motion_val[0][mot_xy + 1][1] = my; + mot_xy += s->c.b8_stride; + s->c.cur_pic.motion_val[0][mot_xy ][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy ][1] = my; + s->c.cur_pic.motion_val[0][mot_xy + 1][0] = mx; + s->c.cur_pic.motion_val[0][mot_xy + 1][1] = my; } } /** * get fullpel ME search limits. */ -static inline void get_limits(MpegEncContext *s, int x, int y, int bframe) +static inline void get_limits(MPVEncContext *const s, int x, int y, int bframe) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL)); int max_range = MAX_MV >> (1 + !!(c->flags&FLAG_QPEL)); /* if(c->avctx->me_range) c->range= c->avctx->me_range >> 1; else c->range= 16; */ - if (s->unrestricted_mv) { + if (c->unrestricted_mv) { c->xmin = - x - 16; c->ymin = - y - 16; - c->xmax = - x + s->width; - c->ymax = - y + s->height; - } else if (!(av_builtin_constant_p(bframe) && bframe) && s->out_format == FMT_H261){ + c->xmax = - x + s->c.width; + c->ymax = - y + s->c.height; + } else if (!(av_builtin_constant_p(bframe) && bframe) && s->c.out_format == FMT_H261){ // Search range of H.261 is different from other codec standards c->xmin = (x > 15) ? - 15 : 0; c->ymin = (y > 15) ? - 15 : 0; - c->xmax = (x < s->mb_width * 16 - 16) ? 15 : 0; - c->ymax = (y < s->mb_height * 16 - 16) ? 15 : 0; + c->xmax = (x < s->c.mb_width * 16 - 16) ? 15 : 0; + c->ymax = (y < s->c.mb_height * 16 - 16) ? 15 : 0; } else { c->xmin = - x; c->ymin = - y; - c->xmax = - x + s->mb_width *16 - 16; - c->ymax = - y + s->mb_height*16 - 16; + c->xmax = - x + s->c.mb_width *16 - 16; + c->ymax = - y + s->c.mb_height*16 - 16; } if(!range || range > max_range) range = max_range; @@ -584,9 +589,9 @@ static inline void init_mv4_ref(MotionEstContext *c){ c->src[3][0] = c->src[2][0] + 8; } -static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) +static inline int h263_mv4_search(MPVEncContext *const s, int mx, int my, int shift) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int size= 1; const int h=8; int block; @@ -595,7 +600,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int same=1; const int stride= c->stride; const uint8_t *mv_penalty = c->current_mv_penalty; - int safety_clipping= s->unrestricted_mv && (s->width&15) && (s->height&15); + int safety_clipping = c->unrestricted_mv && (s->c.width&15) && (s->c.height&15); init_mv4_ref(c); @@ -604,28 +609,28 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int pred_x4, pred_y4; int dmin4; static const int off[4]= {2, 1, 1, -1}; - const int mot_stride = s->b8_stride; - const int mot_xy = s->block_index[block]; + const int mot_stride = s->c.b8_stride; + const int mot_xy = s->c.block_index[block]; if(safety_clipping){ - c->xmax = - 16*s->mb_x + s->width - 8*(block &1); - c->ymax = - 16*s->mb_y + s->height - 8*(block>>1); + c->xmax = - 16*s->c.mb_x + s->c.width - 8*(block &1); + c->ymax = - 16*s->c.mb_y + s->c.height - 8*(block>>1); } - P_LEFT[0] = s->cur_pic.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->cur_pic.motion_val[0][mot_xy - 1][1]; + P_LEFT[0] = s->c.cur_pic.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->c.cur_pic.motion_val[0][mot_xy - 1][1]; if (P_LEFT[0] > c->xmax * (1 << shift)) P_LEFT[0] = c->xmax * (1 << shift); /* special case for first line */ - if (s->first_slice_line && block<2) { + if (s->c.first_slice_line && block < 2) { c->pred_x= pred_x4= P_LEFT[0]; c->pred_y= pred_y4= P_LEFT[1]; } else { - P_TOP[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][0]; - P_TOPRIGHT[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][1]; + P_TOP[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][0]; + P_TOPRIGHT[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + off[block]][1]; if (P_TOP[1] > c->ymax * (1 << shift)) P_TOP[1] = c->ymax * (1 << shift); if (P_TOPRIGHT[0] < c->xmin * (1 << shift)) P_TOPRIGHT[0] = c->xmin * (1 << shift); if (P_TOPRIGHT[0] > c->xmax * (1 << shift)) P_TOPRIGHT[0] = c->xmax * (1 << shift); @@ -641,7 +646,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) P_MV1[1]= my; if(safety_clipping) for(i=1; i<10; i++){ - if (s->first_slice_line && block<2 && i>1 && i<9) + if (s->c.first_slice_line && block < 2 && i > 1 && i < 9) continue; if (i>4 && i<9) continue; @@ -657,28 +662,22 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) int dxy; const int offset= ((block&1) + (block>>1)*stride)*8; uint8_t *dest_y = c->scratchpad + offset; - if(s->quarter_sample){ + if (s->c.quarter_sample) { const uint8_t *ref = c->ref[block][0] + (mx4>>2) + (my4>>2)*stride; dxy = ((my4 & 3) << 2) | (mx4 & 3); - if(s->no_rounding) - s->qdsp.put_no_rnd_qpel_pixels_tab[1][dxy](dest_y, ref, stride); - else - s->qdsp.put_qpel_pixels_tab[1][dxy](dest_y, ref, stride); + c->qpel_put[1][dxy](dest_y, ref, stride); }else{ const uint8_t *ref = c->ref[block][0] + (mx4>>1) + (my4>>1)*stride; dxy = ((my4 & 1) << 1) | (mx4 & 1); - if(s->no_rounding) - s->hdsp.put_no_rnd_pixels_tab[1][dxy](dest_y , ref , stride, h); - else - s->hdsp.put_pixels_tab [1][dxy](dest_y , ref , stride, h); + c->hpel_put[1][dxy](dest_y, ref, stride, h); } dmin_sum+= (mv_penalty[mx4-pred_x4] + mv_penalty[my4-pred_y4])*c->mb_penalty_factor; }else dmin_sum+= dmin4; - if(s->quarter_sample){ + if (s->c.quarter_sample) { mx4_sum+= mx4/2; my4_sum+= my4/2; }else{ @@ -686,8 +685,8 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) my4_sum+= my4; } - s->cur_pic.motion_val[0][s->block_index[block]][0] = mx4; - s->cur_pic.motion_val[0][s->block_index[block]][1] = my4; + s->c.cur_pic.motion_val[0][s->c.block_index[block]][0] = mx4; + s->c.cur_pic.motion_val[0][s->c.block_index[block]][1] = my4; if(mx4 != mx || my4 != my) same=0; } @@ -698,7 +697,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) if (c->me_sub_cmp[0] != c->mb_cmp[0]) { dmin_sum += c->mb_cmp[0](s, s->new_pic->data[0] + - s->mb_x * 16 + s->mb_y * 16 * stride, + s->c.mb_x * 16 + s->c.mb_y * 16 * stride, c->scratchpad, stride, 16); } @@ -711,18 +710,13 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) my= ff_h263_round_chroma(my4_sum); dxy = ((my & 1) << 1) | (mx & 1); - offset= (s->mb_x*8 + (mx>>1)) + (s->mb_y*8 + (my>>1))*s->uvlinesize; + offset = (s->c.mb_x*8 + (mx>>1)) + (s->c.mb_y*8 + (my>>1))*s->c.uvlinesize; - if(s->no_rounding){ - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad , s->last_pic.data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad + 8, s->last_pic.data[2] + offset, s->uvlinesize, 8); - }else{ - s->hdsp.put_pixels_tab [1][dxy](c->scratchpad , s->last_pic.data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_pixels_tab [1][dxy](c->scratchpad + 8, s->last_pic.data[2] + offset, s->uvlinesize, 8); - } + c->hpel_put[1][dxy](c->scratchpad , s->c.last_pic.data[1] + offset, s->c.uvlinesize, 8); + c->hpel_put[1][dxy](c->scratchpad + 8, s->c.last_pic.data[2] + offset, s->c.uvlinesize, 8); - dmin_sum += c->mb_cmp[1](s, s->new_pic->data[1] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad, s->uvlinesize, 8); - dmin_sum += c->mb_cmp[1](s, s->new_pic->data[2] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad + 8, s->uvlinesize, 8); + dmin_sum += c->mb_cmp[1](s, s->new_pic->data[1] + s->c.mb_x * 8 + s->c.mb_y * 8 * s->c.uvlinesize, c->scratchpad, s->c.uvlinesize, 8); + dmin_sum += c->mb_cmp[1](s, s->new_pic->data[2] + s->c.mb_x * 8 + s->c.mb_y * 8 * s->c.uvlinesize, c->scratchpad + 8, s->c.uvlinesize, 8); } c->pred_x= mx; @@ -730,7 +724,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) switch(c->avctx->mb_cmp&0xFF){ /*case FF_CMP_SSE: - return dmin_sum+ 32*s->qscale*s->qscale;*/ + return dmin_sum+ 32*s->c.qscale*s->c.qscale;*/ case FF_CMP_RD: return dmin_sum; default: @@ -738,33 +732,34 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) } } -static inline void init_interlaced_ref(MpegEncContext *s, int ref_index){ - MotionEstContext * const c= &s->me; +static inline void init_interlaced_ref(MPVEncContext *const s, int ref_index) +{ + MotionEstContext *const c = &s->me; - c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->linesize; - c->src[1][0] = c->src[0][0] + s->linesize; + c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->c.linesize; + c->src[1][0] = c->src[0][0] + s->c.linesize; if(c->flags & FLAG_CHROMA){ - c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->uvlinesize; - c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->uvlinesize; - c->src[1][1] = c->src[0][1] + s->uvlinesize; - c->src[1][2] = c->src[0][2] + s->uvlinesize; + c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->c.uvlinesize; + c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->c.uvlinesize; + c->src[1][1] = c->src[0][1] + s->c.uvlinesize; + c->src[1][2] = c->src[0][2] + s->c.uvlinesize; } } -static int interlaced_search(MpegEncContext *s, int ref_index, +static int interlaced_search(MPVEncContext *const s, int ref_index, int16_t (*mv_tables[2][2])[2], uint8_t *field_select_tables[2], int mx, int my, int user_field_select) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int size=0; const int h=8; int block; int P[10][2]; const uint8_t * const mv_penalty = c->current_mv_penalty; int same=1; - const int stride= 2*s->linesize; + const int stride = 2*s->c.linesize; int dmin_sum= 0; - const int mot_stride= s->mb_stride; - const int xy= s->mb_x + s->mb_y*mot_stride; + const int mot_stride = s->c.mb_stride; + const int xy = s->c.mb_x + s->c.mb_y*mot_stride; c->ymin>>=1; c->ymax>>=1; @@ -795,7 +790,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, c->pred_x= P_LEFT[0]; c->pred_y= P_LEFT[1]; - if(!s->first_slice_line){ + if (!s->c.first_slice_line) { P_TOP[0] = mv_table[xy - mot_stride][0]; P_TOP[1] = mv_table[xy - mot_stride][1]; P_TOPRIGHT[0] = mv_table[xy - mot_stride + 1][0]; @@ -825,11 +820,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, const uint8_t *ref = c->ref[field_select+ref_index][0] + (mx_i>>1) + (my_i>>1)*stride; dxy = ((my_i & 1) << 1) | (mx_i & 1); - if(s->no_rounding){ - s->hdsp.put_no_rnd_pixels_tab[size][dxy](c->scratchpad, ref , stride, h); - }else{ - s->hdsp.put_pixels_tab [size][dxy](c->scratchpad, ref , stride, h); - } + c->hpel_put[size][dxy](c->scratchpad, ref, stride, h); dmin = c->mb_cmp[size](s, c->src[block][0], c->scratchpad, stride, h); dmin+= (mv_penalty[mx_i-c->pred_x] + mv_penalty[my_i-c->pred_y] + 1)*c->mb_penalty_factor; }else @@ -865,7 +856,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, switch(c->avctx->mb_cmp&0xFF){ /*case FF_CMP_SSE: - return dmin_sum+ 32*s->qscale*s->qscale;*/ + return dmin_sum+ 32*s->c.qscale*s->c.qscale;*/ case FF_CMP_RD: return dmin_sum; default: @@ -898,57 +889,57 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){ } } -void ff_estimate_p_frame_motion(MpegEncContext * s, +void ff_estimate_p_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const uint8_t *pix, *ppix; int sum, mx = 0, my = 0, dmin = 0; int varc; ///< the variance of the block (sum of squared (p[y][x]-average)) int vard; ///< sum of squared differences with the estimated motion vector int P[10][2]; - const int shift= 1+s->quarter_sample; + const int shift = 1 + s->c.quarter_sample; int mb_type=0; - init_ref(c, s->new_pic->data, s->last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); + init_ref(c, s->new_pic->data, s->c.last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); - av_assert0(s->quarter_sample==0 || s->quarter_sample==1); - av_assert0(s->linesize == c->stride); - av_assert0(s->uvlinesize == c->uvstride); + av_assert0(s->c.quarter_sample == 0 || s->c.quarter_sample == 1); + av_assert0(s->c.linesize == c->stride); + av_assert0(s->c.uvlinesize == c->uvstride); - c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); - c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); - c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); + c->sub_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); + c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; /* intra / predictive decision */ pix = c->src[0][0]; - sum = s->mpvencdsp.pix_sum(pix, s->linesize); - varc = s->mpvencdsp.pix_norm1(pix, s->linesize) - + sum = s->mpvencdsp.pix_sum(pix, s->c.linesize); + varc = s->mpvencdsp.pix_norm1(pix, s->c.linesize) - (((unsigned) sum * sum) >> 8) + 500; - s->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; - s->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8; + s->mb_mean[s->c.mb_stride * mb_y + mb_x] = (sum + 128) >> 8; + s->mb_var [s->c.mb_stride * mb_y + mb_x] = (varc + 128) >> 8; c->mb_var_sum_temp += (varc+128)>>8; - if (s->motion_est != FF_ME_ZERO) { - const int mot_stride = s->b8_stride; - const int mot_xy = s->block_index[0]; + if (c->motion_est != FF_ME_ZERO) { + const int mot_stride = s->c.b8_stride; + const int mot_xy = s->c.block_index[0]; - P_LEFT[0] = s->cur_pic.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->cur_pic.motion_val[0][mot_xy - 1][1]; + P_LEFT[0] = s->c.cur_pic.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->c.cur_pic.motion_val[0][mot_xy - 1][1]; if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = c->xmax << shift; - if (!s->first_slice_line) { - P_TOP[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->cur_pic.motion_val[0][mot_xy - mot_stride + 2][0]; - P_TOPRIGHT[1] = s->cur_pic.motion_val[0][mot_xy - mot_stride + 2][1]; + if (!s->c.first_slice_line) { + P_TOP[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + 2][0]; + P_TOPRIGHT[1] = s->c.cur_pic.motion_val[0][mot_xy - mot_stride + 2][1]; if (P_TOP[1] > (c->ymax << shift)) P_TOP[1] = c->ymax << shift; if (P_TOPRIGHT[0] < (c->xmin * (1 << shift))) @@ -959,7 +950,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, P_MEDIAN[0] = mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); P_MEDIAN[1] = mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); - if (s->out_format == FMT_H263) { + if (s->c.out_format == FMT_H263) { c->pred_x = P_MEDIAN[0]; c->pred_y = P_MEDIAN[1]; } else { /* MPEG-1 at least */ @@ -974,21 +965,21 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, } /* At this point (mx,my) are full-pell and the relative displacement */ - ppix = c->ref[0][0] + (my * s->linesize) + mx; + ppix = c->ref[0][0] + (my * s->c.linesize) + mx; - vard = c->sse(NULL, pix, ppix, s->linesize, 16); + vard = c->sse(NULL, pix, ppix, s->c.linesize, 16); - s->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; + s->mc_mb_var[s->c.mb_stride * mb_y + mb_x] = (vard+128)>>8; c->mc_mb_var_sum_temp += (vard+128)>>8; if (c->avctx->mb_decision > FF_MB_DECISION_SIMPLE) { - int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); - int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + int p_score = FFMIN(vard, varc - 500 + (s->lambda2 >> FF_LAMBDA_SHIFT)*100); + int i_score = varc - 500 + (s->lambda2 >> FF_LAMBDA_SHIFT)*20; c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); if (vard*2 + 200*256 > varc && !s->intra_penalty) mb_type|= CANDIDATE_MB_TYPE_INTRA; - if (varc*2 + 200*256 > vard || s->qscale > 24){ + if (varc*2 + 200*256 > vard || s->c.qscale > 24){ // if (varc*2 + 200*256 + 50*(s->lambda2>>FF_LAMBDA_SHIFT) > vard){ mb_type|= CANDIDATE_MB_TYPE_INTER; c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); @@ -999,7 +990,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, mx *= 1 << shift; my *= 1 << shift; } - if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + if ((c->avctx->flags & AV_CODEC_FLAG_4MV) && !c->skip && varc>50<<8 && vard>10<<8){ if(h263_mv4_search(s, mx, my, shift) < INT_MAX) mb_type|=CANDIDATE_MB_TYPE_INTER4V; @@ -1007,9 +998,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, set_p_mv_tables(s, mx, my, 0); }else set_p_mv_tables(s, mx, my, 1); - if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + if ((c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) && !c->skip){ //FIXME varc/d checks - if(interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0) < INT_MAX) + if(interlaced_search(s, 0, s->c.p_field_mv_table, s->p_field_select_table, mx, my, 0) < INT_MAX) mb_type |= CANDIDATE_MB_TYPE_INTER_I; } }else{ @@ -1020,7 +1011,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) dmin= get_mb_score(s, mx, my, 0, 0, 0, 16, 1); - if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + if ((c->avctx->flags & AV_CODEC_FLAG_4MV) && !c->skip && varc>50<<8 && vard>10<<8){ int dmin4= h263_mv4_search(s, mx, my, shift); if(dmin4 < dmin){ @@ -1028,9 +1019,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, dmin=dmin4; } } - if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + if ((c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) && !c->skip){ //FIXME varc/d checks - int dmin_i= interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0); + int dmin_i= interlaced_search(s, 0, s->c.p_field_mv_table, s->p_field_select_table, mx, my, 0); if(dmin_i < dmin){ mb_type = CANDIDATE_MB_TYPE_INTER_I; dmin= dmin_i; @@ -1047,46 +1038,46 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, mean*= 0x01010101; for(i=0; i<16; i++){ - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 0]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 4]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+ 8]) = mean; - *(uint32_t*)(&c->scratchpad[i*s->linesize+12]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 0]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 4]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+ 8]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->c.linesize+12]) = mean; } - intra_score= c->mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16); + intra_score= c->mb_cmp[0](s, c->scratchpad, pix, s->c.linesize, 16); } intra_score += c->mb_penalty_factor*16 + s->intra_penalty; if(intra_score < dmin){ mb_type= CANDIDATE_MB_TYPE_INTRA; - s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup + s->c.cur_pic.mb_type[mb_y*s->c.mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup }else - s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = 0; + s->c.cur_pic.mb_type[mb_y*s->c.mb_stride + mb_x] = 0; { - int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); - int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + int p_score = FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score = varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); } } - s->mb_type[mb_y*s->mb_stride + mb_x]= mb_type; + s->mb_type[mb_y*s->c.mb_stride + mb_x] = mb_type; } -int ff_pre_estimate_p_frame_motion(MpegEncContext * s, +int ff_pre_estimate_p_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int mx, my, dmin; int P[10][2]; - const int shift= 1+s->quarter_sample; - const int xy= mb_x + mb_y*s->mb_stride; - init_ref(c, s->new_pic->data, s->last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); + const int shift = 1 + s->c.quarter_sample; + const int xy = mb_x + mb_y*s->c.mb_stride; + init_ref(c, s->new_pic->data, s->c.last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); - av_assert0(s->quarter_sample==0 || s->quarter_sample==1); + av_assert0(s->c.quarter_sample == 0 || s->c.quarter_sample == 1); - c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp); - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp); + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; @@ -1097,16 +1088,16 @@ int ff_pre_estimate_p_frame_motion(MpegEncContext * s, if(P_LEFT[0] < (c->xmin<xmin<first_slice_line) { + if (s->c.first_slice_line) { c->pred_x= P_LEFT[0]; c->pred_y= P_LEFT[1]; P_TOP[0]= P_TOPRIGHT[0]= P_MEDIAN[0]= P_TOP[1]= P_TOPRIGHT[1]= P_MEDIAN[1]= 0; //FIXME } else { - P_TOP[0] = s->p_mv_table[xy + s->mb_stride ][0]; - P_TOP[1] = s->p_mv_table[xy + s->mb_stride ][1]; - P_TOPRIGHT[0] = s->p_mv_table[xy + s->mb_stride - 1][0]; - P_TOPRIGHT[1] = s->p_mv_table[xy + s->mb_stride - 1][1]; + P_TOP[0] = s->p_mv_table[xy + s->c.mb_stride ][0]; + P_TOP[1] = s->p_mv_table[xy + s->c.mb_stride ][1]; + P_TOPRIGHT[0] = s->p_mv_table[xy + s->c.mb_stride - 1][0]; + P_TOPRIGHT[1] = s->p_mv_table[xy + s->c.mb_stride - 1][1]; if(P_TOP[1] < (c->ymin<ymin< (c->xmax<xmax<ymin<ymin<me; + MotionEstContext *const c = &s->me; int mx = 0, my = 0, dmin = 0; int P[10][2]; - const int shift= 1+s->quarter_sample; - const int mot_stride = s->mb_stride; + const int shift= 1+s->c.quarter_sample; + const int mot_stride = s->c.mb_stride; const int mot_xy = mb_y*mot_stride + mb_x; const uint8_t * const mv_penalty = c->mv_penalty[f_code] + MAX_DMV; int mv_scale; @@ -1142,14 +1133,14 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, get_limits(s, 16*mb_x, 16*mb_y, 1); - if (s->motion_est != FF_ME_ZERO) { + if (c->motion_est != FF_ME_ZERO) { P_LEFT[0] = mv_table[mot_xy - 1][0]; P_LEFT[1] = mv_table[mot_xy - 1][1]; if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = (c->xmax << shift); /* special case for first line */ - if (!s->first_slice_line) { + if (!s->c.first_slice_line) { P_TOP[0] = mv_table[mot_xy - mot_stride ][0]; P_TOP[1] = mv_table[mot_xy - mot_stride ][1]; P_TOPRIGHT[0] = mv_table[mot_xy - mot_stride + 1][0]; @@ -1165,9 +1156,9 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, c->pred_y = P_LEFT[1]; if(mv_table == s->b_forw_mv_table){ - mv_scale= (s->pb_time<<16) / (s->pp_time<c.pb_time<<16) / (s->c.pp_time<pb_time - s->pp_time) * (1 << 16)) / (s->pp_time<c.pb_time - s->c.pp_time) * (1 << 16)) / (s->c.pp_time<p_mv_table, mv_scale, 0, 16); @@ -1178,14 +1169,14 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) dmin= get_mb_score(s, mx, my, 0, ref_index, 0, 16, 1); -// s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; +// s->mb_type[mb_y*s->c.mb_width + mb_x]= mb_type; mv_table[mot_xy][0]= mx; mv_table[mot_xy][1]= my; return dmin; } -static inline int check_bidir_mv(MpegEncContext * s, +static inline int check_bidir_mv(MPVEncContext *const s, int motion_fx, int motion_fy, int motion_bx, int motion_by, int pred_fx, int pred_fy, @@ -1195,7 +1186,7 @@ static inline int check_bidir_mv(MpegEncContext * s, //FIXME optimize? //FIXME better f_code prediction (max mv & distance) //FIXME pointers - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const uint8_t * const mv_penalty_f = c->mv_penalty[s->f_code] + MAX_DMV; // f_code of the prev frame const uint8_t * const mv_penalty_b = c->mv_penalty[s->b_code] + MAX_DMV; // f_code of the prev frame int stride= c->stride; @@ -1208,34 +1199,34 @@ static inline int check_bidir_mv(MpegEncContext * s, const uint8_t *const *ref_data = c->ref[0]; const uint8_t *const *ref2_data = c->ref[2]; - if(s->quarter_sample){ + if(s->c.quarter_sample){ dxy = ((motion_fy & 3) << 2) | (motion_fx & 3); src_x = motion_fx >> 2; src_y = motion_fy >> 2; ptr = ref_data[0] + (src_y * stride) + src_x; - s->qdsp.put_qpel_pixels_tab[0][dxy](dest_y, ptr, stride); + s->c.qdsp.put_qpel_pixels_tab[0][dxy](dest_y, ptr, stride); dxy = ((motion_by & 3) << 2) | (motion_bx & 3); src_x = motion_bx >> 2; src_y = motion_by >> 2; ptr = ref2_data[0] + (src_y * stride) + src_x; - s->qdsp.avg_qpel_pixels_tab[size][dxy](dest_y, ptr, stride); + s->c.qdsp.avg_qpel_pixels_tab[size][dxy](dest_y, ptr, stride); }else{ dxy = ((motion_fy & 1) << 1) | (motion_fx & 1); src_x = motion_fx >> 1; src_y = motion_fy >> 1; ptr = ref_data[0] + (src_y * stride) + src_x; - s->hdsp.put_pixels_tab[size][dxy](dest_y , ptr , stride, h); + s->c.hdsp.put_pixels_tab[size][dxy](dest_y , ptr , stride, h); dxy = ((motion_by & 1) << 1) | (motion_bx & 1); src_x = motion_bx >> 1; src_y = motion_by >> 1; ptr = ref2_data[0] + (src_y * stride) + src_x; - s->hdsp.avg_pixels_tab[size][dxy](dest_y , ptr , stride, h); + s->c.hdsp.avg_pixels_tab[size][dxy](dest_y , ptr , stride, h); } fbmin = (mv_penalty_f[motion_fx-pred_fx] + mv_penalty_f[motion_fy-pred_fy])*c->mb_penalty_factor @@ -1250,10 +1241,10 @@ static inline int check_bidir_mv(MpegEncContext * s, } /* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/ -static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) +static inline int bidir_refine(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; - const int mot_stride = s->mb_stride; + MotionEstContext *const c = &s->me; + const int mot_stride = s->c.mb_stride; const int xy = mb_y *mot_stride + mb_x; int fbmin; int pred_fx= s->b_bidir_forw_mv_table[xy-1][0]; @@ -1284,10 +1275,10 @@ static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) pred_bx, pred_by, 0, 16); - if(s->avctx->bidir_refine){ + if (c->avctx->bidir_refine) { int end; static const uint8_t limittab[5]={0,8,32,64,80}; - const int limit= limittab[s->avctx->bidir_refine]; + const int limit = limittab[c->avctx->bidir_refine]; static const int8_t vect[][4]={ { 0, 0, 0, 1}, { 0, 0, 0,-1}, { 0, 0, 1, 0}, { 0, 0,-1, 0}, { 0, 1, 0, 0}, { 0,-1, 0, 0}, { 1, 0, 0, 0}, {-1, 0, 0, 0}, @@ -1397,16 +1388,16 @@ CHECK_BIDIR(-(a),-(b),-(c),-(d)) return fbmin; } -static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) +static inline int direct_search(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int P[10][2]; - const int mot_stride = s->mb_stride; + const int mot_stride = s->c.mb_stride; const int mot_xy = mb_y*mot_stride + mb_x; - const int shift= 1+s->quarter_sample; + const int shift= 1+s->c.quarter_sample; int dmin, i; - const int time_pp= s->pp_time; - const int time_pb= s->pb_time; + const int time_pp= s->c.pp_time; + const int time_pb= s->c.pb_time; int mx, my, xmin, xmax, ymin, ymax; int16_t (*mv_table)[2]= s->b_direct_mv_table; @@ -1414,18 +1405,18 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) ymin= xmin=(-32)>>shift; ymax= xmax= 31>>shift; - if (IS_8X8(s->next_pic.mb_type[mot_xy])) { - s->mv_type= MV_TYPE_8X8; + if (IS_8X8(s->c.next_pic.mb_type[mot_xy])) { + s->c.mv_type = MV_TYPE_8X8; }else{ - s->mv_type= MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; } for(i=0; i<4; i++){ - int index= s->block_index[i]; + int index= s->c.block_index[i]; int min, max; - c->co_located_mv[i][0] = s->next_pic.motion_val[0][index][0]; - c->co_located_mv[i][1] = s->next_pic.motion_val[0][index][1]; + c->co_located_mv[i][0] = s->c.next_pic.motion_val[0][index][0]; + c->co_located_mv[i][1] = s->c.next_pic.motion_val[0][index][1]; c->direct_basis_mv[i][0]= c->co_located_mv[i][0]*time_pb/time_pp + ((i& 1)<<(shift+3)); c->direct_basis_mv[i][1]= c->co_located_mv[i][1]*time_pb/time_pp + ((i>>1)<<(shift+3)); // c->direct_basis_mv[1][i][0]= c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(shift+3); @@ -1435,17 +1426,17 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) min= FFMIN(c->direct_basis_mv[i][0], c->direct_basis_mv[i][0] - c->co_located_mv[i][0])>>shift; max+= 16*mb_x + 1; // +-1 is for the simpler rounding min+= 16*mb_x - 1; - xmax= FFMIN(xmax, s->width - max); + xmax= FFMIN(xmax, s->c.width - max); xmin= FFMAX(xmin, - 16 - min); max= FFMAX(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; min= FFMIN(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; max+= 16*mb_y + 1; // +-1 is for the simpler rounding min+= 16*mb_y - 1; - ymax= FFMIN(ymax, s->height - max); + ymax= FFMIN(ymax, s->c.height - max); ymin= FFMAX(ymin, - 16 - min); - if(s->mv_type == MV_TYPE_16X16) break; + if(s->c.mv_type == MV_TYPE_16X16) break; } av_assert2(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16); @@ -1470,7 +1461,7 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) P_LEFT[1] = av_clip(mv_table[mot_xy - 1][1], ymin * (1 << shift), ymax << shift); /* special case for first line */ - if (!s->first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped + if (!s->c.first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped P_TOP[0] = av_clip(mv_table[mot_xy - mot_stride ][0], xmin * (1 << shift), xmax << shift); P_TOP[1] = av_clip(mv_table[mot_xy - mot_stride ][1], ymin * (1 << shift), ymax << shift); P_TOPRIGHT[0] = av_clip(mv_table[mot_xy - mot_stride + 1][0], xmin * (1 << shift), xmax << shift); @@ -1499,27 +1490,27 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) return dmin; } -void ff_estimate_b_frame_motion(MpegEncContext * s, +void ff_estimate_b_frame_motion(MPVEncContext *const s, int mb_x, int mb_y) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int fmin, bmin, dmin, fbmin, bimin, fimin; int type=0; - const int xy = mb_y*s->mb_stride + mb_x; - init_ref(c, s->new_pic->data, s->last_pic.data, - s->next_pic.data, 16 * mb_x, 16 * mb_y, 2); + const int xy = mb_y*s->c.mb_stride + mb_x; + init_ref(c, s->new_pic->data, s->c.last_pic.data, + s->c.next_pic.data, 16 * mb_x, 16 * mb_y, 2); get_limits(s, 16*mb_x, 16*mb_y, 1); c->skip=0; - if (s->codec_id == AV_CODEC_ID_MPEG4 && s->next_pic.mbskip_table[xy]) { + if (s->c.codec_id == AV_CODEC_ID_MPEG4 && s->c.next_pic.mbskip_table[xy]) { int score= direct_search(s, mb_x, mb_y); //FIXME just check 0,0 score= ((unsigned)(score*score + 128*256))>>16; c->mc_mb_var_sum_temp += score; - s->mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE - s->mb_type[mb_y*s->mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; + s->mc_mb_var[mb_y*s->c.mb_stride + mb_x] = score; //FIXME use SSE + s->mb_type[mb_y*s->c.mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; return; } @@ -1528,7 +1519,7 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); - if (s->codec_id == AV_CODEC_ID_MPEG4) + if (s->c.codec_id == AV_CODEC_ID_MPEG4) dmin= direct_search(s, mb_x, mb_y); else dmin= INT_MAX; @@ -1541,20 +1532,20 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, c->skip=0; bmin = estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, 2, s->b_code) + 2 * c->mb_penalty_factor; - ff_dlog(s, " %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); + ff_dlog(c->avctx, " %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); c->skip=0; fbmin= bidir_refine(s, mb_x, mb_y) + c->mb_penalty_factor; - ff_dlog(s, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); + ff_dlog(c->avctx, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (c->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { //FIXME mb type penalty c->skip=0; - c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[s->f_code] + MAX_DMV; fimin= interlaced_search(s, 0, s->b_field_mv_table[0], s->b_field_select_table[0], s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1], 0); - c->current_mv_penalty= c->mv_penalty[s->b_code] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[s->b_code] + MAX_DMV; bimin= interlaced_search(s, 2, s->b_field_mv_table[1], s->b_field_select_table[1], s->b_back_mv_table[xy][0], s->b_back_mv_table[xy][1], 0); @@ -1588,7 +1579,7 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, score= ((unsigned)(score*score + 128*256))>>16; c->mc_mb_var_sum_temp += score; - s->mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE + s->mc_mb_var[mb_y*s->c.mb_stride + mb_x] = score; //FIXME use SSE } if(c->avctx->mb_decision > FF_MB_DECISION_SIMPLE){ @@ -1602,40 +1593,43 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, } //FIXME something smarter if(dmin>256*256*16) type&= ~CANDIDATE_MB_TYPE_DIRECT; //do not try direct mode if it is invalid for this MB - if (s->codec_id == AV_CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && + if (s->c.codec_id == AV_CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && s->mpv_flags & FF_MPV_FLAG_MV0 && *(uint32_t*)s->b_direct_mv_table[xy]) type |= CANDIDATE_MB_TYPE_DIRECT0; } - s->mb_type[mb_y*s->mb_stride + mb_x]= type; + s->mb_type[mb_y*s->c.mb_stride + mb_x]= type; } /* find best f_code for ME which do unlimited searches */ -int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type) +int ff_get_best_fcode(MPVMainEncContext *const m, const int16_t (*mv_table)[2], int type) { - if (s->motion_est != FF_ME_ZERO) { + MPVEncContext *const s = &m->s; + MotionEstContext *const c = &s->me; + + if (c->motion_est != FF_ME_ZERO) { int score[8]; - int i, y, range= s->avctx->me_range ? s->avctx->me_range : (INT_MAX/2); - const uint8_t * fcode_tab = s->fcode_tab; + int i, range = c->avctx->me_range ? c->avctx->me_range : (INT_MAX/2); + const uint8_t * fcode_tab = m->fcode_tab; int best_fcode=-1; int best_score=-10000000; - if (s->msmpeg4_version != MSMP4_UNUSED) + if (s->c.msmpeg4_version != MSMP4_UNUSED) range= FFMIN(range, 16); - else if(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) + else if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && + c->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) range= FFMIN(range, 256); - for(i=0; i<8; i++) score[i]= s->mb_num*(8-i); + for(i=0; i<8; i++) score[i]= s->c.mb_num*(8-i); - for(y=0; ymb_height; y++){ + for (int y = 0; y < s->c.mb_height; y++) { int x; - int xy= y*s->mb_stride; - for(x=0; xmb_width; x++, xy++){ + int xy= y*s->c.mb_stride; + for(x=0; xc.mb_width; x++, xy++){ if(s->mb_type[xy] & type){ int mx= mv_table[xy][0]; int my= mv_table[xy][1]; - int fcode= FFMAX(fcode_tab[mx + MAX_MV], - fcode_tab[my + MAX_MV]); + int fcode = FFMAX(fcode_tab[mx], fcode_tab[my]); int j; if (mx >= range || mx < -range || @@ -1643,7 +1637,7 @@ int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type continue; for(j=0; jpict_type == AV_PICTURE_TYPE_B || + if (s->c.pict_type == AV_PICTURE_TYPE_B || s->mc_mb_var[xy] < s->mb_var[xy]) score[j]-= 170; } @@ -1664,42 +1658,42 @@ int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type } } -void ff_fix_long_p_mvs(MpegEncContext * s, int type) +void ff_fix_long_p_mvs(MPVEncContext *const s, int type) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int f_code= s->f_code; int y, range; - av_assert0(s->pict_type==AV_PICTURE_TYPE_P); + av_assert0(s->c.pict_type == AV_PICTURE_TYPE_P); - range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); + range = (((s->c.out_format == FMT_MPEG1 || s->c.msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); - av_assert0(range <= 16 || s->msmpeg4_version == MSMP4_UNUSED); - av_assert0(range <=256 || !(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL)); + av_assert0(range <= 16 || s->c.msmpeg4_version == MSMP4_UNUSED); + av_assert0(range <=256 || !(s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && c->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL)); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; - if (s->avctx->flags & AV_CODEC_FLAG_4MV) { - const int wrap= s->b8_stride; + if (c->avctx->flags & AV_CODEC_FLAG_4MV) { + const int wrap= s->c.b8_stride; /* clip / convert to intra 8x8 type MVs */ - for(y=0; ymb_height; y++){ + for(y=0; yc.mb_height; y++){ int xy= y*2*wrap; - int i= y*s->mb_stride; + int i= y*s->c.mb_stride; int x; - for(x=0; xmb_width; x++){ + for(x=0; xc.mb_width; x++){ if(s->mb_type[i]&CANDIDATE_MB_TYPE_INTER4V){ int block; for(block=0; block<4; block++){ int off= (block& 1) + (block>>1)*wrap; - int mx = s->cur_pic.motion_val[0][ xy + off ][0]; - int my = s->cur_pic.motion_val[0][ xy + off ][1]; + int mx = s->c.cur_pic.motion_val[0][ xy + off ][0]; + int my = s->c.cur_pic.motion_val[0][ xy + off ][1]; if( mx >=range || mx <-range || my >=range || my <-range){ s->mb_type[i] &= ~CANDIDATE_MB_TYPE_INTER4V; s->mb_type[i] |= type; - s->cur_pic.mb_type[i] = type; + s->c.cur_pic.mb_type[i] = type; } } } @@ -1713,14 +1707,14 @@ void ff_fix_long_p_mvs(MpegEncContext * s, int type) /** * @param truncate 1 for truncation, 0 for using intra */ -void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_select, +void ff_fix_long_mvs(MPVEncContext *const s, uint8_t *field_select_table, int field_select, int16_t (*mv_table)[2], int f_code, int type, int truncate) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int y, h_range, v_range; // RAL: 8 in MPEG-1, 16 in MPEG-4 - int range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); + int range = (((s->c.out_format == FMT_MPEG1 || s->c.msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; @@ -1728,10 +1722,10 @@ void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_ v_range= field_select_table ? range>>1 : range; /* clip / convert to intra 16x16 type MVs */ - for(y=0; ymb_height; y++){ + for(y=0; yc.mb_height; y++){ int x; - int xy= y*s->mb_stride; - for(x=0; xmb_width; x++){ + int xy= y*s->c.mb_stride; + for(x=0; xc.mb_width; x++){ if (s->mb_type[xy] & type){ // RAL: "type" test added... if (!field_select_table || field_select_table[xy] == field_select) { if( mv_table[xy][0] >=h_range || mv_table[xy][0] <-h_range diff --git a/libavcodec/motion_est.h b/libavcodec/motion_est.h index 12f7cd43ab..7e57a3a79b 100644 --- a/libavcodec/motion_est.h +++ b/libavcodec/motion_est.h @@ -28,7 +28,8 @@ #include "me_cmp.h" #include "qpeldsp.h" -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; +typedef struct MPVMainEncContext MPVMainEncContext; #if ARCH_IA64 // Limit static arrays to avoid gcc failing "short data segment overflowed" #define MAX_MV 1024 @@ -47,14 +48,13 @@ struct MpegEncContext; */ typedef struct MotionEstContext { AVCodecContext *avctx; + int motion_est; ///< ME algorithm int skip; ///< set if ME is skipped for the current MB int co_located_mv[4][2]; ///< mv from last P-frame for direct mode ME int direct_basis_mv[4][2]; uint8_t *scratchpad; /**< data area for the ME algo, so that * the ME does not need to malloc/free. */ uint8_t *temp; - uint32_t *map; ///< map to avoid duplicate evaluations - uint32_t *score_map; ///< map to store the scores unsigned map_generation; int pre_penalty_factor; int penalty_factor; /**< an estimate of the bits required to @@ -69,6 +69,7 @@ typedef struct MotionEstContext { int mb_flags; int pre_pass; ///< = 1 for the pre pass int dia_size; + int unrestricted_mv; ///< mv can point outside of the coded picture int xmin; int xmax; int ymin; @@ -98,21 +99,14 @@ typedef struct MotionEstContext { qpel_mc_func(*qpel_avg)[16]; const uint8_t (*mv_penalty)[MAX_DMV * 2 + 1]; ///< bit amount needed to encode a MV const uint8_t *current_mv_penalty; - int (*sub_motion_search)(struct MpegEncContext *s, + int (*sub_motion_search)(MPVEncContext *s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h); -} MotionEstContext; -static inline int ff_h263_round_chroma(int x) -{ - //FIXME static or not? - static const uint8_t h263_chroma_roundtab[16] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - }; - return h263_chroma_roundtab[x & 0xf] + (x >> 3); -} + uint32_t map[ME_MAP_SIZE]; ///< map to avoid duplicate evaluations + uint32_t score_map[ME_MAP_SIZE];///< map to store the scores +} MotionEstContext; /** * Performs one-time initialization of the MotionEstContext. @@ -120,27 +114,27 @@ static inline int ff_h263_round_chroma(int x) int ff_me_init(MotionEstContext *c, struct AVCodecContext *avctx, const struct MECmpContext *mecc, int mpvenc); -void ff_me_init_pic(struct MpegEncContext *s); +void ff_me_init_pic(MPVEncContext *s); -void ff_estimate_p_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); -void ff_estimate_b_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); +void ff_estimate_p_frame_motion(MPVEncContext *s, int mb_x, int mb_y); +void ff_estimate_b_frame_motion(MPVEncContext *s, int mb_x, int mb_y); -int ff_pre_estimate_p_frame_motion(struct MpegEncContext *s, +int ff_pre_estimate_p_frame_motion(MPVEncContext *s, int mb_x, int mb_y); -int ff_epzs_motion_search(struct MpegEncContext *s, int *mx_ptr, int *my_ptr, +int ff_epzs_motion_search(MPVEncContext *s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, int size, int h); -int ff_get_mb_score(struct MpegEncContext *s, int mx, int my, int src_index, +int ff_get_mb_score(MPVEncContext *s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate); -int ff_get_best_fcode(struct MpegEncContext *s, +int ff_get_best_fcode(MPVMainEncContext *m, const int16_t (*mv_table)[2], int type); -void ff_fix_long_p_mvs(struct MpegEncContext *s, int type); -void ff_fix_long_mvs(struct MpegEncContext *s, uint8_t *field_select_table, +void ff_fix_long_p_mvs(MPVEncContext *s, int type); +void ff_fix_long_mvs(MPVEncContext *s, uint8_t *field_select_table, int field_select, int16_t (*mv_table)[2], int f_code, int type, int truncate); diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c index b2701aa32e..aa669e0ee7 100644 --- a/libavcodec/motion_est_template.c +++ b/libavcodec/motion_est_template.c @@ -25,7 +25,7 @@ */ #include "libavutil/qsort.h" -#include "mpegvideo.h" +#include "mpegvideoenc.h" //Let us hope gcc will remove the unused vars ...(gcc 3.2.2 seems to do it ...) #define LOAD_COMMON\ @@ -47,12 +47,12 @@ COPY3_IF_LT(dmin, d, bx, hx, by, hy)\ } -static int hpel_motion_search(MpegEncContext * s, +static int hpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int mx = *mx_ptr; const int my = *my_ptr; const int penalty_factor= c->sub_penalty_factor; @@ -152,7 +152,7 @@ static int hpel_motion_search(MpegEncContext * s, return dmin; } -static int no_sub_motion_search(MpegEncContext * s, +static int no_sub_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) @@ -162,11 +162,11 @@ static int no_sub_motion_search(MpegEncContext * s, return dmin; } -static inline int get_mb_score(MpegEncContext *s, int mx, int my, +static inline int get_mb_score(MPVEncContext *const s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int penalty_factor= c->mb_penalty_factor; const int flags= c->mb_flags; const int qpel= flags & FLAG_QPEL; @@ -189,7 +189,7 @@ static inline int get_mb_score(MpegEncContext *s, int mx, int my, return d; } -int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index, +int ff_get_mb_score(MPVEncContext *const s, int mx, int my, int src_index, int ref_index, int size, int h, int add_rate) { return get_mb_score(s, mx, my, src_index, ref_index, size, h, add_rate); @@ -204,12 +204,12 @@ int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index, COPY3_IF_LT(dmin, d, bx, hx, by, hy)\ } -static int qpel_motion_search(MpegEncContext * s, +static int qpel_motion_search(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; const int mx = *mx_ptr; const int my = *my_ptr; const int penalty_factor= c->sub_penalty_factor; @@ -403,21 +403,21 @@ static int qpel_motion_search(MpegEncContext * s, } #define check(x,y,S,v)\ -if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\ -if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\ -if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\ -if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\ +if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->c.mb_x, s->c.mb_y);\ +if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->c.mb_x, s->c.mb_y);\ #define LOAD_COMMON2\ uint32_t *map= c->map;\ const int qpel= flags&FLAG_QPEL;\ const int shift= 1+qpel;\ -static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, +static av_always_inline int small_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int next_dir=-1; LOAD_COMMON @@ -454,11 +454,11 @@ static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, } } -static int funny_diamond_search(MpegEncContext * s, int *best, int dmin, +static int funny_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int dia_size; LOAD_COMMON @@ -496,11 +496,11 @@ static int funny_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int hex_search(MpegEncContext * s, int *best, int dmin, +static int hex_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags, int dia_size) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -530,11 +530,11 @@ static int hex_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int l2s_dia_search(MpegEncContext * s, int *best, int dmin, +static int l2s_dia_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -568,11 +568,11 @@ static int l2s_dia_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int umh_search(MpegEncContext * s, int *best, int dmin, +static int umh_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -615,11 +615,11 @@ static int umh_search(MpegEncContext * s, int *best, int dmin, return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, 2); } -static int full_search(MpegEncContext * s, int *best, int dmin, +static int full_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON LOAD_COMMON2 @@ -678,11 +678,11 @@ static int full_search(MpegEncContext * s, int *best, int dmin, } #define MAX_SAB_SIZE ME_MAP_SIZE -static int sab_diamond_search(MpegEncContext * s, int *best, int dmin, +static int sab_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; Minima minima[MAX_SAB_SIZE]; const int minima_count= FFABS(c->dia_size); @@ -768,11 +768,11 @@ static int sab_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static int var_diamond_search(MpegEncContext * s, int *best, int dmin, +static int var_diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; me_cmp_func cmpf, chroma_cmpf; int dia_size; LOAD_COMMON @@ -829,10 +829,10 @@ static int var_diamond_search(MpegEncContext * s, int *best, int dmin, return dmin; } -static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dmin, +static av_always_inline int diamond_search(MPVEncContext *const s, int *best, int dmin, int src_index, int ref_index, const int penalty_factor, int size, int h, int flags){ - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; if(c->dia_size==-1) return funny_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags); else if(c->dia_size<-1) @@ -857,11 +857,11 @@ static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dm it takes fewer iterations. And it increases the chance that we find the optimal mv. */ -static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int *mx_ptr, int *my_ptr, +static av_always_inline int epzs_motion_search_internal(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, int flags, int size, int h) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int best[2]={0, 0}; /**< x and y coordinates of the best motion vector. i.e. the difference between the position of the block currently being encoded and the position of @@ -871,8 +871,8 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int corresponding to the mv stored in best[]. */ unsigned map_generation; int penalty_factor; - const int ref_mv_stride= s->mb_stride; //pass as arg FIXME - const int ref_mv_xy = s->mb_x + s->mb_y * ref_mv_stride; // add to last_mv before passing FIXME + const int ref_mv_stride= s->c.mb_stride; //pass as arg FIXME + const int ref_mv_xy = s->c.mb_x + s->c.mb_y * ref_mv_stride; // add to last_mv before passing FIXME me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON @@ -896,17 +896,17 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int score_map[0]= dmin; //FIXME precalc first term below? - if ((s->pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || + if ((s->c.pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || s->mpv_flags & FF_MPV_FLAG_MV0) dmin += (mv_penalty[pred_x] + mv_penalty[pred_y])*penalty_factor; /* first line */ - if (s->first_slice_line) { + if (s->c.first_slice_line) { CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) }else{ - if(dmin<((h*h*s->avctx->mv0_threshold)>>8) + if (dmin < ((h * h * c->avctx->mv0_threshold) >> 8) && ( P_LEFT[0] |P_LEFT[1] |P_TOP[0] |P_TOP[1] |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){ @@ -930,13 +930,13 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int if(c->pre_pass){ CHECK_CLIPPED_MV((last_mv[ref_mv_xy-1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy-1][1]*ref_mv_scale + (1<<15))>>16) - if(!s->first_slice_line) + if(!s->c.first_slice_line) CHECK_CLIPPED_MV((last_mv[ref_mv_xy-ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy-ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) }else{ CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16) - if(s->mb_y+1end_mb_y) //FIXME replace at least with last_slice_line + if(s->c.mb_y+1c.end_mb_y) //FIXME replace at least with last_slice_line CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) } @@ -944,10 +944,10 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int if(c->avctx->last_predictor_count){ const int count= c->avctx->last_predictor_count; - const int xstart= FFMAX(0, s->mb_x - count); - const int ystart= FFMAX(0, s->mb_y - count); - const int xend= FFMIN(s->mb_width , s->mb_x + count + 1); - const int yend= FFMIN(s->mb_height, s->mb_y + count + 1); + const int xstart= FFMAX(0, s->c.mb_x - count); + const int ystart= FFMAX(0, s->c.mb_y - count); + const int xend= FFMIN(s->c.mb_width , s->c.mb_x + count + 1); + const int yend= FFMIN(s->c.mb_height, s->c.mb_y + count + 1); int mb_y; for(mb_y=ystart; mb_yme; + MotionEstContext *const c = &s->me; //FIXME convert other functions in the same way if faster if(c->flags==0 && h==16 && size==0){ return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, 0, 0, 16); @@ -990,19 +990,19 @@ int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr, } } -static int epzs_motion_search2(MpegEncContext * s, +static int epzs_motion_search2(MPVEncContext *const s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, const int16_t (*last_mv)[2], int ref_mv_scale, const int size) { - MotionEstContext * const c= &s->me; + MotionEstContext *const c = &s->me; int best[2]={0, 0}; int d, dmin; unsigned map_generation; const int penalty_factor= c->penalty_factor; const int h=8; - const int ref_mv_stride= s->mb_stride; - const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride; + const int ref_mv_stride= s->c.mb_stride; + const int ref_mv_xy= s->c.mb_x + s->c.mb_y *ref_mv_stride; me_cmp_func cmpf, chroma_cmpf; LOAD_COMMON int flags= c->flags; @@ -1016,7 +1016,7 @@ static int epzs_motion_search2(MpegEncContext * s, dmin = 1000000; /* first line */ - if (s->first_slice_line) { + if (s->c.first_slice_line) { CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) @@ -1034,7 +1034,7 @@ static int epzs_motion_search2(MpegEncContext * s, if(dmin>64*4){ CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16) - if(s->mb_y+1end_mb_y) //FIXME replace at least with last_slice_line + if(s->c.mb_y+1c.end_mb_y) //FIXME replace at least with last_slice_line CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) } diff --git a/libavcodec/motionpixels.c b/libavcodec/motionpixels.c index 287f35f305..e5c3daece6 100644 --- a/libavcodec/motionpixels.c +++ b/libavcodec/motionpixels.c @@ -70,7 +70,6 @@ static av_cold int mp_decode_end(AVCodecContext *avctx) static av_cold int mp_decode_init(AVCodecContext *avctx) { - av_unused static AVOnce init_static_once = AV_ONCE_INIT; MotionPixelsContext *mp = avctx->priv_data; int w4 = (avctx->width + 3) & ~3; int h4 = (avctx->height + 3) & ~3; @@ -95,6 +94,7 @@ static av_cold int mp_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); #if !CONFIG_HARDCODED_TABLES + static AVOnce init_static_once = AV_ONCE_INIT; ff_thread_once(&init_static_once, motionpixels_tableinit); #endif diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c index f799252bf2..fe04514e16 100644 --- a/libavcodec/movtextdec.c +++ b/libavcodec/movtextdec.c @@ -443,7 +443,7 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, return 0; } -static int mov_text_init(AVCodecContext *avctx) { +static av_cold int mov_text_init(AVCodecContext *avctx) { /* * TODO: Handle the default text style. * NB: Most players ignore styles completely, with the result that @@ -561,7 +561,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, return avpkt->size; } -static int mov_text_decode_close(AVCodecContext *avctx) +static av_cold int mov_text_decode_close(AVCodecContext *avctx) { MovTextContext *m = avctx->priv_data; mov_text_cleanup_ftab(m); @@ -569,7 +569,7 @@ static int mov_text_decode_close(AVCodecContext *avctx) return 0; } -static void mov_text_flush(AVCodecContext *avctx) +static av_cold void mov_text_flush(AVCodecContext *avctx) { MovTextContext *m = avctx->priv_data; if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c index fd8c7dc9f7..b78dadfc07 100644 --- a/libavcodec/movtextenc.c +++ b/libavcodec/movtextenc.c @@ -259,7 +259,7 @@ static int encode_sample_description(AVCodecContext *avctx) // Build font table // We can't build a complete font table since that would require // scanning all dialogs first. But we can at least fill in what - // is avaiable in the ASS header + // is available in the ASS header if (style && ass->styles_count) { // Find unique font names if (style->font_name) { diff --git a/libavcodec/mpc7.c b/libavcodec/mpc7.c index f1ce4075cd..83cef60914 100644 --- a/libavcodec/mpc7.c +++ b/libavcodec/mpc7.c @@ -323,6 +323,5 @@ const FFCodec ff_mpc7_decoder = { FF_CODEC_DECODE_CB(mpc7_decode_frame), .flush = mpc7_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/mpc8.c b/libavcodec/mpc8.c index 2785259119..df23ef3701 100644 --- a/libavcodec/mpc8.c +++ b/libavcodec/mpc8.c @@ -155,7 +155,13 @@ static av_cold int mpc8_decode_init(AVCodecContext * avctx) init_get_bits(&gb, avctx->extradata, 16); - skip_bits(&gb, 3);//sample rate + uint8_t sample_rate_idx = get_bits(&gb, 3); + static const int sample_rates[] = { 44100, 48000, 37800, 32000 }; + if (sample_rate_idx >= FF_ARRAY_ELEMS(sample_rates)) { + av_log(avctx, AV_LOG_ERROR, "invalid sample rate index (%u)\n", sample_rate_idx); + return AVERROR_INVALIDDATA; + } + avctx->sample_rate = sample_rates[sample_rate_idx]; c->maxbands = get_bits(&gb, 5) + 1; if (c->maxbands >= BANDS) { av_log(avctx,AV_LOG_ERROR, "maxbands %d too high\n", c->maxbands); @@ -393,6 +399,5 @@ const FFCodec ff_mpc8_decoder = { FF_CODEC_DECODE_CB(mpc8_decode_frame), .flush = mpc8_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 444ea83f3c..62a77b6806 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -28,7 +28,6 @@ #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/attributes.h" -#include "libavutil/avassert.h" #include "libavutil/thread.h" #include "mpegvideo.h" @@ -90,15 +89,13 @@ av_cold void ff_init_2d_vlc_rl(const uint16_t table_vlc[][2], RL_VLC_ELEM rl_vlc const int8_t table_run[], const uint8_t table_level[], int n, unsigned static_size, int flags) { - int i; - VLCElem table[680] = { 0 }; - VLC vlc = { .table = table, .table_allocated = static_size }; - av_assert0(static_size <= FF_ARRAY_ELEMS(table)); - vlc_init(&vlc, TEX_VLC_BITS, n + 2, &table_vlc[0][1], 4, 2, &table_vlc[0][0], 4, 2, VLC_INIT_USE_STATIC | flags); + ff_vlc_init_table_sparse(rl_vlc, static_size, TEX_VLC_BITS, n + 2, + &table_vlc[0][1], 4, 2, &table_vlc[0][0], 4, 2, + NULL, 0, 0, flags); - for (i = 0; i < vlc.table_size; i++) { - int code = vlc.table[i].sym; - int len = vlc.table[i].len; + for (unsigned i = 0; i < static_size; i++) { + int idx = rl_vlc[i].sym; + int len = rl_vlc[i].len; int level, run; if (len == 0) { // illegal code @@ -106,20 +103,20 @@ av_cold void ff_init_2d_vlc_rl(const uint16_t table_vlc[][2], RL_VLC_ELEM rl_vlc level = MAX_LEVEL; } else if (len<0) { //more bits needed run = 0; - level = code; + level = idx; } else { - if (code == n) { //esc + if (idx == n) { //esc run = 65; level = 0; - } else if (code == n + 1) { //eob + } else if (idx == n + 1) { //eob run = 0; level = 127; } else { - run = table_run [code] + 1; - level = table_level[code]; + run = table_run [idx] + 1; + level = table_level[idx]; } } - rl_vlc[i].len = len; + rl_vlc[i].len8 = len; rl_vlc[i].level = level; rl_vlc[i].run = run; } @@ -279,7 +276,7 @@ end: } if (i > MAX_INDEX) - i = AVERROR_INVALIDDATA; + return AVERROR_INVALIDDATA; - return i; + return 0; } diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 4f784611de..3ea8d02e1b 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -29,6 +29,7 @@ #define UNCHECKED_BITSTREAM_READER 1 #include +#include #include "libavutil/attributes.h" #include "libavutil/emms.h" @@ -43,10 +44,10 @@ #include "codec_internal.h" #include "decode.h" #include "error_resilience.h" +#include "get_bits.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "idctdsp.h" -#include "internal.h" #include "mpeg_er.h" #include "mpeg12.h" #include "mpeg12codecs.h" @@ -58,7 +59,6 @@ #include "mpegvideodec.h" #include "profiles.h" #include "startcode.h" -#include "thread.h" #define A53_MAX_CC_COUNT 2000 @@ -66,12 +66,19 @@ enum Mpeg2ClosedCaptionsFormat { CC_FORMAT_AUTO, CC_FORMAT_A53_PART4, CC_FORMAT_SCTE20, - CC_FORMAT_DVD + CC_FORMAT_DVD, + CC_FORMAT_DISH }; +typedef struct Mpeg12SliceContext { + MPVContext c; + GetBitContext gb; + + DECLARE_ALIGNED_32(int16_t, block)[12][64]; +} Mpeg12SliceContext; + typedef struct Mpeg1Context { - MpegEncContext mpeg_enc_ctx; - int repeat_field; /* true if we must repeat the field */ + Mpeg12SliceContext slice; AVPanScan pan_scan; /* some temporary storage for the panscan */ enum AVStereo3DType stereo3d_type; int has_stereo3d; @@ -81,8 +88,7 @@ typedef struct Mpeg1Context { int has_afd; int slice_count; unsigned aspect_ratio_info; - AVRational save_aspect; - int save_width, save_height, save_progressive_seq; + int save_progressive_seq, save_chroma_format; AVRational frame_rate_ext; /* MPEG-2 specific framerate modificator */ unsigned frame_rate_index; int sync; /* Did we reach a sync point like a GOP/SEQ/KEYFrame? */ @@ -90,11 +96,13 @@ typedef struct Mpeg1Context { int tmpgexs; int first_slice; int extradata_decoded; + int vbv_delay; + int64_t bit_rate; int64_t timecode_frame_start; /*< GOP timecode frame start number, in non drop frame format */ } Mpeg1Context; /* as H.263, but only 17 codes */ -static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) +static int mpeg_decode_motion(Mpeg12SliceContext *const s, int fcode, int pred) { int code, sign, val, shift; @@ -124,19 +132,19 @@ static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) #define check_scantable_index(ctx, x) \ do { \ if ((x) > MAX_INDEX) { \ - av_log(ctx->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", \ - ctx->mb_x, ctx->mb_y); \ + av_log(ctx->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", \ + ctx->c.mb_x, ctx->c.mb_y); \ return AVERROR_INVALIDDATA; \ } \ } while (0) -static inline int mpeg1_decode_block_inter(MpegEncContext *s, +static inline int mpeg1_decode_block_inter(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, i, j, run; - const uint8_t *const scantable = s->intra_scantable.permutated; - const uint16_t *quant_matrix = s->inter_matrix; - const int qscale = s->qscale; + const uint8_t *const scantable = s->c.intra_scantable.permutated; + const uint16_t *quant_matrix = s->c.inter_matrix; + const int qscale = s->c.qscale; { OPEN_READER(re, &s->gb); @@ -210,17 +218,17 @@ end: check_scantable_index(s, i); - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; return 0; } -static inline int mpeg2_decode_block_non_intra(MpegEncContext *s, +static inline int mpeg2_decode_block_non_intra(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, i, j, run; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->c.intra_scantable.permutated; const uint16_t *quant_matrix; - const int qscale = s->qscale; + const int qscale = s->c.qscale; int mismatch; mismatch = 1; @@ -229,9 +237,9 @@ static inline int mpeg2_decode_block_non_intra(MpegEncContext *s, OPEN_READER(re, &s->gb); i = -1; if (n < 4) - quant_matrix = s->inter_matrix; + quant_matrix = s->c.inter_matrix; else - quant_matrix = s->chroma_inter_matrix; + quant_matrix = s->c.chroma_inter_matrix; // Special case for first coefficient, no need to add second VLC table. UPDATE_CACHE(re, &s->gb); @@ -295,38 +303,38 @@ end: check_scantable_index(s, i); - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; return 0; } -static inline int mpeg2_decode_block_intra(MpegEncContext *s, +static inline int mpeg2_decode_block_intra(Mpeg12SliceContext *const s, int16_t *block, int n) { int level, dc, diff, i, j, run; int component; const RL_VLC_ELEM *rl_vlc; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->c.intra_scantable.permutated; const uint16_t *quant_matrix; - const int qscale = s->qscale; + const int qscale = s->c.qscale; int mismatch; /* DC coefficient */ if (n < 4) { - quant_matrix = s->intra_matrix; + quant_matrix = s->c.intra_matrix; component = 0; } else { - quant_matrix = s->chroma_intra_matrix; + quant_matrix = s->c.chroma_intra_matrix; component = (n & 1) + 1; } diff = decode_dc(&s->gb, component); - dc = s->last_dc[component]; + dc = s->c.last_dc[component]; dc += diff; - s->last_dc[component] = dc; - block[0] = dc * (1 << (3 - s->intra_dc_precision)); - ff_tlog(s->avctx, "dc=%d\n", block[0]); + s->c.last_dc[component] = dc; + block[0] = dc * (1 << (3 - s->c.intra_dc_precision)); + ff_tlog(s->c.avctx, "dc=%d\n", block[0]); mismatch = block[0] ^ 1; i = 0; - if (s->intra_vlc_format) + if (s->c.intra_vlc_format) rl_vlc = ff_mpeg2_rl_vlc; else rl_vlc = ff_mpeg1_rl_vlc; @@ -377,14 +385,10 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, check_scantable_index(s, i); - s->block_last_index[n] = i; return 0; } -/******************************************/ -/* decoding */ - -static inline int get_dmv(MpegEncContext *s) +static inline int get_dmv(Mpeg12SliceContext *const s) { if (get_bits1(&s->gb)) return 1 - (get_bits1(&s->gb) << 1); @@ -398,51 +402,51 @@ static inline int get_dmv(MpegEncContext *s) #define MT_16X8 2 #define MT_DMV 3 -static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) +static int mpeg_decode_mb(Mpeg12SliceContext *const s, int *mb_skip_run) { int i, j, k, cbp, val, mb_type, motion_type; - const int mb_block_count = 4 + (1 << s->chroma_format); + const int mb_block_count = 4 + (1 << s->c.chroma_format); int ret; - ff_tlog(s->avctx, "decode_mb: x=%d y=%d\n", s->mb_x, s->mb_y); + ff_tlog(s->c.avctx, "decode_mb: x=%d y=%d\n", s->c.mb_x, s->c.mb_y); - av_assert2(s->mb_skipped == 0); + av_assert2(s->c.mb_skipped == 0); - if (s->mb_skip_run-- != 0) { - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->mb_skipped = 1; - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + if ((*mb_skip_run)-- != 0) { + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.mb_skipped = 1; + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int mb_type; - if (s->mb_x) - mb_type = s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1]; + if (s->c.mb_x) + mb_type = s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride - 1]; else // FIXME not sure if this is allowed in MPEG at all - mb_type = s->cur_pic.mb_type[s->mb_width + (s->mb_y - 1) * s->mb_stride - 1]; + mb_type = s->c.cur_pic.mb_type[s->c.mb_width + (s->c.mb_y - 1) * s->c.mb_stride - 1]; if (IS_INTRA(mb_type)) { - av_log(s->avctx, AV_LOG_ERROR, "skip with previntra\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "skip with previntra\n"); return AVERROR_INVALIDDATA; } - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = mb_type | MB_TYPE_SKIP; - if ((s->mv[0][0][0] | s->mv[0][0][1] | s->mv[1][0][0] | s->mv[1][0][1]) == 0) - s->mb_skipped = 1; + if ((s->c.mv[0][0][0] | s->c.mv[0][0][1] | s->c.mv[1][0][0] | s->c.mv[1][0][1]) == 0) + s->c.mb_skipped = 1; } return 0; } - switch (s->pict_type) { + switch (s->c.pict_type) { default: case AV_PICTURE_TYPE_I: if (get_bits1(&s->gb) == 0) { if (get_bits1(&s->gb) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(s->c.avctx, AV_LOG_ERROR, "Invalid mb type in I-frame at %d %d\n", - s->mb_x, s->mb_y); + s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } mb_type = MB_TYPE_QUANT | MB_TYPE_INTRA; @@ -453,159 +457,157 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) case AV_PICTURE_TYPE_P: mb_type = get_vlc2(&s->gb, ff_mb_ptype_vlc, MB_PTYPE_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Invalid mb type in P-frame at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "Invalid mb type in P-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } break; case AV_PICTURE_TYPE_B: mb_type = get_vlc2(&s->gb, ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Invalid mb type in B-frame at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "Invalid mb type in B-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } break; } - ff_tlog(s->avctx, "mb_type=%x\n", mb_type); + ff_tlog(s->c.avctx, "mb_type=%x\n", mb_type); // motion_type = 0; /* avoid warning */ if (IS_INTRA(mb_type)) { - s->bdsp.clear_blocks(s->block[0]); + s->c.bdsp.clear_blocks(s->block[0]); - if (!s->chroma_y_shift) - s->bdsp.clear_blocks(s->block[6]); + if (!s->c.chroma_y_shift) + s->c.bdsp.clear_blocks(s->block[6]); /* compute DCT type */ // FIXME: add an interlaced_dct coded var? - if (s->picture_structure == PICT_FRAME && - !s->frame_pred_frame_dct) - s->interlaced_dct = get_bits1(&s->gb); + if (s->c.picture_structure == PICT_FRAME && + !s->c.frame_pred_frame_dct) + s->c.interlaced_dct = get_bits1(&s->gb); if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - if (s->concealment_motion_vectors) { + if (s->c.concealment_motion_vectors) { /* just parse them */ - if (s->picture_structure != PICT_FRAME) + if (s->c.picture_structure != PICT_FRAME) skip_bits1(&s->gb); /* field select */ - s->mv[0][0][0] = - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = mpeg_decode_motion(s, s->mpeg_f_code[0][0], - s->last_mv[0][0][0]); - s->mv[0][0][1] = - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = mpeg_decode_motion(s, s->mpeg_f_code[0][1], - s->last_mv[0][0][1]); + s->c.mv[0][0][0] = + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = mpeg_decode_motion(s, s->c.mpeg_f_code[0][0], + s->c.last_mv[0][0][0]); + s->c.mv[0][0][1] = + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = mpeg_decode_motion(s, s->c.mpeg_f_code[0][1], + s->c.last_mv[0][0][1]); - check_marker(s->avctx, &s->gb, "after concealment_motion_vectors"); + check_marker(s->c.avctx, &s->gb, "after concealment_motion_vectors"); } else { /* reset mv prediction */ - memset(s->last_mv, 0, sizeof(s->last_mv)); + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); } - s->mb_intra = 1; + s->c.mb_intra = 1; - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { for (i = 0; i < mb_block_count; i++) if ((ret = mpeg2_decode_block_intra(s, s->block[i], i)) < 0) return ret; } else { for (i = 0; i < 6; i++) { ret = ff_mpeg1_decode_block_intra(&s->gb, - s->intra_matrix, - s->intra_scantable.permutated, - s->last_dc, s->block[i], - i, s->qscale); + s->c.intra_matrix, + s->c.intra_scantable.permutated, + s->c.last_dc, s->block[i], + i, s->c.qscale); if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", - s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", + s->c.mb_x, s->c.mb_y); return ret; } - - s->block_last_index[i] = ret; } } } else { if (mb_type & MB_TYPE_ZERO_MV) { av_assert2(mb_type & MB_TYPE_CBP); - s->mv_dir = MV_DIR_FORWARD; - if (s->picture_structure == PICT_FRAME) { - if (s->picture_structure == PICT_FRAME - && !s->frame_pred_frame_dct) - s->interlaced_dct = get_bits1(&s->gb); - s->mv_type = MV_TYPE_16X16; + s->c.mv_dir = MV_DIR_FORWARD; + if (s->c.picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME + && !s->c.frame_pred_frame_dct) + s->c.interlaced_dct = get_bits1(&s->gb); + s->c.mv_type = MV_TYPE_16X16; } else { - s->mv_type = MV_TYPE_FIELD; + s->c.mv_type = MV_TYPE_FIELD; mb_type |= MB_TYPE_INTERLACED; - s->field_select[0][0] = s->picture_structure - 1; + s->c.field_select[0][0] = s->c.picture_structure - 1; } if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - s->last_mv[0][0][0] = 0; - s->last_mv[0][0][1] = 0; - s->last_mv[0][1][0] = 0; - s->last_mv[0][1][1] = 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = 0; + s->c.last_mv[0][0][1] = 0; + s->c.last_mv[0][1][0] = 0; + s->c.last_mv[0][1][1] = 0; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; } else { av_assert2(mb_type & MB_TYPE_BIDIR_MV); // FIXME decide if MBs in field pictures are MB_TYPE_INTERLACED /* get additional motion vector type */ - if (s->picture_structure == PICT_FRAME && s->frame_pred_frame_dct) { + if (s->c.picture_structure == PICT_FRAME && s->c.frame_pred_frame_dct) { motion_type = MT_FRAME; } else { motion_type = get_bits(&s->gb, 2); - if (s->picture_structure == PICT_FRAME && HAS_CBP(mb_type)) - s->interlaced_dct = get_bits1(&s->gb); + if (s->c.picture_structure == PICT_FRAME && HAS_CBP(mb_type)) + s->c.interlaced_dct = get_bits1(&s->gb); } if (IS_QUANT(mb_type)) - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); /* motion vectors */ - s->mv_dir = MB_TYPE_MV_2_MV_DIR(mb_type); - ff_tlog(s->avctx, "motion_type=%d\n", motion_type); + s->c.mv_dir = MB_TYPE_MV_2_MV_DIR(mb_type); + ff_tlog(s->c.avctx, "motion_type=%d\n", motion_type); switch (motion_type) { case MT_FRAME: /* or MT_16X8 */ - if (s->picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x16; - s->mv_type = MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { /* MT_FRAME */ - s->mv[i][0][0] = - s->last_mv[i][0][0] = - s->last_mv[i][1][0] = - mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][0][0]); - s->mv[i][0][1] = - s->last_mv[i][0][1] = - s->last_mv[i][1][1] = - mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][0][1]); + s->c.mv[i][0][0] = + s->c.last_mv[i][0][0] = + s->c.last_mv[i][1][0] = + mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][0][0]); + s->c.mv[i][0][1] = + s->c.last_mv[i][0][1] = + s->c.last_mv[i][1][1] = + mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][0][1]); /* full_pel: only for MPEG-1 */ - if (s->full_pel[i]) { - s->mv[i][0][0] *= 2; - s->mv[i][0][1] *= 2; + if (s->c.full_pel[i]) { + s->c.mv[i][0][0] *= 2; + s->c.mv[i][0][1] *= 2; } } } } else { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; - s->mv_type = MV_TYPE_16X8; + s->c.mv_type = MV_TYPE_16X8; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { /* MT_16X8 */ for (j = 0; j < 2; j++) { - s->field_select[i][j] = get_bits1(&s->gb); + s->c.field_select[i][j] = get_bits1(&s->gb); for (k = 0; k < 2; k++) { - val = mpeg_decode_motion(s, s->mpeg_f_code[i][k], - s->last_mv[i][j][k]); - s->last_mv[i][j][k] = val; - s->mv[i][j][k] = val; + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][k], + s->c.last_mv[i][j][k]); + s->c.last_mv[i][j][k] = val; + s->c.mv[i][j][k] = val; } } } @@ -613,121 +615,122 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } break; case MT_FIELD: - s->mv_type = MV_TYPE_FIELD; - if (s->picture_structure == PICT_FRAME) { + s->c.mv_type = MV_TYPE_FIELD; + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { for (j = 0; j < 2; j++) { - s->field_select[i][j] = get_bits1(&s->gb); - val = mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][j][0]); - s->last_mv[i][j][0] = val; - s->mv[i][j][0] = val; - ff_tlog(s->avctx, "fmx=%d\n", val); - val = mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][j][1] >> 1); - s->last_mv[i][j][1] = 2 * val; - s->mv[i][j][1] = val; - ff_tlog(s->avctx, "fmy=%d\n", val); + s->c.field_select[i][j] = get_bits1(&s->gb); + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][j][0]); + s->c.last_mv[i][j][0] = val; + s->c.mv[i][j][0] = val; + ff_tlog(s->c.avctx, "fmx=%d\n", val); + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][j][1] >> 1); + s->c.last_mv[i][j][1] = 2 * val; + s->c.mv[i][j][1] = val; + ff_tlog(s->c.avctx, "fmy=%d\n", val); } } } } else { - av_assert0(!s->progressive_sequence); + av_assert0(!s->c.progressive_sequence); mb_type |= MB_TYPE_16x16 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { - s->field_select[i][0] = get_bits1(&s->gb); + s->c.field_select[i][0] = get_bits1(&s->gb); for (k = 0; k < 2; k++) { - val = mpeg_decode_motion(s, s->mpeg_f_code[i][k], - s->last_mv[i][0][k]); - s->last_mv[i][0][k] = val; - s->last_mv[i][1][k] = val; - s->mv[i][0][k] = val; + val = mpeg_decode_motion(s, s->c.mpeg_f_code[i][k], + s->c.last_mv[i][0][k]); + s->c.last_mv[i][0][k] = val; + s->c.last_mv[i][1][k] = val; + s->c.mv[i][0][k] = val; } } } } break; case MT_DMV: - if (s->progressive_sequence){ - av_log(s->avctx, AV_LOG_ERROR, "MT_DMV in progressive_sequence\n"); + if (s->c.progressive_sequence){ + av_log(s->c.avctx, AV_LOG_ERROR, "MT_DMV in progressive_sequence\n"); return AVERROR_INVALIDDATA; } - s->mv_type = MV_TYPE_DMV; + s->c.mv_type = MV_TYPE_DMV; for (i = 0; i < 2; i++) { if (HAS_MV(mb_type, i)) { int dmx, dmy, mx, my, m; - const int my_shift = s->picture_structure == PICT_FRAME; + const int my_shift = s->c.picture_structure == PICT_FRAME; - mx = mpeg_decode_motion(s, s->mpeg_f_code[i][0], - s->last_mv[i][0][0]); - s->last_mv[i][0][0] = mx; - s->last_mv[i][1][0] = mx; + mx = mpeg_decode_motion(s, s->c.mpeg_f_code[i][0], + s->c.last_mv[i][0][0]); + s->c.last_mv[i][0][0] = mx; + s->c.last_mv[i][1][0] = mx; dmx = get_dmv(s); - my = mpeg_decode_motion(s, s->mpeg_f_code[i][1], - s->last_mv[i][0][1] >> my_shift); + my = mpeg_decode_motion(s, s->c.mpeg_f_code[i][1], + s->c.last_mv[i][0][1] >> my_shift); dmy = get_dmv(s); - s->last_mv[i][0][1] = my * (1 << my_shift); - s->last_mv[i][1][1] = my * (1 << my_shift); + s->c.last_mv[i][0][1] = my * (1 << my_shift); + s->c.last_mv[i][1][1] = my * (1 << my_shift); - s->mv[i][0][0] = mx; - s->mv[i][0][1] = my; - s->mv[i][1][0] = mx; // not used - s->mv[i][1][1] = my; // not used + s->c.mv[i][0][0] = mx; + s->c.mv[i][0][1] = my; + s->c.mv[i][1][0] = mx; // not used + s->c.mv[i][1][1] = my; // not used - if (s->picture_structure == PICT_FRAME) { + if (s->c.picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x16 | MB_TYPE_INTERLACED; - // m = 1 + 2 * s->top_field_first; - m = s->top_field_first ? 1 : 3; + // m = 1 + 2 * s->c.top_field_first; + m = s->c.top_field_first ? 1 : 3; /* top -> top pred */ - s->mv[i][2][0] = ((mx * m + (mx > 0)) >> 1) + dmx; - s->mv[i][2][1] = ((my * m + (my > 0)) >> 1) + dmy - 1; + s->c.mv[i][2][0] = ((mx * m + (mx > 0)) >> 1) + dmx; + s->c.mv[i][2][1] = ((my * m + (my > 0)) >> 1) + dmy - 1; m = 4 - m; - s->mv[i][3][0] = ((mx * m + (mx > 0)) >> 1) + dmx; - s->mv[i][3][1] = ((my * m + (my > 0)) >> 1) + dmy + 1; + s->c.mv[i][3][0] = ((mx * m + (mx > 0)) >> 1) + dmx; + s->c.mv[i][3][1] = ((my * m + (my > 0)) >> 1) + dmy + 1; } else { mb_type |= MB_TYPE_16x16; - s->mv[i][2][0] = ((mx + (mx > 0)) >> 1) + dmx; - s->mv[i][2][1] = ((my + (my > 0)) >> 1) + dmy; - if (s->picture_structure == PICT_TOP_FIELD) - s->mv[i][2][1]--; + s->c.mv[i][2][0] = ((mx + (mx > 0)) >> 1) + dmx; + s->c.mv[i][2][1] = ((my + (my > 0)) >> 1) + dmy; + if (s->c.picture_structure == PICT_TOP_FIELD) + s->c.mv[i][2][1]--; else - s->mv[i][2][1]++; + s->c.mv[i][2][1]++; } } } break; default: - av_log(s->avctx, AV_LOG_ERROR, - "00 motion_type at %d %d\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "00 motion_type at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } } - s->mb_intra = 0; + s->c.mb_intra = 0; + s->c.last_dc[0] = s->c.last_dc[1] = s->c.last_dc[2] = 128 << s->c.intra_dc_precision; if (HAS_CBP(mb_type)) { - s->bdsp.clear_blocks(s->block[0]); + s->c.bdsp.clear_blocks(s->block[0]); cbp = get_vlc2(&s->gb, ff_mb_pat_vlc, MB_PAT_VLC_BITS, 1); if (mb_block_count > 6) { cbp *= 1 << mb_block_count - 6; - cbp |= get_bits(&s->gb, mb_block_count - 6); - s->bdsp.clear_blocks(s->block[6]); + cbp |= get_bits(&s->gb, mb_block_count - 6); + s->c.bdsp.clear_blocks(s->block[6]); } if (cbp <= 0) { - av_log(s->avctx, AV_LOG_ERROR, - "invalid cbp %d at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_ERROR, + "invalid cbp %d at %d %d\n", cbp, s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { cbp <<= 12 - mb_block_count; for (i = 0; i < mb_block_count; i++) { @@ -735,7 +738,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if ((ret = mpeg2_decode_block_non_intra(s, s->block[i], i)) < 0) return ret; } else { - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } cbp += cbp; } @@ -745,18 +748,18 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if ((ret = mpeg1_decode_block_inter(s, s->block[i], i)) < 0) return ret; } else { - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } cbp += cbp; } } } else { for (i = 0; i < 12; i++) - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } } - s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = mb_type; + s->c.cur_pic.mb_type[s->c.mb_x + s->c.mb_y * s->c.mb_stride] = mb_type; return 0; } @@ -764,9 +767,10 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) static av_cold int mpeg_decode_init(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; int ret; + s2->slice_ctx_size = sizeof(s->slice); s2->out_format = FMT_MPEG1; if ( avctx->codec_tag != AV_RL32("VCR2") @@ -778,34 +782,11 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx) ff_mpeg12_init_vlcs(); - s2->chroma_format = 1; - s->repeat_field = 0; + s2->chroma_format = CHROMA_420; avctx->color_range = AVCOL_RANGE_MPEG; return 0; } -#if HAVE_THREADS -static int mpeg_decode_update_thread_context(AVCodecContext *avctx, - const AVCodecContext *avctx_from) -{ - Mpeg1Context *ctx = avctx->priv_data, *ctx_from = avctx_from->priv_data; - MpegEncContext *s = &ctx->mpeg_enc_ctx, *s1 = &ctx_from->mpeg_enc_ctx; - int err; - - if (avctx == avctx_from || !s1->context_initialized) - return 0; - - err = ff_mpeg_update_thread_context(avctx, avctx_from); - if (err) - return err; - - if (!s->context_initialized) - memcpy(s + 1, s1 + 1, sizeof(Mpeg1Context) - sizeof(MpegEncContext)); - - return 0; -} -#endif - static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { #if CONFIG_MPEG1_NVDEC_HWACCEL AV_PIX_FMT_CUDA, @@ -857,17 +838,17 @@ static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = { static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; const enum AVPixelFormat *pix_fmts; if (CONFIG_GRAY && (avctx->flags & AV_CODEC_FLAG_GRAY)) return AV_PIX_FMT_GRAY8; - if (s->chroma_format < 2) + if (s->chroma_format < CHROMA_422) pix_fmts = avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ? mpeg1_hwaccel_pixfmt_list_420 : mpeg2_hwaccel_pixfmt_list_420; - else if (s->chroma_format == 2) + else if (s->chroma_format == CHROMA_422) pix_fmts = mpeg12_pixfmt_list_422; else pix_fmts = mpeg12_pixfmt_list_444; @@ -880,7 +861,7 @@ static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) static int mpeg_decode_postinit(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int ret; if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { @@ -937,9 +918,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (!s->context_initialized || avctx->coded_width != s->width || avctx->coded_height != s->height || - s1->save_width != s->width || - s1->save_height != s->height || - av_cmp_q(s1->save_aspect, s->avctx->sample_aspect_ratio) || + s1->save_chroma_format != s->chroma_format || (s1->save_progressive_seq != s->progressive_sequence && FFALIGN(s->height, 16) != FFALIGN(s->height, 32)) || 0) { if (s->context_initialized) @@ -949,17 +928,15 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (ret < 0) return ret; - if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->bit_rate && - (s->bit_rate != 0x3FFFF*400)) { - avctx->rc_max_rate = s->bit_rate; - } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && s->bit_rate && - (s->bit_rate != 0x3FFFF*400 || s->vbv_delay != 0xFFFF)) { - avctx->bit_rate = s->bit_rate; + if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && s1->bit_rate && + (s1->bit_rate != 0x3FFFF*400)) { + avctx->rc_max_rate = s1->bit_rate; + } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && s1->bit_rate && + (s1->bit_rate != 0x3FFFF*400 || s1->vbv_delay != 0xFFFF)) { + avctx->bit_rate = s1->bit_rate; } - s1->save_aspect = s->avctx->sample_aspect_ratio; - s1->save_width = s->width; - s1->save_height = s->height; s1->save_progressive_seq = s->progressive_sequence; + s1->save_chroma_format = s->chroma_format; /* low_delay may be forced, in this case we will have B-frames * that behave like P-frames. */ @@ -968,12 +945,6 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { // MPEG-1 fps avctx->framerate = ff_mpeg12_frame_rate_tab[s1->frame_rate_index]; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; } else { // MPEG-2 // MPEG-2 fps @@ -982,16 +953,11 @@ FF_ENABLE_DEPRECATION_WARNINGS ff_mpeg12_frame_rate_tab[s1->frame_rate_index].num * s1->frame_rate_ext.num, ff_mpeg12_frame_rate_tab[s1->frame_rate_index].den * s1->frame_rate_ext.den, 1 << 30); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif switch (s->chroma_format) { - case 1: avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; break; - case 2: - case 3: avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break; + case CHROMA_420: avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; break; + case CHROMA_422: + case CHROMA_444: avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break; default: av_assert0(0); } } // MPEG-2 @@ -1001,7 +967,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if ((ret = ff_mpv_common_init(s)) < 0) return ret; if (!s->avctx->lowres) - ff_mpv_framesize_disable(&s->sc); + for (int i = 0; i < s->slice_context_count; i++) + ff_mpv_framesize_disable(&s->thread_context[i]->sc); } return 0; } @@ -1010,24 +977,25 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int ref, f_code, vbv_delay, ret; - ret = init_get_bits8(&s->gb, buf, buf_size); + ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - ref = get_bits(&s->gb, 10); /* temporal ref */ - s->pict_type = get_bits(&s->gb, 3); + ref = get_bits(gb, 10); /* temporal ref */ + s->pict_type = get_bits(gb, 3); if (s->pict_type == 0 || s->pict_type > 3) return AVERROR_INVALIDDATA; - vbv_delay = get_bits(&s->gb, 16); - s->vbv_delay = vbv_delay; + vbv_delay = get_bits(gb, 16); + s1->vbv_delay = vbv_delay; if (s->pict_type == AV_PICTURE_TYPE_P || s->pict_type == AV_PICTURE_TYPE_B) { - s->full_pel[0] = get_bits1(&s->gb); - f_code = get_bits(&s->gb, 3); + s->full_pel[0] = get_bits1(gb); + f_code = get_bits(gb, 3); if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) return AVERROR_INVALIDDATA; f_code += !f_code; @@ -1035,8 +1003,8 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, s->mpeg_f_code[0][1] = f_code; } if (s->pict_type == AV_PICTURE_TYPE_B) { - s->full_pel[1] = get_bits1(&s->gb); - f_code = get_bits(&s->gb, 3); + s->full_pel[1] = get_bits1(gb); + f_code = get_bits(gb, 3); if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) return AVERROR_INVALIDDATA; f_code += !f_code; @@ -1048,43 +1016,42 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf, av_log(avctx, AV_LOG_DEBUG, "vbv_delay %d, ref %d type:%d\n", vbv_delay, ref, s->pict_type); - s->y_dc_scale = 8; - s->c_dc_scale = 8; return 0; } -static void mpeg_decode_sequence_extension(Mpeg1Context *s1) +static void mpeg_decode_sequence_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int horiz_size_ext, vert_size_ext; int bit_rate_ext; - skip_bits(&s->gb, 1); /* profile and level esc*/ - s->avctx->profile = get_bits(&s->gb, 3); - s->avctx->level = get_bits(&s->gb, 4); - s->progressive_sequence = get_bits1(&s->gb); /* progressive_sequence */ - s->chroma_format = get_bits(&s->gb, 2); /* chroma_format 1=420, 2=422, 3=444 */ + skip_bits(gb, 1); /* profile and level esc*/ + s->avctx->profile = get_bits(gb, 3); + s->avctx->level = get_bits(gb, 4); + s->progressive_sequence = get_bits1(gb); /* progressive_sequence */ + s->chroma_format = get_bits(gb, 2); /* chroma_format 1=420, 2=422, 3=444 */ if (!s->chroma_format) { - s->chroma_format = 1; + s->chroma_format = CHROMA_420; av_log(s->avctx, AV_LOG_WARNING, "Chroma format invalid\n"); } - horiz_size_ext = get_bits(&s->gb, 2); - vert_size_ext = get_bits(&s->gb, 2); + horiz_size_ext = get_bits(gb, 2); + vert_size_ext = get_bits(gb, 2); s->width |= (horiz_size_ext << 12); s->height |= (vert_size_ext << 12); - bit_rate_ext = get_bits(&s->gb, 12); /* XXX: handle it */ - s->bit_rate += (bit_rate_ext << 18) * 400LL; - check_marker(s->avctx, &s->gb, "after bit rate extension"); - s->avctx->rc_buffer_size += get_bits(&s->gb, 8) * 1024 * 16 << 10; + bit_rate_ext = get_bits(gb, 12); /* XXX: handle it */ + s1->bit_rate += (bit_rate_ext << 18) * 400LL; + check_marker(s->avctx, gb, "after bit rate extension"); + s->avctx->rc_buffer_size += get_bits(gb, 8) * 1024 * 16 << 10; - s->low_delay = get_bits1(&s->gb); + s->low_delay = get_bits1(gb); if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; - s1->frame_rate_ext.num = get_bits(&s->gb, 2) + 1; - s1->frame_rate_ext.den = get_bits(&s->gb, 5) + 1; + s1->frame_rate_ext.num = get_bits(gb, 2) + 1; + s1->frame_rate_ext.den = get_bits(gb, 5) + 1; ff_dlog(s->avctx, "sequence extension\n"); s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; @@ -1093,24 +1060,25 @@ static void mpeg_decode_sequence_extension(Mpeg1Context *s1) av_log(s->avctx, AV_LOG_DEBUG, "profile: %d, level: %d ps: %d cf:%d vbv buffer: %d, bitrate:%"PRId64"\n", s->avctx->profile, s->avctx->level, s->progressive_sequence, s->chroma_format, - s->avctx->rc_buffer_size, s->bit_rate); + s->avctx->rc_buffer_size, s1->bit_rate); } -static void mpeg_decode_sequence_display_extension(Mpeg1Context *s1) +static void mpeg_decode_sequence_display_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int color_description, w, h; - skip_bits(&s->gb, 3); /* video format */ - color_description = get_bits1(&s->gb); + skip_bits(gb, 3); /* video format */ + color_description = get_bits1(gb); if (color_description) { - s->avctx->color_primaries = get_bits(&s->gb, 8); - s->avctx->color_trc = get_bits(&s->gb, 8); - s->avctx->colorspace = get_bits(&s->gb, 8); + s->avctx->color_primaries = get_bits(gb, 8); + s->avctx->color_trc = get_bits(gb, 8); + s->avctx->colorspace = get_bits(gb, 8); } - w = get_bits(&s->gb, 14); - skip_bits(&s->gb, 1); // marker - h = get_bits(&s->gb, 14); + w = get_bits(gb, 14); + skip_bits(gb, 1); // marker + h = get_bits(gb, 14); // remaining 3 bits are zero padding s1->pan_scan.width = 16 * w; @@ -1120,9 +1088,10 @@ static void mpeg_decode_sequence_display_extension(Mpeg1Context *s1) av_log(s->avctx, AV_LOG_DEBUG, "sde w:%d, h:%d\n", w, h); } -static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) +static void mpeg_decode_picture_display_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int i, nofco; nofco = 1; @@ -1140,10 +1109,10 @@ static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) } } for (i = 0; i < nofco; i++) { - s1->pan_scan.position[i][0] = get_sbits(&s->gb, 16); - skip_bits(&s->gb, 1); // marker - s1->pan_scan.position[i][1] = get_sbits(&s->gb, 16); - skip_bits(&s->gb, 1); // marker + s1->pan_scan.position[i][0] = get_sbits(gb, 16); + skip_bits(gb, 1); // marker + s1->pan_scan.position[i][1] = get_sbits(gb, 16); + skip_bits(gb, 1); // marker } if (s->avctx->debug & FF_DEBUG_PICT_INFO) @@ -1154,14 +1123,14 @@ static void mpeg_decode_picture_display_extension(Mpeg1Context *s1) s1->pan_scan.position[2][0], s1->pan_scan.position[2][1]); } -static int load_matrix(MpegEncContext *s, uint16_t matrix0[64], - uint16_t matrix1[64], int intra) +static int load_matrix(MPVContext *const s, GetBitContext *const gb, + uint16_t matrix0[64], uint16_t matrix1[64], int intra) { int i; for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - int v = get_bits(&s->gb, 8); + int v = get_bits(gb, 8); if (v == 0) { av_log(s->avctx, AV_LOG_ERROR, "matrix damaged\n"); return AVERROR_INVALIDDATA; @@ -1177,29 +1146,31 @@ static int load_matrix(MpegEncContext *s, uint16_t matrix0[64], return 0; } -static void mpeg_decode_quant_matrix_extension(MpegEncContext *s) +static void mpeg_decode_quant_matrix_extension(MPVContext *const s, + GetBitContext *const gb) { ff_dlog(s->avctx, "matrix extension\n"); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_intra_matrix, s->intra_matrix, 1); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_inter_matrix, s->inter_matrix, 0); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_intra_matrix, NULL, 1); - if (get_bits1(&s->gb)) - load_matrix(s, s->chroma_inter_matrix, NULL, 0); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_intra_matrix, s->intra_matrix, 1); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_inter_matrix, s->inter_matrix, 0); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_intra_matrix, NULL, 1); + if (get_bits1(gb)) + load_matrix(s, gb, s->chroma_inter_matrix, NULL, 0); } -static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) +static int mpeg_decode_picture_coding_extension(Mpeg1Context *const s1, + GetBitContext *const gb) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; s->full_pel[0] = s->full_pel[1] = 0; - s->mpeg_f_code[0][0] = get_bits(&s->gb, 4); - s->mpeg_f_code[0][1] = get_bits(&s->gb, 4); - s->mpeg_f_code[1][0] = get_bits(&s->gb, 4); - s->mpeg_f_code[1][1] = get_bits(&s->gb, 4); + s->mpeg_f_code[0][0] = get_bits(gb, 4); + s->mpeg_f_code[0][1] = get_bits(gb, 4); + s->mpeg_f_code[1][0] = get_bits(gb, 4); + s->mpeg_f_code[1][1] = get_bits(gb, 4); s->mpeg_f_code[0][0] += !s->mpeg_f_code[0][0]; s->mpeg_f_code[0][1] += !s->mpeg_f_code[0][1]; s->mpeg_f_code[1][0] += !s->mpeg_f_code[1][0]; @@ -1218,22 +1189,22 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) s->pict_type = AV_PICTURE_TYPE_B; } - s->intra_dc_precision = get_bits(&s->gb, 2); - s->picture_structure = get_bits(&s->gb, 2); - s->top_field_first = get_bits1(&s->gb); - s->frame_pred_frame_dct = get_bits1(&s->gb); - s->concealment_motion_vectors = get_bits1(&s->gb); - s->q_scale_type = get_bits1(&s->gb); - s->intra_vlc_format = get_bits1(&s->gb); - s->alternate_scan = get_bits1(&s->gb); - s->repeat_first_field = get_bits1(&s->gb); - s->chroma_420_type = get_bits1(&s->gb); - s->progressive_frame = get_bits1(&s->gb); + s->intra_dc_precision = get_bits(gb, 2); + s->picture_structure = get_bits(gb, 2); + s->top_field_first = get_bits1(gb); + s->frame_pred_frame_dct = get_bits1(gb); + s->concealment_motion_vectors = get_bits1(gb); + s->q_scale_type = get_bits1(gb); + s->intra_vlc_format = get_bits1(gb); + s->alternate_scan = get_bits1(gb); + s->repeat_first_field = get_bits1(gb); + s->chroma_420_type = get_bits1(gb); + s->progressive_frame = get_bits1(gb); - // We only initialize intra_scantable, as both scantables always coincide - // and all code therefore only uses the intra one. - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); + // We only initialize intra_scantable.permutated, as this is all we use. + ff_permute_scantable(s->intra_scantable.permutated, + s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct, + s->idsp.idct_permutation); /* composite display not parsed */ ff_dlog(s->avctx, "intra_dc_precision=%d\n", s->intra_dc_precision); @@ -1251,7 +1222,7 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) { - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; AVCodecContext *avctx = s->avctx; int second_field = 0; int ret; @@ -1331,9 +1302,6 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) *sd->data = s1->afd; s1->has_afd = 0; } - - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_finish_setup(avctx); } else { // second field second_field = 1; if (!s->cur_pic.ptr) { @@ -1361,7 +1329,7 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) } if (avctx->hwaccel) { - if ((ret = FF_HW_CALL(avctx, start_frame, buf, buf_size)) < 0) + if ((ret = FF_HW_CALL(avctx, start_frame, NULL, buf, buf_size)) < 0) return ret; } else if (s->codec_tag == MKTAG('V', 'C', 'R', '2')) { // Exchange UV @@ -1383,37 +1351,37 @@ static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) /** * Decode a slice. - * MpegEncContext.mb_y must be set to the MB row from the startcode. + * Mpeg12SliceContext.c.mb_y must be set to the MB row from the startcode. * @return DECODE_SLICE_ERROR if the slice is damaged, * DECODE_SLICE_OK if this slice is OK */ -static int mpeg_decode_slice(MpegEncContext *s, int mb_y, +static int mpeg_decode_slice(Mpeg12SliceContext *const s, int mb_y, const uint8_t **buf, int buf_size) { - AVCodecContext *avctx = s->avctx; - const int lowres = s->avctx->lowres; - const int field_pic = s->picture_structure != PICT_FRAME; + AVCodecContext *avctx = s->c.avctx; + const int lowres = s->c.avctx->lowres; + const int field_pic = s->c.picture_structure != PICT_FRAME; int ret; - s->resync_mb_x = - s->resync_mb_y = -1; + s->c.resync_mb_x = + s->c.resync_mb_y = -1; - av_assert0(mb_y < s->mb_height); + av_assert0(mb_y < s->c.mb_height); ret = init_get_bits8(&s->gb, *buf, buf_size); if (ret < 0) return ret; - if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16) + if (s->c.codec_id != AV_CODEC_ID_MPEG1VIDEO && s->c.mb_height > 2800/16) skip_bits(&s->gb, 3); - ff_mpeg1_clean_buffers(s); - s->interlaced_dct = 0; + ff_mpeg1_clean_buffers(&s->c); + s->c.interlaced_dct = 0; - s->qscale = mpeg_get_qscale(s); + s->c.qscale = mpeg_get_qscale(&s->gb, s->c.q_scale_type); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "qscale == 0\n"); + if (s->c.qscale == 0) { + av_log(s->c.avctx, AV_LOG_ERROR, "qscale == 0\n"); return AVERROR_INVALIDDATA; } @@ -1421,31 +1389,31 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, if (skip_1stop_8data_bits(&s->gb) < 0) return AVERROR_INVALIDDATA; - s->mb_x = 0; + s->c.mb_x = 0; - if (mb_y == 0 && s->codec_tag == AV_RL32("SLIF")) { + if (mb_y == 0 && s->c.codec_tag == AV_RL32("SLIF")) { skip_bits1(&s->gb); } else { while (get_bits_left(&s->gb) > 0) { int code = get_vlc2(&s->gb, ff_mbincr_vlc, MBINCR_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "first mb_incr damaged\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "first mb_incr damaged\n"); return AVERROR_INVALIDDATA; } if (code >= 33) { if (code == 33) - s->mb_x += 33; + s->c.mb_x += 33; /* otherwise, stuffing, nothing to do */ } else { - s->mb_x += code; + s->c.mb_x += code; break; } } } - if (s->mb_x >= (unsigned) s->mb_width) { - av_log(s->avctx, AV_LOG_ERROR, "initial skip overflow\n"); + if (s->c.mb_x >= (unsigned) s->c.mb_width) { + av_log(s->c.avctx, AV_LOG_ERROR, "initial skip overflow\n"); return AVERROR_INVALIDDATA; } @@ -1455,102 +1423,101 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, buf_end = avpriv_find_start_code(buf_start + 2, *buf + buf_size, &start_code); if (buf_end < *buf + buf_size) buf_end -= 4; - s->mb_y = mb_y; + s->c.mb_y = mb_y; if (FF_HW_CALL(avctx, decode_slice, buf_start, buf_end - buf_start) < 0) return DECODE_SLICE_ERROR; *buf = buf_end; return DECODE_SLICE_OK; } - s->resync_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y = mb_y; - s->mb_skip_run = 0; - ff_init_block_index(s); + s->c.resync_mb_x = s->c.mb_x; + s->c.resync_mb_y = s->c.mb_y = mb_y; + ff_init_block_index(&s->c); - if (s->mb_y == 0 && s->mb_x == 0 && (s->first_field || s->picture_structure == PICT_FRAME)) { - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.mb_y == 0 && s->c.mb_x == 0 && (s->c.first_field || s->c.picture_structure == PICT_FRAME)) { + if (s->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(s->c.avctx, AV_LOG_DEBUG, "qp:%d fc:%2d%2d%2d%2d %c %s %s %s %s dc:%d pstruct:%d fdct:%d cmv:%d qtype:%d ivlc:%d rff:%d %s\n", - s->qscale, - s->mpeg_f_code[0][0], s->mpeg_f_code[0][1], - s->mpeg_f_code[1][0], s->mpeg_f_code[1][1], - s->pict_type == AV_PICTURE_TYPE_I ? 'I' : - (s->pict_type == AV_PICTURE_TYPE_P ? 'P' : - (s->pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), - s->progressive_sequence ? "ps" : "", - s->progressive_frame ? "pf" : "", - s->alternate_scan ? "alt" : "", - s->top_field_first ? "top" : "", - s->intra_dc_precision, s->picture_structure, - s->frame_pred_frame_dct, s->concealment_motion_vectors, - s->q_scale_type, s->intra_vlc_format, - s->repeat_first_field, s->chroma_420_type ? "420" : ""); + s->c.qscale, + s->c.mpeg_f_code[0][0], s->c.mpeg_f_code[0][1], + s->c.mpeg_f_code[1][0], s->c.mpeg_f_code[1][1], + s->c.pict_type == AV_PICTURE_TYPE_I ? 'I' : + (s->c.pict_type == AV_PICTURE_TYPE_P ? 'P' : + (s->c.pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), + s->c.progressive_sequence ? "ps" : "", + s->c.progressive_frame ? "pf" : "", + s->c.alternate_scan ? "alt" : "", + s->c.top_field_first ? "top" : "", + s->c.intra_dc_precision, s->c.picture_structure, + s->c.frame_pred_frame_dct, s->c.concealment_motion_vectors, + s->c.q_scale_type, s->c.intra_vlc_format, + s->c.repeat_first_field, s->c.chroma_420_type ? "420" : ""); } } - for (;;) { - if ((ret = mpeg_decode_mb(s, s->block)) < 0) + for (int mb_skip_run = 0;;) { + ret = mpeg_decode_mb(s, &mb_skip_run); + if (ret < 0) return ret; // Note motion_val is normally NULL unless we want to extract the MVs. - if (s->cur_pic.motion_val[0]) { - const int wrap = s->b8_stride; - int xy = s->mb_x * 2 + s->mb_y * 2 * wrap; - int b8_xy = 4 * (s->mb_x + s->mb_y * s->mb_stride); + if (s->c.cur_pic.motion_val[0]) { + const int wrap = s->c.b8_stride; + int xy = s->c.mb_x * 2 + s->c.mb_y * 2 * wrap; + int b8_xy = 4 * (s->c.mb_x + s->c.mb_y * s->c.mb_stride); int motion_x, motion_y, dir, i; for (i = 0; i < 2; i++) { for (dir = 0; dir < 2; dir++) { - if (s->mb_intra || - (dir == 1 && s->pict_type != AV_PICTURE_TYPE_B)) { + if (s->c.mb_intra || + (dir == 1 && s->c.pict_type != AV_PICTURE_TYPE_B)) { motion_x = motion_y = 0; - } else if (s->mv_type == MV_TYPE_16X16 || - (s->mv_type == MV_TYPE_FIELD && field_pic)) { - motion_x = s->mv[dir][0][0]; - motion_y = s->mv[dir][0][1]; - } else { /* if ((s->mv_type == MV_TYPE_FIELD) || (s->mv_type == MV_TYPE_16X8)) */ - motion_x = s->mv[dir][i][0]; - motion_y = s->mv[dir][i][1]; + } else if (s->c.mv_type == MV_TYPE_16X16 || + (s->c.mv_type == MV_TYPE_FIELD && field_pic)) { + motion_x = s->c.mv[dir][0][0]; + motion_y = s->c.mv[dir][0][1]; + } else { /* if ((s->c.mv_type == MV_TYPE_FIELD) || (s->c.mv_type == MV_TYPE_16X8)) */ + motion_x = s->c.mv[dir][i][0]; + motion_y = s->c.mv[dir][i][1]; } - s->cur_pic.motion_val[dir][xy][0] = motion_x; - s->cur_pic.motion_val[dir][xy][1] = motion_y; - s->cur_pic.motion_val[dir][xy + 1][0] = motion_x; - s->cur_pic.motion_val[dir][xy + 1][1] = motion_y; - s->cur_pic.ref_index [dir][b8_xy] = - s->cur_pic.ref_index [dir][b8_xy + 1] = s->field_select[dir][i]; - av_assert2(s->field_select[dir][i] == 0 || - s->field_select[dir][i] == 1); + s->c.cur_pic.motion_val[dir][xy][0] = motion_x; + s->c.cur_pic.motion_val[dir][xy][1] = motion_y; + s->c.cur_pic.motion_val[dir][xy + 1][0] = motion_x; + s->c.cur_pic.motion_val[dir][xy + 1][1] = motion_y; + s->c.cur_pic.ref_index [dir][b8_xy] = + s->c.cur_pic.ref_index [dir][b8_xy + 1] = s->c.field_select[dir][i]; + av_assert2(s->c.field_select[dir][i] == 0 || + s->c.field_select[dir][i] == 1); } xy += wrap; b8_xy += 2; } } - s->dest[0] += 16 >> lowres; - s->dest[1] +=(16 >> lowres) >> s->chroma_x_shift; - s->dest[2] +=(16 >> lowres) >> s->chroma_x_shift; + s->c.dest[0] += 16 >> lowres; + s->c.dest[1] +=(16 >> lowres) >> s->c.chroma_x_shift; + s->c.dest[2] +=(16 >> lowres) >> s->c.chroma_x_shift; - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(&s->c, s->block); - if (++s->mb_x >= s->mb_width) { - const int mb_size = 16 >> s->avctx->lowres; + if (++s->c.mb_x >= s->c.mb_width) { + const int mb_size = 16 >> s->c.avctx->lowres; int left; - ff_mpeg_draw_horiz_band(s, mb_size * (s->mb_y >> field_pic), mb_size); - ff_mpv_report_decode_progress(s); + ff_mpeg_draw_horiz_band(&s->c, mb_size * (s->c.mb_y >> field_pic), mb_size); - s->mb_x = 0; - s->mb_y += 1 << field_pic; + s->c.mb_x = 0; + s->c.mb_y += 1 << field_pic; - if (s->mb_y >= s->mb_height) { + if (s->c.mb_y >= s->c.mb_height) { int left = get_bits_left(&s->gb); - int is_d10 = s->chroma_format == 2 && - s->pict_type == AV_PICTURE_TYPE_I && + int is_d10 = s->c.chroma_format == CHROMA_422 && + s->c.pict_type == AV_PICTURE_TYPE_I && avctx->profile == 0 && avctx->level == 5 && - s->intra_dc_precision == 2 && - s->q_scale_type == 1 && s->alternate_scan == 0 && - s->progressive_frame == 0 + s->c.intra_dc_precision == 2 && + s->c.q_scale_type == 1 && s->c.alternate_scan == 0 && + s->c.progressive_frame == 0 /* vbv_delay == 0xBBB || 0xE10 */; if (left >= 32 && !is_d10) { @@ -1570,7 +1537,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, (left && show_bits(&s->gb, FFMIN(left, 23)) && !is_d10) || ((avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) && left > 8)) { av_log(avctx, AV_LOG_ERROR, "end mismatch left=%d %0X at %d %d\n", - left, left>0 ? show_bits(&s->gb, FFMIN(left, 23)) : 0, s->mb_x, s->mb_y); + left, left>0 ? show_bits(&s->gb, FFMIN(left, 23)) : 0, s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } else goto eos; @@ -1580,134 +1547,136 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, // area, we detect this here instead of running into the end expecting // more data left = get_bits_left(&s->gb); - if (s->mb_y >= ((s->height + 15) >> 4) && - !s->progressive_sequence && + if (s->c.mb_y >= ((s->c.height + 15) >> 4) && + !s->c.progressive_sequence && left <= 25 && left >= 0 && - s->mb_skip_run == -1 && + mb_skip_run == -1 && (!left || show_bits(&s->gb, left) == 0)) goto eos; - ff_init_block_index(s); + ff_init_block_index(&s->c); } /* skip mb handling */ - if (s->mb_skip_run == -1) { + if (mb_skip_run == -1) { /* read increment again */ - s->mb_skip_run = 0; + mb_skip_run = 0; for (;;) { int code = get_vlc2(&s->gb, ff_mbincr_vlc, MBINCR_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "mb incr damaged\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "mb incr damaged\n"); return AVERROR_INVALIDDATA; } if (code >= 33) { if (code == 33) { - s->mb_skip_run += 33; + mb_skip_run += 33; } else if (code == 35) { - if (s->mb_skip_run != 0 || show_bits(&s->gb, 15) != 0) { - av_log(s->avctx, AV_LOG_ERROR, "slice mismatch\n"); + if (mb_skip_run != 0 || show_bits(&s->gb, 15) != 0) { + av_log(s->c.avctx, AV_LOG_ERROR, "slice mismatch\n"); return AVERROR_INVALIDDATA; } goto eos; /* end of slice */ } /* otherwise, stuffing, nothing to do */ } else { - s->mb_skip_run += code; + mb_skip_run += code; break; } } - if (s->mb_skip_run) { + if (mb_skip_run) { int i; - if (s->pict_type == AV_PICTURE_TYPE_I) { - av_log(s->avctx, AV_LOG_ERROR, - "skipped MB in I-frame at %d %d\n", s->mb_x, s->mb_y); + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + av_log(s->c.avctx, AV_LOG_ERROR, + "skipped MB in I-frame at %d %d\n", s->c.mb_x, s->c.mb_y); return AVERROR_INVALIDDATA; } /* skip mb */ - s->mb_intra = 0; + s->c.mb_intra = 0; for (i = 0; i < 12; i++) - s->block_last_index[i] = -1; - if (s->picture_structure == PICT_FRAME) - s->mv_type = MV_TYPE_16X16; + s->c.block_last_index[i] = -1; + s->c.last_dc[0] = s->c.last_dc[1] = s->c.last_dc[2] = 128 << s->c.intra_dc_precision; + if (s->c.picture_structure == PICT_FRAME) + s->c.mv_type = MV_TYPE_16X16; else - s->mv_type = MV_TYPE_FIELD; - if (s->pict_type == AV_PICTURE_TYPE_P) { + s->c.mv_type = MV_TYPE_FIELD; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { /* if P type, zero motion vector is implied */ - s->mv_dir = MV_DIR_FORWARD; - s->mv[0][0][0] = s->mv[0][0][1] = 0; - s->last_mv[0][0][0] = s->last_mv[0][0][1] = 0; - s->last_mv[0][1][0] = s->last_mv[0][1][1] = 0; - s->field_select[0][0] = (s->picture_structure - 1) & 1; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv[0][0][0] = s->c.mv[0][0][1] = 0; + s->c.last_mv[0][0][0] = s->c.last_mv[0][0][1] = 0; + s->c.last_mv[0][1][0] = s->c.last_mv[0][1][1] = 0; + s->c.field_select[0][0] = (s->c.picture_structure - 1) & 1; } else { /* if B type, reuse previous vectors and directions */ - s->mv[0][0][0] = s->last_mv[0][0][0]; - 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; + s->c.mv[0][0][0] = s->c.last_mv[0][0][0]; + s->c.mv[0][0][1] = s->c.last_mv[0][0][1]; + s->c.mv[1][0][0] = s->c.last_mv[1][0][0]; + s->c.mv[1][0][1] = s->c.last_mv[1][0][1]; + s->c.field_select[0][0] = (s->c.picture_structure - 1) & 1; + s->c.field_select[1][0] = (s->c.picture_structure - 1) & 1; } } } } eos: // end of slice if (get_bits_left(&s->gb) < 0) { - av_log(s, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb)); + av_log(s->c.avctx, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb)); return AVERROR_INVALIDDATA; } *buf += (get_bits_count(&s->gb) - 1) / 8; - ff_dlog(s, "Slice start:%d %d end:%d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y); + ff_dlog(s->c.avctx, "Slice start:%d %d end:%d %d\n", s->c.resync_mb_x, s->c.resync_mb_y, s->c.mb_x, s->c.mb_y); return 0; } static int slice_decode_thread(AVCodecContext *c, void *arg) { - MpegEncContext *s = *(void **) arg; + Mpeg12SliceContext *const s = *(void **) arg; const uint8_t *buf = s->gb.buffer; - int mb_y = s->start_mb_y; - const int field_pic = s->picture_structure != PICT_FRAME; + const uint8_t *end = buf + get_bits_bytesize(&s->gb, 0); + int mb_y = s->c.start_mb_y; + const int field_pic = s->c.picture_structure != PICT_FRAME; - s->er.error_count = (3 * (s->end_mb_y - s->start_mb_y) * s->mb_width) >> field_pic; + s->c.er.error_count = (3 * (s->c.end_mb_y - s->c.start_mb_y) * s->c.mb_width) >> field_pic; for (;;) { uint32_t start_code; int ret; - ret = mpeg_decode_slice(s, mb_y, &buf, s->gb.buffer_end - buf); + ret = mpeg_decode_slice(s, mb_y, &buf, end - buf); emms_c(); ff_dlog(c, "ret:%d resync:%d/%d mb:%d/%d ts:%d/%d ec:%d\n", - ret, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, - s->start_mb_y, s->end_mb_y, s->er.error_count); + ret, s->c.resync_mb_x, s->c.resync_mb_y, s->c.mb_x, s->c.mb_y, + s->c.start_mb_y, s->c.end_mb_y, s->c.er.error_count); if (ret < 0) { if (c->err_recognition & AV_EF_EXPLODE) return ret; - if (s->resync_mb_x >= 0 && s->resync_mb_y >= 0) - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x, s->mb_y, + if (s->c.resync_mb_x >= 0 && s->c.resync_mb_y >= 0) + ff_er_add_slice(&s->c.er, s->c.resync_mb_x, s->c.resync_mb_y, + s->c.mb_x, s->c.mb_y, ER_AC_ERROR | ER_DC_ERROR | ER_MV_ERROR); } else { - ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, - s->mb_x - 1, s->mb_y, + ff_er_add_slice(&s->c.er, s->c.resync_mb_x, s->c.resync_mb_y, + s->c.mb_x - 1, s->c.mb_y, ER_AC_END | ER_DC_END | ER_MV_END); } - if (s->mb_y == s->end_mb_y) + if (s->c.mb_y == s->c.end_mb_y) return 0; start_code = -1; - buf = avpriv_find_start_code(buf, s->gb.buffer_end, &start_code); + buf = avpriv_find_start_code(buf, end, &start_code); if (start_code < SLICE_MIN_START_CODE || start_code > SLICE_MAX_START_CODE) return AVERROR_INVALIDDATA; mb_y = start_code - SLICE_MIN_START_CODE; - if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16) + if (s->c.codec_id != AV_CODEC_ID_MPEG1VIDEO && s->c.mb_height > 2800/16) mb_y += (*buf&0xE0)<<2; mb_y <<= field_pic; - if (s->picture_structure == PICT_BOTTOM_FIELD) + if (s->c.picture_structure == PICT_BOTTOM_FIELD) mb_y++; - if (mb_y >= s->end_mb_y) + if (mb_y >= s->c.end_mb_y) return AVERROR_INVALIDDATA; } } @@ -1719,7 +1688,7 @@ static int slice_decode_thread(AVCodecContext *c, void *arg) static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; if (!s->context_initialized || !s->cur_pic.ptr) return 0; @@ -1770,45 +1739,46 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int width, height; int i, v, j; - int ret = init_get_bits8(&s->gb, buf, buf_size); + int ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - width = get_bits(&s->gb, 12); - height = get_bits(&s->gb, 12); + width = get_bits(gb, 12); + height = get_bits(gb, 12); if (width == 0 || height == 0) { av_log(avctx, AV_LOG_WARNING, "Invalid horizontal or vertical size value.\n"); if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return AVERROR_INVALIDDATA; } - s1->aspect_ratio_info = get_bits(&s->gb, 4); + s1->aspect_ratio_info = get_bits(gb, 4); if (s1->aspect_ratio_info == 0) { av_log(avctx, AV_LOG_ERROR, "aspect ratio has forbidden 0 value\n"); if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) return AVERROR_INVALIDDATA; } - s1->frame_rate_index = get_bits(&s->gb, 4); + s1->frame_rate_index = get_bits(gb, 4); if (s1->frame_rate_index == 0 || s1->frame_rate_index > 13) { av_log(avctx, AV_LOG_WARNING, "frame_rate_index %d is invalid\n", s1->frame_rate_index); s1->frame_rate_index = 1; } - s->bit_rate = get_bits(&s->gb, 18) * 400LL; - if (check_marker(s->avctx, &s->gb, "in sequence header") == 0) { + s1->bit_rate = get_bits(gb, 18) * 400; + if (check_marker(s->avctx, gb, "in sequence header") == 0) { return AVERROR_INVALIDDATA; } - s->avctx->rc_buffer_size = get_bits(&s->gb, 10) * 1024 * 16; - skip_bits(&s->gb, 1); + s->avctx->rc_buffer_size = get_bits(gb, 10) * 1024 * 16; + skip_bits(gb, 1); /* get matrix */ - if (get_bits1(&s->gb)) { - load_matrix(s, s->chroma_intra_matrix, s->intra_matrix, 1); + if (get_bits1(gb)) { + load_matrix(s, gb, s->chroma_intra_matrix, s->intra_matrix, 1); } else { for (i = 0; i < 64; i++) { j = s->idsp.idct_permutation[i]; @@ -1817,8 +1787,8 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, s->chroma_intra_matrix[j] = v; } } - if (get_bits1(&s->gb)) { - load_matrix(s, s->chroma_inter_matrix, s->inter_matrix, 0); + if (get_bits1(gb)) { + load_matrix(s, gb, s->chroma_inter_matrix, s->inter_matrix, 0); } else { for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[i]; @@ -1828,7 +1798,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, } } - if (show_bits(&s->gb, 23) != 0) { + if (show_bits(gb, 23) != 0) { av_log(s->avctx, AV_LOG_ERROR, "sequence header damaged\n"); return AVERROR_INVALIDDATA; } @@ -1842,7 +1812,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, s->picture_structure = PICT_FRAME; s->first_field = 0; s->frame_pred_frame_dct = 1; - s->chroma_format = 1; + s->chroma_format = CHROMA_420; s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) @@ -1850,7 +1820,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, if (s->avctx->debug & FF_DEBUG_PICT_INFO) av_log(s->avctx, AV_LOG_DEBUG, "vbv buffer: %d, bitrate:%"PRId64", aspect_ratio_info: %d \n", - s->avctx->rc_buffer_size, s->bit_rate, s1->aspect_ratio_info); + s->avctx->rc_buffer_size, s1->bit_rate, s1->aspect_ratio_info); return 0; } @@ -1858,7 +1828,7 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, static int vcr2_init_sequence(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; int i, v, ret; /* start new MPEG-1 context decoding */ @@ -1875,7 +1845,8 @@ static int vcr2_init_sequence(AVCodecContext *avctx) if ((ret = ff_mpv_common_init(s)) < 0) return ret; if (!s->avctx->lowres) - ff_mpv_framesize_disable(&s->sc); + for (int i = 0; i < s->slice_context_count; i++) + ff_mpv_framesize_disable(&s->thread_context[i]->sc); for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[i]; @@ -1893,15 +1864,14 @@ static int vcr2_init_sequence(AVCodecContext *avctx) s->picture_structure = PICT_FRAME; s->first_field = 0; s->frame_pred_frame_dct = 1; - s->chroma_format = 1; + s->chroma_format = CHROMA_420; if (s->codec_tag == AV_RL32("BW10")) { s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; } else { s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; } - s1->save_width = s->width; - s1->save_height = s->height; s1->save_progressive_seq = s->progressive_sequence; + s1->save_chroma_format = s->chroma_format; return 0; } @@ -1917,6 +1887,12 @@ static void mpeg_set_cc_format(AVCodecContext *avctx, enum Mpeg2ClosedCaptionsFo av_log(avctx, AV_LOG_DEBUG, "CC: first seen substream is %s format\n", label); } + +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS + avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } static int mpeg_decode_a53_cc(AVCodecContext *avctx, @@ -1943,7 +1919,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, if (ret >= 0) memcpy(s1->a53_buf_ref->data + old_size, p + 7, cc_count * UINT64_C(3)); - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_A53_PART4, "A/53 Part 4"); } return 1; @@ -1969,9 +1944,9 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); if (ret >= 0) { uint8_t field, cc1, cc2; - uint8_t *cap = s1->a53_buf_ref->data; + uint8_t *cap = s1->a53_buf_ref->data + old_size; - memset(s1->a53_buf_ref->data + old_size, 0, cc_count * 3); + memset(cap, 0, cc_count * 3); for (i = 0; i < cc_count && get_bits_left(&gb) >= 26; i++) { skip_bits(&gb, 2); // priority field = get_bits(&gb, 2); @@ -1984,7 +1959,7 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, cap[0] = cap[1] = cap[2] = 0x00; } else { field = (field == 2 ? 1 : 0); - if (!s1->mpeg_enc_ctx.top_field_first) field = !field; + if (!s1->slice.c.top_field_first) field = !field; cap[0] = 0x04 | field; cap[1] = ff_reverse[cc1]; cap[2] = ff_reverse[cc2]; @@ -1993,7 +1968,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, } } - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_SCTE20, "SCTE-20"); } return 1; @@ -2042,7 +2016,7 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); if (ret >= 0) { uint8_t field1 = !!(p[4] & 0x80); - uint8_t *cap = s1->a53_buf_ref->data; + uint8_t *cap = s1->a53_buf_ref->data + old_size; p += 5; for (i = 0; i < cc_count; i++) { cap[0] = (p[0] == 0xff && field1) ? 0xfc : 0xfd; @@ -2056,10 +2030,72 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, } } - avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; mpeg_set_cc_format(avctx, CC_FORMAT_DVD, "DVD"); } return 1; + } else if ((!s1->cc_format || s1->cc_format == CC_FORMAT_DISH) && + buf_size >= 12 && + p[0] == 0x05 && p[1] == 0x02) { + /* extract Dish Network CC data */ + const uint8_t cc_header = 0xf8 | 0x04 /* valid */ | 0x00 /* line 21 field 1 */; + uint8_t cc_data[4] = {0}; + int cc_count = 0; + uint8_t cc_type = p[7]; + p += 8; + buf_size -= 8; + + if (cc_type == 0x05 && buf_size >= 7) { + cc_type = p[6]; + p += 7; + buf_size -= 7; + } + + if (cc_type == 0x02 && buf_size >= 4) { /* 2-byte caption, can be repeated */ + cc_count = 1; + cc_data[0] = p[1]; + cc_data[1] = p[2]; + cc_type = p[3]; + + /* Only repeat characters when the next type flag + * is 0x04 and the characters are repeatable (i.e., less than + * 32 with the parity stripped). + */ + if (cc_type == 0x04 && (cc_data[0] & 0x7f) < 32) { + cc_count = 2; + cc_data[2] = cc_data[0]; + cc_data[3] = cc_data[1]; + } + } else if (cc_type == 0x04 && buf_size >= 5) { /* 4-byte caption, not repeated */ + cc_count = 2; + cc_data[0] = p[1]; + cc_data[1] = p[2]; + cc_data[2] = p[3]; + cc_data[3] = p[4]; + } + + if (cc_count > 0) { + int ret; + int old_size = s1->a53_buf_ref ? s1->a53_buf_ref->size : 0; + const uint64_t new_size = (old_size + cc_count * UINT64_C(3)); + if (new_size > 3 * A53_MAX_CC_COUNT) + return AVERROR(EINVAL); + + ret = av_buffer_realloc(&s1->a53_buf_ref, new_size); + if (ret >= 0) { + uint8_t *cap = s1->a53_buf_ref->data + old_size; + cap[0] = cc_header; + cap[1] = cc_data[0]; + cap[2] = cc_data[1]; + if (cc_count == 2) { + cap[3] = cc_header; + cap[4] = cc_data[2]; + cap[5] = cc_data[3]; + } + } + + mpeg_set_cc_format(avctx, CC_FORMAT_DISH, "Dish Network"); + } + return 1; } return 0; } @@ -2067,7 +2103,6 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, static void mpeg_decode_user_data(AVCodecContext *avctx, const uint8_t *p, int buf_size) { - Mpeg1Context *s = avctx->priv_data; const uint8_t *buf_end = p + buf_size; Mpeg1Context *s1 = avctx->priv_data; @@ -2083,7 +2118,7 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, int i; for(i=0; i<20; i++) if (!memcmp(p+i, "\0TMPGEXS\0", 9)){ - s->tmpgexs= 1; + s1->tmpgexs = 1; } } /* we parse the DTG active format information */ @@ -2138,21 +2173,22 @@ static int mpeg_decode_gop(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { Mpeg1Context *s1 = avctx->priv_data; - MpegEncContext *s = &s1->mpeg_enc_ctx; + MPVContext *const s = &s1->slice.c; + GetBitContext gb0, *const gb = &gb0; int broken_link; int64_t tc; - int ret = init_get_bits8(&s->gb, buf, buf_size); + int ret = init_get_bits8(gb, buf, buf_size); if (ret < 0) return ret; - tc = s1->timecode_frame_start = get_bits(&s->gb, 25); + tc = s1->timecode_frame_start = get_bits(gb, 25); - s1->closed_gop = get_bits1(&s->gb); + s1->closed_gop = get_bits1(gb); /* broken_link indicates that after editing the * reference frames of the first B-Frames after GOP I-Frame * are missing (open gop) */ - broken_link = get_bits1(&s->gb); + broken_link = get_bits1(gb); if (s->avctx->debug & FF_DEBUG_PICT_INFO) { char tcbuf[AV_TIMECODE_STR_SIZE]; @@ -2165,11 +2201,40 @@ static int mpeg_decode_gop(AVCodecContext *avctx, return 0; } +static void mpeg12_execute_slice_threads(AVCodecContext *avctx, + Mpeg1Context *const s) +{ + if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && + !avctx->hwaccel) { + MPVContext *const s2 = &s->slice.c; + int error_count = 0; + + avctx->execute(avctx, slice_decode_thread, + s2->mpeg12_contexts, NULL, + s->slice_count, sizeof(s2->mpeg12_contexts[0])); + + for (int i = 0; i < s->slice_count; i++) { + MpegEncContext *const slice = s2->thread_context[i]; + int slice_err = atomic_load_explicit(&slice->er.error_count, + memory_order_relaxed); + // error_count can get set to INT_MAX on serious errors. + // So use saturated addition. + if ((unsigned)slice_err > INT_MAX - error_count) { + error_count = INT_MAX; + break; + } + error_count += slice_err; + } + atomic_store_explicit(&s2->er.error_count, error_count, + memory_order_relaxed); + } +} + static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, int *got_output, const uint8_t *buf, int buf_size) { Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; const uint8_t *buf_ptr = buf; const uint8_t *buf_end = buf + buf_size; int ret, input_size; @@ -2182,18 +2247,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &start_code); if (start_code > 0x1ff) { if (!skip_frame) { - if (HAVE_THREADS && - (avctx->active_thread_type & FF_THREAD_SLICE) && - !avctx->hwaccel) { - int i; - av_assert0(avctx->thread_count > 1); - - avctx->execute(avctx, slice_decode_thread, - &s2->thread_context[0], NULL, - s->slice_count, sizeof(void *)); - for (i = 0; i < s->slice_count; i++) - s2->er.error_count += s2->thread_context[i]->er.error_count; - } + mpeg12_execute_slice_threads(avctx, s); ret = slice_end(avctx, picture, got_output); if (ret < 0) @@ -2252,15 +2306,8 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, s2->intra_dc_precision= 3; s2->intra_matrix[0]= 1; } - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && - !avctx->hwaccel && s->slice_count) { - int i; - - avctx->execute(avctx, slice_decode_thread, - s2->thread_context, NULL, - s->slice_count, sizeof(void *)); - for (i = 0; i < s->slice_count; i++) - s2->er.error_count += s2->thread_context[i]->er.error_count; + if (s->slice_count) { + mpeg12_execute_slice_threads(avctx, s); s->slice_count = 0; } if (last_code == 0 || last_code == SLICE_MIN_START_CODE) { @@ -2283,15 +2330,17 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } break; - case EXT_START_CODE: - ret = init_get_bits8(&s2->gb, buf_ptr, input_size); + case EXT_START_CODE: { + GetBitContext gb0, *const gb = &gb0; + + ret = init_get_bits8(gb, buf_ptr, input_size); if (ret < 0) return ret; - switch (get_bits(&s2->gb, 4)) { + switch (get_bits(gb, 4)) { case 0x1: if (last_code == 0) { - mpeg_decode_sequence_extension(s); + mpeg_decode_sequence_extension(s, gb); } else { av_log(avctx, AV_LOG_ERROR, "ignoring seq ext after %X\n", last_code); @@ -2300,17 +2349,17 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, } break; case 0x2: - mpeg_decode_sequence_display_extension(s); + mpeg_decode_sequence_display_extension(s, gb); break; case 0x3: - mpeg_decode_quant_matrix_extension(s2); + mpeg_decode_quant_matrix_extension(s2, gb); break; case 0x7: - mpeg_decode_picture_display_extension(s); + mpeg_decode_picture_display_extension(s, gb); break; case 0x8: if (last_code == PICTURE_START_CODE) { - int ret = mpeg_decode_picture_coding_extension(s); + int ret = mpeg_decode_picture_coding_extension(s, gb); if (ret < 0) return ret; } else { @@ -2322,6 +2371,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, break; } break; + } case USER_START_CODE: mpeg_decode_user_data(avctx, buf_ptr, input_size); break; @@ -2458,15 +2508,14 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, int threshold = (s2->mb_height * s->slice_count + s2->slice_context_count / 2) / s2->slice_context_count; - av_assert0(avctx->thread_count > 1); if (threshold <= mb_y) { - MpegEncContext *thread_context = s2->thread_context[s->slice_count]; + Mpeg12SliceContext *const thread_context = s2->mpeg12_contexts[s->slice_count]; - thread_context->start_mb_y = mb_y; - thread_context->end_mb_y = s2->mb_height; + thread_context->c.start_mb_y = mb_y; + thread_context->c.end_mb_y = s2->mb_height; if (s->slice_count) { s2->thread_context[s->slice_count - 1]->end_mb_y = mb_y; - ret = ff_update_duplicate_context(thread_context, s2); + ret = ff_update_duplicate_context(&thread_context->c, s2); if (ret < 0) return ret; } @@ -2477,7 +2526,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, } buf_ptr += 2; // FIXME add minimum number of bytes per slice } else { - ret = mpeg_decode_slice(s2, mb_y, &buf_ptr, input_size); + ret = mpeg_decode_slice(&s->slice, mb_y, &buf_ptr, input_size); emms_c(); if (ret < 0) { @@ -2506,7 +2555,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, int ret; int buf_size = avpkt->size; Mpeg1Context *s = avctx->priv_data; - MpegEncContext *s2 = &s->mpeg_enc_ctx; + MPVContext *const s2 = &s->slice.c; if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == SEQ_END_CODE)) { /* special case for last picture */ @@ -2566,7 +2615,7 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, return ret; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; @@ -2599,7 +2648,6 @@ const FFCodec ff_mpeg1video_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = flush, .p.max_lowres = 3, - UPDATE_THREAD_CONTEXT(mpeg_decode_update_thread_context), .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_MPEG1_NVDEC_HWACCEL HWACCEL_NVDEC(mpeg1), @@ -2620,7 +2668,7 @@ const FFCodec ff_mpeg1video_decoder = { static const AVOption mpeg2video_options[] = { { "cc_format", "extract a specific Closed Captions format", M2V_OFFSET(cc_format), AV_OPT_TYPE_INT, { .i64 = CC_FORMAT_AUTO }, - CC_FORMAT_AUTO, CC_FORMAT_DVD, M2V_PARAM, .unit = "cc_format" }, + CC_FORMAT_AUTO, CC_FORMAT_DISH, M2V_PARAM, .unit = "cc_format" }, { "auto", "pick first seen CC substream", 0, AV_OPT_TYPE_CONST, { .i64 = CC_FORMAT_AUTO }, .flags = M2V_PARAM, .unit = "cc_format" }, @@ -2630,6 +2678,8 @@ static const AVOption mpeg2video_options[] = { { .i64 = CC_FORMAT_SCTE20 }, .flags = M2V_PARAM, .unit = "cc_format" }, { "dvd", "pick DVD CC substream", 0, AV_OPT_TYPE_CONST, { .i64 = CC_FORMAT_DVD }, .flags = M2V_PARAM, .unit = "cc_format" }, + { "dish", "pick Dish Network CC substream", 0, AV_OPT_TYPE_CONST, + { .i64 = CC_FORMAT_DISH }, .flags = M2V_PARAM, .unit = "cc_format" }, { NULL } }; @@ -2704,18 +2754,18 @@ const FFCodec ff_mpegvideo_decoder = { }; typedef struct IPUContext { - MpegEncContext m; + Mpeg12SliceContext m; int flags; - DECLARE_ALIGNED(32, int16_t, block)[6][64]; } IPUContext; static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt) { IPUContext *s = avctx->priv_data; - MpegEncContext *m = &s->m; - GetBitContext *gb = &m->gb; + MPVContext *const m = &s->m.c; + GetBitContext *const gb = &s->m.gb; + int16_t (*const block)[64] = s->m.block; int ret; // Check for minimal intra MB size (considering mb header, luma & chroma dc VLC, ac EOB VLC) @@ -2736,8 +2786,9 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, m->intra_vlc_format = !!(s->flags & 0x20); m->alternate_scan = !!(s->flags & 0x10); - ff_init_scantable(m->idsp.idct_permutation, &m->intra_scantable, - s->flags & 0x10 ? ff_alternate_vertical_scan : ff_zigzag_direct); + ff_permute_scantable(m->intra_scantable.permutated, + s->flags & 0x10 ? ff_alternate_vertical_scan : ff_zigzag_direct, + m->idsp.idct_permutation); m->last_dc[0] = m->last_dc[1] = m->last_dc[2] = 1 << (7 + (s->flags & 3)); m->qscale = 1; @@ -2762,19 +2813,19 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, skip_bits1(gb); if (intraquant) - m->qscale = mpeg_get_qscale(m); + m->qscale = mpeg_get_qscale(gb, m->q_scale_type); - memset(s->block, 0, sizeof(s->block)); + memset(block, 0, 6 * sizeof(*block)); for (int n = 0; n < 6; n++) { if (s->flags & 0x80) { - ret = ff_mpeg1_decode_block_intra(&m->gb, + ret = ff_mpeg1_decode_block_intra(gb, m->intra_matrix, m->intra_scantable.permutated, - m->last_dc, s->block[n], + m->last_dc, block[n], n, m->qscale); } else { - ret = mpeg2_decode_block_intra(m, s->block[n], n); + ret = mpeg2_decode_block_intra(&s->m, block[n], n); } if (ret < 0) @@ -2782,17 +2833,17 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, } m->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x, - frame->linesize[0], s->block[0]); + frame->linesize[0], block[0]); m->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8, - frame->linesize[0], s->block[1]); + frame->linesize[0], block[1]); m->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x, - frame->linesize[0], s->block[2]); + frame->linesize[0], block[2]); m->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8, - frame->linesize[0], s->block[3]); + frame->linesize[0], block[3]); m->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), - frame->linesize[1], s->block[4]); + frame->linesize[1], block[4]); m->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), - frame->linesize[2], s->block[5]); + frame->linesize[2], block[5]); } } @@ -2808,7 +2859,7 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, static av_cold int ipu_decode_init(AVCodecContext *avctx) { IPUContext *s = avctx->priv_data; - MpegEncContext *m = &s->m; + MPVContext *const m = &s->m.c; avctx->pix_fmt = AV_PIX_FMT_YUV420P; m->avctx = avctx; diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index e56571da03..fb480d0eec 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -25,6 +25,7 @@ * MPEG-1/2 encoder */ +#include #include #include "config.h" @@ -46,9 +47,9 @@ #include "mpeg12vlc.h" #include "mpegutils.h" #include "mpegvideo.h" -#include "mpegvideodata.h" #include "mpegvideoenc.h" #include "profiles.h" +#include "put_bits.h" #include "rl.h" #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER @@ -72,7 +73,7 @@ static uint32_t mpeg1_lum_dc_uni[512]; static uint32_t mpeg1_chr_dc_uni[512]; typedef struct MPEG12EncContext { - MpegEncContext mpeg; + MPVMainEncContext mpeg; AVRational frame_rate_ext; unsigned frame_rate_index; @@ -137,157 +138,27 @@ av_cold void ff_mpeg1_init_uni_ac_vlc(const int8_t max_level[], } #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER -static int find_frame_rate_index(AVCodecContext *avctx, MPEG12EncContext *mpeg12) -{ - int i; - AVRational bestq = (AVRational) {0, 0}; - AVRational ext; - AVRational target = av_inv_q(avctx->time_base); - - for (i = 1; i < 14; i++) { - if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && - i >= 9) - break; - - for (ext.num=1; ext.num <= 4; ext.num++) { - for (ext.den=1; ext.den <= 32; ext.den++) { - AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]); - - if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) - continue; - if (av_gcd(ext.den, ext.num) != 1) - continue; - - if ( bestq.num==0 - || av_nearer_q(target, bestq, q) < 0 - || ext.num==1 && ext.den==1 && av_nearer_q(target, bestq, q) == 0) { - bestq = q; - mpeg12->frame_rate_index = i; - mpeg12->frame_rate_ext.num = ext.num; - mpeg12->frame_rate_ext.den = ext.den; - } - } - } - } - - if (av_cmp_q(target, bestq)) - return -1; - else - return 0; -} - -static av_cold int encode_init(AVCodecContext *avctx) -{ - MPEG12EncContext *const mpeg12 = avctx->priv_data; - int ret; - int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; - - if (avctx->width > max_size || avctx->height > max_size) { - av_log(avctx, AV_LOG_ERROR, "%s does not support resolutions above %dx%d\n", - CONFIG_SMALL ? avctx->codec->name : avctx->codec->long_name, - max_size, max_size); - return AVERROR(EINVAL); - } - if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { - av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); - return AVERROR(EINVAL); - } - - if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { - if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { - av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" - "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); - return AVERROR(EINVAL); - } - } - - if (avctx->profile == AV_PROFILE_UNKNOWN) { - if (avctx->level != AV_LEVEL_UNKNOWN) { - av_log(avctx, AV_LOG_ERROR, "Set profile and level\n"); - return AVERROR(EINVAL); - } - /* Main or 4:2:2 */ - avctx->profile = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? AV_PROFILE_MPEG2_MAIN - : AV_PROFILE_MPEG2_422; - } - if (avctx->level == AV_LEVEL_UNKNOWN) { - if (avctx->profile == AV_PROFILE_MPEG2_422) { /* 4:2:2 */ - if (avctx->width <= 720 && avctx->height <= 608) - avctx->level = 5; /* Main */ - else - avctx->level = 2; /* High */ - } else { - if (avctx->profile != AV_PROFILE_MPEG2_HIGH && - avctx->pix_fmt != AV_PIX_FMT_YUV420P) { - av_log(avctx, AV_LOG_ERROR, - "Only High(1) and 4:2:2(0) profiles support 4:2:2 color sampling\n"); - return AVERROR(EINVAL); - } - if (avctx->width <= 720 && avctx->height <= 576) - avctx->level = 8; /* Main */ - else if (avctx->width <= 1440) - avctx->level = 6; /* High 1440 */ - else - avctx->level = 4; /* High */ - } - } - - if ((ret = ff_mpv_encode_init(avctx)) < 0) - return ret; - - if (find_frame_rate_index(avctx, mpeg12) < 0) { - if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", - avctx->time_base.den, avctx->time_base.num); - return AVERROR(EINVAL); - } else { - av_log(avctx, AV_LOG_INFO, - "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", - avctx->time_base.den, avctx->time_base.num); - } - } - - if (mpeg12->drop_frame_timecode) - mpeg12->tc.flags |= AV_TIMECODE_FLAG_DROPFRAME; - if (mpeg12->drop_frame_timecode && mpeg12->frame_rate_index != 4) { - av_log(avctx, AV_LOG_ERROR, - "Drop frame time code only allowed with 1001/30000 fps\n"); - return AVERROR(EINVAL); - } - - if (mpeg12->tc_opt_str) { - AVRational rate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; - int ret = av_timecode_init_from_string(&mpeg12->tc, rate, mpeg12->tc_opt_str, avctx); - if (ret < 0) - return ret; - mpeg12->drop_frame_timecode = !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME); - mpeg12->timecode_frame_start = mpeg12->tc.start; - } else { - mpeg12->timecode_frame_start = 0; // default is -1 - } - - return 0; -} - -static void put_header(MpegEncContext *s, uint32_t header) +static void put_header(MPVEncContext *const s, uint32_t header) { align_put_bits(&s->pb); put_bits32(&s->pb, header); } /* put sequence header if needed */ -static void mpeg1_encode_sequence_header(MpegEncContext *s) +static void mpeg1_encode_sequence_header(MPEG12EncContext *mpeg12) { - MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)s; + MPVEncContext *const s = &mpeg12->mpeg.s; unsigned int vbv_buffer_size, fps, v; int constraint_parameter_flag; AVRational framerate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; uint64_t time_code; int64_t best_aspect_error = INT64_MAX; - AVRational aspect_ratio = s->avctx->sample_aspect_ratio; + AVRational aspect_ratio = s->c.avctx->sample_aspect_ratio; int aspect_ratio_info; - if (!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY)) + put_bits_assume_flushed(&s->pb); + + if (!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY)) return; if (aspect_ratio.num == 0 || aspect_ratio.den == 0) @@ -296,15 +167,15 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) /* MPEG-1 header repeated every GOP */ put_header(s, SEQ_START_CODE); - put_sbits(&s->pb, 12, s->width & 0xFFF); - put_sbits(&s->pb, 12, s->height & 0xFFF); + put_sbits(&s->pb, 12, s->c.width & 0xFFF); + put_sbits(&s->pb, 12, s->c.height & 0xFFF); for (int i = 1; i < 15; i++) { int64_t error = aspect_ratio.num * (1LL<<32) / aspect_ratio.den; - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || i <= 1) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO || i <= 1) error -= (1LL<<32) / ff_mpeg1_aspect[i]; else - error -= (1LL<<32)*ff_mpeg2_aspect[i].num * s->height / s->width / ff_mpeg2_aspect[i].den; + error -= (1LL<<32)*ff_mpeg2_aspect[i].num * s->c.height / s->c.width / ff_mpeg2_aspect[i].den; error = FFABS(error); @@ -317,20 +188,20 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 4, aspect_ratio_info); put_bits(&s->pb, 4, mpeg12->frame_rate_index); - if (s->avctx->rc_max_rate) { - v = (s->avctx->rc_max_rate + 399) / 400; - if (v > 0x3ffff && s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.avctx->rc_max_rate) { + v = (s->c.avctx->rc_max_rate + 399) / 400; + if (v > 0x3ffff && s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) v = 0x3ffff; } else { v = 0x3FFFF; } - if (s->avctx->rc_buffer_size) - vbv_buffer_size = s->avctx->rc_buffer_size; + if (s->c.avctx->rc_buffer_size) + vbv_buffer_size = s->c.avctx->rc_buffer_size; else /* VBV calculation: Scaled so that a VCD has the proper * VBV size of 40 kilobytes */ - vbv_buffer_size = av_rescale_rnd(s->bit_rate, 20, 1151929 / 2, AV_ROUND_ZERO) * 8 * 1024; + vbv_buffer_size = av_rescale_rnd(mpeg12->mpeg.bit_rate, 20, 1151929 / 2, AV_ROUND_ZERO) * 8 * 1024; vbv_buffer_size = (vbv_buffer_size + 16383) / 16384; put_sbits(&s->pb, 18, v); @@ -338,48 +209,48 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_sbits(&s->pb, 10, vbv_buffer_size); constraint_parameter_flag = - s->width <= 768 && - s->height <= 576 && - s->mb_width * s->mb_height <= 396 && - s->mb_width * s->mb_height * framerate.num <= 396 * 25 * framerate.den && + s->c.width <= 768 && + s->c.height <= 576 && + s->c.mb_width * s->c.mb_height <= 396 && + s->c.mb_width * s->c.mb_height * framerate.num <= 396 * 25 * framerate.den && framerate.num <= framerate.den * 30 && - s->avctx->me_range && - s->avctx->me_range < 128 && + s->c.avctx->me_range && + s->c.avctx->me_range < 128 && vbv_buffer_size <= 20 && v <= 1856000 / 400 && - s->codec_id == AV_CODEC_ID_MPEG1VIDEO; + s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO; put_bits(&s->pb, 1, constraint_parameter_flag); - ff_write_quant_matrix(&s->pb, s->avctx->intra_matrix); - ff_write_quant_matrix(&s->pb, s->avctx->inter_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->intra_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->inter_matrix); - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { const AVFrameSideData *side_data; - int width = s->width; - int height = s->height; + int width = s->c.width; + int height = s->c.height; int use_seq_disp_ext; put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 1); // seq ext - put_bits(&s->pb, 1, s->avctx->profile == AV_PROFILE_MPEG2_422); // escx 1 for 4:2:2 profile + put_bits(&s->pb, 1, s->c.avctx->profile == AV_PROFILE_MPEG2_422); // escx 1 for 4:2:2 profile - put_bits(&s->pb, 3, s->avctx->profile); // profile - put_bits(&s->pb, 4, s->avctx->level); // level + put_bits(&s->pb, 3, s->c.avctx->profile); // profile + put_bits(&s->pb, 4, s->c.avctx->level); // level - put_bits(&s->pb, 1, s->progressive_sequence); - put_bits(&s->pb, 2, s->chroma_format); - put_bits(&s->pb, 2, s->width >> 12); - put_bits(&s->pb, 2, s->height >> 12); + put_bits(&s->pb, 1, s->c.progressive_sequence); + put_bits(&s->pb, 2, s->c.chroma_format); + put_bits(&s->pb, 2, s->c.width >> 12); + put_bits(&s->pb, 2, s->c.height >> 12); put_bits(&s->pb, 12, v >> 18); // bitrate ext put_bits(&s->pb, 1, 1); // marker put_bits(&s->pb, 8, vbv_buffer_size >> 10); // vbv buffer ext - put_bits(&s->pb, 1, s->low_delay); + put_bits(&s->pb, 1, s->c.low_delay); put_bits(&s->pb, 2, mpeg12->frame_rate_ext.num-1); // frame_rate_ext_n put_bits(&s->pb, 5, mpeg12->frame_rate_ext.den-1); // frame_rate_ext_d - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, AV_FRAME_DATA_PANSCAN); + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_PANSCAN); if (side_data) { const AVPanScan *pan_scan = (AVPanScan *)side_data->data; if (pan_scan->width && pan_scan->height) { @@ -388,11 +259,11 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) } } - use_seq_disp_ext = (width != s->width || - height != s->height || - s->avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || - s->avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - s->avctx->colorspace != AVCOL_SPC_UNSPECIFIED || + use_seq_disp_ext = (width != s->c.width || + height != s->c.height || + s->c.avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + s->c.avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + s->c.avctx->colorspace != AVCOL_SPC_UNSPECIFIED || mpeg12->video_format != VIDEO_FORMAT_UNSPECIFIED); if (mpeg12->seq_disp_ext == 1 || @@ -401,9 +272,9 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 4, 2); // sequence display extension put_bits(&s->pb, 3, mpeg12->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 - put_bits(&s->pb, 8, s->avctx->colorspace); // matrix_coefficients + put_bits(&s->pb, 8, s->c.avctx->color_primaries); // colour_primaries + put_bits(&s->pb, 8, s->c.avctx->color_trc); // transfer_characteristics + put_bits(&s->pb, 8, s->c.avctx->colorspace); // matrix_coefficients put_bits(&s->pb, 14, width); // display_horizontal_size put_bits(&s->pb, 1, 1); // marker_bit put_bits(&s->pb, 14, height); // display_vertical_size @@ -416,10 +287,10 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) /* time code: we must convert from the real frame rate to a * fake MPEG frame rate in case of low frame rate */ fps = (framerate.num + framerate.den / 2) / framerate.den; - time_code = s->cur_pic.ptr->coded_picture_number + + time_code = s->c.cur_pic.ptr->coded_picture_number + mpeg12->timecode_frame_start; - mpeg12->gop_picture_number = s->cur_pic.ptr->coded_picture_number; + mpeg12->gop_picture_number = s->c.cur_pic.ptr->coded_picture_number; av_assert0(mpeg12->drop_frame_timecode == !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME)); if (mpeg12->drop_frame_timecode) @@ -430,12 +301,12 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_bits(&s->pb, 1, 1); put_bits(&s->pb, 6, (uint32_t)((time_code / fps) % 60)); put_bits(&s->pb, 6, (uint32_t)((time_code % fps))); - put_bits(&s->pb, 1, !!(s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) || - s->intra_only || !mpeg12->gop_picture_number); + put_bits(&s->pb, 1, !!(s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) || + mpeg12->mpeg.intra_only || !mpeg12->gop_picture_number); put_bits(&s->pb, 1, 0); // broken link } -static inline void encode_mb_skip_run(MpegEncContext *s, int run) +static inline void encode_mb_skip_run(MPVEncContext *const s, int run) { while (run >= 33) { put_bits(&s->pb, 11, 0x008); @@ -445,57 +316,61 @@ static inline void encode_mb_skip_run(MpegEncContext *s, int run) ff_mpeg12_mbAddrIncrTable[run][0]); } -static av_always_inline void put_qscale(MpegEncContext *s) +static av_always_inline void put_qscale(MPVEncContext *const s) { - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); } -void ff_mpeg1_encode_slice_header(MpegEncContext *s) +void ff_mpeg1_encode_slice_header(MPVEncContext *const s) { - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->height > 2800) { - put_header(s, SLICE_MIN_START_CODE + (s->mb_y & 127)); + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO && s->c.height > 2800) { + put_header(s, SLICE_MIN_START_CODE + (s->c.mb_y & 127)); /* slice_vertical_position_extension */ - put_bits(&s->pb, 3, s->mb_y >> 7); + put_bits(&s->pb, 3, s->c.mb_y >> 7); } else { - put_header(s, SLICE_MIN_START_CODE + s->mb_y); + av_assert1(s->c.mb_y <= SLICE_MAX_START_CODE - SLICE_MIN_START_CODE); + put_header(s, SLICE_MIN_START_CODE + s->c.mb_y); } put_qscale(s); /* slice extra information */ put_bits(&s->pb, 1, 0); } -void ff_mpeg1_encode_picture_header(MpegEncContext *s) +static int mpeg1_encode_picture_header(MPVMainEncContext *const m) { - MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)s; + MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)m; + MPVEncContext *const s = &m->s; const AVFrameSideData *side_data; - mpeg1_encode_sequence_header(s); + + put_bits_assume_flushed(&s->pb); + + mpeg1_encode_sequence_header(mpeg12); /* MPEG-1 picture header */ put_header(s, PICTURE_START_CODE); /* temporal reference */ - // RAL: s->picture_number instead of s->fake_picture_number put_bits(&s->pb, 10, (s->picture_number - mpeg12->gop_picture_number) & 0x3ff); - put_bits(&s->pb, 3, s->pict_type); + put_bits(&s->pb, 3, s->c.pict_type); - s->vbv_delay_pos = put_bytes_count(&s->pb, 0); + m->vbv_delay_pos = put_bytes_count(&s->pb, 0); put_bits(&s->pb, 16, 0xFFFF); /* vbv_delay */ // RAL: Forward f_code also needed for B-frames - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || + s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 1, 0); /* half pel coordinates */ - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) put_bits(&s->pb, 3, s->f_code); /* forward_f_code */ else put_bits(&s->pb, 3, 7); /* forward_f_code */ } // RAL: Backward f_code necessary for B-frames - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 1, 0); /* half pel coordinates */ - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) put_bits(&s->pb, 3, s->b_code); /* backward_f_code */ else put_bits(&s->pb, 3, 7); /* backward_f_code */ @@ -503,45 +378,45 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); /* extra bit picture */ - s->frame_pred_frame_dct = 1; - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + s->c.frame_pred_frame_dct = 1; + if (s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO) { put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 8); /* pic ext */ - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || + s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 4, s->f_code); put_bits(&s->pb, 4, s->f_code); } else { put_bits(&s->pb, 8, 255); } - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { put_bits(&s->pb, 4, s->b_code); put_bits(&s->pb, 4, s->b_code); } else { put_bits(&s->pb, 8, 255); } - put_bits(&s->pb, 2, s->intra_dc_precision); + put_bits(&s->pb, 2, s->c.intra_dc_precision); - av_assert0(s->picture_structure == PICT_FRAME); - put_bits(&s->pb, 2, s->picture_structure); - if (s->progressive_sequence) + av_assert0(s->c.picture_structure == PICT_FRAME); + put_bits(&s->pb, 2, s->c.picture_structure); + if (s->c.progressive_sequence) put_bits(&s->pb, 1, 0); /* no repeat */ else - put_bits(&s->pb, 1, !!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + put_bits(&s->pb, 1, !!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); /* XXX: optimize the generation of this flag with entropy measures */ - s->frame_pred_frame_dct = s->progressive_sequence; + s->c.frame_pred_frame_dct = s->c.progressive_sequence; - put_bits(&s->pb, 1, s->frame_pred_frame_dct); - put_bits(&s->pb, 1, s->concealment_motion_vectors); - put_bits(&s->pb, 1, s->q_scale_type); - put_bits(&s->pb, 1, s->intra_vlc_format); - put_bits(&s->pb, 1, s->alternate_scan); - put_bits(&s->pb, 1, s->repeat_first_field); - s->progressive_frame = s->progressive_sequence; + put_bits(&s->pb, 1, s->c.frame_pred_frame_dct); + put_bits(&s->pb, 1, s->c.concealment_motion_vectors); + put_bits(&s->pb, 1, s->c.q_scale_type); + put_bits(&s->pb, 1, s->c.intra_vlc_format); + put_bits(&s->pb, 1, s->c.alternate_scan); + put_bits(&s->pb, 1, s->c.repeat_first_field); + s->c.progressive_frame = s->c.progressive_sequence; /* chroma_420_type */ - put_bits(&s->pb, 1, s->chroma_format == - CHROMA_420 ? s->progressive_frame : 0); - put_bits(&s->pb, 1, s->progressive_frame); + put_bits(&s->pb, 1, s->c.chroma_format == + CHROMA_420 ? s->c.progressive_frame : 0); + put_bits(&s->pb, 1, s->c.progressive_frame); put_bits(&s->pb, 1, 0); /* composite_display_flag */ } if (mpeg12->scan_offset) { @@ -551,7 +426,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) for (i = 0; i < sizeof(svcd_scan_offset_placeholder); i++) put_bits(&s->pb, 8, svcd_scan_offset_placeholder[i]); } - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_STEREO3D); if (side_data) { const AVStereo3D *stereo = (AVStereo3D *)side_data->data; @@ -577,67 +452,61 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) if (fpa_type != 0) { put_header(s, USER_START_CODE); - put_bits(&s->pb, 8, 'J'); // S3D_video_format_signaling_identifier - put_bits(&s->pb, 8, 'P'); - put_bits(&s->pb, 8, '3'); - put_bits(&s->pb, 8, 'D'); + // S3D_video_format_signaling_identifier + put_bits32(&s->pb, MKBETAG('J','P','3','D')); put_bits(&s->pb, 8, 0x03); // S3D_video_format_length put_bits(&s->pb, 1, 1); // reserved_bit put_bits(&s->pb, 7, fpa_type); // S3D_video_format_type - put_bits(&s->pb, 8, 0x04); // reserved_data[0] - put_bits(&s->pb, 8, 0xFF); // reserved_data[1] + put_bits(&s->pb, 16, 0x04FF); // reserved_data } } if (CONFIG_MPEG2VIDEO_ENCODER && mpeg12->a53_cc) { - side_data = av_frame_get_side_data(s->cur_pic.ptr->f, + side_data = av_frame_get_side_data(s->c.cur_pic.ptr->f, AV_FRAME_DATA_A53_CC); if (side_data) { if (side_data->size <= A53_MAX_CC_COUNT * 3 && side_data->size % 3 == 0) { - int i = 0; - put_header (s, USER_START_CODE); - put_bits(&s->pb, 8, 'G'); // user_identifier - put_bits(&s->pb, 8, 'A'); - put_bits(&s->pb, 8, '9'); - put_bits(&s->pb, 8, '4'); + put_bits32(&s->pb, MKBETAG('G','A','9','4')); // user_identifier put_bits(&s->pb, 8, 3); // user_data_type_code put_bits(&s->pb, 8, (side_data->size / 3 & A53_MAX_CC_COUNT) | 0x40); // flags, cc_count put_bits(&s->pb, 8, 0xff); // em_data - for (i = 0; i < side_data->size; i++) + for (int i = 0; i < side_data->size; i++) put_bits(&s->pb, 8, side_data->data[i]); put_bits(&s->pb, 8, 0xff); // marker_bits } else { - av_log(s->avctx, AV_LOG_WARNING, + av_log(s->c.avctx, AV_LOG_WARNING, "Closed Caption size (%"SIZE_SPECIFIER") can not exceed " "93 bytes and must be a multiple of 3\n", side_data->size); } } } - s->mb_y = 0; + s->c.mb_y = 0; ff_mpeg1_encode_slice_header(s); + + return 0; } -static inline void put_mb_modes(MpegEncContext *s, int n, int bits, +static inline void put_mb_modes(MPVEncContext *const s, int n, int bits, int has_mv, int field_motion) { put_bits(&s->pb, n, bits); - if (!s->frame_pred_frame_dct) { + if (!s->c.frame_pred_frame_dct) { if (has_mv) /* motion_type: frame/field */ put_bits(&s->pb, 2, 2 - field_motion); - put_bits(&s->pb, 1, s->interlaced_dct); + put_bits(&s->pb, 1, s->c.interlaced_dct); } } // RAL: Parameter added: f_or_b_code -static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code) +static void mpeg1_encode_motion(MPVEncContext *const s, int val, int f_or_b_code) { if (val == 0) { /* zero vector, corresponds to ff_mpeg12_mbMotionVectorTable[0] */ @@ -674,7 +543,7 @@ static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code) } } -static inline void encode_dc(MpegEncContext *s, int diff, int component) +static inline void encode_dc(MPVEncContext *const s, int diff, int component) { unsigned int diff_u = diff + 255; if (diff_u >= 511) { @@ -708,23 +577,23 @@ static inline void encode_dc(MpegEncContext *s, int diff, int component) } } -static void mpeg1_encode_block(MpegEncContext *s, const int16_t *block, int n) +static void mpeg1_encode_block(MPVEncContext *const s, const int16_t block[], int n) { int alevel, level, last_non_zero, dc, diff, i, j, run, last_index, sign; int code, component; const uint16_t (*table_vlc)[2] = ff_mpeg1_vlc_table; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; /* DC coef */ - if (s->mb_intra) { + if (s->c.mb_intra) { component = (n <= 3 ? 0 : (n & 1) + 1); dc = block[0]; /* overflow is impossible */ - diff = dc - s->last_dc[component]; + diff = dc - s->c.last_dc[component]; encode_dc(s, diff, component); - s->last_dc[component] = dc; + s->c.last_dc[component] = dc; i = 1; - if (s->intra_vlc_format) + if (s->c.intra_vlc_format) table_vlc = ff_mpeg2_vlc_table; } else { /* encode the first coefficient: needs to be done here because @@ -745,7 +614,7 @@ static void mpeg1_encode_block(MpegEncContext *s, const int16_t *block, int n) last_non_zero = i - 1; for (; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; next_coef: @@ -763,13 +632,12 @@ next_coef: put_bits(&s->pb, table_vlc[code][1] + 1, (table_vlc[code][0] << 1) + sign); } else { - /* Escape seems to be pretty rare <5% so I do not optimize it; - * the following value is the common escape value for both - * possible tables (i.e. table_vlc[111]). */ - put_bits(&s->pb, 6, 0x01); + /* Escape seems to be pretty rare <5% so I do not optimize it. + * The following encodes run together with the common escape + * value of both tables 000001b. */ + put_bits(&s->pb, 6 + 6, 0x01 << 6 | run); /* escape: only clip in this case */ - put_bits(&s->pb, 6, run); - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) { if (alevel < 128) { put_sbits(&s->pb, 8, level); } else { @@ -789,55 +657,55 @@ next_coef: put_bits(&s->pb, table_vlc[112][1], table_vlc[112][0]); } -static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, +static av_always_inline void mpeg1_encode_mb_internal(MPVEncContext *const s, const int16_t block[8][64], int motion_x, int motion_y, int mb_block_count, int chroma_y_shift) { /* MPEG-1 is always 420. */ -#define IS_MPEG1(s) (chroma_y_shift == 1 && (s)->codec_id == AV_CODEC_ID_MPEG1VIDEO) +#define IS_MPEG1(s) (chroma_y_shift == 1 && (s)->c.codec_id == AV_CODEC_ID_MPEG1VIDEO) int i, cbp; - const int mb_x = s->mb_x; - const int mb_y = s->mb_y; - const int first_mb = mb_x == s->resync_mb_x && mb_y == s->resync_mb_y; + const int mb_x = s->c.mb_x; + const int mb_y = s->c.mb_y; + const int first_mb = mb_x == s->c.resync_mb_x && mb_y == s->c.resync_mb_y; /* compute cbp */ cbp = 0; for (i = 0; i < mb_block_count; i++) - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (mb_block_count - 1 - i); - if (cbp == 0 && !first_mb && s->mv_type == MV_TYPE_16X16 && - (mb_x != s->mb_width - 1 || - (mb_y != s->end_mb_y - 1 && IS_MPEG1(s))) && - ((s->pict_type == AV_PICTURE_TYPE_P && (motion_x | motion_y) == 0) || - (s->pict_type == AV_PICTURE_TYPE_B && s->mv_dir == s->last_mv_dir && - (((s->mv_dir & MV_DIR_FORWARD) - ? ((s->mv[0][0][0] - s->last_mv[0][0][0]) | - (s->mv[0][0][1] - s->last_mv[0][0][1])) : 0) | - ((s->mv_dir & MV_DIR_BACKWARD) - ? ((s->mv[1][0][0] - s->last_mv[1][0][0]) | - (s->mv[1][0][1] - s->last_mv[1][0][1])) : 0)) == 0))) { + if (cbp == 0 && !first_mb && s->c.mv_type == MV_TYPE_16X16 && + (mb_x != s->c.mb_width - 1 || + (mb_y != s->c.end_mb_y - 1 && IS_MPEG1(s))) && + ((s->c.pict_type == AV_PICTURE_TYPE_P && (motion_x | motion_y) == 0) || + (s->c.pict_type == AV_PICTURE_TYPE_B && s->c.mv_dir == s->last_mv_dir && + (((s->c.mv_dir & MV_DIR_FORWARD) + ? ((s->c.mv[0][0][0] - s->c.last_mv[0][0][0]) | + (s->c.mv[0][0][1] - s->c.last_mv[0][0][1])) : 0) | + ((s->c.mv_dir & MV_DIR_BACKWARD) + ? ((s->c.mv[1][0][0] - s->c.last_mv[1][0][0]) | + (s->c.mv[1][0][1] - s->c.last_mv[1][0][1])) : 0)) == 0))) { s->mb_skip_run++; - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; s->misc_bits++; s->last_bits++; - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->last_mv[0][0][0] = - s->last_mv[0][0][1] = - s->last_mv[0][1][0] = - s->last_mv[0][1][1] = 0; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.last_mv[0][0][0] = + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][0] = + s->c.last_mv[0][1][1] = 0; } } else { if (first_mb) { av_assert0(s->mb_skip_run == 0); - encode_mb_skip_run(s, s->mb_x); + encode_mb_skip_run(s, s->c.mb_x); } else { encode_mb_skip_run(s, s->mb_skip_run); } - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if (s->dquant && cbp) { /* macroblock_type: macroblock_quant = 1 */ put_mb_modes(s, 2, 1, 0, 0); @@ -845,23 +713,23 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } else { /* macroblock_type: macroblock_quant = 0 */ put_mb_modes(s, 1, 1, 0, 0); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); s->i_count++; - } else if (s->mb_intra) { + } else if (s->c.mb_intra) { if (s->dquant && cbp) { put_mb_modes(s, 6, 0x01, 0, 0); put_qscale(s); } else { put_mb_modes(s, 5, 0x03, 0, 0); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); s->i_count++; - memset(s->last_mv, 0, sizeof(s->last_mv)); - } else if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->mv_type == MV_TYPE_16X16) { + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); + } else if (s->c.pict_type == AV_PICTURE_TYPE_P) { + if (s->c.mv_type == MV_TYPE_16X16) { if (cbp != 0) { if ((motion_x | motion_y) == 0) { if (s->dquant) { @@ -883,34 +751,34 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, s->misc_bits += get_bits_diff(s); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_x - s->last_mv[0][0][0], + motion_x - s->c.last_mv[0][0][0], s->f_code); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_y - s->last_mv[0][0][1], + motion_y - s->c.last_mv[0][0][1], s->f_code); s->mv_bits += get_bits_diff(s); } } else { put_bits(&s->pb, 3, 1); /* motion only */ - if (!s->frame_pred_frame_dct) + if (!s->c.frame_pred_frame_dct) put_bits(&s->pb, 2, 2); /* motion_type: frame */ s->misc_bits += get_bits_diff(s); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_x - s->last_mv[0][0][0], + motion_x - s->c.last_mv[0][0][0], s->f_code); // RAL: f_code parameter added mpeg1_encode_motion(s, - motion_y - s->last_mv[0][0][1], + motion_y - s->c.last_mv[0][0][1], s->f_code); - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; s->mv_bits += get_bits_diff(s); } - s->last_mv[0][1][0] = s->last_mv[0][0][0] = motion_x; - s->last_mv[0][1][1] = s->last_mv[0][0][1] = motion_y; + s->c.last_mv[0][1][0] = s->c.last_mv[0][0][0] = motion_x; + s->c.last_mv[0][1][1] = s->c.last_mv[0][0][1] = motion_y; } else { - av_assert2(!s->frame_pred_frame_dct && s->mv_type == MV_TYPE_FIELD); + av_assert2(!s->c.frame_pred_frame_dct && s->c.mv_type == MV_TYPE_FIELD); if (cbp) { if (s->dquant) { @@ -922,19 +790,19 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } else { put_bits(&s->pb, 3, 1); /* motion only */ put_bits(&s->pb, 2, 1); /* motion_type: field */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[0][i]); + put_bits(&s->pb, 1, s->c.field_select[0][i]); mpeg1_encode_motion(s, - s->mv[0][i][0] - s->last_mv[0][i][0], + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][i][1] - (s->last_mv[0][i][1] >> 1), + s->c.mv[0][i][1] - (s->c.last_mv[0][i][1] >> 1), s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = 2 * s->mv[0][i][1]; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = 2 * s->c.mv[0][i][1]; } s->mv_bits += get_bits_diff(s); } @@ -951,91 +819,91 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, } } } else { - if (s->mv_type == MV_TYPE_16X16) { + if (s->c.mv_type == MV_TYPE_16X16) { if (cbp) { // With coded bloc pattern if (s->dquant) { - if (s->mv_dir == MV_DIR_FORWARD) + if (s->c.mv_dir == MV_DIR_FORWARD) put_mb_modes(s, 6, 3, 1, 0); else - put_mb_modes(s, 8 - s->mv_dir, 2, 1, 0); + put_mb_modes(s, 8 - s->c.mv_dir, 2, 1, 0); put_qscale(s); } else { - put_mb_modes(s, 5 - s->mv_dir, 3, 1, 0); + put_mb_modes(s, 5 - s->c.mv_dir, 3, 1, 0); } } else { // No coded bloc pattern - put_bits(&s->pb, 5 - s->mv_dir, 2); - if (!s->frame_pred_frame_dct) + put_bits(&s->pb, 5 - s->c.mv_dir, 2); + if (!s->c.frame_pred_frame_dct) put_bits(&s->pb, 2, 2); /* motion_type: frame */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { mpeg1_encode_motion(s, - s->mv[0][0][0] - s->last_mv[0][0][0], + s->c.mv[0][0][0] - s->c.last_mv[0][0][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][0][1] - s->last_mv[0][0][1], + s->c.mv[0][0][1] - s->c.last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = s->mv[0][0][0]; - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = s->mv[0][0][1]; + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = s->c.mv[0][0][0]; + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = s->c.mv[0][0][1]; } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { mpeg1_encode_motion(s, - s->mv[1][0][0] - s->last_mv[1][0][0], + s->c.mv[1][0][0] - s->c.last_mv[1][0][0], s->b_code); mpeg1_encode_motion(s, - s->mv[1][0][1] - s->last_mv[1][0][1], + s->c.mv[1][0][1] - s->c.last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0] = - s->last_mv[1][1][0] = s->mv[1][0][0]; - s->last_mv[1][0][1] = - s->last_mv[1][1][1] = s->mv[1][0][1]; + s->c.last_mv[1][0][0] = + s->c.last_mv[1][1][0] = s->c.mv[1][0][0]; + s->c.last_mv[1][0][1] = + s->c.last_mv[1][1][1] = s->c.mv[1][0][1]; } } else { - av_assert2(s->mv_type == MV_TYPE_FIELD); - av_assert2(!s->frame_pred_frame_dct); + av_assert2(s->c.mv_type == MV_TYPE_FIELD); + av_assert2(!s->c.frame_pred_frame_dct); if (cbp) { // With coded bloc pattern if (s->dquant) { - if (s->mv_dir == MV_DIR_FORWARD) + if (s->c.mv_dir == MV_DIR_FORWARD) put_mb_modes(s, 6, 3, 1, 1); else - put_mb_modes(s, 8 - s->mv_dir, 2, 1, 1); + put_mb_modes(s, 8 - s->c.mv_dir, 2, 1, 1); put_qscale(s); } else { - put_mb_modes(s, 5 - s->mv_dir, 3, 1, 1); + put_mb_modes(s, 5 - s->c.mv_dir, 3, 1, 1); } } else { // No coded bloc pattern - put_bits(&s->pb, 5 - s->mv_dir, 2); + put_bits(&s->pb, 5 - s->c.mv_dir, 2); put_bits(&s->pb, 2, 1); /* motion_type: field */ - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; } s->misc_bits += get_bits_diff(s); - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[0][i]); + put_bits(&s->pb, 1, s->c.field_select[0][i]); mpeg1_encode_motion(s, - s->mv[0][i][0] - s->last_mv[0][i][0], + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], s->f_code); mpeg1_encode_motion(s, - s->mv[0][i][1] - (s->last_mv[0][i][1] >> 1), + s->c.mv[0][i][1] - (s->c.last_mv[0][i][1] >> 1), s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = s->mv[0][i][1] * 2; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = s->c.mv[0][i][1] * 2; } } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { for (i = 0; i < 2; i++) { - put_bits(&s->pb, 1, s->field_select[1][i]); + put_bits(&s->pb, 1, s->c.field_select[1][i]); mpeg1_encode_motion(s, - s->mv[1][i][0] - s->last_mv[1][i][0], + s->c.mv[1][i][0] - s->c.last_mv[1][i][0], s->b_code); mpeg1_encode_motion(s, - s->mv[1][i][1] - (s->last_mv[1][i][1] >> 1), + s->c.mv[1][i][1] - (s->c.last_mv[1][i][1] >> 1), s->b_code); - s->last_mv[1][i][0] = s->mv[1][i][0]; - s->last_mv[1][i][1] = s->mv[1][i][1] * 2; + s->c.last_mv[1][i][0] = s->c.mv[1][i][0]; + s->c.last_mv[1][i][1] = s->c.mv[1][i][1] * 2; } } } @@ -1057,17 +925,19 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, if (cbp & (1 << (mb_block_count - 1 - i))) mpeg1_encode_block(s, block[i], i); s->mb_skip_run = 0; - if (s->mb_intra) + if (s->c.mb_intra) s->i_tex_bits += get_bits_diff(s); else s->p_tex_bits += get_bits_diff(s); } } -void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], - int motion_x, int motion_y) +static void mpeg12_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) { - if (s->chroma_format == CHROMA_420) + if (!s->c.mb_intra) + s->c.last_dc[0] = s->c.last_dc[1] = s->c.last_dc[2] = 128 << s->c.intra_dc_precision; + if (s->c.chroma_format == CHROMA_420) mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 6, 1); else mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 8, 0); @@ -1138,16 +1008,117 @@ static av_cold void mpeg12_encode_init_static(void) fcode_tab[mv + MAX_MV] = f_code; } -av_cold void ff_mpeg1_encode_init(MpegEncContext *s) +static av_cold int find_frame_rate_index(AVCodecContext *avctx, MPEG12EncContext *mpeg12) +{ + AVRational bestq = (AVRational) {0, 0}; + AVRational ext; + AVRational target = av_inv_q(avctx->time_base); + + for (int i = 1; i < 14; i++) { + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && + i >= 9) + break; + + for (ext.num = 1; ext.num <= 4; ext.num++) { + for (ext.den = 1; ext.den <= 32; ext.den++) { + AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]); + + if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) + continue; + if (av_gcd(ext.den, ext.num) != 1) + continue; + + if ( bestq.num==0 + || av_nearer_q(target, bestq, q) < 0 + || ext.num==1 && ext.den==1 && av_nearer_q(target, bestq, q) == 0) { + bestq = q; + mpeg12->frame_rate_index = i; + mpeg12->frame_rate_ext.num = ext.num; + mpeg12->frame_rate_ext.den = ext.den; + } + } + } + } + + if (av_cmp_q(target, bestq)) + return -1; + else + return 0; +} + +static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; + MPEG12EncContext *const mpeg12 = avctx->priv_data; + MPVMainEncContext *const m = &mpeg12->mpeg; + MPVEncContext *const s = &m->s; + int ret; + int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[s->intra_dc_precision]; + if (avctx->width > max_size || avctx->height > max_size) { + av_log(avctx, AV_LOG_ERROR, "%s does not support resolutions above %dx%d\n", + CONFIG_SMALL ? avctx->codec->name : avctx->codec->long_name, + max_size, max_size); + return AVERROR(EINVAL); + } + if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { + av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); + return AVERROR(EINVAL); + } + + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { + av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" + "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); + return AVERROR(EINVAL); + } + } + + if (s->c.q_scale_type == 1) { + if (avctx->qmax > 28) { + av_log(avctx, AV_LOG_ERROR, + "non linear quant only supports qmax <= 28 currently\n"); + return AVERROR_PATCHWELCOME; + } + } + + if (avctx->profile == AV_PROFILE_UNKNOWN) { + if (avctx->level != AV_LEVEL_UNKNOWN) { + av_log(avctx, AV_LOG_ERROR, "Set profile and level\n"); + return AVERROR(EINVAL); + } + /* Main or 4:2:2 */ + avctx->profile = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? AV_PROFILE_MPEG2_MAIN + : AV_PROFILE_MPEG2_422; + } + if (avctx->level == AV_LEVEL_UNKNOWN) { + if (avctx->profile == AV_PROFILE_MPEG2_422) { /* 4:2:2 */ + if (avctx->width <= 720 && avctx->height <= 608) + avctx->level = 5; /* Main */ + else + avctx->level = 2; /* High */ + } else { + if (avctx->profile != AV_PROFILE_MPEG2_HIGH && + avctx->pix_fmt != AV_PIX_FMT_YUV420P) { + av_log(avctx, AV_LOG_ERROR, + "Only High(1) and 4:2:2(0) profiles support 4:2:2 color sampling\n"); + return AVERROR(EINVAL); + } + if (avctx->width <= 720 && avctx->height <= 576) + avctx->level = 8; /* Main */ + else if (avctx->width <= 1440) + avctx->level = 6; /* High 1440 */ + else + avctx->level = 4; /* High */ + } + } + + m->encode_picture_header = mpeg1_encode_picture_header; + s->encode_mb = mpeg12_encode_mb; s->me.mv_penalty = mv_penalty; - s->fcode_tab = fcode_tab; - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + m->fcode_tab = fcode_tab + MAX_MV; + if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { s->min_qcoeff = -255; s->max_qcoeff = 255; } else { @@ -1155,7 +1126,7 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s) s->max_qcoeff = 2047; s->mpeg_quant = 1; } - if (s->intra_vlc_format) { + if (s->c.intra_vlc_format) { s->intra_ac_vlc_length = s->intra_ac_vlc_last_length = uni_mpeg2_ac_vlc_len; } else { @@ -1165,7 +1136,77 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s) s->inter_ac_vlc_length = s->inter_ac_vlc_last_length = uni_mpeg1_ac_vlc_len; + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && + s->c.thread_context[s->c.slice_context_count - 1]->start_mb_y > + SLICE_MAX_START_CODE - SLICE_MIN_START_CODE) { + // MPEG-1 slices must not start at a MB row number that would make + // their start code > SLICE_MAX_START_CODE. So make the last slice + // bigger if needed and evenly distribute the first 174 rows. + static_assert(MAX_THREADS <= 1 + SLICE_MAX_START_CODE - SLICE_MIN_START_CODE, + "With more than 175 slice contexts, we have to handle " + "the case in which there is no work to do for some " + "slice contexts."); + const int mb_height = SLICE_MAX_START_CODE - SLICE_MIN_START_CODE; + const int nb_slices = s->c.slice_context_count - 1; + + s->c.thread_context[nb_slices]->start_mb_y = mb_height; + + av_assert1(nb_slices >= 1); + for (int i = 0; i < nb_slices; i++) { + s->c.thread_context[i]->start_mb_y = + (mb_height * (i ) + nb_slices / 2) / nb_slices; + s->c.thread_context[i]->end_mb_y = + (mb_height * (i + 1) + nb_slices / 2) / nb_slices; + } + } + + if (find_frame_rate_index(avctx, mpeg12) < 0) { + if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", + avctx->time_base.den, avctx->time_base.num); + return AVERROR(EINVAL); + } else { + av_log(avctx, AV_LOG_INFO, + "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", + avctx->time_base.den, avctx->time_base.num); + } + } + + if (avctx->rc_max_rate && + avctx->rc_min_rate == avctx->rc_max_rate && + 90000LL * (avctx->rc_buffer_size - 1) > + avctx->rc_max_rate * 0xFFFFLL) { + av_log(avctx, AV_LOG_INFO, + "Warning vbv_delay will be set to 0xFFFF (=VBR) as the " + "specified vbv buffer is too large for the given bitrate!\n"); + } + + if (mpeg12->drop_frame_timecode) + mpeg12->tc.flags |= AV_TIMECODE_FLAG_DROPFRAME; + if (mpeg12->drop_frame_timecode && mpeg12->frame_rate_index != 4) { + av_log(avctx, AV_LOG_ERROR, + "Drop frame time code only allowed with 1001/30000 fps\n"); + return AVERROR(EINVAL); + } + + if (mpeg12->tc_opt_str) { + AVRational rate = ff_mpeg12_frame_rate_tab[mpeg12->frame_rate_index]; + int ret = av_timecode_init_from_string(&mpeg12->tc, rate, mpeg12->tc_opt_str, avctx); + if (ret < 0) + return ret; + mpeg12->drop_frame_timecode = !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME); + mpeg12->timecode_frame_start = mpeg12->tc.start; + } else { + mpeg12->timecode_frame_start = 0; // default is -1 + } + ff_thread_once(&init_static_once, mpeg12_encode_init_static); + + return 0; } #define OFFSET(x) offsetof(MPEG12EncContext, x) @@ -1191,9 +1232,9 @@ static const AVOption mpeg1_options[] = { static const AVOption mpeg2_options[] = { COMMON_OPTS { "intra_vlc", "Use MPEG-2 intra VLC table.", - FF_MPV_OFFSET(intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "non_linear_quant", "Use nonlinear quantizer.", FF_MPV_OFFSET(q_scale_type), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "alternate_scan", "Enable alternate scantable.", FF_MPV_OFFSET(alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + FF_MPV_OFFSET(c.intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "non_linear_quant", "Use nonlinear quantizer.", FF_MPV_OFFSET(c.q_scale_type), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "alternate_scan", "Enable alternate scantable.", FF_MPV_OFFSET(c.alternate_scan), 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 }, { "seq_disp_ext", "Write sequence_display_extension blocks.", OFFSET(seq_disp_ext), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE, .unit = "seq_disp_ext" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, .unit = "seq_disp_ext" }, @@ -1238,11 +1279,11 @@ const FFCodec ff_mpeg1video_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.supported_framerates = ff_mpeg12_frame_rate_tab + 1, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_FRAMERATES_ARRAY(ff_mpeg12_frame_rate_tab + 1), + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg1_class, @@ -1257,12 +1298,11 @@ const FFCodec ff_mpeg2video_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.supported_framerates = ff_mpeg2_frame_rate_tab, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUV422P, - AV_PIX_FMT_NONE }, + CODEC_FRAMERATES_ARRAY(ff_mpeg2_frame_rate_tab), + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg2_class, diff --git a/libavcodec/mpeg12enc.h b/libavcodec/mpeg12enc.h index 0b35af8a30..a8aeadbb3e 100644 --- a/libavcodec/mpeg12enc.h +++ b/libavcodec/mpeg12enc.h @@ -24,12 +24,16 @@ #include -#include "mpegvideo.h" +#include "mpegvideoenc.h" +#include "mpegvideodata.h" -void ff_mpeg1_encode_picture_header(MpegEncContext *s); -void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], - int motion_x, int motion_y); -void ff_mpeg1_encode_init(MpegEncContext *s); -void ff_mpeg1_encode_slice_header(MpegEncContext *s); +void ff_mpeg1_encode_slice_header(MPVEncContext *s); + +// Must not be called before intra_dc_precision has been sanitized in ff_mpv_encode_init() +static inline void ff_mpeg1_encode_init(MPVEncContext *s) +{ + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[s->c.intra_dc_precision]; +} #endif /* AVCODEC_MPEG12ENC_H */ diff --git a/libavcodec/mpeg4audio_sample_rates.h b/libavcodec/mpeg4audio_sample_rates.h index 0b8caa6d76..a847a97994 100644 --- a/libavcodec/mpeg4audio_sample_rates.h +++ b/libavcodec/mpeg4audio_sample_rates.h @@ -23,6 +23,10 @@ #ifndef AVCODEC_MPEG4AUDIO_SAMPLE_RATES_H #define AVCODEC_MPEG4AUDIO_SAMPLE_RATES_H +// This table contains only 13 real elements and is padded with zeroes. +// It is used by the AAC encoder as sample rate table, so the encoder +// needs to actually support all of these rates and it needs to have +// a trailing zero. const int ff_mpeg4audio_sample_rates[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 diff --git a/libavcodec/mpeg4video.c b/libavcodec/mpeg4video.c index 3133cc22c4..a53ce72dfd 100644 --- a/libavcodec/mpeg4video.c +++ b/libavcodec/mpeg4video.c @@ -20,35 +20,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/thread.h" - #include "mpegutils.h" #include "mpegvideo.h" #include "mpeg4video.h" #include "mpeg4data.h" -static av_cold void mpeg4_init_rl_intra(void) +int ff_mpeg4_get_video_packet_prefix_length(enum AVPictureType pict_type, + int f_code, int b_code) { - static uint8_t mpeg4_rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; - ff_rl_init(&ff_mpeg4_rl_intra, mpeg4_rl_intra_table); -} - -av_cold void ff_mpeg4_init_rl_intra(void) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - ff_thread_once(&init_static_once, mpeg4_init_rl_intra); -} - -int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s) -{ - switch (s->pict_type) { + switch (pict_type) { case AV_PICTURE_TYPE_I: return 16; case AV_PICTURE_TYPE_P: case AV_PICTURE_TYPE_S: - return s->f_code + 15; + return f_code + 15; case AV_PICTURE_TYPE_B: - return FFMAX3(s->f_code, s->b_code, 2) + 15; + return FFMAX3(f_code, b_code, 2) + 15; default: return -1; } @@ -56,17 +43,20 @@ int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s) void ff_mpeg4_clean_buffers(MpegEncContext *s) { - int c_wrap, c_xy, l_wrap, l_xy; + const int mb_height = s->mb_height; + int c_wrap, l_wrap, l_xy; l_wrap = s->b8_stride; l_xy = (2 * s->mb_y - 1) * l_wrap + s->mb_x * 2 - 1; c_wrap = s->mb_stride; - c_xy = (s->mb_y - 1) * c_wrap + s->mb_x - 1; + int u_xy = 2 * mb_height * l_wrap + s->mb_y * c_wrap + s->mb_x - 1; + int v_xy = u_xy + c_wrap * (mb_height + 1); + int16_t (*ac_val)[16] = s->ac_val; /* clean AC */ - memset(s->ac_val[0] + l_xy, 0, (l_wrap * 2 + 1) * 16 * sizeof(int16_t)); - memset(s->ac_val[1] + c_xy, 0, (c_wrap + 1) * 16 * sizeof(int16_t)); - memset(s->ac_val[2] + c_xy, 0, (c_wrap + 1) * 16 * sizeof(int16_t)); + memset(ac_val + l_xy, 0, (l_wrap * 2 + 1) * sizeof(*ac_val)); + memset(ac_val + u_xy, 0, (c_wrap + 1) * sizeof(*ac_val)); + memset(ac_val + v_xy, 0, (c_wrap + 1) * sizeof(*ac_val)); /* clean MV */ // we can't clear the MVs as they might be needed by a B-frame diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index 29b11eb92e..274b21a067 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -28,7 +28,8 @@ #include "mpegvideo.h" void ff_mpeg4_clean_buffers(MpegEncContext *s); -int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s); +int ff_mpeg4_get_video_packet_prefix_length(enum AVPictureType pict_type, + int f_code, int b_code); void ff_mpeg4_init_direct_mv(MpegEncContext *s); /** @@ -36,94 +37,4 @@ void ff_mpeg4_init_direct_mv(MpegEncContext *s); */ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my); -#if 0 //3IV1 is quite rare and it slows things down a tiny bit -#define IS_3IV1 s->codec_tag == AV_RL32("3IV1") -#else -#define IS_3IV1 0 -#endif - -/** - * Predict the dc. - * encoding quantized level -> quantized diff - * decoding quantized diff -> quantized level - * @param n block index (0-3 are luma, 4-5 are chroma) - * @param dir_ptr pointer to an integer where the prediction direction will be stored - */ -static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level, - int *dir_ptr, int encoding) -{ - int a, b, c, wrap, pred, scale, ret; - int16_t *dc_val; - - /* find prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - if (IS_3IV1) - scale = 8; - - wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; - - /* B C - * A X - */ - a = dc_val[-1]; - b = dc_val[-1 - wrap]; - c = dc_val[-wrap]; - - /* outside slice handling (we can't do that by memset as we need the - * dc for error resilience) */ - if (s->first_slice_line && n != 3) { - if (n != 2) - b = c = 1024; - if (n != 1 && s->mb_x == s->resync_mb_x) - b = a = 1024; - } - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) { - if (n == 0 || n == 4 || n == 5) - b = 1024; - } - - if (abs(a - b) < abs(b - c)) { - pred = c; - *dir_ptr = 1; /* top */ - } else { - pred = a; - *dir_ptr = 0; /* left */ - } - /* we assume pred is positive */ - pred = FASTDIV((pred + (scale >> 1)), scale); - - if (encoding) { - ret = level - pred; - } else { - level += pred; - ret = level; - } - level *= scale; - if (level & (~2047)) { - if (!s->encoding && (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE))) { - if (level < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "dc<0 at %dx%d\n", s->mb_x, s->mb_y); - 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 AVERROR_INVALIDDATA; - } - } - if (level < 0) - level = 0; - else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) - level = 2047; - } - dc_val[0] = level; - - return ret; -} - #endif /* AVCODEC_MPEG4VIDEO_H */ diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c index b00b523bde..a2a22234f2 100644 --- a/libavcodec/mpeg4video_parser.c +++ b/libavcodec/mpeg4video_parser.c @@ -84,7 +84,7 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, { struct Mp4vParseContext *pc = s1->priv_data; Mpeg4DecContext *dec_ctx = &pc->dec_ctx; - MpegEncContext *s = &dec_ctx->m; + MPVContext *const s = &dec_ctx->h.c; GetBitContext gb1, *gb = &gb1; int ret; @@ -92,13 +92,14 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, if (avctx->extradata_size && pc->first_picture) { init_get_bits(gb, avctx->extradata, avctx->extradata_size * 8); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 1, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 1, 1); if (ret < 0) av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata\n"); } init_get_bits(gb, buf, 8 * buf_size); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 0, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 0, 1); + avctx->has_b_frames = !s->low_delay; if (s->width && (!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height)) { ret = ff_set_dimensions(avctx, s->width, s->height); @@ -123,7 +124,7 @@ static av_cold int mpeg4video_parse_init(AVCodecParserContext *s) pc->first_picture = 1; pc->dec_ctx.quant_precision = 5; - pc->dec_ctx.m.slice_context_count = 1; + pc->dec_ctx.h.c.slice_context_count = 1; pc->dec_ctx.showed_packed_warning = 1; return 0; } diff --git a/libavcodec/mpeg4videodata.h b/libavcodec/mpeg4videodata.h index 8aac8a2255..baca8a0b9a 100644 --- a/libavcodec/mpeg4videodata.h +++ b/libavcodec/mpeg4videodata.h @@ -35,7 +35,6 @@ extern const int8_t ff_mpeg4_intra_level[102]; extern const int8_t ff_mpeg4_intra_run[102]; extern RLTable ff_mpeg4_rl_intra; -void ff_mpeg4_init_rl_intra(void); /* Note this is identical to the intra rvlc except that it is reordered. */ extern RLTable ff_rvlc_rl_inter; diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index debcafc4c0..f3d138387b 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -24,6 +24,7 @@ #include "config_components.h" +#include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/thread.h" @@ -35,6 +36,7 @@ #include "mpegvideo.h" #include "mpegvideodata.h" #include "mpegvideodec.h" +#include "mpegvideo_unquantize.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videodec.h" @@ -46,9 +48,14 @@ #include "profiles.h" #include "qpeldsp.h" #include "threadprogress.h" -#include "xvididct.h" #include "unary.h" +#if 0 //3IV1 is quite rare and it slows things down a tiny bit +#define IS_3IV1 (s->codec_tag == AV_RL32("3IV1")) +#else +#define IS_3IV1 0 +#endif + /* The defines below define the number of bits that are read at once for * reading vlc values. Changing these may improve speed and data cache needs * be aware though that decreasing them may need the number of stages that is @@ -74,6 +81,12 @@ static const int16_t mb_type_b_map[4] = { MB_TYPE_FORWARD_MV | MB_TYPE_16x16, }; +static inline Mpeg4DecContext *h263_to_mpeg4(H263DecContext *h) +{ + av_assert2(h->c.codec_id == AV_CODEC_ID_MPEG4 && h->c.avctx->priv_data == h); + return (Mpeg4DecContext*)h; +} + static void gmc1_motion(MpegEncContext *s, const Mpeg4DecContext *ctx, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture) @@ -312,55 +325,55 @@ void ff_mpeg4_decode_studio(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb * @param n block index (0-3 are luma, 4-5 are chroma) * @param dir the ac prediction direction */ -void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir) +void ff_mpeg4_pred_ac(H263DecContext *const h, int16_t *block, int n, int dir) { int i; int16_t *ac_val, *ac_val1; - int8_t *const qscale_table = s->cur_pic.qscale_table; + int8_t *const qscale_table = h->c.cur_pic.qscale_table; /* find prediction */ - ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + ac_val = &h->c.ac_val[0][0] + h->c.block_index[n] * 16; ac_val1 = ac_val; - if (s->ac_pred) { + if (h->c.ac_pred) { if (dir == 0) { - const int xy = s->mb_x - 1 + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x - 1 + h->c.mb_y * h->c.mb_stride; /* left prediction */ ac_val -= 16; - if (s->mb_x == 0 || s->qscale == qscale_table[xy] || + if (h->c.mb_x == 0 || h->c.qscale == qscale_table[xy] || n == 1 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i << 3]] += ac_val[i]; + block[h->c.idsp.idct_permutation[i << 3]] += ac_val[i]; } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i << 3]] += ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->qscale); + block[h->c.idsp.idct_permutation[i << 3]] += ROUNDED_DIV(ac_val[i] * qscale_table[xy], h->c.qscale); } } else { - const int xy = s->mb_x + s->mb_y * s->mb_stride - s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride - h->c.mb_stride; /* top prediction */ - ac_val -= 16 * s->block_wrap[n]; + ac_val -= 16 * h->c.block_wrap[n]; - if (s->mb_y == 0 || s->qscale == qscale_table[xy] || + if (h->c.mb_y == 0 || h->c.qscale == qscale_table[xy] || n == 2 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i]] += ac_val[i + 8]; + block[h->c.idsp.idct_permutation[i]] += ac_val[i + 8]; } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) - block[s->idsp.idct_permutation[i]] += ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->qscale); + block[h->c.idsp.idct_permutation[i]] += ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], h->c.qscale); } } } /* left copy */ for (i = 1; i < 8; i++) - ac_val1[i] = block[s->idsp.idct_permutation[i << 3]]; + ac_val1[i] = block[h->c.idsp.idct_permutation[i << 3]]; /* top copy */ for (i = 1; i < 8; i++) - ac_val1[8 + i] = block[s->idsp.idct_permutation[i]]; + ac_val1[8 + i] = block[h->c.idsp.idct_permutation[i]]; } /** @@ -369,28 +382,28 @@ void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir) */ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) { - MpegEncContext *s = &ctx->m; - int bits_count = get_bits_count(&s->gb); - int v = show_bits(&s->gb, 16); + H263DecContext *const h = &ctx->h; + int bits_count = get_bits_count(&h->gb); + int v = show_bits(&h->gb, 16); - if (s->workaround_bugs & FF_BUG_NO_PADDING && !ctx->resync_marker) + if (h->c.workaround_bugs & FF_BUG_NO_PADDING && !ctx->resync_marker) return 0; while (v <= 0xFF) { - if (s->pict_type == AV_PICTURE_TYPE_B || - (v >> (8 - s->pict_type) != 1) || s->partitioned_frame) + if (h->c.pict_type == AV_PICTURE_TYPE_B || + (v >> (8 - h->c.pict_type) != 1) || h->partitioned_frame) break; - skip_bits(&s->gb, 8 + s->pict_type); - bits_count += 8 + s->pict_type; - v = show_bits(&s->gb, 16); + skip_bits(&h->gb, 8 + h->c.pict_type); + bits_count += 8 + h->c.pict_type; + v = show_bits(&h->gb, 16); } - if (bits_count + 8 >= s->gb.size_in_bits) { + if (bits_count + 8 >= h->gb.size_in_bits) { v >>= 8; v |= 0x7F >> (7 - (bits_count & 7)); if (v == 0x7F) - return s->mb_num; + return h->c.mb_num; } else { static const uint16_t mpeg4_resync_prefix[8] = { 0x7F00, 0x7E00, 0x7C00, 0x7800, 0x7000, 0x6000, 0x4000, 0x0000 @@ -398,23 +411,23 @@ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) if (v == mpeg4_resync_prefix[bits_count & 7]) { int len, mb_num; - int mb_num_bits = av_log2(s->mb_num - 1) + 1; - GetBitContext gb = s->gb; + int mb_num_bits = av_log2(h->c.mb_num - 1) + 1; + GetBitContext gb = h->gb; - skip_bits(&s->gb, 1); - align_get_bits(&s->gb); + skip_bits(&h->gb, 1); + align_get_bits(&h->gb); for (len = 0; len < 32; len++) - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) break; - mb_num = get_bits(&s->gb, mb_num_bits); - if (!mb_num || mb_num > s->mb_num || get_bits_count(&s->gb)+6 > s->gb.size_in_bits) + mb_num = get_bits(&h->gb, mb_num_bits); + if (!mb_num || mb_num > h->c.mb_num || get_bits_count(&h->gb) + 6 > h->gb.size_in_bits) mb_num= -1; - s->gb = gb; + h->gb = gb; - if (len >= ff_mpeg4_get_video_packet_prefix_length(s)) + if (len >= ff_mpeg4_get_video_packet_prefix_length(h->c.pict_type, ctx->f_code, ctx->b_code)) return mb_num; } } @@ -423,7 +436,7 @@ static inline int mpeg4_is_resync(Mpeg4DecContext *ctx) static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + MpegEncContext *s = &ctx->h.c; int a = 2 << ctx->sprite_warping_accuracy; int rho = 3 - ctx->sprite_warping_accuracy; int r = 16 / a; @@ -598,7 +611,8 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g ctx->sprite_shift[1] = alpha + beta + rho - min_ab + 2; break; default: - av_assert0(0); + av_unreachable("num_sprite_warping_points outside of 0..3 results in an error" + "in which num_sprite_warping_points is reset to zero"); } /* try to simplify the situation */ if (sprite_delta[0][0] == a << ctx->sprite_shift[0] && @@ -677,13 +691,12 @@ overflow: } static int decode_new_pred(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; int len = FFMIN(ctx->time_increment_bits + 3, 15); get_bits(gb, len); if (get_bits1(gb)) get_bits(gb, len); - check_marker(s->avctx, gb, "after new_pred"); + check_marker(ctx->h.c.avctx, gb, "after new_pred"); return 0; } @@ -692,124 +705,125 @@ static int decode_new_pred(Mpeg4DecContext *ctx, GetBitContext *gb) { * Decode the next video packet. * @return <0 if something went wrong */ -int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) +int ff_mpeg4_decode_video_packet_header(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); - int mb_num_bits = av_log2(s->mb_num - 1) + 1; + int mb_num_bits = av_log2(h->c.mb_num - 1) + 1; int header_extension = 0, mb_num, len; /* is there enough space left for a video packet + header */ - if (get_bits_count(&s->gb) > s->gb.size_in_bits - 20) + if (get_bits_count(&h->gb) > h->gb.size_in_bits - 20) return AVERROR_INVALIDDATA; for (len = 0; len < 32; len++) - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) break; - if (len != ff_mpeg4_get_video_packet_prefix_length(s)) { - av_log(s->avctx, AV_LOG_ERROR, "marker does not match f_code\n"); + if (len != ff_mpeg4_get_video_packet_prefix_length(h->c.pict_type, ctx->f_code, ctx->b_code)) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker does not match f_code\n"); return AVERROR_INVALIDDATA; } if (ctx->shape != RECT_SHAPE) { - header_extension = get_bits1(&s->gb); + header_extension = get_bits1(&h->gb); // FIXME more stuff here } - mb_num = get_bits(&s->gb, mb_num_bits); - 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); + mb_num = get_bits(&h->gb, mb_num_bits); + if (mb_num >= h->c.mb_num || !mb_num) { + av_log(h->c.avctx, AV_LOG_ERROR, + "illegal mb_num in video packet (%d %d) \n", mb_num, h->c.mb_num); return AVERROR_INVALIDDATA; } - s->mb_x = mb_num % s->mb_width; - s->mb_y = mb_num / s->mb_width; + h->c.mb_x = mb_num % h->c.mb_width; + h->c.mb_y = mb_num / h->c.mb_width; if (ctx->shape != BIN_ONLY_SHAPE) { - int qscale = get_bits(&s->gb, ctx->quant_precision); + int qscale = get_bits(&h->gb, ctx->quant_precision); if (qscale) - s->chroma_qscale = s->qscale = qscale; + h->c.chroma_qscale = h->c.qscale = qscale; } if (ctx->shape == RECT_SHAPE) - header_extension = get_bits1(&s->gb); + header_extension = get_bits1(&h->gb); if (header_extension) { - while (get_bits1(&s->gb) != 0) + while (get_bits1(&h->gb) != 0) ; - check_marker(s->avctx, &s->gb, "before time_increment in video packed header"); - skip_bits(&s->gb, ctx->time_increment_bits); /* time_increment */ - check_marker(s->avctx, &s->gb, "before vop_coding_type in video packed header"); + check_marker(h->c.avctx, &h->gb, "before time_increment in video packed header"); + skip_bits(&h->gb, ctx->time_increment_bits); /* time_increment */ + check_marker(h->c.avctx, &h->gb, "before vop_coding_type in video packed header"); - skip_bits(&s->gb, 2); /* vop coding type */ + skip_bits(&h->gb, 2); /* vop coding type */ // FIXME not rect stuff here if (ctx->shape != BIN_ONLY_SHAPE) { - skip_bits(&s->gb, 3); /* intra dc vlc threshold */ + skip_bits(&h->gb, 3); /* intra dc vlc threshold */ // FIXME don't just ignore everything - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - if (mpeg4_decode_sprite_trajectory(ctx, &s->gb) < 0) + if (mpeg4_decode_sprite_trajectory(ctx, &h->gb) < 0) return AVERROR_INVALIDDATA; - av_log(s->avctx, AV_LOG_ERROR, "untested\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "untested\n"); } // FIXME reduced res stuff here - if (s->pict_type != AV_PICTURE_TYPE_I) { - int f_code = get_bits(&s->gb, 3); /* fcode_for */ + if (h->c.pict_type != AV_PICTURE_TYPE_I) { + int f_code = get_bits(&h->gb, 3); /* fcode_for */ if (f_code == 0) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Error, video packet header damaged (f_code=0)\n"); } - if (s->pict_type == AV_PICTURE_TYPE_B) { - int b_code = get_bits(&s->gb, 3); + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + int b_code = get_bits(&h->gb, 3); if (b_code == 0) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Error, video packet header damaged (b_code=0)\n"); } } } if (ctx->new_pred) - decode_new_pred(ctx, &s->gb); + decode_new_pred(ctx, &h->gb); return 0; } -static void reset_studio_dc_predictors(MpegEncContext *s) +static void reset_studio_dc_predictors(Mpeg4DecContext *const ctx) { + MPVContext *const s = &ctx->h.c; /* 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); + s->last_dc[2] = 1 << (s->avctx->bits_per_raw_sample + ctx->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) +int ff_mpeg4_decode_studio_slice_header(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; - GetBitContext *gb = &s->gb; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + GetBitContext *gb = &h->gb; unsigned vlc_len; uint16_t mb_num; if (get_bits_left(gb) >= 32 && get_bits_long(gb, 32) == SLICE_STARTCODE) { - vlc_len = av_log2(s->mb_width * s->mb_height) + 1; + vlc_len = av_log2(h->c.mb_width * h->c.mb_height) + 1; mb_num = get_bits(gb, vlc_len); - if (mb_num >= s->mb_num) + if (mb_num >= h->c.mb_num) return AVERROR_INVALIDDATA; - s->mb_x = mb_num % s->mb_width; - s->mb_y = mb_num / s->mb_width; + h->c.mb_x = mb_num % h->c.mb_width; + h->c.mb_y = mb_num / h->c.mb_width; if (ctx->shape != BIN_ONLY_SHAPE) - s->qscale = mpeg_get_qscale(s); + h->c.qscale = mpeg_get_qscale(&h->gb, h->c.q_scale_type); if (get_bits1(gb)) { /* slice_extension_flag */ skip_bits1(gb); /* intra_slice */ @@ -819,7 +833,7 @@ int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) skip_bits(gb, 8); /* extra_information_slice */ } - reset_studio_dc_predictors(s); + reset_studio_dc_predictors(ctx); } else { return AVERROR_INVALIDDATA; @@ -835,9 +849,9 @@ int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) */ static inline int get_amv(Mpeg4DecContext *ctx, int n) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; int x, y, mb_v, sum, dx, dy, shift; - int len = 1 << (s->f_code + 4); + int len = 1 << (ctx->f_code + 4); const int a = ctx->sprite_warping_accuracy; if (s->workaround_bugs & FF_BUG_AMV) @@ -880,23 +894,103 @@ static inline int get_amv(Mpeg4DecContext *ctx, int n) return sum; } +/** + * Predict the dc. + * @param n block index (0-3 are luma, 4-5 are chroma) + * @param dir_ptr pointer to an integer where the prediction direction will be stored + */ +static inline int mpeg4_pred_dc(MpegEncContext *s, int n, int *dir_ptr) +{ + const int16_t *const dc_val = s->dc_val + s->block_index[n]; + const int wrap = s->block_wrap[n]; + int pred; + + /* find prediction */ + + /* B C + * A X + */ + int a = dc_val[-1]; + int b = dc_val[-1 - wrap]; + int c = dc_val[-wrap]; + + /* outside slice handling (we can't do that by memset as we need the + * dc for error resilience) */ + if (s->first_slice_line && n != 3) { + if (n != 2) + b = c = 1024; + if (n != 1 && s->mb_x == s->resync_mb_x) + b = a = 1024; + } + if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) { + if (n == 0 || n == 4 || n == 5) + b = 1024; + } + + if (abs(a - b) < abs(b - c)) { + pred = c; + *dir_ptr = 1; /* top */ + } else { + pred = a; + *dir_ptr = 0; /* left */ + } + return pred; +} + +static inline int mpeg4_get_level_dc(MpegEncContext *s, int n, int pred, int level) +{ + int scale = n < 4 ? s->y_dc_scale : s->c_dc_scale; + int ret; + + if (IS_3IV1) + scale = 8; + + /* we assume pred is positive */ + pred = FASTDIV((pred + (scale >> 1)), scale); + + level += pred; + ret = level; + level *= scale; + if (level & (~2047)) { + if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) { + if (level < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "dc<0 at %dx%d\n", s->mb_x, s->mb_y); + 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 AVERROR_INVALIDDATA; + } + } + if (level < 0) + level = 0; + else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) + level = 2047; + } + s->dc_val[s->block_index[n]] = level; + + return ret; +} + /** * Decode the dc value. * @param n block index (0-3 are luma, 4-5 are chroma) * @param dir_ptr the prediction direction will be stored here * @return the quantized dc */ -static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) +static inline int mpeg4_decode_dc(H263DecContext *const h, int n, int *dir_ptr) { - int level, code; + int level, code, pred; if (n < 4) - code = get_vlc2(&s->gb, dc_lum, DC_VLC_BITS, 1); + code = get_vlc2(&h->gb, dc_lum, DC_VLC_BITS, 1); else - code = get_vlc2(&s->gb, dc_chrom, DC_VLC_BITS, 1); + code = get_vlc2(&h->gb, dc_chrom, DC_VLC_BITS, 1); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc vlc\n"); return AVERROR_INVALIDDATA; } @@ -905,28 +999,29 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) } else { if (IS_3IV1) { if (code == 1) - level = 2 * get_bits1(&s->gb) - 1; + level = 2 * get_bits1(&h->gb) - 1; else { - if (get_bits1(&s->gb)) - level = get_bits(&s->gb, code - 1) + (1 << (code - 1)); + if (get_bits1(&h->gb)) + level = get_bits(&h->gb, code - 1) + (1 << (code - 1)); else - level = -get_bits(&s->gb, code - 1) - (1 << (code - 1)); + level = -get_bits(&h->gb, code - 1) - (1 << (code - 1)); } } else { - level = get_xbits(&s->gb, code); + level = get_xbits(&h->gb, code); } if (code > 8) { - 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"); + if (get_bits1(&h->gb) == 0) { /* marker */ + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc marker bit missing\n"); return AVERROR_INVALIDDATA; } } } } - return ff_mpeg4_pred_dc(s, n, level, dir_ptr, 0); + pred = mpeg4_pred_dc(&h->c, n, dir_ptr); + return mpeg4_get_level_dc(&h->c, n, pred, level); } /** @@ -935,85 +1030,85 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) */ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int mb_num = 0; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; /* decode first partition */ - s->first_slice_line = 1; - for (; s->mb_y < s->mb_height; s->mb_y++) { - ff_init_block_index(s); - for (; s->mb_x < s->mb_width; s->mb_x++) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + h->c.first_slice_line = 1; + for (; h->c.mb_y < h->c.mb_height; h->c.mb_y++) { + ff_init_block_index(&h->c); + for (; h->c.mb_x < h->c.mb_width; h->c.mb_x++) { + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int cbpc; int dir = 0; mb_num++; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) - s->first_slice_line = 0; + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + if (h->c.mb_x == h->c.resync_mb_x && h->c.mb_y == h->c.resync_mb_y + 1) + h->c.first_slice_line = 0; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { int i; do { - if (show_bits(&s->gb, 19) == DC_MARKER) + if (show_bits(&h->gb, 19) == DC_MARKER) return mb_num - 1; - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 8); - s->cbp_table[xy] = cbpc & 3; - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - s->mb_intra = 1; + h->c.cbp_table[xy] = cbpc & 3; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.mb_intra = 1; if (cbpc & 4) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + h->c.cur_pic.qscale_table[xy] = h->c.qscale; - s->mbintra_table[xy] = 1; + h->c.mbintra_table[xy] = 1; for (i = 0; i < 6; i++) { int dc_pred_dir; - int dc = mpeg4_decode_dc(s, i, &dc_pred_dir); + int dc = mpeg4_decode_dc(h, i, &dc_pred_dir); if (dc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "DC corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "DC corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return dc; } dir <<= 1; if (dc_pred_dir) dir |= 1; } - s->pred_dir_table[xy] = dir; + h->c.pred_dir_table[xy] = dir; } else { /* P/S_TYPE */ int mx, my, pred_x, pred_y, bits; - int16_t *const mot_val = s->cur_pic.motion_val[0][s->block_index[0]]; - const int stride = s->b8_stride * 2; + int16_t *const mot_val = h->c.cur_pic.motion_val[0][h->c.block_index[0]]; + const int stride = h->c.b8_stride * 2; try_again: - bits = show_bits(&s->gb, 17); + bits = show_bits(&h->gb, 17); if (bits == MOTION_MARKER) return mb_num - 1; - skip_bits1(&s->gb); + skip_bits1(&h->gb); if (bits & 0x10000) { /* skip mb */ - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_FORWARD_MV; mx = get_amv(ctx, 0); my = get_amv(ctx, 1); } else { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; mx = my = 0; @@ -1027,27 +1122,26 @@ try_again: mot_val[1 + stride] = mot_val[3 + stride] = my; - if (s->mbintra_table[xy]) - ff_clean_intra_table_entries(s); + ff_h263_clean_intra_table_entries(&h->c, xy); continue; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } if (cbpc == 20) goto try_again; - s->cbp_table[xy] = cbpc & (8 + 3); // 8 is dquant + h->c.cbp_table[xy] = cbpc & (8 + 3); // 8 is dquant - s->mb_intra = ((cbpc & 4) != 0); + h->c.mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) { - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; - s->mbintra_table[xy] = 1; + if (h->c.mb_intra) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.mbintra_table[xy] = 1; mot_val[0] = mot_val[2] = mot_val[0 + stride] = @@ -1057,34 +1151,33 @@ try_again: mot_val[1 + stride] = mot_val[3 + stride] = 0; } else { - if (s->mbintra_table[xy]) - ff_clean_intra_table_entries(s); + ff_h263_clean_intra_table_entries(&h->c, xy); - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE && (cbpc & 16) == 0) - s->mcsel = get_bits1(&s->gb); + h->c.mcsel = get_bits1(&h->gb); else - s->mcsel = 0; + h->c.mcsel = 0; if ((cbpc & 16) == 0) { /* 16x16 motion prediction */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - if (!s->mcsel) { - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + if (!h->c.mcsel) { + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { mx = get_amv(ctx, 0); my = get_amv(ctx, 1); - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_FORWARD_MV; } @@ -1099,15 +1192,15 @@ try_again: mot_val[3 + stride] = my; } else { int i; - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; for (i = 0; i < 4; i++) { - 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); + int16_t *mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; mot_val[0] = mx; @@ -1117,7 +1210,7 @@ try_again: } } } - s->mb_x = 0; + h->c.mb_x = 0; } return mb_num; @@ -1127,91 +1220,91 @@ try_again: * decode second partition. * @return <0 if an error occurred */ -static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) +static int mpeg4_decode_partition_b(H263DecContext *const h, int mb_count) { int mb_num = 0; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; - s->mb_x = s->resync_mb_x; - s->first_slice_line = 1; - for (s->mb_y = s->resync_mb_y; mb_num < mb_count; s->mb_y++) { - ff_init_block_index(s); - for (; mb_num < mb_count && s->mb_x < s->mb_width; s->mb_x++) { - const int xy = s->mb_x + s->mb_y * s->mb_stride; + h->c.mb_x = h->c.resync_mb_x; + h->c.first_slice_line = 1; + for (h->c.mb_y = h->c.resync_mb_y; mb_num < mb_count; h->c.mb_y++) { + ff_init_block_index(&h->c); + for (; mb_num < mb_count && h->c.mb_x < h->c.mb_width; h->c.mb_x++) { + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; mb_num++; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - if (s->mb_x == s->resync_mb_x && s->mb_y == s->resync_mb_y + 1) - s->first_slice_line = 0; + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + if (h->c.mb_x == h->c.resync_mb_x && h->c.mb_y == h->c.resync_mb_y + 1) + h->c.first_slice_line = 0; - if (s->pict_type == AV_PICTURE_TYPE_I) { - int ac_pred = get_bits1(&s->gb); - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + int ac_pred = get_bits1(&h->gb); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - s->cbp_table[xy] |= cbpy << 2; - s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + h->c.cbp_table[xy] |= cbpy << 2; + h->c.cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; } else { /* P || S_TYPE */ - if (IS_INTRA(s->cur_pic.mb_type[xy])) { + if (IS_INTRA(h->c.cur_pic.mb_type[xy])) { int i; int dir = 0; - int ac_pred = get_bits1(&s->gb); - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + int ac_pred = get_bits1(&h->gb); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->cbp_table[xy] & 8) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + if (h->c.cbp_table[xy] & 8) + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + h->c.cur_pic.qscale_table[xy] = h->c.qscale; for (i = 0; i < 6; i++) { int dc_pred_dir; - int dc = mpeg4_decode_dc(s, i, &dc_pred_dir); + int dc = mpeg4_decode_dc(h, i, &dc_pred_dir); if (dc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "DC corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "DC corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return dc; } dir <<= 1; if (dc_pred_dir) dir |= 1; } - s->cbp_table[xy] &= 3; // remove dquant - s->cbp_table[xy] |= cbpy << 2; - s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; - s->pred_dir_table[xy] = dir; - } else if (IS_SKIP(s->cur_pic.mb_type[xy])) { - s->cur_pic.qscale_table[xy] = s->qscale; - s->cbp_table[xy] = 0; + h->c.cbp_table[xy] &= 3; // remove dquant + h->c.cbp_table[xy] |= cbpy << 2; + h->c.cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + h->c.pred_dir_table[xy] = dir; + } else if (IS_SKIP(h->c.cur_pic.mb_type[xy])) { + h->c.cur_pic.qscale_table[xy] = h->c.qscale; + h->c.cbp_table[xy] = 0; } else { - int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + int cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "P cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "P cbpy corrupted at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->cbp_table[xy] & 8) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->cur_pic.qscale_table[xy] = s->qscale; + if (h->c.cbp_table[xy] & 8) + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + h->c.cur_pic.qscale_table[xy] = h->c.qscale; - s->cbp_table[xy] &= 3; // remove dquant - s->cbp_table[xy] |= (cbpy ^ 0xf) << 2; + h->c.cbp_table[xy] &= 3; // remove dquant + h->c.cbp_table[xy] |= (cbpy ^ 0xf) << 2; } } } if (mb_num >= mb_count) return 0; - s->mb_x = 0; + h->c.mb_x = 0; } return 0; } @@ -1220,62 +1313,62 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) * Decode the first and second partition. * @return <0 if error (and sets error type in the error_status_table) */ -int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) +int ff_mpeg4_decode_partitions(H263DecContext *const h) { - MpegEncContext *s = &ctx->m; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); 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; + const int part_a_error = h->c.pict_type == AV_PICTURE_TYPE_I ? (ER_DC_ERROR | ER_MV_ERROR) : ER_MV_ERROR; + const int part_a_end = h->c.pict_type == AV_PICTURE_TYPE_I ? (ER_DC_END | ER_MV_END) : ER_MV_END; mb_num = mpeg4_decode_partition_a(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); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, part_a_error); 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); + if (h->c.resync_mb_x + h->c.resync_mb_y * h->c.mb_width + mb_num > h->c.mb_num) { + av_log(h->c.avctx, AV_LOG_ERROR, "slice below monitor ...\n"); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, part_a_error); return AVERROR_INVALIDDATA; } - s->mb_num_left = mb_num; + h->mb_num_left = mb_num; - if (s->pict_type == AV_PICTURE_TYPE_I) { - while (show_bits(&s->gb, 9) == 1) - skip_bits(&s->gb, 9); - if (get_bits(&s->gb, 19) != DC_MARKER) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + while (show_bits(&h->gb, 9) == 1) + skip_bits(&h->gb, 9); + if (get_bits(&h->gb, 19) != DC_MARKER) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing after first I partition at %d %d\n", - s->mb_x, s->mb_y); + h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } else { - while (show_bits(&s->gb, 10) == 1) - skip_bits(&s->gb, 10); - if (get_bits(&s->gb, 17) != MOTION_MARKER) { - av_log(s->avctx, AV_LOG_ERROR, + while (show_bits(&h->gb, 10) == 1) + skip_bits(&h->gb, 10); + if (get_bits(&h->gb, 17) != MOTION_MARKER) { + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing after first P partition at %d %d\n", - s->mb_x, s->mb_y); + h->c.mb_x, h->c.mb_y); 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); + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, part_a_end); - ret = mpeg4_decode_partition_b(s, mb_num); + ret = mpeg4_decode_partition_b(h, 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); + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x, h->c.mb_y, ER_DC_ERROR); 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, - s->mb_x - 1, s->mb_y, ER_DC_END); + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_er_add_slice(&h->c.er, h->c.resync_mb_x, h->c.resync_mb_y, + h->c.mb_x - 1, h->c.mb_y, ER_DC_END); } return 0; @@ -1289,8 +1382,8 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, int n, int coded, int intra, int use_intra_dc_vlc, int rvlc) { - MpegEncContext *s = &ctx->m; - int level, i, last, run, qmul, qadd; + H263DecContext *const h = &ctx->h; + int level, i, last, run, qmul, qadd, pred; int av_uninit(dc_pred_dir); const RLTable *rl; const RL_VLC_ELEM *rl_vlc; @@ -1299,17 +1392,18 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, // Note intra & rvlc should be optimized away if this is inlined if (intra) { + // FIXME add short header support if (use_intra_dc_vlc) { /* DC coef */ - if (s->partitioned_frame) { - level = s->dc_val[0][s->block_index[n]]; + if (h->partitioned_frame) { + level = h->c.dc_val[h->c.block_index[n]]; if (n < 4) - level = FASTDIV((level + (s->y_dc_scale >> 1)), s->y_dc_scale); + level = FASTDIV((level + (h->c.y_dc_scale >> 1)), h->c.y_dc_scale); else - level = FASTDIV((level + (s->c_dc_scale >> 1)), s->c_dc_scale); - dc_pred_dir = (s->pred_dir_table[s->mb_x + s->mb_y * s->mb_stride] << n) & 32; + level = FASTDIV((level + (h->c.c_dc_scale >> 1)), h->c.c_dc_scale); + dc_pred_dir = (h->c.pred_dir_table[h->c.mb_x + h->c.mb_y * h->c.mb_stride] << n) & 32; } else { - level = mpeg4_decode_dc(s, n, &dc_pred_dir); + level = mpeg4_decode_dc(h, n, &dc_pred_dir); if (level < 0) return level; } @@ -1317,7 +1411,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, i = 0; } else { i = -1; - ff_mpeg4_pred_dc(s, n, 0, &dc_pred_dir, 0); + pred = mpeg4_pred_dc(&h->c, n, &dc_pred_dir); } if (!coded) goto not_coded; @@ -1329,20 +1423,20 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, rl = &ff_mpeg4_rl_intra; rl_vlc = ff_mpeg4_rl_intra.rl_vlc[0]; } - if (s->ac_pred) { + if (h->c.ac_pred) { if (dc_pred_dir == 0) - scan_table = s->permutated_intra_v_scantable; /* left */ + scan_table = h->c.permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->c.permutated_intra_h_scantable; /* top */ } else { - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; } qmul = 1; qadd = 0; } else { i = -1; if (!coded) { - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } if (rvlc) @@ -1350,9 +1444,9 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, else rl = &ff_h263_rl_inter; - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; - if (s->mpeg_quant) { + if (ctx->mpeg_quant) { qmul = 1; qadd = 0; if (rvlc) @@ -1360,61 +1454,61 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, else rl_vlc = ff_h263_rl_inter.rl_vlc[0]; } else { - qmul = s->qscale << 1; - qadd = (s->qscale - 1) | 1; + qmul = h->c.qscale << 1; + qadd = (h->c.qscale - 1) | 1; if (rvlc) - rl_vlc = ff_rvlc_rl_inter.rl_vlc[s->qscale]; + rl_vlc = ff_rvlc_rl_inter.rl_vlc[h->c.qscale]; else - rl_vlc = ff_h263_rl_inter.rl_vlc[s->qscale]; + rl_vlc = ff_h263_rl_inter.rl_vlc[h->c.qscale]; } } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); for (;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 0); if (level == 0) { /* escape */ if (rvlc) { - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "1. marker bit missing in rvlc esc\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - last = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 6); - SKIP_COUNTER(re, &s->gb, 1 + 1 + 6); - UPDATE_CACHE(re, &s->gb); + last = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); + SKIP_COUNTER(re, &h->gb, 1 + 1 + 6); + UPDATE_CACHE(re, &h->gb); - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "2. marker bit missing in rvlc esc\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - level = SHOW_UBITS(re, &s->gb, 11); - SKIP_CACHE(re, &s->gb, 11); + level = SHOW_UBITS(re, &h->gb, 11); + SKIP_CACHE(re, &h->gb, 11); - if (SHOW_UBITS(re, &s->gb, 5) != 0x10) { - av_log(s->avctx, AV_LOG_ERROR, "reverse esc missing\n"); + if (SHOW_UBITS(re, &h->gb, 5) != 0x10) { + av_log(h->c.avctx, AV_LOG_ERROR, "reverse esc missing\n"); return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 5); + SKIP_CACHE(re, &h->gb, 5); level = level * qmul + qadd; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - SKIP_COUNTER(re, &s->gb, 1 + 11 + 5 + 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + SKIP_COUNTER(re, &h->gb, 1 + 11 + 5 + 1); i += run + 1; if (last) i += 192; } else { int cache; - cache = GET_CACHE(re, &s->gb); + cache = GET_CACHE(re, &h->gb); if (IS_3IV1) cache ^= 0xC0000000; @@ -1422,54 +1516,54 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (cache & 0x80000000) { if (cache & 0x40000000) { /* third escape */ - SKIP_CACHE(re, &s->gb, 2); - last = SHOW_UBITS(re, &s->gb, 1); - SKIP_CACHE(re, &s->gb, 1); - run = SHOW_UBITS(re, &s->gb, 6); - SKIP_COUNTER(re, &s->gb, 2 + 1 + 6); - UPDATE_CACHE(re, &s->gb); + SKIP_CACHE(re, &h->gb, 2); + last = SHOW_UBITS(re, &h->gb, 1); + SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); + SKIP_COUNTER(re, &h->gb, 2 + 1 + 6); + UPDATE_CACHE(re, &h->gb); if (IS_3IV1) { - level = SHOW_SBITS(re, &s->gb, 12); - LAST_SKIP_BITS(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + LAST_SKIP_BITS(re, &h->gb, 12); } else { - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "1. marker bit missing in 3. esc\n"); - if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&s->gb) <= 0) + if (!(h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; } - SKIP_CACHE(re, &s->gb, 1); + SKIP_CACHE(re, &h->gb, 1); - level = SHOW_SBITS(re, &s->gb, 12); - SKIP_CACHE(re, &s->gb, 12); + level = SHOW_SBITS(re, &h->gb, 12); + SKIP_CACHE(re, &h->gb, 12); - if (SHOW_UBITS(re, &s->gb, 1) == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (SHOW_UBITS(re, &h->gb, 1) == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "2. marker bit missing in 3. esc\n"); - if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&s->gb) <= 0) + if (!(h->c.avctx->err_recognition & AV_EF_IGNORE_ERR) || get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; } - SKIP_COUNTER(re, &s->gb, 1 + 12 + 1); + SKIP_COUNTER(re, &h->gb, 1 + 12 + 1); } #if 0 - if (s->error_recognition >= FF_ER_COMPLIANT) { + if (h->c.error_recognition >= FF_ER_COMPLIANT) { const int abs_level= FFABS(level); if (abs_level<=MAX_LEVEL && run<=MAX_RUN) { 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"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, vlc encoding possible\n"); return AVERROR_INVALIDDATA; } - if (s->error_recognition > FF_ER_COMPLIANT) { + if (h->c.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"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, esc 1 encoding possible\n"); 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"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal 3. esc, esc 2 encoding possible\n"); return AVERROR_INVALIDDATA; } } @@ -1482,11 +1576,11 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, level = level * qmul - qadd; if ((unsigned)(level + 2048) > 4095) { - if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_AGGRESSIVE)) { + if (h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_AGGRESSIVE)) { if (level > 2560 || level < -2560) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "|level| overflow in 3. esc, qp=%d\n", - s->qscale); + h->c.qscale); return AVERROR_INVALIDDATA; } } @@ -1498,33 +1592,33 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, i += 192; } else { /* second escape */ - SKIP_BITS(re, &s->gb, 2); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 2); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i += run + rl->max_run[run >> 7][level / qmul] + 1; // FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { /* first escape */ - SKIP_BITS(re, &s->gb, 1); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 1); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i += run; level = level + rl->max_level[run >> 7][(run - 1) & 63] * qmul; // FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } } else { i += run; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } - ff_tlog(s->avctx, "dct[%d][%d] = %- 4d end?:%d\n", scan_table[i&63]&7, scan_table[i&63] >> 3, level, i>62); + ff_tlog(h->c.avctx, "dct[%d][%d] = %- 4d end?:%d\n", scan_table[i&63]&7, scan_table[i&63] >> 3, level, i>62); if (i > 62) { i -= 192; if (i & (~63)) { - av_log(s->avctx, AV_LOG_ERROR, - "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "ac-tex damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } @@ -1534,22 +1628,22 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, block[scan_table[i]] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } not_coded: if (intra) { if (!use_intra_dc_vlc) { - block[0] = ff_mpeg4_pred_dc(s, n, block[0], &dc_pred_dir, 0); + block[0] = mpeg4_get_level_dc(&h->c, n, pred, block[0]); i -= i >> 31; // if (i == -1) i = 0; } - ff_mpeg4_pred_ac(s, block, n, dc_pred_dir); - if (s->ac_pred) + ff_mpeg4_pred_ac(h, block, n, dc_pred_dir); + if (h->c.ac_pred) i = 63; // FIXME not optimal } - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } @@ -1557,74 +1651,71 @@ not_coded: * decode partition C of one MB. * @return <0 if an error occurred */ -static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) +static int mpeg4_decode_partitioned_mb(H263DecContext *const h) { - Mpeg4DecContext *ctx = s->avctx->priv_data; - int cbp, mb_type, use_intra_dc_vlc; - const int xy = s->mb_x + s->mb_y * s->mb_stride; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; - av_assert2(s == (void*)ctx); + const int mb_type = h->c.cur_pic.mb_type[xy]; + int cbp = h->c.cbp_table[xy]; - mb_type = s->cur_pic.mb_type[xy]; - cbp = s->cbp_table[xy]; + const int use_intra_dc_vlc = h->c.qscale < ctx->intra_dc_threshold; - use_intra_dc_vlc = s->qscale < ctx->intra_dc_threshold; + if (h->c.cur_pic.qscale_table[xy] != h->c.qscale) + ff_set_qscale(&h->c, h->c.cur_pic.qscale_table[xy]); - if (s->cur_pic.qscale_table[xy] != s->qscale) - ff_set_qscale(s, s->cur_pic.qscale_table[xy]); - - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.pict_type == AV_PICTURE_TYPE_P || + h->c.pict_type == AV_PICTURE_TYPE_S) { int i; for (i = 0; i < 4; i++) { - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + h->c.mv[0][i][0] = h->c.cur_pic.motion_val[0][h->c.block_index[i]][0]; + h->c.mv[0][i][1] = h->c.cur_pic.motion_val[0][h->c.block_index[i]][1]; } - s->mb_intra = IS_INTRA(mb_type); + h->c.mb_intra = IS_INTRA(mb_type); if (IS_SKIP(mb_type)) { /* skip mb */ for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - if (s->pict_type == AV_PICTURE_TYPE_S + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->mcsel = 1; - s->mb_skipped = 0; - s->cur_pic.mbskip_table[xy] = 0; + h->c.mcsel = 1; + h->c.mb_skipped = 0; + h->c.cur_pic.mbskip_table[xy] = 0; } else { - s->mcsel = 0; - s->mb_skipped = 1; - s->cur_pic.mbskip_table[xy] = 1; + h->c.mcsel = 0; + h->c.mb_skipped = 1; + h->c.cur_pic.mbskip_table[xy] = 1; } - } else if (s->mb_intra) { - s->ac_pred = IS_ACPRED(s->cur_pic.mb_type[xy]); - } else if (!s->mb_intra) { - // s->mcsel = 0; // FIXME do we need to init that? + } else if (h->c.mb_intra) { + h->c.ac_pred = IS_ACPRED(h->c.cur_pic.mb_type[xy]); + } else if (!h->c.mb_intra) { + // h->c.mcsel = 0; // FIXME do we need to init that? - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if (IS_8X8(mb_type)) { - s->mv_type = MV_TYPE_8X8; + h->c.mv_type = MV_TYPE_8X8; } else { - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; } } } else { /* I-Frame */ - s->mb_intra = 1; - s->ac_pred = IS_ACPRED(s->cur_pic.mb_type[xy]); + h->c.mb_intra = 1; + h->c.ac_pred = IS_ACPRED(h->c.cur_pic.mb_type[xy]); } if (!IS_SKIP(mb_type)) { int i; - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, s->mb_intra, + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, h->c.mb_intra, use_intra_dc_vlc, ctx->rvlc) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "texture corrupted at %d %d %d\n", - s->mb_x, s->mb_y, s->mb_intra); + h->c.mb_x, h->c.mb_y, h->c.mb_intra); return AVERROR_INVALIDDATA; } cbp += cbp; @@ -1632,301 +1723,300 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) } /* per-MB end of slice check */ - if (--s->mb_num_left <= 0) { + if (--h->mb_num_left <= 0) { if (mpeg4_is_resync(ctx)) return SLICE_END; else return SLICE_NOEND; } else { if (mpeg4_is_resync(ctx)) { - const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1; - if (s->cbp_table[xy + delta]) + const int delta = h->c.mb_x + 1 == h->c.mb_width ? 2 : 1; + if (h->c.cbp_table[xy + delta]) return SLICE_END; } return SLICE_OK; } } -static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int mpeg4_decode_mb(H263DecContext *const h) { - Mpeg4DecContext *ctx = s->avctx->priv_data; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; - const int xy = s->mb_x + s->mb_y * s->mb_stride; + const int xy = h->c.mb_x + h->c.mb_y * h->c.mb_stride; int next; - av_assert2(s == (void*)ctx); - av_assert2(s->h263_pred); + av_assert2(h->c.h263_pred); - if (s->pict_type == AV_PICTURE_TYPE_P || - s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.pict_type == AV_PICTURE_TYPE_P || + h->c.pict_type == AV_PICTURE_TYPE_S) { do { - if (get_bits1(&s->gb)) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - if (s->pict_type == AV_PICTURE_TYPE_S && + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mcsel = 1; - s->mv[0][0][0] = get_amv(ctx, 0); - s->mv[0][0][1] = get_amv(ctx, 1); - s->cur_pic.mbskip_table[xy] = 0; - s->mb_skipped = 0; + h->c.mcsel = 1; + h->c.mv[0][0][0] = get_amv(ctx, 0); + h->c.mv[0][0][1] = get_amv(ctx, 1); + h->c.cur_pic.mbskip_table[xy] = 0; + h->c.mb_skipped = 0; } else { - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; - s->mcsel = 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->cur_pic.mbskip_table[xy] = 1; - s->mb_skipped = 1; + h->c.mcsel = 0; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.cur_pic.mbskip_table[xy] = 1; + h->c.mb_skipped = 1; } goto end; } - cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "mcbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "mcbpc damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 20); - s->bdsp.clear_blocks(s->block[0]); dquant = cbpc & 8; - s->mb_intra = ((cbpc & 4) != 0); - if (s->mb_intra) + h->c.mb_intra = ((cbpc & 4) != 0); + if (h->c.mb_intra) goto intra; + h->c.bdsp.clear_blocks(h->block[0]); - if (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE && (cbpc & 16) == 0) - s->mcsel = get_bits1(&s->gb); + h->c.mcsel = get_bits1(&h->gb); else - s->mcsel = 0; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1) ^ 0x0F; + h->c.mcsel = 0; + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1) ^ 0x0F; if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "P cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "P cbpy damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } cbp = (cbpc & 3) | (cbpy << 2); if (dquant) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - if ((!s->progressive_sequence) && - (cbp || (s->workaround_bugs & FF_BUG_XVID_ILACE))) - s->interlaced_dct = get_bits1(&s->gb); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); + if ((!h->c.progressive_sequence) && + (cbp || (h->c.workaround_bugs & FF_BUG_XVID_ILACE))) + h->c.interlaced_dct = get_bits1(&h->gb); - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { - if (s->mcsel) { - s->cur_pic.mb_type[xy] = MB_TYPE_GMC | MB_TYPE_16x16 | + if (h->c.mcsel) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 global motion prediction */ - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; mx = get_amv(ctx, 0); my = get_amv(ctx, 1); - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; - } else if ((!s->progressive_sequence) && get_bits1(&s->gb)) { - s->cur_pic.mb_type[xy] = MB_TYPE_16x8 | MB_TYPE_FORWARD_MV | + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; + } else if ((!h->c.progressive_sequence) && get_bits1(&h->gb)) { + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x8 | MB_TYPE_FORWARD_MV | MB_TYPE_INTERLACED; /* 16x8 field motion prediction */ - s->mv_type = MV_TYPE_FIELD; + h->c.mv_type = MV_TYPE_FIELD; - s->field_select[0][0] = get_bits1(&s->gb); - s->field_select[0][1] = get_bits1(&s->gb); + h->c.field_select[0][0] = get_bits1(&h->gb); + h->c.field_select[0][1] = get_bits1(&h->gb); - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y / 2, s->f_code); + my = ff_h263_decode_motion(h, pred_y / 2, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; } } else { - s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + h->c.cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; /* 16x16 motion prediction */ - s->mv_type = MV_TYPE_16X16; - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - mx = ff_h263_decode_motion(s, pred_x, s->f_code); + h->c.mv_type = MV_TYPE_16X16; + ff_h263_pred_motion(&h->c, 0, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; } } else { - s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; - s->mv_type = MV_TYPE_8X8; + h->c.cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; + h->c.mv_type = MV_TYPE_8X8; for (i = 0; i < 4; i++) { - 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); + int16_t *mot_val = ff_h263_pred_motion(&h->c, i, 0, &pred_x, &pred_y); + mx = ff_h263_decode_motion(h, pred_x, ctx->f_code); if (mx >= 0xffff) return AVERROR_INVALIDDATA; - my = ff_h263_decode_motion(s, pred_y, s->f_code); + my = ff_h263_decode_motion(h, pred_y, ctx->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->mv[0][i][0] = mx; - s->mv[0][i][1] = my; + h->c.mv[0][i][0] = mx; + h->c.mv[0][i][1] = my; mot_val[0] = mx; mot_val[1] = my; } } - } else if (s->pict_type == AV_PICTURE_TYPE_B) { + } else if (h->c.pict_type == AV_PICTURE_TYPE_B) { int modb1; // first bit of modb int modb2; // second bit of modb int mb_type; - s->mb_intra = 0; // B-frames never contain intra blocks - s->mcsel = 0; // ... true gmc blocks + h->c.mb_intra = 0; // B-frames never contain intra blocks + h->c.mcsel = 0; // ... true gmc blocks - if (s->mb_x == 0) { + if (h->c.mb_x == 0) { for (i = 0; i < 2; i++) { - s->last_mv[i][0][0] = - s->last_mv[i][0][1] = - s->last_mv[i][1][0] = - s->last_mv[i][1][1] = 0; + h->c.last_mv[i][0][0] = + h->c.last_mv[i][0][1] = + h->c.last_mv[i][1][0] = + h->c.last_mv[i][1][1] = 0; } - ff_thread_progress_await(&s->next_pic.ptr->progress, s->mb_y); + ff_thread_progress_await(&h->c.next_pic.ptr->progress, h->c.mb_y); } /* if we skipped it in the future P-frame than skip it now too */ - s->mb_skipped = s->next_pic.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC + h->c.mb_skipped = h->c.next_pic.mbskip_table[h->c.mb_y * h->c.mb_stride + h->c.mb_x]; // Note, skiptab=0 if last was GMC - if (s->mb_skipped) { + if (h->c.mb_skipped) { /* skip mb */ for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; + h->c.block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = - s->mv[0][0][1] = - s->mv[1][0][0] = - s->mv[1][0][1] = 0; - s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = + h->c.mv[0][0][1] = + h->c.mv[1][0][0] = + h->c.mv[1][0][1] = 0; + h->c.cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; goto end; } - modb1 = get_bits1(&s->gb); + modb1 = get_bits1(&h->gb); if (modb1) { // like MB_TYPE_B_DIRECT but no vectors coded mb_type = MB_TYPE_DIRECT2 | MB_TYPE_SKIP | MB_TYPE_BIDIR_MV; cbp = 0; } else { - modb2 = get_bits1(&s->gb); - mb_type = get_vlc2(&s->gb, mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 1); + modb2 = get_bits1(&h->gb); + mb_type = get_vlc2(&h->gb, mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 1); if (mb_type < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal MB_type\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal MB_type\n"); return AVERROR_INVALIDDATA; } if (modb2) { cbp = 0; } else { - s->bdsp.clear_blocks(s->block[0]); - cbp = get_bits(&s->gb, 6); + h->c.bdsp.clear_blocks(h->block[0]); + cbp = get_bits(&h->gb, 6); } if ((!IS_DIRECT(mb_type)) && cbp) { - if (get_bits1(&s->gb)) - ff_set_qscale(s, s->qscale + get_bits1(&s->gb) * 4 - 2); + if (get_bits1(&h->gb)) + ff_set_qscale(&h->c, h->c.qscale + get_bits1(&h->gb) * 4 - 2); } - if (!s->progressive_sequence) { + if (!h->c.progressive_sequence) { if (cbp) - s->interlaced_dct = get_bits1(&s->gb); + h->c.interlaced_dct = get_bits1(&h->gb); - if (!IS_DIRECT(mb_type) && get_bits1(&s->gb)) { + if (!IS_DIRECT(mb_type) && get_bits1(&h->gb)) { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; mb_type &= ~MB_TYPE_16x16; if (HAS_FORWARD_MV(mb_type)) { - s->field_select[0][0] = get_bits1(&s->gb); - s->field_select[0][1] = get_bits1(&s->gb); + h->c.field_select[0][0] = get_bits1(&h->gb); + h->c.field_select[0][1] = get_bits1(&h->gb); } if (HAS_BACKWARD_MV(mb_type)) { - s->field_select[1][0] = get_bits1(&s->gb); - s->field_select[1][1] = get_bits1(&s->gb); + h->c.field_select[1][0] = get_bits1(&h->gb); + h->c.field_select[1][1] = get_bits1(&h->gb); } } } - s->mv_dir = 0; + h->c.mv_dir = 0; if ((mb_type & (MB_TYPE_DIRECT2 | MB_TYPE_INTERLACED)) == 0) { - s->mv_type = MV_TYPE_16X16; + h->c.mv_type = MV_TYPE_16X16; if (HAS_FORWARD_MV(mb_type)) { - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; - mx = ff_h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); - my = ff_h263_decode_motion(s, s->last_mv[0][0][1], s->f_code); - s->last_mv[0][1][0] = - s->last_mv[0][0][0] = - s->mv[0][0][0] = mx; - s->last_mv[0][1][1] = - s->last_mv[0][0][1] = - s->mv[0][0][1] = my; + mx = ff_h263_decode_motion(h, h->c.last_mv[0][0][0], ctx->f_code); + my = ff_h263_decode_motion(h, h->c.last_mv[0][0][1], ctx->f_code); + h->c.last_mv[0][1][0] = + h->c.last_mv[0][0][0] = + h->c.mv[0][0][0] = mx; + h->c.last_mv[0][1][1] = + h->c.last_mv[0][0][1] = + h->c.mv[0][0][1] = my; } if (HAS_BACKWARD_MV(mb_type)) { - s->mv_dir |= MV_DIR_BACKWARD; + h->c.mv_dir |= MV_DIR_BACKWARD; - mx = ff_h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); - my = ff_h263_decode_motion(s, s->last_mv[1][0][1], s->b_code); - s->last_mv[1][1][0] = - s->last_mv[1][0][0] = - s->mv[1][0][0] = mx; - s->last_mv[1][1][1] = - s->last_mv[1][0][1] = - s->mv[1][0][1] = my; + mx = ff_h263_decode_motion(h, h->c.last_mv[1][0][0], ctx->b_code); + my = ff_h263_decode_motion(h, h->c.last_mv[1][0][1], ctx->b_code); + h->c.last_mv[1][1][0] = + h->c.last_mv[1][0][0] = + h->c.mv[1][0][0] = mx; + h->c.last_mv[1][1][1] = + h->c.last_mv[1][0][1] = + h->c.mv[1][0][1] = my; } } else if (!IS_DIRECT(mb_type)) { - s->mv_type = MV_TYPE_FIELD; + h->c.mv_type = MV_TYPE_FIELD; if (HAS_FORWARD_MV(mb_type)) { - s->mv_dir = MV_DIR_FORWARD; + h->c.mv_dir = MV_DIR_FORWARD; for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, s->last_mv[0][i][0], s->f_code); - my = ff_h263_decode_motion(s, s->last_mv[0][i][1] / 2, s->f_code); - s->last_mv[0][i][0] = - s->mv[0][i][0] = mx; - s->last_mv[0][i][1] = (s->mv[0][i][1] = my) * 2; + mx = ff_h263_decode_motion(h, h->c.last_mv[0][i][0], ctx->f_code); + my = ff_h263_decode_motion(h, h->c.last_mv[0][i][1] / 2, ctx->f_code); + h->c.last_mv[0][i][0] = + h->c.mv[0][i][0] = mx; + h->c.last_mv[0][i][1] = (h->c.mv[0][i][1] = my) * 2; } } if (HAS_BACKWARD_MV(mb_type)) { - s->mv_dir |= MV_DIR_BACKWARD; + h->c.mv_dir |= MV_DIR_BACKWARD; for (i = 0; i < 2; i++) { - mx = ff_h263_decode_motion(s, s->last_mv[1][i][0], s->b_code); - my = ff_h263_decode_motion(s, s->last_mv[1][i][1] / 2, s->b_code); - s->last_mv[1][i][0] = - s->mv[1][i][0] = mx; - s->last_mv[1][i][1] = (s->mv[1][i][1] = my) * 2; + mx = ff_h263_decode_motion(h, h->c.last_mv[1][i][0], ctx->b_code); + my = ff_h263_decode_motion(h, h->c.last_mv[1][i][1] / 2, ctx->b_code); + h->c.last_mv[1][i][0] = + h->c.mv[1][i][0] = mx; + h->c.last_mv[1][i][1] = (h->c.mv[1][i][1] = my) * 2; } } } @@ -1937,56 +2027,56 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mx = my = 0; } else { - mx = ff_h263_decode_motion(s, 0, 1); - my = ff_h263_decode_motion(s, 0, 1); + mx = ff_h263_decode_motion(h, 0, 1); + my = ff_h263_decode_motion(h, 0, 1); } - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - mb_type |= ff_mpeg4_set_direct_mv(s, mx, my); + h->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + mb_type |= ff_mpeg4_set_direct_mv(&h->c, mx, my); } - s->cur_pic.mb_type[xy] = mb_type; + h->c.cur_pic.mb_type[xy] = mb_type; } else { /* I-Frame */ int use_intra_dc_vlc; do { - cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbpc = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if (cbpc < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpc damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpc damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } } while (cbpc == 8); dquant = cbpc & 4; - s->mb_intra = 1; + h->c.mb_intra = 1; intra: - s->ac_pred = get_bits1(&s->gb); - if (s->ac_pred) - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.ac_pred) + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; else - s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; + h->c.cur_pic.mb_type[xy] = MB_TYPE_INTRA; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "I cbpy damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, + "I cbpy damaged at %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } cbp = (cbpc & 3) | (cbpy << 2); - use_intra_dc_vlc = s->qscale < ctx->intra_dc_threshold; + use_intra_dc_vlc = h->c.qscale < ctx->intra_dc_threshold; if (dquant) - ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); + ff_set_qscale(&h->c, h->c.qscale + quant_tab[get_bits(&h->gb, 2)]); - if (!s->progressive_sequence) - s->interlaced_dct = get_bits1(&s->gb); + if (!h->c.progressive_sequence) + h->c.interlaced_dct = get_bits1(&h->gb); - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, 1, use_intra_dc_vlc, 0) < 0) return AVERROR_INVALIDDATA; cbp += cbp; @@ -1996,7 +2086,7 @@ intra: /* decode each block */ for (i = 0; i < 6; i++) { - if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, 0, 0, 0) < 0) + if (mpeg4_decode_block(ctx, h->block[i], i, cbp & 32, 0, 0, 0) < 0) return AVERROR_INVALIDDATA; cbp += cbp; } @@ -2005,18 +2095,18 @@ end: /* per-MB end of slice check */ 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)) { + if (h->c.mb_x + h->c.mb_y*h->c.mb_width + 1 > next && (h->c.avctx->err_recognition & AV_EF_AGGRESSIVE)) { return AVERROR_INVALIDDATA; - } else if (s->mb_x + s->mb_y*s->mb_width + 1 >= next) + } else if (h->c.mb_x + h->c.mb_y*h->c.mb_width + 1 >= next) return SLICE_END; - if (s->pict_type == AV_PICTURE_TYPE_B) { - const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1; - ff_thread_progress_await(&s->next_pic.ptr->progress, - (s->mb_x + delta >= s->mb_width) - ? FFMIN(s->mb_y + 1, s->mb_height - 1) - : s->mb_y); - if (s->next_pic.mbskip_table[xy + delta]) + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + const int delta = h->c.mb_x + 1 == h->c.mb_width ? 2 : 1; + ff_thread_progress_await(&h->c.next_pic.ptr->progress, + (h->c.mb_x + delta >= h->c.mb_width) + ? FFMIN(h->c.mb_y + 1, h->c.mb_height - 1) + : h->c.mb_y); + if (h->c.next_pic.mbskip_table[xy + delta]) return SLICE_OK; } @@ -2063,19 +2153,19 @@ static const uint8_t ac_state_tab[22][2] = {0, 11} }; -static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n) +static int mpeg4_decode_studio_block(Mpeg4DecContext *const ctx, int32_t block[64], int n) { - Mpeg4DecContext *ctx = s->avctx->priv_data; + H263DecContext *const h = &ctx->h; int cc, dct_dc_size, dct_diff, code, j, idx = 1, group = 0, run = 0, additional_code_len, sign, mismatch; const VLCElem *cur_vlc = studio_intra_tab[0]; - const uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = h->c.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); - int shift = 3 - s->dct_precision; + const int min = -1 * (1 << (h->c.avctx->bits_per_raw_sample + 6)); + const int max = ((1 << (h->c.avctx->bits_per_raw_sample + 6)) - 1); + int shift = 3 - ctx->dct_precision; mismatch = 1; @@ -2083,35 +2173,35 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n if (n < 4) { cc = 0; - dct_dc_size = get_vlc2(&s->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); - quant_matrix = s->intra_matrix; + dct_dc_size = get_vlc2(&h->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); + quant_matrix = h->c.intra_matrix; } else { cc = (n & 1) + 1; if (ctx->rgb) - dct_dc_size = get_vlc2(&s->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); + dct_dc_size = get_vlc2(&h->gb, studio_luma_dc, STUDIO_INTRA_BITS, 2); else - dct_dc_size = get_vlc2(&s->gb, studio_chroma_dc, STUDIO_INTRA_BITS, 2); - quant_matrix = s->chroma_intra_matrix; + dct_dc_size = get_vlc2(&h->gb, studio_chroma_dc, STUDIO_INTRA_BITS, 2); + quant_matrix = h->c.chroma_intra_matrix; } if (dct_dc_size == 0) { dct_diff = 0; } else { - dct_diff = get_xbits(&s->gb, dct_dc_size); + dct_diff = get_xbits(&h->gb, dct_dc_size); if (dct_dc_size > 8) { - if(!check_marker(s->avctx, &s->gb, "dct_dc_size > 8")) + if(!check_marker(h->c.avctx, &h->gb, "dct_dc_size > 8")) return AVERROR_INVALIDDATA; } } - s->last_dc[cc] += dct_diff; + h->c.last_dc[cc] += dct_diff; - if (s->mpeg_quant) - block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision); + if (ctx->mpeg_quant) + block[0] = h->c.last_dc[cc] * (8 >> h->c.intra_dc_precision); else - block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision) * (8 >> s->dct_precision); + block[0] = h->c.last_dc[cc] * (8 >> h->c.intra_dc_precision) * (8 >> ctx->dct_precision); /* TODO: support mpeg_quant for AC coefficients */ block[0] = av_clip(block[0], min, max); @@ -2119,10 +2209,10 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n /* AC Coefficients */ while (1) { - group = get_vlc2(&s->gb, cur_vlc, STUDIO_INTRA_BITS, 2); + group = get_vlc2(&h->gb, cur_vlc, STUDIO_INTRA_BITS, 2); if (group < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal ac coefficient group vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal ac coefficient group vlc\n"); return AVERROR_INVALIDDATA; } @@ -2136,12 +2226,12 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n /* Zero run length (Table B.47) */ run = 1 << additional_code_len; if (additional_code_len) - run += get_bits(&s->gb, additional_code_len); + run += get_bits(&h->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); + code = get_bits(&h->gb, additional_code_len); sign = code & 1; code >>= 1; run = (1 << (additional_code_len - 1)) + code; @@ -2155,20 +2245,20 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n if (idx > 63) return AVERROR_INVALIDDATA; j = scantable[idx++]; - block[j] = get_xbits(&s->gb, additional_code_len); + block[j] = get_xbits(&h->gb, additional_code_len); } else if (group == 21) { /* Escape */ if (idx > 63) return AVERROR_INVALIDDATA; j = scantable[idx++]; - additional_code_len = s->avctx->bits_per_raw_sample + s->dct_precision + 4; - flc = get_bits(&s->gb, additional_code_len); + additional_code_len = h->c.avctx->bits_per_raw_sample + ctx->dct_precision + 4; + flc = get_bits(&h->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] = ((block[j] * quant_matrix[j] * s->qscale) * (1 << shift)) / 16; + block[j] = ((block[j] * quant_matrix[j] * h->c.qscale) * (1 << shift)) / 16; block[j] = av_clip(block[j], min, max); mismatch ^= block[j]; } @@ -2178,24 +2268,26 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n return 0; } -static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[256], int n) +static int mpeg4_decode_dpcm_macroblock(Mpeg4DecContext *const ctx, + int16_t macroblock[256], int n) { - int i, j, w, h, idx = 0; + H263DecContext *const h = &ctx->h; + int j, w, height, idx = 0; int block_mean, rice_parameter, rice_prefix_code, rice_suffix_code, dpcm_residual, left, top, topleft, min_left_top, max_left_top, p, p2, output; - h = 16 >> (n ? s->chroma_y_shift : 0); - w = 16 >> (n ? s->chroma_x_shift : 0); + height = 16 >> (n ? h->c.chroma_y_shift : 0); + w = 16 >> (n ? h->c.chroma_x_shift : 0); - block_mean = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + block_mean = get_bits(&h->gb, h->c.avctx->bits_per_raw_sample); if (block_mean == 0){ - av_log(s->avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); return AVERROR_INVALIDDATA; } - s->last_dc[n] = block_mean * (1 << (s->dct_precision + s->intra_dc_precision)); + h->c.last_dc[n] = block_mean * (1 << (ctx->dct_precision + h->c.intra_dc_precision)); - rice_parameter = get_bits(&s->gb, 4); + rice_parameter = get_bits(&h->gb, 4); if (rice_parameter == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); return AVERROR_INVALIDDATA; } @@ -2203,29 +2295,29 @@ static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[25 rice_parameter = 0; if (rice_parameter > 11) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); return AVERROR_INVALIDDATA; } - for (i = 0; i < h; i++) { - output = 1 << (s->avctx->bits_per_raw_sample - 1); - top = 1 << (s->avctx->bits_per_raw_sample - 1); + for (int i = 0; i < height; i++) { + output = 1 << (h->c.avctx->bits_per_raw_sample - 1); + top = 1 << (h->c.avctx->bits_per_raw_sample - 1); for (j = 0; j < w; j++) { left = output; topleft = top; - rice_prefix_code = get_unary(&s->gb, 1, 12); + rice_prefix_code = get_unary(&h->gb, 1, 12); /* Escape */ if (rice_prefix_code == 11) - dpcm_residual = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + dpcm_residual = get_bits(&h->gb, h->c.avctx->bits_per_raw_sample); else { if (rice_prefix_code == 12) { - av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_prefix_code\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Forbidden rice_prefix_code\n"); return AVERROR_INVALIDDATA; } - rice_suffix_code = get_bitsz(&s->gb, rice_parameter); + rice_suffix_code = get_bitsz(&h->gb, rice_parameter); dpcm_residual = (rice_prefix_code << rice_parameter) + rice_suffix_code; } @@ -2254,56 +2346,56 @@ static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[25 if (p2 > p) dpcm_residual *= -1; - macroblock[idx++] = output = (dpcm_residual + p) & ((1 << s->avctx->bits_per_raw_sample) - 1); + macroblock[idx++] = output = (dpcm_residual + p) & ((1 << h->c.avctx->bits_per_raw_sample) - 1); } } return 0; } -static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) +static int mpeg4_decode_studio_mb(H263DecContext *const h) { - Mpeg4DecContext *const ctx = (Mpeg4DecContext*)s; + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); int i; ctx->dpcm_direction = 0; /* StudioMacroblock */ /* Assumes I-VOP */ - s->mb_intra = 1; - if (get_bits1(&s->gb)) { /* compression_mode */ + h->c.mb_intra = 1; + if (get_bits1(&h->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); + if (!get_bits1(&h->gb)) { + skip_bits1(&h->gb); + h->c.qscale = mpeg_get_qscale(&h->gb, h->c.q_scale_type); } - for (i = 0; i < mpeg4_block_count[s->chroma_format]; i++) { - if (mpeg4_decode_studio_block(s, ctx->block32[i], i) < 0) + for (i = 0; i < mpeg4_block_count[h->c.chroma_format]; i++) { + if (mpeg4_decode_studio_block(ctx, ctx->block32[i], i) < 0) return AVERROR_INVALIDDATA; } } else { /* DPCM */ - check_marker(s->avctx, &s->gb, "DPCM block start"); - ctx->dpcm_direction = get_bits1(&s->gb) ? -1 : 1; + check_marker(h->c.avctx, &h->gb, "DPCM block start"); + ctx->dpcm_direction = get_bits1(&h->gb) ? -1 : 1; for (i = 0; i < 3; i++) { - if (mpeg4_decode_dpcm_macroblock(s, ctx->dpcm_macroblock[i], i) < 0) + if (mpeg4_decode_dpcm_macroblock(ctx, ctx->dpcm_macroblock[i], i) < 0) return AVERROR_INVALIDDATA; } } - if (get_bits_left(&s->gb) >= 24 && show_bits(&s->gb, 23) == 0) { - next_start_code_studio(&s->gb); + if (get_bits_left(&h->gb) >= 24 && show_bits(&h->gb, 23) == 0) { + next_start_code_studio(&h->gb); return SLICE_END; } //vcon-stp9L1.bits (first frame) - if (get_bits_left(&s->gb) == 0) + if (get_bits_left(&h->gb) == 0) return SLICE_END; //vcon-stp2L1.bits, vcon-stp3L1.bits, vcon-stp6L1.bits, vcon-stp7L1.bits, vcon-stp8L1.bits, vcon-stp10L1.bits (first frame) - if (get_bits_left(&s->gb) < 8U && show_bits(&s->gb, get_bits_left(&s->gb)) == 0) + if (get_bits_left(&h->gb) < 8U && show_bits(&h->gb, get_bits_left(&h->gb)) == 0) return SLICE_END; return SLICE_OK; @@ -2462,7 +2554,7 @@ static void extension_and_user_data(MpegEncContext *s, GetBitContext *gb, int id static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; int width, height, aspect_ratio_info; int bits_per_raw_sample; int rgb, chroma_format; @@ -2538,7 +2630,7 @@ static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) 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 */ + ctx->mpeg_quant = get_bits1(gb); /* mpeg2_stream */ next_start_code_studio(gb); extension_and_user_data(s, gb, 2); @@ -2548,7 +2640,7 @@ static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int width, height, vo_ver_id, aspect_ratio_info; /* vol header */ @@ -2562,12 +2654,12 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) */ if (ctx->vo_type == CORE_STUDIO_VO_TYPE || ctx->vo_type == SIMPLE_STUDIO_VO_TYPE) { - if (s->avctx->profile != AV_PROFILE_UNKNOWN && s->avctx->profile != AV_PROFILE_MPEG4_SIMPLE_STUDIO) + if (h->c.avctx->profile != AV_PROFILE_UNKNOWN && h->c.avctx->profile != AV_PROFILE_MPEG4_SIMPLE_STUDIO) return AVERROR_INVALIDDATA; - s->studio_profile = 1; - s->avctx->profile = AV_PROFILE_MPEG4_SIMPLE_STUDIO; + h->c.studio_profile = 1; + h->c.avctx->profile = AV_PROFILE_MPEG4_SIMPLE_STUDIO; return decode_studio_vol_header(ctx, gb); - } else if (s->studio_profile) { + } else if (h->c.studio_profile) { return AVERROR_PATCHWELCOME; } @@ -2579,97 +2671,97 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) } aspect_ratio_info = get_bits(gb, 4); if (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 + h->c.avctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width + h->c.avctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height } else { - s->avctx->sample_aspect_ratio = ff_h263_pixel_aspect[aspect_ratio_info]; + h->c.avctx->sample_aspect_ratio = ff_h263_pixel_aspect[aspect_ratio_info]; } if ((ctx->vol_control_parameters = get_bits1(gb))) { /* vol control parameter */ int chroma_format = get_bits(gb, 2); if (chroma_format != CHROMA_420) - av_log(s->avctx, AV_LOG_ERROR, "illegal chroma format\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal chroma format\n"); - s->low_delay = get_bits1(gb); + h->c.low_delay = get_bits1(gb); if (get_bits1(gb)) { /* vbv parameters */ get_bits(gb, 15); /* first_half_bitrate */ - check_marker(s->avctx, gb, "after first_half_bitrate"); + check_marker(h->c.avctx, gb, "after first_half_bitrate"); get_bits(gb, 15); /* latter_half_bitrate */ - check_marker(s->avctx, gb, "after latter_half_bitrate"); + check_marker(h->c.avctx, gb, "after latter_half_bitrate"); get_bits(gb, 15); /* first_half_vbv_buffer_size */ - check_marker(s->avctx, gb, "after first_half_vbv_buffer_size"); + check_marker(h->c.avctx, gb, "after first_half_vbv_buffer_size"); get_bits(gb, 3); /* latter_half_vbv_buffer_size */ get_bits(gb, 11); /* first_half_vbv_occupancy */ - check_marker(s->avctx, gb, "after first_half_vbv_occupancy"); + check_marker(h->c.avctx, gb, "after first_half_vbv_occupancy"); get_bits(gb, 15); /* latter_half_vbv_occupancy */ - check_marker(s->avctx, gb, "after latter_half_vbv_occupancy"); + check_marker(h->c.avctx, gb, "after latter_half_vbv_occupancy"); } } else { /* is setting low delay flag only once the smartest thing to do? * low delay detection will not be overridden. */ - if (s->picture_number == 0) { + if (h->picture_number == 0) { switch (ctx->vo_type) { case SIMPLE_VO_TYPE: case ADV_SIMPLE_VO_TYPE: - s->low_delay = 1; + h->c.low_delay = 1; break; default: - s->low_delay = 0; + h->c.low_delay = 0; } } } ctx->shape = get_bits(gb, 2); /* vol shape */ if (ctx->shape != RECT_SHAPE) - av_log(s->avctx, AV_LOG_ERROR, "only rectangular vol supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "only rectangular vol supported\n"); if (ctx->shape == GRAY_SHAPE && vo_ver_id != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Gray shape not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Gray shape not supported\n"); skip_bits(gb, 4); /* video_object_layer_shape_extension */ } - check_marker(s->avctx, gb, "before time_increment_resolution"); + check_marker(h->c.avctx, gb, "before time_increment_resolution"); - s->avctx->framerate.num = get_bits(gb, 16); - if (!s->avctx->framerate.num) { - av_log(s->avctx, AV_LOG_ERROR, "framerate==0\n"); + h->c.avctx->framerate.num = get_bits(gb, 16); + if (!h->c.avctx->framerate.num) { + av_log(h->c.avctx, AV_LOG_ERROR, "framerate==0\n"); return AVERROR_INVALIDDATA; } - ctx->time_increment_bits = av_log2(s->avctx->framerate.num - 1) + 1; + ctx->time_increment_bits = av_log2(h->c.avctx->framerate.num - 1) + 1; if (ctx->time_increment_bits < 1) ctx->time_increment_bits = 1; - check_marker(s->avctx, gb, "before fixed_vop_rate"); + check_marker(h->c.avctx, gb, "before fixed_vop_rate"); if (get_bits1(gb) != 0) /* fixed_vop_rate */ - s->avctx->framerate.den = get_bits(gb, ctx->time_increment_bits); + h->c.avctx->framerate.den = get_bits(gb, ctx->time_increment_bits); else - s->avctx->framerate.den = 1; + h->c.avctx->framerate.den = 1; ctx->t_frame = 0; if (ctx->shape != BIN_ONLY_SHAPE) { if (ctx->shape == RECT_SHAPE) { - check_marker(s->avctx, gb, "before width"); + check_marker(h->c.avctx, gb, "before width"); width = get_bits(gb, 13); - check_marker(s->avctx, gb, "before height"); + check_marker(h->c.avctx, gb, "before height"); height = get_bits(gb, 13); - check_marker(s->avctx, gb, "after height"); + check_marker(h->c.avctx, gb, "after height"); if (width && height && /* they should be non zero but who knows */ - !(s->width && s->codec_tag == AV_RL32("MP4S"))) { - if (s->width && s->height && - (s->width != width || s->height != height)) - s->context_reinit = 1; - s->width = width; - s->height = height; + !(h->c.width && h->c.codec_tag == AV_RL32("MP4S"))) { + if (h->c.width && h->c.height && + (h->c.width != width || h->c.height != height)) + h->c.context_reinit = 1; + h->c.width = width; + h->c.height = height; } } - s->progressive_sequence = - s->progressive_frame = get_bits1(gb) ^ 1; - s->interlaced_dct = 0; - if (!get_bits1(gb) && (s->avctx->debug & FF_DEBUG_PICT_INFO)) - av_log(s->avctx, AV_LOG_INFO, /* OBMC Disable */ + h->c.progressive_sequence = + h->c.progressive_frame = get_bits1(gb) ^ 1; + h->c.interlaced_dct = 0; + if (!get_bits1(gb) && (h->c.avctx->debug & FF_DEBUG_PICT_INFO)) + av_log(h->c.avctx, AV_LOG_INFO, /* OBMC Disable */ "MPEG-4 OBMC not supported (very likely buggy encoder)\n"); if (vo_ver_id == 1) ctx->vol_sprite_usage = get_bits1(gb); /* vol_sprite_usage */ @@ -2677,22 +2769,22 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->vol_sprite_usage = get_bits(gb, 2); /* vol_sprite_usage */ if (ctx->vol_sprite_usage == STATIC_SPRITE) - av_log(s->avctx, AV_LOG_ERROR, "Static Sprites not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Static Sprites not supported\n"); if (ctx->vol_sprite_usage == STATIC_SPRITE || ctx->vol_sprite_usage == GMC_SPRITE) { if (ctx->vol_sprite_usage == STATIC_SPRITE) { skip_bits(gb, 13); // sprite_width - check_marker(s->avctx, gb, "after sprite_width"); + check_marker(h->c.avctx, gb, "after sprite_width"); skip_bits(gb, 13); // sprite_height - check_marker(s->avctx, gb, "after sprite_height"); + check_marker(h->c.avctx, gb, "after sprite_height"); skip_bits(gb, 13); // sprite_left - check_marker(s->avctx, gb, "after sprite_left"); + check_marker(h->c.avctx, gb, "after sprite_left"); skip_bits(gb, 13); // sprite_top - check_marker(s->avctx, gb, "after sprite_top"); + check_marker(h->c.avctx, gb, "after sprite_top"); } ctx->num_sprite_warping_points = get_bits(gb, 6); if (ctx->num_sprite_warping_points > 3) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "%d sprite_warping_points\n", ctx->num_sprite_warping_points); ctx->num_sprite_warping_points = 0; @@ -2708,9 +2800,9 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) if (get_bits1(gb) == 1) { /* not_8_bit */ ctx->quant_precision = get_bits(gb, 4); /* quant_precision */ if (get_bits(gb, 4) != 8) /* bits_per_pixel */ - av_log(s->avctx, AV_LOG_ERROR, "N-bit not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "N-bit not supported\n"); if (ctx->quant_precision != 5) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "quant precision %d\n", ctx->quant_precision); if (ctx->quant_precision < 3 || ctx->quant_precision > 9) ctx->quant_precision = 5; @@ -2720,10 +2812,10 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) // FIXME a bunch of grayscale shape things - if ((s->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ + if ((ctx->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ int i, v; - mpeg4_load_default_matrices(s); + mpeg4_load_default_matrices(&h->c); /* load custom intra matrix */ if (get_bits1(gb)) { @@ -2731,7 +2823,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) for (i = 0; i < 64; i++) { int j; if (get_bits_left(gb) < 8) { - av_log(s->avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); return AVERROR_INVALIDDATA; } v = get_bits(gb, 8); @@ -2739,16 +2831,14 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) break; last = v; - j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = last; - s->chroma_intra_matrix[j] = last; + j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.intra_matrix[j] = last; } /* replicate last value */ for (; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = last; - s->chroma_intra_matrix[j] = last; + int j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.intra_matrix[j] = last; } } @@ -2758,7 +2848,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) for (i = 0; i < 64; i++) { int j; if (get_bits_left(gb) < 8) { - av_log(s->avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "insufficient data for custom matrix\n"); return AVERROR_INVALIDDATA; } v = get_bits(gb, 8); @@ -2766,16 +2856,14 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) break; last = v; - j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->inter_matrix[j] = v; - s->chroma_inter_matrix[j] = v; + j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.inter_matrix[j] = v; } /* replicate last value */ for (; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; - s->inter_matrix[j] = last; - s->chroma_inter_matrix[j] = last; + int j = h->c.idsp.idct_permutation[ff_zigzag_direct[i]]; + h->c.inter_matrix[j] = last; } } @@ -2783,12 +2871,12 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) } if (vo_ver_id != 1) - s->quarter_sample = get_bits1(gb); + h->c.quarter_sample = get_bits1(gb); else - s->quarter_sample = 0; + h->c.quarter_sample = 0; if (get_bits_left(gb) < 4) { - av_log(s->avctx, AV_LOG_ERROR, "VOL Header truncated\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "VOL Header truncated\n"); return AVERROR_INVALIDDATA; } @@ -2810,7 +2898,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* inter4v_blocks */ ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* not coded blocks */ } - if (!check_marker(s->avctx, gb, "in complexity estimation part 1")) { + if (!check_marker(h->c.avctx, gb, "in complexity estimation part 1")) { skip_bits_long(gb, pos - get_bits_count(gb)); goto no_cplx_est; } @@ -2828,7 +2916,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel2 */ ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel4 */ } - if (!check_marker(s->avctx, gb, "in complexity estimation part 2")) { + if (!check_marker(h->c.avctx, gb, "in complexity estimation part 2")) { skip_bits_long(gb, pos - get_bits_count(gb)); goto no_cplx_est; } @@ -2837,7 +2925,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* qpel */ } } else - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid Complexity estimation method %d\n", estimation_method); } else { @@ -2850,19 +2938,19 @@ no_cplx_est: ctx->resync_marker = !get_bits1(gb); /* resync_marker_disabled */ - s->data_partitioning = get_bits1(gb); - if (s->data_partitioning) + h->data_partitioning = get_bits1(gb); + if (h->data_partitioning) ctx->rvlc = get_bits1(gb); if (vo_ver_id != 1) { ctx->new_pred = get_bits1(gb); if (ctx->new_pred) { - av_log(s->avctx, AV_LOG_ERROR, "new pred not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "new pred not supported\n"); skip_bits(gb, 2); /* requested upstream message type */ skip_bits1(gb); /* newpred segment type */ } if (get_bits1(gb)) // reduced_res_vop - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "reduced resolution VOP not supported\n"); } else { ctx->new_pred = 0; @@ -2893,21 +2981,23 @@ no_cplx_est: ctx->scalability = 0; *gb = bak; } else - av_log(s->avctx, AV_LOG_ERROR, "scalability not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "scalability not supported\n"); // bin shape stuff FIXME } } - if (s->avctx->debug&FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, low_delay:%d %s%s%s%s\n", - s->avctx->framerate.den, s->avctx->framerate.num, + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, low_delay:%d %s%s%s%s\n", + h->c.avctx->framerate.den, h->c.avctx->framerate.num, ctx->time_increment_bits, ctx->quant_precision, - s->progressive_sequence, - s->low_delay, - ctx->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "", - s->data_partitioning ? "partition " : "", ctx->rvlc ? "rvlc " : "" + h->c.progressive_sequence, + h->c.low_delay, + ctx->scalability ? "scalability " :"" , + h->c.quarter_sample ? "qpel " : "", + h->data_partitioning ? "partition " : "", + ctx->rvlc ? "rvlc " : "" ); } @@ -2920,7 +3010,7 @@ no_cplx_est: */ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; char buf[256]; int i; int e; @@ -2941,7 +3031,7 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) if (e >= 2) { ctx->divx_version = ver; ctx->divx_build = build; - s->divx_packed = e == 3 && last == 'p'; + h->divx_packed = e == 3 && last == 'p'; } /* libavcodec detection */ @@ -2952,7 +3042,7 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) e = sscanf(buf, "Lavc%d.%d.%d", &ver, &ver2, &ver3) + 1; if (e > 1) { if (ver > 0xFFU || ver2 > 0xFFU || ver3 > 0xFFU) { - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "Unknown Lavc version string encountered, %d.%d.%d; " "clamping sub-version values to 8-bits.\n", ver, ver2, ver3); @@ -2975,22 +3065,51 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) return 0; } -int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) +static av_cold void permute_quant_matrix(uint16_t matrix[64], + const uint8_t new_perm[64], + const uint8_t old_perm[64]) +{ + uint16_t tmp[64]; + + memcpy(tmp, matrix, sizeof(tmp)); + for (int i = 0; i < 64; ++i) + matrix[new_perm[i]] = tmp[old_perm[i]]; +} + +static av_cold void switch_to_xvid_idct(AVCodecContext *const avctx, + MpegEncContext *const s) +{ + uint8_t old_permutation[64]; + + memcpy(old_permutation, s->idsp.idct_permutation, sizeof(old_permutation)); + + avctx->idct_algo = FF_IDCT_XVID; + ff_mpv_idct_init(s); + ff_permute_scantable(s->permutated_intra_h_scantable, + s->alternate_scan ? ff_alternate_vertical_scan : ff_alternate_horizontal_scan, + s->idsp.idct_permutation); + + // Normal (i.e. non-studio) MPEG-4 does not use the chroma matrices. + permute_quant_matrix(s->inter_matrix, s->idsp.idct_permutation, old_permutation); + permute_quant_matrix(s->intra_matrix, s->idsp.idct_permutation, old_permutation); +} + +void ff_mpeg4_workaround_bugs(AVCodecContext *avctx) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) { - if (s->codec_tag == AV_RL32("XVID") || - s->codec_tag == AV_RL32("XVIX") || - s->codec_tag == AV_RL32("RMP4") || - s->codec_tag == AV_RL32("ZMP4") || - s->codec_tag == AV_RL32("SIPP")) + if (h->c.codec_tag == AV_RL32("XVID") || + h->c.codec_tag == AV_RL32("XVIX") || + h->c.codec_tag == AV_RL32("RMP4") || + h->c.codec_tag == AV_RL32("ZMP4") || + h->c.codec_tag == AV_RL32("SIPP")) ctx->xvid_build = 0; } if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) - if (s->codec_tag == AV_RL32("DIVX") && ctx->vo_type == 0 && + if (h->c.codec_tag == AV_RL32("DIVX") && ctx->vo_type == 0 && ctx->vol_control_parameters == 0) ctx->divx_version = 400; // divx 4 @@ -2999,68 +3118,68 @@ int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) ctx->divx_build = -1; } - if (s->workaround_bugs & FF_BUG_AUTODETECT) { - if (s->codec_tag == AV_RL32("XVIX")) - s->workaround_bugs |= FF_BUG_XVID_ILACE; + if (h->c.workaround_bugs & FF_BUG_AUTODETECT) { + if (h->c.codec_tag == AV_RL32("XVIX")) + h->c.workaround_bugs |= FF_BUG_XVID_ILACE; - if (s->codec_tag == AV_RL32("UMP4")) - s->workaround_bugs |= FF_BUG_UMP4; + if (h->c.codec_tag == AV_RL32("UMP4")) + h->c.workaround_bugs |= FF_BUG_UMP4; if (ctx->divx_version >= 500 && ctx->divx_build < 1814) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA; + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA; if (ctx->divx_version > 502 && ctx->divx_build < 1814) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA2; + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA2; if (ctx->xvid_build <= 3U) - s->padding_bug_score = 256 * 256 * 256 * 64; + h->padding_bug_score = 256 * 256 * 256 * 64; if (ctx->xvid_build <= 1U) - s->workaround_bugs |= FF_BUG_QPEL_CHROMA; + h->c.workaround_bugs |= FF_BUG_QPEL_CHROMA; if (ctx->xvid_build <= 12U) - s->workaround_bugs |= FF_BUG_EDGE; + h->c.workaround_bugs |= FF_BUG_EDGE; if (ctx->xvid_build <= 32U) - s->workaround_bugs |= FF_BUG_DC_CLIP; + h->c.workaround_bugs |= FF_BUG_DC_CLIP; #define SET_QPEL_FUNC(postfix1, postfix2) \ - s->qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \ - s->qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \ - s->qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2; + h->c.qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \ + h->c.qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \ + h->c.qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2; if (ctx->lavc_build < 4653U) - s->workaround_bugs |= FF_BUG_STD_QPEL; + h->c.workaround_bugs |= FF_BUG_STD_QPEL; if (ctx->lavc_build < 4655U) - s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; + h->c.workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; if (ctx->lavc_build < 4670U) - s->workaround_bugs |= FF_BUG_EDGE; + h->c.workaround_bugs |= FF_BUG_EDGE; if (ctx->lavc_build <= 4712U) - s->workaround_bugs |= FF_BUG_DC_CLIP; + h->c.workaround_bugs |= FF_BUG_DC_CLIP; if ((ctx->lavc_build&0xFF) >= 100) { if (ctx->lavc_build > 3621476 && ctx->lavc_build < 3752552 && (ctx->lavc_build < 3752037 || ctx->lavc_build > 3752191) // 3.2.1+ ) - s->workaround_bugs |= FF_BUG_IEDGE; + h->c.workaround_bugs |= FF_BUG_IEDGE; } if (ctx->divx_version >= 0) - s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; + h->c.workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE; if (ctx->divx_version == 501 && ctx->divx_build == 20020416) - s->padding_bug_score = 256 * 256 * 256 * 64; + h->padding_bug_score = 256 * 256 * 256 * 64; if (ctx->divx_version < 500U) - s->workaround_bugs |= FF_BUG_EDGE; + h->c.workaround_bugs |= FF_BUG_EDGE; if (ctx->divx_version >= 0) - s->workaround_bugs |= FF_BUG_HPEL_CHROMA; + h->c.workaround_bugs |= FF_BUG_HPEL_CHROMA; } - if (s->workaround_bugs & FF_BUG_STD_QPEL) { + if (h->c.workaround_bugs & FF_BUG_STD_QPEL) { SET_QPEL_FUNC(qpel_pixels_tab[0][5], qpel16_mc11_old_c) SET_QPEL_FUNC(qpel_pixels_tab[0][7], qpel16_mc31_old_c) SET_QPEL_FUNC(qpel_pixels_tab[0][9], qpel16_mc12_old_c) @@ -3077,58 +3196,54 @@ int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) } if (avctx->debug & FF_DEBUG_BUGS) - av_log(s->avctx, AV_LOG_DEBUG, + av_log(h->c.avctx, AV_LOG_DEBUG, "bugs: %X lavc_build:%d xvid_build:%d divx_version:%d divx_build:%d %s\n", - s->workaround_bugs, ctx->lavc_build, ctx->xvid_build, - ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : ""); + h->c.workaround_bugs, ctx->lavc_build, ctx->xvid_build, + ctx->divx_version, ctx->divx_build, h->divx_packed ? "p" : ""); if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0 && - avctx->idct_algo == FF_IDCT_AUTO) { - avctx->idct_algo = FF_IDCT_XVID; - ff_mpv_idct_init(s); - return 1; + avctx->idct_algo == FF_IDCT_AUTO && !h->c.studio_profile) { + switch_to_xvid_idct(avctx, &h->c); } - - return 0; } static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, int parse_only) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; int time_incr, time_increment; int64_t pts; - s->mcsel = 0; - s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */ - if (s->pict_type == AV_PICTURE_TYPE_B && s->low_delay && - ctx->vol_control_parameters == 0 && !(s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY)) { - av_log(s->avctx, AV_LOG_ERROR, "low_delay flag set incorrectly, clearing it\n"); - s->low_delay = 0; + h->c.mcsel = 0; + h->c.pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */ + if (h->c.pict_type == AV_PICTURE_TYPE_B && h->c.low_delay && + ctx->vol_control_parameters == 0 && !(h->c.avctx->flags & AV_CODEC_FLAG_LOW_DELAY)) { + av_log(h->c.avctx, AV_LOG_ERROR, "low_delay flag set incorrectly, clearing it\n"); + h->c.low_delay = 0; } - s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; - if (s->partitioned_frame) - s->decode_mb = mpeg4_decode_partitioned_mb; + h->partitioned_frame = h->data_partitioning && h->c.pict_type != AV_PICTURE_TYPE_B; + if (h->partitioned_frame) + h->decode_mb = mpeg4_decode_partitioned_mb; else - s->decode_mb = mpeg4_decode_mb; + h->decode_mb = mpeg4_decode_mb; time_incr = 0; while (get_bits1(gb) != 0) time_incr++; - check_marker(s->avctx, gb, "before time_increment"); + check_marker(h->c.avctx, gb, "before time_increment"); if (ctx->time_increment_bits == 0 || !(show_bits(gb, ctx->time_increment_bits + 1) & 1)) { - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "time_increment_bits %d is invalid in relation to the current bitstream, this is likely caused by a missing VOL header\n", ctx->time_increment_bits); for (ctx->time_increment_bits = 1; ctx->time_increment_bits < 16; ctx->time_increment_bits++) { - if (s->pict_type == AV_PICTURE_TYPE_P || - (s->pict_type == AV_PICTURE_TYPE_S && + if (h->c.pict_type == AV_PICTURE_TYPE_P || + (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE)) { if ((show_bits(gb, ctx->time_increment_bits + 6) & 0x37) == 0x30) break; @@ -3136,7 +3251,7 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, break; } - av_log(s->avctx, AV_LOG_WARNING, + av_log(h->c.avctx, AV_LOG_WARNING, "time_increment_bits set to %d bits, based on bitstream analysis\n", ctx->time_increment_bits); } @@ -3145,83 +3260,84 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, else time_increment = get_bits(gb, ctx->time_increment_bits); - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->last_time_base = s->time_base; - s->time_base += time_incr; - s->time = s->time_base * (int64_t)s->avctx->framerate.num + time_increment; - if (s->workaround_bugs & FF_BUG_UMP4) { - if (s->time < s->last_non_b_time) { + if (h->c.pict_type != AV_PICTURE_TYPE_B) { + h->c.last_time_base = h->c.time_base; + h->c.time_base += time_incr; + h->c.time = h->c.time_base * (int64_t)h->c.avctx->framerate.num + time_increment; + if (h->c.workaround_bugs & FF_BUG_UMP4) { + if (h->c.time < h->c.last_non_b_time) { /* header is not mpeg-4-compatible, broken encoder, * trying to workaround */ - s->time_base++; - s->time += s->avctx->framerate.num; + h->c.time_base++; + h->c.time += h->c.avctx->framerate.num; } } - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; } else { - s->time = (s->last_time_base + time_incr) * (int64_t)s->avctx->framerate.num + time_increment; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); - if (s->pp_time <= s->pb_time || - s->pp_time <= s->pp_time - s->pb_time || - s->pp_time <= 0) { + h->c.time = (h->c.last_time_base + time_incr) * (int64_t)h->c.avctx->framerate.num + time_increment; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); + if (h->c.pp_time <= h->c.pb_time || + h->c.pp_time <= h->c.pp_time - h->c.pb_time || + h->c.pp_time <= 0) { /* messed up order, maybe after seeking? skipping current B-frame */ return FRAME_SKIPPED; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); if (ctx->t_frame == 0) - ctx->t_frame = s->pb_time; + ctx->t_frame = h->c.pb_time; if (ctx->t_frame == 0) ctx->t_frame = 1; // 1/0 protection - s->pp_field_time = (ROUNDED_DIV(s->last_non_b_time, ctx->t_frame) - - ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; - s->pb_field_time = (ROUNDED_DIV(s->time, ctx->t_frame) - - ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; - if (s->pp_field_time <= s->pb_field_time || s->pb_field_time <= 1) { - s->pb_field_time = 2; - s->pp_field_time = 4; - if (!s->progressive_sequence) + h->c.pp_field_time = (ROUNDED_DIV(h->c.last_non_b_time, ctx->t_frame) - + ROUNDED_DIV(h->c.last_non_b_time - h->c.pp_time, ctx->t_frame)) * 2; + h->c.pb_field_time = (ROUNDED_DIV(h->c.time, ctx->t_frame) - + ROUNDED_DIV(h->c.last_non_b_time - h->c.pp_time, ctx->t_frame)) * 2; + if (h->c.pp_field_time <= h->c.pb_field_time || h->c.pb_field_time <= 1) { + h->c.pb_field_time = 2; + h->c.pp_field_time = 4; + if (!h->c.progressive_sequence) return FRAME_SKIPPED; } } - if (s->avctx->framerate.den) - pts = ROUNDED_DIV(s->time, s->avctx->framerate.den); + if (h->c.avctx->framerate.den) + pts = ROUNDED_DIV(h->c.time, h->c.avctx->framerate.den); else pts = AV_NOPTS_VALUE; - ff_dlog(s->avctx, "MPEG4 PTS: %"PRId64"\n", pts); + ff_dlog(h->c.avctx, "MPEG4 PTS: %"PRId64"\n", pts); - check_marker(s->avctx, gb, "before vop_coded"); + check_marker(h->c.avctx, gb, "before vop_coded"); /* vop coded */ if (get_bits1(gb) != 1) { - if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_ERROR, "vop not coded\n"); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_ERROR, "vop not coded\n"); + h->skipped_last_frame = 1; return FRAME_SKIPPED; } if (ctx->new_pred) decode_new_pred(ctx, gb); if (ctx->shape != BIN_ONLY_SHAPE && - (s->pict_type == AV_PICTURE_TYPE_P || - (s->pict_type == AV_PICTURE_TYPE_S && + (h->c.pict_type == AV_PICTURE_TYPE_P || + (h->c.pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE))) { /* rounding type for motion estimation */ - s->no_rounding = get_bits1(gb); + h->c.no_rounding = get_bits1(gb); } else { - s->no_rounding = 0; + h->c.no_rounding = 0; } // FIXME reduced res stuff if (ctx->shape != RECT_SHAPE) { - if (ctx->vol_sprite_usage != 1 || s->pict_type != AV_PICTURE_TYPE_I) { + if (ctx->vol_sprite_usage != 1 || h->c.pict_type != AV_PICTURE_TYPE_I) { skip_bits(gb, 13); /* width */ - check_marker(s->avctx, gb, "after width"); + check_marker(h->c.avctx, gb, "after width"); skip_bits(gb, 13); /* height */ - check_marker(s->avctx, gb, "after height"); + check_marker(h->c.avctx, gb, "after height"); skip_bits(gb, 13); /* hor_spat_ref */ - check_marker(s->avctx, gb, "after hor_spat_ref"); + check_marker(h->c.avctx, gb, "after hor_spat_ref"); skip_bits(gb, 13); /* ver_spat_ref */ } skip_bits1(gb); /* change_CR_disable */ @@ -3234,154 +3350,155 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, if (ctx->shape != BIN_ONLY_SHAPE) { skip_bits_long(gb, ctx->cplx_estimation_trash_i); - if (s->pict_type != AV_PICTURE_TYPE_I) + if (h->c.pict_type != AV_PICTURE_TYPE_I) skip_bits_long(gb, ctx->cplx_estimation_trash_p); - if (s->pict_type == AV_PICTURE_TYPE_B) + if (h->c.pict_type == AV_PICTURE_TYPE_B) skip_bits_long(gb, ctx->cplx_estimation_trash_b); if (get_bits_left(gb) < 3) { - av_log(s->avctx, AV_LOG_ERROR, "Header truncated\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "Header truncated\n"); return AVERROR_INVALIDDATA; } ctx->intra_dc_threshold = ff_mpeg4_dc_threshold[get_bits(gb, 3)]; - if (!s->progressive_sequence) { - s->top_field_first = get_bits1(gb); - s->alternate_scan = get_bits1(gb); + if (!h->c.progressive_sequence) { + h->c.top_field_first = get_bits1(gb); + h->c.alternate_scan = get_bits1(gb); } else - s->alternate_scan = 0; + h->c.alternate_scan = 0; } - if (s->alternate_scan) { - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_alternate_vertical_scan); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - } else { - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); - ff_permute_scantable(s->permutated_intra_h_scantable, ff_alternate_horizontal_scan, - s->idsp.idct_permutation); - } - ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - /* Skip at this point when only parsing since the remaining * data is not useful for a parser and requires the * sprite_trajectory VLC to be initialized. */ if (parse_only) goto end; - if (s->pict_type == AV_PICTURE_TYPE_S) { + if (h->c.alternate_scan) { + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, ff_alternate_vertical_scan); + ff_permute_scantable(h->c.permutated_intra_h_scantable, ff_alternate_vertical_scan, + h->c.idsp.idct_permutation); + } else { + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, ff_zigzag_direct); + ff_permute_scantable(h->c.permutated_intra_h_scantable, ff_alternate_horizontal_scan, + h->c.idsp.idct_permutation); + } + ff_permute_scantable(h->c.permutated_intra_v_scantable, ff_alternate_vertical_scan, + h->c.idsp.idct_permutation); + + if (h->c.pict_type == AV_PICTURE_TYPE_S) { if((ctx->vol_sprite_usage == STATIC_SPRITE || ctx->vol_sprite_usage == GMC_SPRITE)) { if (mpeg4_decode_sprite_trajectory(ctx, gb) < 0) return AVERROR_INVALIDDATA; if (ctx->sprite_brightness_change) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "sprite_brightness_change not supported\n"); if (ctx->vol_sprite_usage == STATIC_SPRITE) - av_log(s->avctx, AV_LOG_ERROR, "static sprite not supported\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "static sprite not supported\n"); } else { memset(ctx->sprite_offset, 0, sizeof(ctx->sprite_offset)); memset(ctx->sprite_delta, 0, sizeof(ctx->sprite_delta)); } } + ctx->f_code = 1; + ctx->b_code = 1; if (ctx->shape != BIN_ONLY_SHAPE) { - s->chroma_qscale = s->qscale = get_bits(gb, ctx->quant_precision); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, + h->c.chroma_qscale = h->c.qscale = get_bits(gb, ctx->quant_precision); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG-4 header (qscale=0)\n"); return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then } - if (s->pict_type != AV_PICTURE_TYPE_I) { - s->f_code = get_bits(gb, 3); /* fcode_for */ - if (s->f_code == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type != AV_PICTURE_TYPE_I) { + ctx->f_code = get_bits(gb, 3); /* fcode_for */ + if (ctx->f_code == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG-4 header (f_code=0)\n"); - s->f_code = 1; + ctx->f_code = 1; return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then } - } else - s->f_code = 1; + } - if (s->pict_type == AV_PICTURE_TYPE_B) { - s->b_code = get_bits(gb, 3); - if (s->b_code == 0) { - av_log(s->avctx, AV_LOG_ERROR, + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + ctx->b_code = get_bits(gb, 3); + if (ctx->b_code == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG4 header (b_code=0)\n"); - s->b_code=1; + ctx->b_code=1; return AVERROR_INVALIDDATA; // makes no sense to continue, as the MV decoding will break very quickly } - } else - s->b_code = 1; + } - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qp:%d fc:%d,%d %c size:%d pro:%d alt:%d top:%d %cpel part:%d resync:%d w:%d a:%d rnd:%d vot:%d%s dc:%d ce:%d/%d/%d time:%"PRId64" tincr:%d\n", - s->qscale, s->f_code, s->b_code, - s->pict_type == AV_PICTURE_TYPE_I ? 'I' : (s->pict_type == AV_PICTURE_TYPE_P ? 'P' : (s->pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), - gb->size_in_bits,s->progressive_sequence, s->alternate_scan, - s->top_field_first, s->quarter_sample ? 'q' : 'h', - s->data_partitioning, ctx->resync_marker, + h->c.qscale, ctx->f_code, ctx->b_code, + h->c.pict_type == AV_PICTURE_TYPE_I ? 'I' : (h->c.pict_type == AV_PICTURE_TYPE_P ? 'P' : (h->c.pict_type == AV_PICTURE_TYPE_B ? 'B' : 'S')), + gb->size_in_bits,h->c.progressive_sequence, h->c.alternate_scan, + h->c.top_field_first, h->c.quarter_sample ? 'q' : 'h', + h->data_partitioning, ctx->resync_marker, ctx->num_sprite_warping_points, ctx->sprite_warping_accuracy, - 1 - s->no_rounding, ctx->vo_type, + 1 - h->c.no_rounding, ctx->vo_type, ctx->vol_control_parameters ? " VOLC" : " ", ctx->intra_dc_threshold, ctx->cplx_estimation_trash_i, ctx->cplx_estimation_trash_p, ctx->cplx_estimation_trash_b, - s->time, + h->c.time, time_increment ); } if (!ctx->scalability) { - if (ctx->shape != RECT_SHAPE && s->pict_type != AV_PICTURE_TYPE_I) + if (ctx->shape != RECT_SHAPE && h->c.pict_type != AV_PICTURE_TYPE_I) skip_bits1(gb); // vop shape coding type } else { if (ctx->enhancement_type) { int load_backward_shape = get_bits1(gb); if (load_backward_shape) - av_log(s->avctx, AV_LOG_ERROR, + av_log(h->c.avctx, AV_LOG_ERROR, "load backward shape isn't supported\n"); } skip_bits(gb, 2); // ref_select_code } } + h->c.dct_unquantize_intra = ctx->mpeg_quant ? ctx->dct_unquantize_mpeg2_intra + : ctx->dct_unquantize_h263_intra; + // The following tells ff_mpv_reconstruct_mb() to unquantize iff mpeg_quant + h->c.dct_unquantize_inter = ctx->mpeg_quant ? ctx->dct_unquantize_mpeg2_inter : NULL; + end: /* detect buggy encoders which don't set the low_delay flag * (divx4/xvid/opendivx). Note we cannot detect divx5 without B-frames * easily (although it's buggy too) */ if (ctx->vo_type == 0 && ctx->vol_control_parameters == 0 && - ctx->divx_version == -1 && s->picture_number == 0) { - av_log(s->avctx, AV_LOG_WARNING, + ctx->divx_version == -1 && h->picture_number == 0) { + av_log(h->c.avctx, AV_LOG_WARNING, "looks like this file was encoded with (divx4/(old)xvid/opendivx) -> forcing low_delay flag\n"); - s->low_delay = 1; + h->c.low_delay = 1; } - s->picture_number++; // better than pic number==0 always ;) + h->picture_number++; // better than pic number==0 always ;) - // FIXME add short header support - s->y_dc_scale_table = ff_mpeg4_y_dc_scale_table; - s->c_dc_scale_table = ff_mpeg4_c_dc_scale_table; - - if (s->workaround_bugs & FF_BUG_EDGE) { - s->h_edge_pos = s->width; - s->v_edge_pos = s->height; + if (h->c.workaround_bugs & FF_BUG_EDGE) { + h->c.h_edge_pos = h->c.width; + h->c.v_edge_pos = h->c.height; } return 0; } static void decode_smpte_tc(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + AVCodecContext *const avctx = ctx->h.c.avctx; skip_bits(gb, 16); /* Time_code[63..48] */ - check_marker(s->avctx, gb, "after Time_code[63..48]"); + check_marker(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]"); + check_marker(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]"); + check_marker(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]"); + check_marker(avctx, gb, "after Time_code[15..0]"); skip_bits(gb, 4); /* reserved_bits */ } @@ -3391,64 +3508,63 @@ static void decode_smpte_tc(Mpeg4DecContext *ctx, GetBitContext *gb) */ static int decode_studio_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; if (get_bits_left(gb) <= 32) return 0; - s->partitioned_frame = 0; - s->interlaced_dct = 0; - s->decode_mb = mpeg4_decode_studio_mb; + h->partitioned_frame = 0; + h->c.interlaced_dct = 0; + h->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 */ + h->c.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 */ + h->c.progressive_frame = get_bits1(gb) ^ 1; /* progressive_frame */ } - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { if (get_bits1(gb)) - reset_studio_dc_predictors(s); + reset_studio_dc_predictors(ctx); } 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); + h->c.alternate_scan = get_bits1(gb); + h->c.frame_pred_frame_dct = get_bits1(gb); + ctx->dct_precision = get_bits(gb, 2); + h->c.intra_dc_precision = get_bits(gb, 2); + h->c.q_scale_type = get_bits1(gb); } - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); + ff_init_scantable(h->c.idsp.idct_permutation, &h->c.intra_scantable, + h->c.alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); - mpeg4_load_default_matrices(s); + mpeg4_load_default_matrices(&h->c); next_start_code_studio(gb); - extension_and_user_data(s, gb, 4); + extension_and_user_data(&h->c, gb, 4); return 0; } static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) { - MpegEncContext *s = &ctx->m; int visual_object_type; skip_bits(gb, 4); /* visual_object_verid */ visual_object_type = get_bits(gb, 4); if (visual_object_type != VOT_VIDEO_ID) { - avpriv_request_sample(s->avctx, "VO type %u", visual_object_type); + avpriv_request_sample(ctx->h.c.avctx, "VO type %u", visual_object_type); return AVERROR_PATCHWELCOME; } next_start_code_studio(gb); - extension_and_user_data(s, gb, 1); + extension_and_user_data(&ctx->h.c, gb, 1); return 0; } @@ -3463,10 +3579,10 @@ static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) * FRAME_SKIPPED if a not coded VOP is found * 0 else */ -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only) +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only) { - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; unsigned startcode, v; int ret; int vol = 0; @@ -3476,7 +3592,7 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, // If we have not switched to studio profile than we also did not switch bps // that means something else (like a previous instance) outside set bps which - // would be inconsistant with the currect state, thus reset it + // would be inconsistent with the correct state, thus reset it if (!s->studio_profile && s->avctx->bits_per_raw_sample != 8) s->avctx->bits_per_raw_sample = 0; @@ -3562,6 +3678,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, name = "Reserved"; else if (startcode <= 0x1FF) name = "System start"; + else + av_unreachable("Unexpected startcode"); av_log(s->avctx, AV_LOG_DEBUG, "startcode: %3X %s at %d\n", startcode, name, get_bits_count(gb)); } @@ -3609,7 +3727,6 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, end: if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; - s->avctx->has_b_frames = !s->low_delay; if (s->studio_profile) { if (!s->avctx->bits_per_raw_sample) { @@ -3621,17 +3738,55 @@ end: return decode_vop_header(ctx, gb, parse_only); } -int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size) +static int mpeg4_decode_picture_header(H263DecContext *const h) +{ + Mpeg4DecContext *const ctx = h263_to_mpeg4(h); + + h->skipped_last_frame = 0; + + if (ctx->bitstream_buffer) { + int buf_size = get_bits_left(&h->gb) / 8U; + int bitstream_buffer_size = ctx->bitstream_buffer->size; + const uint8_t *buf = h->gb.buffer; + + if (h->divx_packed) { + for (int i = 0; i < buf_size - 3; i++) { + if (buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 1) { + if (buf[i+3] == 0xB0) { + av_log(h->c.avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); + bitstream_buffer_size = 0; + } + break; + } + } + } + ctx->bitstream_buffer->size = 0; + if (bitstream_buffer_size && (h->divx_packed || buf_size <= MAX_NVOP_SIZE)) {// divx 5.01+/xvid frame reorder + int ret = init_get_bits8(&h->gb, ctx->bitstream_buffer->data, + bitstream_buffer_size); + if (ret < 0) + return ret; + } else + av_buffer_unref(&ctx->bitstream_buffer); + } + + return ff_mpeg4_parse_picture_header(ctx, &h->gb, 0, 0); +} + +int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; + int ret; + + av_assert1(!ctx->bitstream_buffer || !ctx->bitstream_buffer->size); /* divx 5.01+ bitstream reorder stuff */ - /* Since this clobbers the input buffer and hwaccel codecs still need the - * data during hwaccel->end_frame we should not do this any earlier */ - if (s->divx_packed) { - int current_pos = s->gb.buffer == s->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3); + if (h->divx_packed) { + int current_pos = ctx->bitstream_buffer && h->gb.buffer == ctx->bitstream_buffer->data ? 0 : (get_bits_count(&h->gb) >> 3); int startcode_found = 0; + uint8_t *buf = pkt->data; + int buf_size = pkt->size; if (buf_size - current_pos > 7) { @@ -3649,21 +3804,17 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size) if (startcode_found) { if (!ctx->showed_packed_warning) { - av_log(s->avctx, AV_LOG_INFO, "Video uses a non-standard and " + av_log(h->c.avctx, AV_LOG_INFO, "Video uses a non-standard and " "wasteful way to store B-frames ('packed B-frames'). " "Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.\n"); ctx->showed_packed_warning = 1; } - av_fast_padded_malloc(&s->bitstream_buffer, - &s->allocated_bitstream_buffer_size, - buf_size - current_pos); - if (!s->bitstream_buffer) { - s->bitstream_buffer_size = 0; - return AVERROR(ENOMEM); - } - memcpy(s->bitstream_buffer, buf + current_pos, - buf_size - current_pos); - s->bitstream_buffer_size = buf_size - current_pos; + ret = av_buffer_replace(&ctx->bitstream_buffer, pkt->buf); + if (ret < 0) + return ret; + + ctx->bitstream_buffer->data = buf + current_pos; + ctx->bitstream_buffer->size = buf_size - current_pos; } } @@ -3672,15 +3823,73 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size) #if CONFIG_MPEG4_DECODER #if HAVE_THREADS +static av_cold void clear_context(MpegEncContext *s) +{ + memset(&s->buffer_pools, 0, sizeof(s->buffer_pools)); + memset(&s->next_pic, 0, sizeof(s->next_pic)); + memset(&s->last_pic, 0, sizeof(s->last_pic)); + memset(&s->cur_pic, 0, sizeof(s->cur_pic)); + + memset(s->thread_context, 0, sizeof(s->thread_context)); + + s->ac_val_base = NULL; + s->ac_val = NULL; + memset(&s->sc, 0, sizeof(s->sc)); + + s->p_field_mv_table_base = NULL; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + s->p_field_mv_table[i][j] = NULL; + + s->dc_val_base = NULL; + s->coded_block_base = NULL; + s->mbintra_table = NULL; + s->cbp_table = NULL; + s->pred_dir_table = NULL; + + s->mbskip_table = NULL; + + s->er.error_status_table = NULL; + s->er.er_temp_buffer = NULL; + s->mb_index2xy = NULL; + + s->context_initialized = 0; + s->context_reinit = 0; +} + +static av_cold int update_mpvctx(MpegEncContext *s, const MpegEncContext *s1) +{ + AVCodecContext *avctx = s->avctx; + // FIXME the following leads to a data race; instead copy only + // the necessary fields. + memcpy(s, s1, sizeof(*s)); + clear_context(s); + + s->avctx = avctx; + + if (s1->context_initialized) { + int err = ff_mpv_common_init(s); + if (err < 0) + return err; + } + return 0; +} + static int mpeg4_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { Mpeg4DecContext *s = dst->priv_data; const Mpeg4DecContext *s1 = src->priv_data; - int init = s->m.context_initialized; + int init = s->h.c.context_initialized; + int ret; - int ret = ff_mpeg_update_thread_context(dst, src); + if (!init) { + ret = update_mpvctx(&s->h.c, &s1->h.c); + if (ret < 0) + return ret; + } + ret = ff_mpeg_update_thread_context(dst, src); if (ret < 0) return ret; @@ -3691,7 +3900,8 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->sprite_brightness_change = s1->sprite_brightness_change; s->sprite_warping_accuracy = s1->sprite_warping_accuracy; s->num_sprite_warping_points = s1->num_sprite_warping_points; - s->m.data_partitioning = s1->m.data_partitioning; + s->h.data_partitioning = s1->h.data_partitioning; + s->mpeg_quant = s1->mpeg_quant; s->rvlc = s1->rvlc; s->resync_marker = s1->resync_marker; s->t_frame = s1->t_frame; @@ -3699,6 +3909,7 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->enhancement_type = s1->enhancement_type; s->scalability = s1->scalability; s->intra_dc_threshold = s1->intra_dc_threshold; + s->h.divx_packed = s1->h.divx_packed; s->divx_version = s1->divx_version; s->divx_build = s1->divx_build; s->xvid_build = s1->xvid_build; @@ -3711,23 +3922,25 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, s->cplx_estimation_trash_b = s1->cplx_estimation_trash_b; s->rgb = s1->rgb; + s->h.skipped_last_frame = s1->h.skipped_last_frame; + s->h.padding_bug_score = s1->h.padding_bug_score; // FIXME: racy + + s->h.picture_number = s1->h.picture_number; + memcpy(s->sprite_shift, s1->sprite_shift, sizeof(s1->sprite_shift)); memcpy(s->sprite_traj, s1->sprite_traj, sizeof(s1->sprite_traj)); - if (!init && s1->xvid_build >= 0) - ff_xvid_idct_init(&s->m.idsp, dst); - - return 0; + return av_buffer_replace(&s->bitstream_buffer, s1->bitstream_buffer); } static int mpeg4_update_thread_context_for_user(AVCodecContext *dst, const AVCodecContext *src) { - MpegEncContext *m = dst->priv_data; - const MpegEncContext *m1 = src->priv_data; + H263DecContext *const h = dst->priv_data; + const H263DecContext *const h1 = src->priv_data; - m->quarter_sample = m1->quarter_sample; - m->divx_packed = m1->divx_packed; + h->c.quarter_sample = h1->c.quarter_sample; + h->divx_packed = h1->divx_packed; return 0; } @@ -3735,7 +3948,6 @@ static int mpeg4_update_thread_context_for_user(AVCodecContext *dst, static av_cold void mpeg4_init_static(void) { - static uint8_t mpeg4_rvlc_rl_tables[2][2][2 * MAX_RUN + MAX_LEVEL + 3]; static VLCElem vlc_buf[6498]; VLCInitState state = VLC_INIT_STATE(vlc_buf); @@ -3757,9 +3969,10 @@ static av_cold void mpeg4_init_static(void) 0, 0); } - ff_mpeg4_init_rl_intra(); - ff_rl_init(&ff_rvlc_rl_inter, mpeg4_rvlc_rl_tables[0]); - ff_rl_init(&ff_rvlc_rl_intra, mpeg4_rvlc_rl_tables[1]); + static uint8_t mpeg4_rl_intra_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; + ff_rl_init(&ff_mpeg4_rl_intra, mpeg4_rl_intra_table); + ff_h263_init_rl_inter(); + INIT_FIRST_VLC_RL(ff_mpeg4_rl_intra, 554); VLC_INIT_RL(ff_rvlc_rl_inter, 1072); INIT_FIRST_VLC_RL(ff_rvlc_rl_intra, 1072); @@ -3782,7 +3995,8 @@ static av_cold int decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + H263DecContext *const h = &ctx->h; + MPVUnquantDSPContext unquant_dsp_ctx; int ret; ctx->divx_version = @@ -3793,15 +4007,28 @@ static av_cold int decode_init(AVCodecContext *avctx) if ((ret = ff_h263_decode_init(avctx)) < 0) return ret; - s->h263_pred = 1; - s->low_delay = 0; /* default, might be overridden in the vol header during header parsing */ - s->decode_mb = mpeg4_decode_mb; + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, 0); + + ctx->dct_unquantize_h263_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + ctx->dct_unquantize_mpeg2_intra = unquant_dsp_ctx.dct_unquantize_mpeg2_intra; + // dct_unquantize_inter is only used with MPEG-2 quantizers, + // so that is all we keep. + ctx->dct_unquantize_mpeg2_inter = unquant_dsp_ctx.dct_unquantize_mpeg2_inter; + + h->c.y_dc_scale_table = ff_mpeg4_y_dc_scale_table; + h->c.c_dc_scale_table = ff_mpeg4_c_dc_scale_table; + + h->c.h263_pred = 1; + h->c.low_delay = 0; /* default, might be overridden in the vol header during header parsing */ + h->decode_header = mpeg4_decode_picture_header; + h->decode_mb = mpeg4_decode_mb; ctx->time_increment_bits = 4; /* default value for broken headers */ ctx->quant_precision = 5; avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; - ff_qpeldsp_init(&s->qdsp); + ff_qpeldsp_init(&h->c.qdsp); ff_mpeg4videodsp_init(&ctx->mdsp); ff_thread_once(&init_static_once, mpeg4_init_static); @@ -3811,16 +4038,33 @@ static av_cold int decode_init(AVCodecContext *avctx) GetBitContext gb; if (init_get_bits8(&gb, avctx->extradata, avctx->extradata_size) >= 0) - ff_mpeg4_decode_picture_header(ctx, &gb, 1, 0); + ff_mpeg4_parse_picture_header(ctx, &gb, 1, 0); } return 0; } -#define OFFSET(x) offsetof(MpegEncContext, x) +static av_cold void mpeg4_flush(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + av_buffer_unref(&ctx->bitstream_buffer); + ff_mpeg_flush(avctx); +} + +static av_cold int mpeg4_close(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + av_buffer_unref(&ctx->bitstream_buffer); + + return ff_mpv_decode_close(avctx); +} + +#define OFFSET(x) offsetof(H263DecContext, x) #define FLAGS AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY static const AVOption mpeg4_options[] = { - {"quarter_sample", "1/4 subpel MC", OFFSET(quarter_sample), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, + {"quarter_sample", "1/4 subpel MC", OFFSET(c.quarter_sample), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, {"divx_packed", "divx style packed b frames", OFFSET(divx_packed), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, {NULL} }; @@ -3840,12 +4084,12 @@ const FFCodec ff_mpeg4_decoder = { .priv_data_size = sizeof(Mpeg4DecContext), .init = decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), - .close = ff_mpv_decode_close, + .close = mpeg4_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, - .flush = ff_mpeg_flush, + .flush = mpeg4_flush, .p.max_lowres = 3, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), UPDATE_THREAD_CONTEXT(mpeg4_update_thread_context), diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h index 734237b16f..aafde454ea 100644 --- a/libavcodec/mpeg4videodec.h +++ b/libavcodec/mpeg4videodec.h @@ -26,13 +26,17 @@ #include #include "get_bits.h" +#include "h263dec.h" #include "mpegvideo.h" #include "mpeg4videodsp.h" #include "libavutil/mem_internal.h" typedef struct Mpeg4DecContext { - MpegEncContext m; + H263DecContext h; + + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames /// number of bits to represent the fractional part of time int time_increment_bits; @@ -49,6 +53,7 @@ typedef struct Mpeg4DecContext { /// sprite shift [isChroma] int sprite_shift[2]; + int mpeg_quant; // reversible vlc int rvlc; /// could this stream contain resync markers @@ -70,6 +75,8 @@ typedef struct Mpeg4DecContext { int divx_build; int xvid_build; int lavc_build; + /// Divx 5.01 puts several frames in a single one, this is used to reorder them + AVBufferRef *bitstream_buffer; int vo_type; @@ -86,27 +93,37 @@ typedef struct Mpeg4DecContext { Mpeg4VideoDSPContext mdsp; - DECLARE_ALIGNED(8, int32_t, block32)[12][64]; + void (*dct_unquantize_mpeg2_inter)(MpegEncContext *s, + int16_t *block, int n, int qscale); + void (*dct_unquantize_mpeg2_intra)(MpegEncContext *s, + int16_t *block, int n, int qscale); + void (*dct_unquantize_h263_intra)(MpegEncContext *s, + int16_t *block, int n, int qscale); + + union { + DECLARE_ALIGNED(8, int32_t, block32)[12][64]; + int16_t dpcm_macroblock[3][256]; + }; // 0 = DCT, 1 = DPCM top to bottom scan, -1 = DPCM bottom to top scan int dpcm_direction; - int16_t dpcm_macroblock[3][256]; + int dct_precision; } Mpeg4DecContext; -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only); +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only); void ff_mpeg4_decode_studio(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int block_size, int uvlinesize, int dct_linesize, int dct_offset); void ff_mpeg4_mcsel_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture); -int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx); -int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx); -int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx); -int ff_mpeg4_workaround_bugs(AVCodecContext *avctx); -void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, +int ff_mpeg4_decode_partitions(H263DecContext *const h); +int ff_mpeg4_decode_video_packet_header(H263DecContext *const h); +int ff_mpeg4_decode_studio_slice_header(H263DecContext *const h); +void ff_mpeg4_workaround_bugs(AVCodecContext *avctx); +void ff_mpeg4_pred_ac(H263DecContext *const h, int16_t *block, int n, int dir); -int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size); +int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt); #endif diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index 98254c2c63..ced4ad24e7 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -29,14 +29,21 @@ #include "mpegvideo.h" #include "h263.h" #include "h263enc.h" +#include "mathops.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videodefs.h" #include "mpeg4videoenc.h" #include "mpegvideoenc.h" #include "profiles.h" +#include "put_bits.h" #include "version.h" +/** + * Minimal fcode that a motion vector component would need. + */ +static uint8_t fcode_tab[MAX_MV*2+1]; + /* The uni_DCtab_* tables below contain unified bits+length tables to encode DC * differences in MPEG-4. Unified in the sense that the specification specifies * this encoding in several steps. */ @@ -66,11 +73,22 @@ static uint8_t uni_mpeg4_inter_rl_len[64 * 64 * 2 * 2]; * max run: 29/41 */ +typedef struct Mpeg4EncContext { + MPVMainEncContext m; + /// number of bits to represent the fractional part of time + int time_increment_bits; +} Mpeg4EncContext; + +static inline Mpeg4EncContext *mainctx_to_mpeg4(MPVMainEncContext *m) +{ + return (Mpeg4EncContext*)m; +} + /** * Return the number of bits that encoding the 8x8 block in block would need. * @param[in] block_last_index last index in scantable order that refers to a non zero element in block. */ -static inline int get_block_rate(MpegEncContext *s, int16_t block[64], +static inline int get_block_rate(MPVEncContext *const s, int16_t block[64], int block_last_index, const uint8_t scantable[64]) { int last = 0; @@ -99,113 +117,143 @@ static inline int get_block_rate(MpegEncContext *s, int16_t block[64], /** * Restore the ac coefficients in block that have been changed by decide_ac_pred(). - * This function also restores s->block_last_index. + * This function also restores s->c.block_last_index. * @param[in,out] block MB coefficients, these will be restored * @param[in] dir ac prediction direction for each 8x8 block * @param[out] st scantable for each 8x8 block * @param[in] zigzag_last_index index referring to the last non zero coefficient in zigzag order */ -static inline void restore_ac_coeffs(MpegEncContext *s, int16_t block[6][64], +static inline void restore_ac_coeffs(MPVEncContext *const s, int16_t block[6][64], const int dir[6], const uint8_t *st[6], const int zigzag_last_index[6]) { int i, n; - memcpy(s->block_last_index, zigzag_last_index, sizeof(int) * 6); + memcpy(s->c.block_last_index, zigzag_last_index, sizeof(int) * 6); for (n = 0; n < 6; n++) { - int16_t *ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + int16_t *ac_val = &s->c.ac_val[0][0] + s->c.block_index[n] * 16; - st[n] = s->intra_scantable.permutated; + st[n] = s->c.intra_scantable.permutated; if (dir[n]) { /* top prediction */ for (i = 1; i < 8; i++) - block[n][s->idsp.idct_permutation[i]] = ac_val[i + 8]; + block[n][s->c.idsp.idct_permutation[i]] = ac_val[i + 8]; } else { /* left prediction */ for (i = 1; i < 8; i++) - block[n][s->idsp.idct_permutation[i << 3]] = ac_val[i]; + block[n][s->c.idsp.idct_permutation[i << 3]] = ac_val[i]; } } } +/** + * Predict the dc. + * @param n block index (0-3 are luma, 4-5 are chroma) + * @param dir_ptr pointer to an integer where the prediction direction will be stored + */ +static int mpeg4_pred_dc(MpegEncContext *s, int n, int *dir_ptr) +{ + const int16_t *const dc_val = s->dc_val + s->block_index[n]; + const int wrap = s->block_wrap[n]; + + /* B C + * A X + */ + const int a = dc_val[-1]; + const int b = dc_val[-1 - wrap]; + const int c = dc_val[-wrap]; + int pred; + + // There is no need for out-of-slice handling here, as all values are set + // appropriately when a new slice is opened. + if (abs(a - b) < abs(b - c)) { + pred = c; + *dir_ptr = 1; /* top */ + } else { + pred = a; + *dir_ptr = 0; /* left */ + } + return pred; +} + /** * Return the optimal value (0 or 1) for the ac_pred element for the given MB in MPEG-4. - * This function will also update s->block_last_index and s->ac_val. + * This function will also update s->c.block_last_index and s->c.ac_val. * @param[in,out] block MB coefficients, these will be updated if 1 is returned * @param[in] dir ac prediction direction for each 8x8 block * @param[out] st scantable for each 8x8 block * @param[out] zigzag_last_index index referring to the last non zero coefficient in zigzag order */ -static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], +static inline int decide_ac_pred(MPVEncContext *const s, int16_t block[6][64], const int dir[6], const uint8_t *st[6], int zigzag_last_index[6]) { int score = 0; int i, n; - const int8_t *const qscale_table = s->cur_pic.qscale_table; + const int8_t *const qscale_table = s->c.cur_pic.qscale_table; - memcpy(zigzag_last_index, s->block_last_index, sizeof(int) * 6); + memcpy(zigzag_last_index, s->c.block_last_index, sizeof(int) * 6); for (n = 0; n < 6; n++) { int16_t *ac_val, *ac_val1; - score -= get_block_rate(s, block[n], s->block_last_index[n], - s->intra_scantable.permutated); + score -= get_block_rate(s, block[n], s->c.block_last_index[n], + s->c.intra_scantable.permutated); - ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; + ac_val = &s->c.ac_val[0][0] + s->c.block_index[n] * 16; ac_val1 = ac_val; if (dir[n]) { - const int xy = s->mb_x + s->mb_y * s->mb_stride - s->mb_stride; + const int xy = s->c.mb_x + s->c.mb_y * s->c.mb_stride - s->c.mb_stride; /* top prediction */ - ac_val -= s->block_wrap[n] * 16; - if (s->mb_y == 0 || s->qscale == qscale_table[xy] || n == 2 || n == 3) { + ac_val -= s->c.block_wrap[n] * 16; + if (s->c.first_slice_line || s->c.qscale == qscale_table[xy] || n == 2 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i]]; - block[n][s->idsp.idct_permutation[i]] = level - ac_val[i + 8]; - ac_val1[i] = block[n][s->idsp.idct_permutation[i << 3]]; + const int level = block[n][s->c.idsp.idct_permutation[i]]; + block[n][s->c.idsp.idct_permutation[i]] = level - ac_val[i + 8]; + ac_val1[i] = block[n][s->c.idsp.idct_permutation[i << 3]]; ac_val1[i + 8] = level; } } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i]]; - block[n][s->idsp.idct_permutation[i]] = level - ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->qscale); - ac_val1[i] = block[n][s->idsp.idct_permutation[i << 3]]; + const int level = block[n][s->c.idsp.idct_permutation[i]]; + block[n][s->c.idsp.idct_permutation[i]] = level - ROUNDED_DIV(ac_val[i + 8] * qscale_table[xy], s->c.qscale); + ac_val1[i] = block[n][s->c.idsp.idct_permutation[i << 3]]; ac_val1[i + 8] = level; } } - st[n] = s->permutated_intra_h_scantable; + st[n] = s->c.permutated_intra_h_scantable; } else { - const int xy = s->mb_x - 1 + s->mb_y * s->mb_stride; + const int xy = s->c.mb_x - 1 + s->c.mb_y * s->c.mb_stride; /* left prediction */ ac_val -= 16; - if (s->mb_x == 0 || s->qscale == qscale_table[xy] || n == 1 || n == 3) { + if (s->c.mb_x == 0 || s->c.qscale == qscale_table[xy] || n == 1 || n == 3) { /* same qscale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i << 3]]; - block[n][s->idsp.idct_permutation[i << 3]] = level - ac_val[i]; + const int level = block[n][s->c.idsp.idct_permutation[i << 3]]; + block[n][s->c.idsp.idct_permutation[i << 3]] = level - ac_val[i]; ac_val1[i] = level; - ac_val1[i + 8] = block[n][s->idsp.idct_permutation[i]]; + ac_val1[i + 8] = block[n][s->c.idsp.idct_permutation[i]]; } } else { /* different qscale, we must rescale */ for (i = 1; i < 8; i++) { - const int level = block[n][s->idsp.idct_permutation[i << 3]]; - block[n][s->idsp.idct_permutation[i << 3]] = level - ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->qscale); + const int level = block[n][s->c.idsp.idct_permutation[i << 3]]; + block[n][s->c.idsp.idct_permutation[i << 3]] = level - ROUNDED_DIV(ac_val[i] * qscale_table[xy], s->c.qscale); ac_val1[i] = level; - ac_val1[i + 8] = block[n][s->idsp.idct_permutation[i]]; + ac_val1[i + 8] = block[n][s->c.idsp.idct_permutation[i]]; } } - st[n] = s->permutated_intra_v_scantable; + st[n] = s->c.permutated_intra_v_scantable; } for (i = 63; i > 0; i--) // FIXME optimize if (block[n][st[n][i]]) break; - s->block_last_index[n] = i; + s->c.block_last_index[n] = i; - score += get_block_rate(s, block[n], s->block_last_index[n], st[n]); + score += get_block_rate(s, block[n], s->c.block_last_index[n], st[n]); } if (score < 0) { @@ -219,39 +267,37 @@ static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], /** * modify mb_type & qscale so that encoding is actually possible in MPEG-4 */ -void ff_clean_mpeg4_qscales(MpegEncContext *s) +void ff_clean_mpeg4_qscales(MPVEncContext *const s) { - int i; - int8_t *const qscale_table = s->cur_pic.qscale_table; - ff_clean_h263_qscales(s); - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + int8_t *const qscale_table = s->c.cur_pic.qscale_table; int odd = 0; /* ok, come on, this isn't funny anymore, there's more code for * handling this MPEG-4 mess than for the actual adaptive quantization */ - for (i = 0; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; odd += qscale_table[mb_xy] & 1; } - if (2 * odd > s->mb_num) + if (2 * odd > s->c.mb_num) odd = 1; else odd = 0; - for (i = 0; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; if ((qscale_table[mb_xy] & 1) != odd) qscale_table[mb_xy]++; if (qscale_table[mb_xy] > 31) qscale_table[mb_xy] = 31; } - for (i = 1; i < s->mb_num; i++) { - int mb_xy = s->mb_index2xy[i]; - if (qscale_table[mb_xy] != qscale_table[s->mb_index2xy[i - 1]] && + for (int i = 1; i < s->c.mb_num; i++) { + int mb_xy = s->c.mb_index2xy[i]; + if (qscale_table[mb_xy] != qscale_table[s->c.mb_index2xy[i - 1]] && (s->mb_type[mb_xy] & CANDIDATE_MB_TYPE_DIRECT)) { s->mb_type[mb_xy] |= CANDIDATE_MB_TYPE_BIDIR; } @@ -276,46 +322,19 @@ static inline void mpeg4_encode_dc(PutBitContext *s, int level, int n) } } -static inline int mpeg4_get_dc_length(int level, int n) -{ - if (n < 4) - return uni_DCtab_lum_len[level + 256]; - else - return uni_DCtab_chrom_len[level + 256]; -} - /** - * Encode an 8x8 block. - * @param n block index (0-3 are luma, 4-5 are chroma) + * Encode the AC coefficients of an 8x8 block. */ -static inline void mpeg4_encode_block(const MpegEncContext *s, - const int16_t *block, int n, int intra_dc, - const uint8_t *scan_table, PutBitContext *dc_pb, - PutBitContext *ac_pb) +static inline void mpeg4_encode_ac_coeffs(const int16_t block[64], + const int last_index, int i, + const uint8_t *const scan_table, + PutBitContext *const ac_pb, + const uint32_t *const bits_tab, + const uint8_t *const len_tab) { - int i, last_non_zero; - const uint32_t *bits_tab; - const uint8_t *len_tab; - const int last_index = s->block_last_index[n]; - - if (s->mb_intra) { // Note gcc (3.2.1 at least) will optimize this away - /* MPEG-4 based DC predictor */ - mpeg4_encode_dc(dc_pb, intra_dc, n); - if (last_index < 1) - return; - i = 1; - bits_tab = uni_mpeg4_intra_rl_bits; - len_tab = uni_mpeg4_intra_rl_len; - } else { - if (last_index < 0) - return; - i = 0; - bits_tab = uni_mpeg4_inter_rl_bits; - len_tab = uni_mpeg4_inter_rl_len; - } + int last_non_zero = i - 1; /* AC coefs */ - last_non_zero = i - 1; for (; i < last_index; i++) { int level = block[scan_table[i]]; if (level) { @@ -349,97 +368,44 @@ static inline void mpeg4_encode_block(const MpegEncContext *s, } } -static int mpeg4_get_block_length(MpegEncContext *s, - const int16_t *block, int n, - int intra_dc, const uint8_t *scan_table) +static void mpeg4_encode_blocks_inter(MPVEncContext *const s, + const int16_t block[6][64], + PutBitContext *ac_pb) { - int i, last_non_zero; - const uint8_t *len_tab; - const int last_index = s->block_last_index[n]; - int len = 0; - - if (s->mb_intra) { // Note gcc (3.2.1 at least) will optimize this away - /* MPEG-4 based DC predictor */ - len += mpeg4_get_dc_length(intra_dc, n); - if (last_index < 1) - return len; - i = 1; - len_tab = uni_mpeg4_intra_rl_len; - } else { + /* encode each block */ + for (int n = 0; n < 6; ++n) { + const int last_index = s->c.block_last_index[n]; if (last_index < 0) - return 0; - i = 0; - len_tab = uni_mpeg4_inter_rl_len; - } + continue; - /* AC coefs */ - last_non_zero = i - 1; - for (; i < last_index; i++) { - int level = block[scan_table[i]]; - if (level) { - int run = i - last_non_zero - 1; - level += 64; - if ((level & (~127)) == 0) { - const int index = UNI_MPEG4_ENC_INDEX(0, run, level); - len += len_tab[index]; - } else { // ESC3 - len += 7 + 2 + 1 + 6 + 1 + 12 + 1; - } - last_non_zero = i; - } + mpeg4_encode_ac_coeffs(block[n], last_index, 0, + s->c.intra_scantable.permutated, ac_pb, + uni_mpeg4_inter_rl_bits, uni_mpeg4_inter_rl_len); } - /* if (i <= last_index) */ { - int level = block[scan_table[i]]; - int run = i - last_non_zero - 1; - level += 64; - if ((level & (~127)) == 0) { - const int index = UNI_MPEG4_ENC_INDEX(1, run, level); - len += len_tab[index]; - } else { // ESC3 - len += 7 + 2 + 1 + 6 + 1 + 12 + 1; - } - } - - return len; } -static inline void mpeg4_encode_blocks(MpegEncContext *s, - const int16_t block[6][64], - const int intra_dc[6], - const uint8_t * const *scan_table, - PutBitContext *dc_pb, - PutBitContext *ac_pb) +static void mpeg4_encode_blocks_intra(MPVEncContext *const s, + const int16_t block[6][64], + const int intra_dc[6], + const uint8_t * const *scan_table, + PutBitContext *dc_pb, + PutBitContext *ac_pb) { - int i; + /* encode each block */ + for (int n = 0; n < 6; ++n) { + mpeg4_encode_dc(dc_pb, intra_dc[n], n); - if (scan_table) { - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) { - for (i = 0; i < 6; i++) - skip_put_bits(&s->pb, - mpeg4_get_block_length(s, block[i], i, - intra_dc[i], scan_table[i])); - } else { - /* encode each block */ - for (i = 0; i < 6; i++) - mpeg4_encode_block(s, block[i], i, - intra_dc[i], scan_table[i], dc_pb, ac_pb); - } - } else { - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) { - for (i = 0; i < 6; i++) - skip_put_bits(&s->pb, - mpeg4_get_block_length(s, block[i], i, 0, - s->intra_scantable.permutated)); - } else { - /* encode each block */ - for (i = 0; i < 6; i++) - mpeg4_encode_block(s, block[i], i, 0, - s->intra_scantable.permutated, dc_pb, ac_pb); - } + const int last_index = s->c.block_last_index[n]; + if (last_index <= 0) + continue; + + mpeg4_encode_ac_coeffs(block[n], last_index, 1, + scan_table[n], ac_pb, + uni_mpeg4_intra_rl_bits, uni_mpeg4_intra_rl_len); } } -static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], +static inline int get_b_cbp(MPVEncContext *const s, int16_t block[6][64], int motion_x, int motion_y, int mb_type) { int cbp = 0, i; @@ -466,14 +432,14 @@ static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], } for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0 && ((cbp >> (5 - i)) & 1) == 0) { - s->block_last_index[i] = -1; - s->bdsp.clear_block(s->block[i]); + if (s->c.block_last_index[i] >= 0 && ((cbp >> (5 - i)) & 1) == 0) { + s->c.block_last_index[i] = -1; + s->c.bdsp.clear_block(s->block[i]); } } } else { for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } } @@ -483,29 +449,29 @@ static inline int get_b_cbp(MpegEncContext *s, int16_t block[6][64], // FIXME this is duplicated to h263.c static const int dquant_code[5] = { 1, 0, 9, 2, 3 }; -void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) +static void mpeg4_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) { int cbpc, cbpy, pred_x, pred_y; PutBitContext *const pb2 = s->data_partitioning ? &s->pb2 : &s->pb; - PutBitContext *const tex_pb = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B ? &s->tex_pb : &s->pb; - PutBitContext *const dc_pb = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_I ? &s->pb2 : &s->pb; - const int interleaved_stats = (s->avctx->flags & AV_CODEC_FLAG_PASS1) && !s->data_partitioning ? 1 : 0; + PutBitContext *const tex_pb = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_B ? &s->tex_pb : &s->pb; + PutBitContext *const dc_pb = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_I ? &s->pb2 : &s->pb; + const int interleaved_stats = (s->c.avctx->flags & AV_CODEC_FLAG_PASS1) && !s->data_partitioning; - if (!s->mb_intra) { + if (!s->c.mb_intra) { int i, cbp; - if (s->pict_type == AV_PICTURE_TYPE_B) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { /* convert from mv_dir to type */ static const int mb_type_table[8] = { -1, 3, 2, 1, -1, -1, -1, 0 }; - int mb_type = mb_type_table[s->mv_dir]; + int mb_type = mb_type_table[s->c.mv_dir]; - if (s->mb_x == 0) { + if (s->c.mb_x == 0) { for (i = 0; i < 2; i++) - s->last_mv[i][0][0] = - s->last_mv[i][0][1] = - s->last_mv[i][1][0] = - s->last_mv[i][1][1] = 0; + s->c.last_mv[i][0][0] = + s->c.last_mv[i][0][1] = + s->c.last_mv[i][1][0] = + s->c.last_mv[i][1][1] = 0; } av_assert2(s->dquant >= -2 && s->dquant <= 2); @@ -513,14 +479,14 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], av_assert2(mb_type >= 0); /* nothing to do if this MB was skipped in the next P-frame */ - if (s->next_pic.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]) { // FIXME avoid DCT & ... - s->mv[0][0][0] = - s->mv[0][0][1] = - s->mv[1][0][0] = - s->mv[1][0][1] = 0; - s->mv_dir = MV_DIR_FORWARD; // doesn't matter - s->qscale -= s->dquant; -// s->mb_skipped = 1; + if (s->c.next_pic.mbskip_table[s->c.mb_y * s->c.mb_stride + s->c.mb_x]) { // FIXME avoid DCT & ... + s->c.mv[0][0][0] = + s->c.mv[0][0][1] = + s->c.mv[1][0][0] = + s->c.mv[1][0][1] = 0; + s->c.mv_dir = MV_DIR_FORWARD; // doesn't matter + s->c.qscale -= s->dquant; +// s->c.mb_skipped = 1; return; } @@ -552,71 +518,71 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], else put_bits(&s->pb, 1, 0); } else - s->qscale -= s->dquant; + s->c.qscale -= s->dquant; - if (!s->progressive_sequence) { + if (!s->c.progressive_sequence) { if (cbp) - put_bits(&s->pb, 1, s->interlaced_dct); + put_bits(&s->pb, 1, s->c.interlaced_dct); if (mb_type) // not direct mode - put_bits(&s->pb, 1, s->mv_type == MV_TYPE_FIELD); + put_bits(&s->pb, 1, s->c.mv_type == MV_TYPE_FIELD); } if (interleaved_stats) s->misc_bits += get_bits_diff(s); if (!mb_type) { - av_assert2(s->mv_dir & MV_DIRECT); + av_assert2(s->c.mv_dir & MV_DIRECT); ff_h263_encode_motion_vector(s, motion_x, motion_y, 1); } else { av_assert2(mb_type > 0 && mb_type < 4); - if (s->mv_type != MV_TYPE_FIELD) { - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_type != MV_TYPE_FIELD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { ff_h263_encode_motion_vector(s, - s->mv[0][0][0] - s->last_mv[0][0][0], - s->mv[0][0][1] - s->last_mv[0][0][1], + s->c.mv[0][0][0] - s->c.last_mv[0][0][0], + s->c.mv[0][0][1] - s->c.last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0] = - s->last_mv[0][1][0] = s->mv[0][0][0]; - s->last_mv[0][0][1] = - s->last_mv[0][1][1] = s->mv[0][0][1]; + s->c.last_mv[0][0][0] = + s->c.last_mv[0][1][0] = s->c.mv[0][0][0]; + s->c.last_mv[0][0][1] = + s->c.last_mv[0][1][1] = s->c.mv[0][0][1]; } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { ff_h263_encode_motion_vector(s, - s->mv[1][0][0] - s->last_mv[1][0][0], - s->mv[1][0][1] - s->last_mv[1][0][1], + s->c.mv[1][0][0] - s->c.last_mv[1][0][0], + s->c.mv[1][0][1] - s->c.last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0] = - s->last_mv[1][1][0] = s->mv[1][0][0]; - s->last_mv[1][0][1] = - s->last_mv[1][1][1] = s->mv[1][0][1]; + s->c.last_mv[1][0][0] = + s->c.last_mv[1][1][0] = s->c.mv[1][0][0]; + s->c.last_mv[1][0][1] = + s->c.last_mv[1][1][1] = s->c.mv[1][0][1]; } } else { - if (s->mv_dir & MV_DIR_FORWARD) { - put_bits(&s->pb, 1, s->field_select[0][0]); - put_bits(&s->pb, 1, s->field_select[0][1]); + if (s->c.mv_dir & MV_DIR_FORWARD) { + put_bits(&s->pb, 1, s->c.field_select[0][0]); + put_bits(&s->pb, 1, s->c.field_select[0][1]); } - if (s->mv_dir & MV_DIR_BACKWARD) { - put_bits(&s->pb, 1, s->field_select[1][0]); - put_bits(&s->pb, 1, s->field_select[1][1]); + if (s->c.mv_dir & MV_DIR_BACKWARD) { + put_bits(&s->pb, 1, s->c.field_select[1][0]); + put_bits(&s->pb, 1, s->c.field_select[1][1]); } - if (s->mv_dir & MV_DIR_FORWARD) { + if (s->c.mv_dir & MV_DIR_FORWARD) { for (i = 0; i < 2; i++) { ff_h263_encode_motion_vector(s, - s->mv[0][i][0] - s->last_mv[0][i][0], - s->mv[0][i][1] - s->last_mv[0][i][1] / 2, + s->c.mv[0][i][0] - s->c.last_mv[0][i][0], + s->c.mv[0][i][1] - s->c.last_mv[0][i][1] / 2, s->f_code); - s->last_mv[0][i][0] = s->mv[0][i][0]; - s->last_mv[0][i][1] = s->mv[0][i][1] * 2; + s->c.last_mv[0][i][0] = s->c.mv[0][i][0]; + s->c.last_mv[0][i][1] = s->c.mv[0][i][1] * 2; } } - if (s->mv_dir & MV_DIR_BACKWARD) { + if (s->c.mv_dir & MV_DIR_BACKWARD) { for (i = 0; i < 2; i++) { ff_h263_encode_motion_vector(s, - s->mv[1][i][0] - s->last_mv[1][i][0], - s->mv[1][i][1] - s->last_mv[1][i][1] / 2, + s->c.mv[1][i][0] - s->c.last_mv[1][i][0], + s->c.mv[1][i][1] - s->c.last_mv[1][i][1] / 2, s->b_code); - s->last_mv[1][i][0] = s->mv[1][i][0]; - s->last_mv[1][i][1] = s->mv[1][i][1] * 2; + s->c.last_mv[1][i][0] = s->c.mv[1][i][0]; + s->c.last_mv[1][i][1] = s->c.mv[1][i][1] * 2; } } } @@ -625,34 +591,34 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (interleaved_stats) s->mv_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, NULL, NULL, NULL, &s->pb); + mpeg4_encode_blocks_inter(s, block, &s->pb); if (interleaved_stats) s->p_tex_bits += get_bits_diff(s); - } else { /* s->pict_type==AV_PICTURE_TYPE_B */ + } else { /* s->c.pict_type == AV_PICTURE_TYPE_B */ cbp = get_p_cbp(s, block, motion_x, motion_y); if ((cbp | motion_x | motion_y | s->dquant) == 0 && - s->mv_type == MV_TYPE_16X16) { + s->c.mv_type == MV_TYPE_16X16) { + const MPVMainEncContext *const m = slice_to_mainenc(s); /* Check if the B-frames can skip it too, as we must skip it * if we skip here why didn't they just compress * the skip-mb bits instead of reusing them ?! */ - if (s->max_b_frames > 0) { - int i; + if (m->max_b_frames > 0) { int x, y, offset; const uint8_t *p_pic; - x = s->mb_x * 16; - y = s->mb_y * 16; + x = s->c.mb_x * 16; + y = s->c.mb_y * 16; - offset = x + y * s->linesize; + offset = x + y * s->c.linesize; p_pic = s->new_pic->data[0] + offset; - s->mb_skipped = 1; - for (i = 0; i < s->max_b_frames; i++) { + s->c.mb_skipped = 1; + for (int i = 0; i < m->max_b_frames; i++) { const uint8_t *b_pic; int diff; - const MPVPicture *pic = s->reordered_input_picture[i + 1]; + const MPVPicture *pic = m->reordered_input_picture[i + 1]; if (!pic || pic->f->pict_type != AV_PICTURE_TYPE_B) break; @@ -661,29 +627,29 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (!pic->shared) b_pic += INPLACE_OFFSET; - if (x + 16 > s->width || y + 16 > s->height) { + if (x + 16 > s->c.width || y + 16 > s->c.height) { int x1, y1; - int xe = FFMIN(16, s->width - x); - int ye = FFMIN(16, s->height - y); + int xe = FFMIN(16, s->c.width - x); + int ye = FFMIN(16, s->c.height - y); diff = 0; for (y1 = 0; y1 < ye; y1++) { for (x1 = 0; x1 < xe; x1++) { - diff += FFABS(p_pic[x1 + y1 * s->linesize] - b_pic[x1 + y1 * s->linesize]); + diff += FFABS(p_pic[x1 + y1 * s->c.linesize] - b_pic[x1 + y1 * s->c.linesize]); } } diff = diff * 256 / (xe * ye); } else { - diff = s->sad_cmp[0](NULL, p_pic, b_pic, s->linesize, 16); + diff = s->sad_cmp[0](NULL, p_pic, b_pic, s->c.linesize, 16); } - if (diff > s->qscale * 70) { // FIXME check that 70 is optimal - s->mb_skipped = 0; + if (diff > s->c.qscale * 70) { // FIXME check that 70 is optimal + s->c.mb_skipped = 0; break; } } } else - s->mb_skipped = 1; + s->c.mb_skipped = 1; - if (s->mb_skipped == 1) { + if (s->c.mb_skipped == 1) { /* skip macroblock */ put_bits(&s->pb, 1, 1); @@ -700,7 +666,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], cbpc = cbp & 3; cbpy = cbp >> 2; cbpy ^= 0xf; - if (s->mv_type == MV_TYPE_16X16) { + if (s->c.mv_type == MV_TYPE_16X16) { if (s->dquant) cbpc += 8; put_bits(&s->pb, @@ -711,9 +677,9 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (s->dquant) put_bits(pb2, 2, dquant_code[s->dquant + 2]); - if (!s->progressive_sequence) { + if (!s->c.progressive_sequence) { if (cbp) - put_bits(pb2, 1, s->interlaced_dct); + put_bits(pb2, 1, s->c.interlaced_dct); put_bits(pb2, 1, 0); } @@ -721,13 +687,13 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], s->misc_bits += get_bits_diff(s); /* motion vectors: 16x16 mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); ff_h263_encode_motion_vector(s, motion_x - pred_x, motion_y - pred_y, s->f_code); - } else if (s->mv_type == MV_TYPE_FIELD) { + } else if (s->c.mv_type == MV_TYPE_FIELD) { if (s->dquant) cbpc += 8; put_bits(&s->pb, @@ -738,49 +704,49 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (s->dquant) put_bits(pb2, 2, dquant_code[s->dquant + 2]); - av_assert2(!s->progressive_sequence); + av_assert2(!s->c.progressive_sequence); if (cbp) - put_bits(pb2, 1, s->interlaced_dct); + put_bits(pb2, 1, s->c.interlaced_dct); put_bits(pb2, 1, 1); if (interleaved_stats) s->misc_bits += get_bits_diff(s); /* motion vectors: 16x8 interlaced mode */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); pred_y /= 2; - put_bits(&s->pb, 1, s->field_select[0][0]); - put_bits(&s->pb, 1, s->field_select[0][1]); + put_bits(&s->pb, 1, s->c.field_select[0][0]); + put_bits(&s->pb, 1, s->c.field_select[0][1]); ff_h263_encode_motion_vector(s, - s->mv[0][0][0] - pred_x, - s->mv[0][0][1] - pred_y, + s->c.mv[0][0][0] - pred_x, + s->c.mv[0][0][1] - pred_y, s->f_code); ff_h263_encode_motion_vector(s, - s->mv[0][1][0] - pred_x, - s->mv[0][1][1] - pred_y, + s->c.mv[0][1][0] - pred_x, + s->c.mv[0][1][1] - pred_y, s->f_code); } else { - av_assert2(s->mv_type == MV_TYPE_8X8); + av_assert2(s->c.mv_type == MV_TYPE_8X8); put_bits(&s->pb, ff_h263_inter_MCBPC_bits[cbpc + 16], ff_h263_inter_MCBPC_code[cbpc + 16]); put_bits(pb2, ff_h263_cbpy_tab[cbpy][1], ff_h263_cbpy_tab[cbpy][0]); - if (!s->progressive_sequence && cbp) - put_bits(pb2, 1, s->interlaced_dct); + if (!s->c.progressive_sequence && cbp) + put_bits(pb2, 1, s->c.interlaced_dct); if (interleaved_stats) s->misc_bits += get_bits_diff(s); for (i = 0; i < 4; i++) { /* motion vectors: 8x8 mode*/ - ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, i, 0, &pred_x, &pred_y); ff_h263_encode_motion_vector(s, - s->cur_pic.motion_val[0][s->block_index[i]][0] - pred_x, - s->cur_pic.motion_val[0][s->block_index[i]][1] - pred_y, + s->c.cur_pic.motion_val[0][s->c.block_index[i]][0] - pred_x, + s->c.cur_pic.motion_val[0][s->c.block_index[i]][1] - pred_y, s->f_code); } } @@ -788,7 +754,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], if (interleaved_stats) s->mv_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, NULL, NULL, NULL, tex_pb); + mpeg4_encode_blocks_inter(s, block, tex_pb); if (interleaved_stats) s->p_tex_bits += get_bits_diff(s); @@ -801,24 +767,30 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], const uint8_t *scan_table[6]; int i; - for (i = 0; i < 6; i++) - dc_diff[i] = ff_mpeg4_pred_dc(s, i, block[i][0], &dir[i], 1); + for (int i = 0; i < 6; i++) { + int pred = mpeg4_pred_dc(&s->c, i, &dir[i]); + int scale = i < 4 ? s->c.y_dc_scale : s->c.c_dc_scale; - if (s->avctx->flags & AV_CODEC_FLAG_AC_PRED) { - s->ac_pred = decide_ac_pred(s, block, dir, scan_table, zigzag_last_index); + pred = FASTDIV((pred + (scale >> 1)), scale); + dc_diff[i] = block[i][0] - pred; + s->c.dc_val[s->c.block_index[i]] = av_clip_uintp2(block[i][0] * scale, 11); + } + + if (s->c.avctx->flags & AV_CODEC_FLAG_AC_PRED) { + s->c.ac_pred = decide_ac_pred(s, block, dir, scan_table, zigzag_last_index); } else { for (i = 0; i < 6; i++) - scan_table[i] = s->intra_scantable.permutated; + scan_table[i] = s->c.intra_scantable.permutated; } /* compute cbp */ cbp = 0; for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 1) + if (s->c.block_last_index[i] >= 1) cbp |= 1 << (5 - i); cbpc = cbp & 3; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { if (s->dquant) cbpc += 4; put_bits(&s->pb, @@ -832,19 +804,19 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], ff_h263_inter_MCBPC_bits[cbpc + 4], ff_h263_inter_MCBPC_code[cbpc + 4]); } - put_bits(pb2, 1, s->ac_pred); + put_bits(pb2, 1, s->c.ac_pred); cbpy = cbp >> 2; put_bits(pb2, ff_h263_cbpy_tab[cbpy][1], ff_h263_cbpy_tab[cbpy][0]); if (s->dquant) put_bits(dc_pb, 2, dquant_code[s->dquant + 2]); - if (!s->progressive_sequence) - put_bits(dc_pb, 1, s->interlaced_dct); + if (!s->c.progressive_sequence) + put_bits(dc_pb, 1, s->c.interlaced_dct); if (interleaved_stats) s->misc_bits += get_bits_diff(s); - mpeg4_encode_blocks(s, block, dc_diff, scan_table, dc_pb, tex_pb); + mpeg4_encode_blocks_intra(s, block, dc_diff, scan_table, dc_pb, tex_pb); if (interleaved_stats) s->i_tex_bits += get_bits_diff(s); @@ -852,7 +824,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], /* restore ac coeffs & last_index stuff * if we messed them up with the prediction */ - if (s->ac_pred) + if (s->c.ac_pred) restore_ac_coeffs(s, block, dir, scan_table, zigzag_last_index); } } @@ -868,30 +840,31 @@ void ff_mpeg4_stuffing(PutBitContext *pbc) } /* must be called before writing the header */ -void ff_set_mpeg4_time(MpegEncContext *s) +void ff_set_mpeg4_time(MPVEncContext *const s) { - if (s->pict_type == AV_PICTURE_TYPE_B) { - ff_mpeg4_init_direct_mv(s); + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + ff_mpeg4_init_direct_mv(&s->c); } else { - s->last_time_base = s->time_base; - s->time_base = FFUDIV(s->time, s->avctx->time_base.den); + s->c.last_time_base = s->c.time_base; + s->c.time_base = FFUDIV(s->c.time, s->c.avctx->time_base.den); } } -static void mpeg4_encode_gop_header(MpegEncContext *s) +static void mpeg4_encode_gop_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int64_t hours, minutes, seconds; int64_t time; put_bits32(&s->pb, GOP_STARTCODE); - time = s->cur_pic.ptr->f->pts; - if (s->reordered_input_picture[1]) - time = FFMIN(time, s->reordered_input_picture[1]->f->pts); - time = time * s->avctx->time_base.num; - s->last_time_base = FFUDIV(time, s->avctx->time_base.den); + time = s->c.cur_pic.ptr->f->pts; + if (m->reordered_input_picture[1]) + time = FFMIN(time, m->reordered_input_picture[1]->f->pts); + time = time * s->c.avctx->time_base.num; + s->c.last_time_base = FFUDIV(time, s->c.avctx->time_base.den); - seconds = FFUDIV(time, s->avctx->time_base.den); + seconds = FFUDIV(time, s->c.avctx->time_base.den); minutes = FFUDIV(seconds, 60); seconds = FFUMOD(seconds, 60); hours = FFUDIV(minutes, 60); minutes = FFUMOD(minutes, 60); hours = FFUMOD(hours , 24); @@ -901,27 +874,28 @@ static void mpeg4_encode_gop_header(MpegEncContext *s) put_bits(&s->pb, 1, 1); put_bits(&s->pb, 6, seconds); - put_bits(&s->pb, 1, !!(s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); + put_bits(&s->pb, 1, !!(s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); put_bits(&s->pb, 1, 0); // broken link == NO ff_mpeg4_stuffing(&s->pb); } -static void mpeg4_encode_visual_object_header(MpegEncContext *s) +static void mpeg4_encode_visual_object_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int profile_and_level_indication; int vo_ver_id; - if (s->avctx->profile != AV_PROFILE_UNKNOWN) { - profile_and_level_indication = s->avctx->profile << 4; - } else if (s->max_b_frames || s->quarter_sample) { + if (s->c.avctx->profile != AV_PROFILE_UNKNOWN) { + profile_and_level_indication = s->c.avctx->profile << 4; + } else if (m->max_b_frames || s->c.quarter_sample) { profile_and_level_indication = 0xF0; // adv simple } else { profile_and_level_indication = 0x00; // simple } - if (s->avctx->level != AV_LEVEL_UNKNOWN) - profile_and_level_indication |= s->avctx->level; + if (s->c.avctx->level != AV_LEVEL_UNKNOWN) + profile_and_level_indication |= s->c.avctx->level; else profile_and_level_indication |= 1; // level 1 @@ -949,13 +923,14 @@ static void mpeg4_encode_visual_object_header(MpegEncContext *s) ff_mpeg4_stuffing(&s->pb); } -static void mpeg4_encode_vol_header(MpegEncContext *s, +static void mpeg4_encode_vol_header(Mpeg4EncContext *const m4, int vo_number, int vol_number) { + MPVEncContext *const s = &m4->m.s; int vo_ver_id, vo_type, aspect_ratio_info; - if (s->max_b_frames || s->quarter_sample) { + if (m4->m.max_b_frames || s->c.quarter_sample) { vo_ver_id = 5; vo_type = ADV_SIMPLE_VO_TYPE; } else { @@ -968,47 +943,39 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, put_bits(&s->pb, 1, 0); /* random access vol */ put_bits(&s->pb, 8, vo_type); /* video obj type indication */ - if (s->workaround_bugs & FF_BUG_MS) { - put_bits(&s->pb, 1, 0); /* is obj layer id= no */ - } else { - put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ - put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ - put_bits(&s->pb, 3, 1); /* is obj layer priority */ - } + put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ + put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ + put_bits(&s->pb, 3, 1); /* is obj layer priority */ - aspect_ratio_info = ff_h263_aspect_to_info(s->avctx->sample_aspect_ratio); + aspect_ratio_info = ff_h263_aspect_to_info(s->c.avctx->sample_aspect_ratio); put_bits(&s->pb, 4, aspect_ratio_info); /* aspect ratio info */ if (aspect_ratio_info == FF_ASPECT_EXTENDED) { - av_reduce(&s->avctx->sample_aspect_ratio.num, &s->avctx->sample_aspect_ratio.den, - s->avctx->sample_aspect_ratio.num, s->avctx->sample_aspect_ratio.den, 255); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.num); - put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.den); + av_reduce(&s->c.avctx->sample_aspect_ratio.num, &s->c.avctx->sample_aspect_ratio.den, + s->c.avctx->sample_aspect_ratio.num, s->c.avctx->sample_aspect_ratio.den, 255); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.num); + put_bits(&s->pb, 8, s->c.avctx->sample_aspect_ratio.den); } - if (s->workaround_bugs & FF_BUG_MS) { - put_bits(&s->pb, 1, 0); /* vol control parameters= no @@@ */ - } else { - put_bits(&s->pb, 1, 1); /* vol control parameters= yes */ - put_bits(&s->pb, 2, 1); /* chroma format YUV 420/YV12 */ - put_bits(&s->pb, 1, s->low_delay); - put_bits(&s->pb, 1, 0); /* vbv parameters= no */ - } + put_bits(&s->pb, 1, 1); /* vol control parameters= yes */ + put_bits(&s->pb, 2, 1); /* chroma format YUV 420/YV12 */ + put_bits(&s->pb, 1, s->c.low_delay); + put_bits(&s->pb, 1, 0); /* vbv parameters= no */ put_bits(&s->pb, 2, RECT_SHAPE); /* vol shape= rectangle */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 16, s->avctx->time_base.den); - if (s->time_increment_bits < 1) - s->time_increment_bits = 1; + put_bits(&s->pb, 16, s->c.avctx->time_base.den); + if (m4->time_increment_bits < 1) + m4->time_increment_bits = 1; put_bits(&s->pb, 1, 1); /* marker bit */ put_bits(&s->pb, 1, 0); /* fixed vop rate=no */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 13, s->width); /* vol width */ + put_bits(&s->pb, 13, s->c.width); /* vol width */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 13, s->height); /* vol height */ + put_bits(&s->pb, 13, s->c.height); /* vol height */ put_bits(&s->pb, 1, 1); /* marker bit */ - put_bits(&s->pb, 1, s->progressive_sequence ? 0 : 1); + put_bits(&s->pb, 1, s->c.progressive_sequence ? 0 : 1); put_bits(&s->pb, 1, 1); /* obmc disable */ if (vo_ver_id == 1) put_bits(&s->pb, 1, 0); /* sprite enable */ @@ -1019,15 +986,15 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, put_bits(&s->pb, 1, s->mpeg_quant); /* quant type = (0 = H.263 style) */ if (s->mpeg_quant) { - ff_write_quant_matrix(&s->pb, s->avctx->intra_matrix); - ff_write_quant_matrix(&s->pb, s->avctx->inter_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->intra_matrix); + ff_write_quant_matrix(&s->pb, s->c.avctx->inter_matrix); } if (vo_ver_id != 1) - put_bits(&s->pb, 1, s->quarter_sample); + put_bits(&s->pb, 1, s->c.quarter_sample); put_bits(&s->pb, 1, 1); /* complexity estimation disable */ put_bits(&s->pb, 1, s->rtp_mode ? 0 : 1); /* resync marker disable */ - put_bits(&s->pb, 1, s->data_partitioning ? 1 : 0); + put_bits(&s->pb, 1, s->data_partitioning); if (s->data_partitioning) put_bits(&s->pb, 1, 0); /* no rvlc */ @@ -1040,41 +1007,44 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, ff_mpeg4_stuffing(&s->pb); /* user data */ - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + if (!(s->c.avctx->flags & AV_CODEC_FLAG_BITEXACT)) { put_bits32(&s->pb, USER_DATA_STARTCODE); ff_put_string(&s->pb, LIBAVCODEC_IDENT, 0); } } /* write MPEG-4 VOP header */ -int ff_mpeg4_encode_picture_header(MpegEncContext *s) +static int mpeg4_encode_picture_header(MPVMainEncContext *const m) { + Mpeg4EncContext *const m4 = mainctx_to_mpeg4(m); + MPVEncContext *const s = &m->s; uint64_t time_incr; int64_t time_div, time_mod; - if (s->pict_type == AV_PICTURE_TYPE_I) { - if (!(s->avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { - if (s->avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT) // HACK, the reference sw is buggy - mpeg4_encode_visual_object_header(s); - if (s->avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT || s->picture_number == 0) // HACK, the reference sw is buggy - mpeg4_encode_vol_header(s, 0, 0); + put_bits_assume_flushed(&s->pb); + + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + if (!(s->c.avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { + if (s->c.avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT) // HACK, the reference sw is buggy + mpeg4_encode_visual_object_header(m); + if (s->c.avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT || s->picture_number == 0) // HACK, the reference sw is buggy + mpeg4_encode_vol_header(m4, 0, 0); } - if (!(s->workaround_bugs & FF_BUG_MS)) - mpeg4_encode_gop_header(s); + mpeg4_encode_gop_header(m); } - s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; + s->partitioned_frame = s->data_partitioning && s->c.pict_type != AV_PICTURE_TYPE_B; put_bits32(&s->pb, VOP_STARTCODE); /* vop header */ - put_bits(&s->pb, 2, s->pict_type - 1); /* pict type: I = 0 , P = 1 */ + put_bits(&s->pb, 2, s->c.pict_type - 1); /* pict type: I = 0 , P = 1 */ - time_div = FFUDIV(s->time, s->avctx->time_base.den); - time_mod = FFUMOD(s->time, s->avctx->time_base.den); - time_incr = time_div - s->last_time_base; + time_div = FFUDIV(s->c.time, s->c.avctx->time_base.den); + time_mod = FFUMOD(s->c.time, s->c.avctx->time_base.den); + time_incr = time_div - s->c.last_time_base; // This limits the frame duration to max 1 day if (time_incr > 3600*24) { - av_log(s->avctx, AV_LOG_ERROR, "time_incr %"PRIu64" too large\n", time_incr); + av_log(s->c.avctx, AV_LOG_ERROR, "time_incr %"PRIu64" too large\n", time_incr); return AVERROR(EINVAL); } while (time_incr--) @@ -1083,24 +1053,24 @@ int ff_mpeg4_encode_picture_header(MpegEncContext *s) put_bits(&s->pb, 1, 0); put_bits(&s->pb, 1, 1); /* marker */ - put_bits(&s->pb, s->time_increment_bits, time_mod); /* time increment */ + put_bits(&s->pb, m4->time_increment_bits, time_mod); /* time increment */ put_bits(&s->pb, 1, 1); /* marker */ put_bits(&s->pb, 1, 1); /* vop coded */ - if (s->pict_type == AV_PICTURE_TYPE_P) { - put_bits(&s->pb, 1, s->no_rounding); /* rounding type */ + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + put_bits(&s->pb, 1, s->c.no_rounding); /* rounding type */ } put_bits(&s->pb, 3, 0); /* intra dc VLC threshold */ - if (!s->progressive_sequence) { - put_bits(&s->pb, 1, !!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); - put_bits(&s->pb, 1, s->alternate_scan); + if (!s->c.progressive_sequence) { + put_bits(&s->pb, 1, !!(s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + put_bits(&s->pb, 1, s->c.alternate_scan); } // FIXME sprite stuff - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); - if (s->pict_type != AV_PICTURE_TYPE_I) + if (s->c.pict_type != AV_PICTURE_TYPE_I) put_bits(&s->pb, 3, s->f_code); /* fcode_for */ - if (s->pict_type == AV_PICTURE_TYPE_B) + if (s->c.pict_type == AV_PICTURE_TYPE_B) put_bits(&s->pb, 3, s->b_code); /* fcode_back */ return 0; @@ -1164,95 +1134,78 @@ static av_cold void init_uni_dc_tab(void) static av_cold void init_uni_mpeg4_rl_tab(RLTable *rl, uint32_t *bits_tab, uint8_t *len_tab) { - int slevel, run, last; + // Type 3 escape method. The escape code is the same for both VLCs + // (0x3, seven bits), so it is hardcoded. + memset(len_tab, 30, 2 * 2 * 64 * 64); + len_tab += 64; + bits_tab += 64; + for (int run = 0; run < 64; ++run) { + for (int level = 1;; ++level) { + // Escape code type 3 not last run (6 bits) marker marker + unsigned code = (3 << 23) | (3 << 21) | (0 << 20) | (run << 14) | (1 << 13) | 1; + // first the negative levels + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] = code | (-level & 0xfff) << 1; + bits_tab[UNI_MPEG4_ENC_INDEX(1, run, -level)] = + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] | (1 << 20) /* last */; - av_assert0(MAX_LEVEL >= 64); - av_assert0(MAX_RUN >= 63); - - for (slevel = -64; slevel < 64; slevel++) { - if (slevel == 0) - continue; - for (run = 0; run < 64; run++) { - for (last = 0; last <= 1; last++) { - const int index = UNI_MPEG4_ENC_INDEX(last, run, slevel + 64); - int level = slevel < 0 ? -slevel : slevel; - int sign = slevel < 0 ? 1 : 0; - int bits, len, code; - int level1, run1; - - len_tab[index] = 100; - - /* ESC0 */ - code = get_rl_index(rl, last, run, level); - bits = rl->table_vlc[code][0]; - len = rl->table_vlc[code][1]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - /* ESC1 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 2; - len++; // esc1 - level1 = level - rl->max_level[last][run]; - if (level1 > 0) { - code = get_rl_index(rl, last, run, level1); - bits <<= rl->table_vlc[code][1]; - len += rl->table_vlc[code][1]; - bits += rl->table_vlc[code][0]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } - /* ESC2 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 4 + 2; - len += 2; // esc2 - run1 = run - rl->max_run[last][level] - 1; - if (run1 >= 0) { - code = get_rl_index(rl, last, run1, level); - bits <<= rl->table_vlc[code][1]; - len += rl->table_vlc[code][1]; - bits += rl->table_vlc[code][0]; - bits = bits * 2 + sign; - len++; - - if (code != rl->n && len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } - /* ESC3 */ - bits = rl->table_vlc[rl->n][0]; - len = rl->table_vlc[rl->n][1]; - bits = bits * 4 + 3; - len += 2; // esc3 - bits = bits * 2 + last; - len++; - bits = bits * 64 + run; - len += 6; - bits = bits * 2 + 1; - len++; // marker - bits = bits * 4096 + (slevel & 0xfff); - len += 12; - bits = bits * 2 + 1; - len++; // marker - - if (len < len_tab[index]) { - bits_tab[index] = bits; - len_tab[index] = len; - } - } + if (level == 64) // positive levels have a range of 1..63 + break; + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] = code | level << 1; + bits_tab[UNI_MPEG4_ENC_INDEX(1, run, level)] = + bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] | (1 << 20) /* last */; } + // Is this needed at all? + len_tab[UNI_MPEG4_ENC_INDEX(0, run, 0)] = + len_tab[UNI_MPEG4_ENC_INDEX(1, run, 0)] = 0; + } + + uint8_t max_run[2][32] = { 0 }; + +#define VLC_NUM_CODES 102 // excluding the escape + av_assert2(rl->n == VLC_NUM_CODES); + for (int i = VLC_NUM_CODES - 1, max_level, cur_run = 0; i >= 0; --i) { + int run = rl->table_run[i], level = rl->table_level[i]; + int last = i >= rl->last; + unsigned code = rl->table_vlc[i][0] << 1; + int len = rl->table_vlc[i][1] + 1; + + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = code; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] = len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len; + + if (!max_run[last][level]) + max_run[last][level] = run + 1; + av_assert2(run + 1 <= max_run[last][level]); + + int run3 = run + max_run[last][level]; + int len3 = len + 7 + 2; + + if (run3 < 64 && len3 < len_tab[UNI_MPEG4_ENC_INDEX(last, run3, level)]) { + unsigned code3 = code | (0x3 << 2 | 0x2) << len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run3, level)] = code3; + len_tab [UNI_MPEG4_ENC_INDEX(last, run3, level)] = len3; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run3, -level)] = code3 | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run3, -level)] = len3; + } + // table_run and table_level are ordered so that all the entries + // with the same last and run are consecutive and level is ascending + // among these entries. By traversing downwards we therefore automatically + // encounter max_level of a given run first, needed for escape method 1. + if (run != cur_run) { + max_level = level; + cur_run = run; + } else + av_assert2(max_level > level); + + code |= 0x3 << (len + 1); + len += 7 + 1; + level += max_level; + av_assert2(len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] >= len); + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, level)] = code; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, level)] = len; + bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1; + len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len; } } @@ -1260,16 +1213,21 @@ static av_cold void mpeg4_encode_init_static(void) { init_uni_dc_tab(); - ff_mpeg4_init_rl_intra(); - init_uni_mpeg4_rl_tab(&ff_mpeg4_rl_intra, uni_mpeg4_intra_rl_bits, uni_mpeg4_intra_rl_len); init_uni_mpeg4_rl_tab(&ff_h263_rl_inter, uni_mpeg4_inter_rl_bits, uni_mpeg4_inter_rl_len); + + for (int f_code = MAX_FCODE; f_code > 0; f_code--) { + for (int mv = -(16 << f_code); mv < (16 << f_code); mv++) + fcode_tab[mv + MAX_MV] = f_code; + } } static av_cold int encode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; - MpegEncContext *s = avctx->priv_data; + Mpeg4EncContext *const m4 = avctx->priv_data; + MPVMainEncContext *const m = &m4->m; + MPVEncContext *const s = &m->s; int ret; if (avctx->width >= (1<<13) || avctx->height >= (1<<13)) { @@ -1277,11 +1235,10 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ff_qpeldsp_init(&s->qdsp); - if ((ret = ff_mpv_encode_init(avctx)) < 0) - return ret; + m->encode_picture_header = mpeg4_encode_picture_header; + s->encode_mb = mpeg4_encode_mb; - ff_thread_once(&init_static_once, mpeg4_encode_init_static); + m->fcode_tab = fcode_tab + MAX_MV; s->min_qcoeff = -2048; s->max_qcoeff = 2047; @@ -1291,27 +1248,43 @@ static av_cold int encode_init(AVCodecContext *avctx) s->inter_ac_vlc_last_length = uni_mpeg4_inter_rl_len + 128 * 64; s->luma_dc_vlc_length = uni_DCtab_lum_len; s->ac_esc_length = 7 + 2 + 1 + 6 + 1 + 12 + 1; - s->y_dc_scale_table = ff_mpeg4_y_dc_scale_table; - s->c_dc_scale_table = ff_mpeg4_c_dc_scale_table; + s->c.y_dc_scale_table = ff_mpeg4_y_dc_scale_table; + s->c.c_dc_scale_table = ff_mpeg4_c_dc_scale_table; - if (s->avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - s->avctx->extradata = av_malloc(1024); - if (!s->avctx->extradata) + ff_qpeldsp_init(&s->c.qdsp); + if ((ret = ff_mpv_encode_init(avctx)) < 0) + return ret; + + ff_thread_once(&init_static_once, mpeg4_encode_init_static); + + if (avctx->time_base.den > (1 << 16) - 1) { + av_log(avctx, AV_LOG_ERROR, + "timebase %d/%d not supported by MPEG 4 standard, " + "the maximum admitted value for the timebase denominator " + "is %d\n", avctx->time_base.num, avctx->time_base.den, + (1 << 16) - 1); + return AVERROR(EINVAL); + } + + m4->time_increment_bits = av_log2(avctx->time_base.den - 1) + 1; + + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + avctx->extradata = av_malloc(1024); + if (!avctx->extradata) return AVERROR(ENOMEM); - init_put_bits(&s->pb, s->avctx->extradata, 1024); + init_put_bits(&s->pb, avctx->extradata, 1024); - if (!(s->workaround_bugs & FF_BUG_MS)) - mpeg4_encode_visual_object_header(s); - mpeg4_encode_vol_header(s, 0, 0); + mpeg4_encode_visual_object_header(m); + mpeg4_encode_vol_header(m4, 0, 0); // ff_mpeg4_stuffing(&s->pb); ? flush_put_bits(&s->pb); - s->avctx->extradata_size = put_bytes_output(&s->pb); + avctx->extradata_size = put_bytes_output(&s->pb); } return 0; } -void ff_mpeg4_init_partitions(MpegEncContext *s) +void ff_mpeg4_init_partitions(MPVEncContext *const s) { uint8_t *start = put_bits_ptr(&s->pb); uint8_t *end = s->pb.buf_end; @@ -1324,13 +1297,13 @@ void ff_mpeg4_init_partitions(MpegEncContext *s) init_put_bits(&s->pb2, start + pb_size + tex_size, pb_size); } -void ff_mpeg4_merge_partitions(MpegEncContext *s) +void ff_mpeg4_merge_partitions(MPVEncContext *const s) { const int pb2_len = put_bits_count(&s->pb2); const int tex_pb_len = put_bits_count(&s->tex_pb); const int bits = put_bits_count(&s->pb); - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { put_bits(&s->pb, 19, DC_MARKER); s->misc_bits += 19 + pb2_len + bits - s->last_bits; s->i_tex_bits += tex_pb_len; @@ -1350,23 +1323,23 @@ void ff_mpeg4_merge_partitions(MpegEncContext *s) s->last_bits = put_bits_count(&s->pb); } -void ff_mpeg4_encode_video_packet_header(MpegEncContext *s) +void ff_mpeg4_encode_video_packet_header(MPVEncContext *const s) { - int mb_num_bits = av_log2(s->mb_num - 1) + 1; + int mb_num_bits = av_log2(s->c.mb_num - 1) + 1; - put_bits(&s->pb, ff_mpeg4_get_video_packet_prefix_length(s), 0); + put_bits(&s->pb, ff_mpeg4_get_video_packet_prefix_length(s->c.pict_type, s->f_code, s->b_code), 0); put_bits(&s->pb, 1, 1); - put_bits(&s->pb, mb_num_bits, s->mb_x + s->mb_y * s->mb_width); - put_bits(&s->pb, 5 /* quant_precision */, s->qscale); + put_bits(&s->pb, mb_num_bits, s->c.mb_x + s->c.mb_y * s->c.mb_width); + put_bits(&s->pb, 5 /* quant_precision */, s->c.qscale); put_bits(&s->pb, 1, 0); /* no HEC */ } -#define OFFSET(x) offsetof(MpegEncContext, x) +#define OFFSET(x) offsetof(MPVEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "data_partitioning", "Use data partitioning.", OFFSET(data_partitioning), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "data_partitioning", "Use data partitioning.", FF_MPV_OFFSET(data_partitioning), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "alternate_scan", "Enable alternate scantable.", OFFSET(c.alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "mpeg_quant", "Use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, VE }, FF_MPV_COMMON_BFRAME_OPTS @@ -1388,13 +1361,14 @@ const FFCodec ff_mpeg4_encoder = { CODEC_LONG_NAME("MPEG-4 part 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(Mpeg4EncContext), .init = encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &mpeg4enc_class, diff --git a/libavcodec/mpeg4videoenc.h b/libavcodec/mpeg4videoenc.h index f0d5c3d077..4e20b8aaa0 100644 --- a/libavcodec/mpeg4videoenc.h +++ b/libavcodec/mpeg4videoenc.h @@ -25,19 +25,28 @@ #include -#include "mpegvideo.h" #include "put_bits.h" -void ff_mpeg4_encode_mb(MpegEncContext *s, - int16_t block[6][64], - int motion_x, int motion_y); -void ff_set_mpeg4_time(MpegEncContext *s); -int ff_mpeg4_encode_picture_header(MpegEncContext *s); +enum { + MAX_PB2_INTRA_SIZE = 1 /* ac_pred */ + 5 /* max cbpy len */ + + 2 /* dquant */ + 1 /* interlaced dct */ + + 4 * (8 /* longest luma dct_dc_size */ + + 9 /* longest dc diff */ + 1 /* marker */) + + 2 * (9 + 9 + 1), + MAX_PB2_INTER_SIZE = 5 /* max cbpy len */ + + 2 /* dquant */ + 1 /* interlaced_dct */ + 1, + MAX_PB2_MB_SIZE = (FFMAX(MAX_PB2_INTER_SIZE, MAX_PB2_INTRA_SIZE) + 7) / 8, + MAX_AC_TEX_MB_SIZE = 64 * 6 * 30 /* longest escape code */ / 8, +}; -void ff_mpeg4_encode_video_packet_header(MpegEncContext *s); +typedef struct MPVEncContext MPVEncContext; + +void ff_set_mpeg4_time(MPVEncContext *s); + +void ff_mpeg4_encode_video_packet_header(MPVEncContext *s); void ff_mpeg4_stuffing(PutBitContext *pbc); -void ff_mpeg4_init_partitions(MpegEncContext *s); -void ff_mpeg4_merge_partitions(MpegEncContext *s); -void ff_clean_mpeg4_qscales(MpegEncContext *s); +void ff_mpeg4_init_partitions(MPVEncContext *s); +void ff_mpeg4_merge_partitions(MPVEncContext *s); +void ff_clean_mpeg4_qscales(MPVEncContext *s); #endif diff --git a/libavcodec/mpeg_er.c b/libavcodec/mpeg_er.c index 3cbdeeebec..5df75d8e85 100644 --- a/libavcodec/mpeg_er.c +++ b/libavcodec/mpeg_er.c @@ -28,11 +28,8 @@ static void set_erpic(ERPicture *dst, const MPVPicture *src) int i; memset(dst, 0, sizeof(*dst)); - if (!src) { - dst->f = NULL; - dst->tf = NULL; + if (!src) return; - } dst->f = src->f; dst->progress = &src->progress; @@ -54,10 +51,7 @@ void ff_mpeg_er_frame_start(MpegEncContext *s) set_erpic(&er->next_pic, s->next_pic.ptr); set_erpic(&er->last_pic, s->last_pic.ptr); - er->pp_time = s->pp_time; - er->pb_time = s->pb_time; er->quarter_sample = s->quarter_sample; - er->partitioned_frame = s->partitioned_frame; ff_er_frame_start(er); } @@ -79,7 +73,7 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, s->mcsel = 0; memcpy(s->mv, mv, sizeof(*mv)); - // The following disables the IDCT. + // The following disables unquantizing and the IDCT. for (size_t i = 0; i < FF_ARRAY_ELEMS(s->block_last_index); i++) s->block_last_index[i] = -1; @@ -96,14 +90,13 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, if (ref) av_log(s->avctx, AV_LOG_DEBUG, "Interlaced error concealment is not fully implemented\n"); - ff_mpv_reconstruct_mb(s, s->block); + ff_mpv_reconstruct_mb(s, NULL); } -int ff_mpeg_er_init(MpegEncContext *s) +av_cold int ff_mpeg_er_init(MpegEncContext *s) { ERContext *er = &s->er; int mb_array_size = s->mb_height * s->mb_stride; - int i; er->avctx = s->avctx; @@ -114,6 +107,10 @@ int ff_mpeg_er_init(MpegEncContext *s) er->mb_stride = s->mb_stride; er->b8_stride = s->b8_stride; + er->dc_val[0] = s->dc_val; + er->dc_val[1] = er->dc_val[0] + s->b8_stride * 2 * s->buffer_pools.alloc_mb_height + s->mb_stride; + er->dc_val[2] = er->dc_val[1] + s->mb_stride * (s->buffer_pools.alloc_mb_height + 1); + er->er_temp_buffer = av_malloc(s->mb_height * s->mb_stride * (4*sizeof(int) + 1)); er->error_status_table = av_mallocz(mb_array_size); if (!er->er_temp_buffer || !er->error_status_table) @@ -122,9 +119,6 @@ int ff_mpeg_er_init(MpegEncContext *s) er->mbskip_table = s->mbskip_table; er->mbintra_table = s->mbintra_table; - for (i = 0; i < FF_ARRAY_ELEMS(s->dc_val); i++) - er->dc_val[i] = s->dc_val[i]; - er->decode_mb = mpeg_er_decode_mb; er->opaque = s; diff --git a/libavcodec/mpeg_er.h b/libavcodec/mpeg_er.h index bb627a4d06..145d1866ed 100644 --- a/libavcodec/mpeg_er.h +++ b/libavcodec/mpeg_er.h @@ -24,4 +24,13 @@ int ff_mpeg_er_init(MpegEncContext *s); void ff_mpeg_er_frame_start(MpegEncContext *s); +static inline void ff_mpv_er_frame_start_ext(MPVContext *const s, int partitioned_frame, + uint16_t pp_time, uint16_t pb_time) +{ + s->er.partitioned_frame = partitioned_frame; + s->er.pp_time = pp_time; + s->er.pb_time = pb_time; + ff_mpeg_er_frame_start(s); +} + #endif /* AVCODEC_MPEG_ER_H */ diff --git a/libavcodec/mpegaudiodec_fixed.c b/libavcodec/mpegaudiodec_fixed.c index b5b6822a19..055e3c64e0 100644 --- a/libavcodec/mpegaudiodec_fixed.c +++ b/libavcodec/mpegaudiodec_fixed.c @@ -72,9 +72,7 @@ const FFCodec ff_mp1_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP2_DECODER @@ -89,9 +87,7 @@ const FFCodec ff_mp2_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3_DECODER @@ -106,9 +102,7 @@ const FFCodec ff_mp3_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3ADU_DECODER @@ -123,9 +117,7 @@ const FFCodec ff_mp3adu_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16), }; #endif #if CONFIG_MP3ON4_DECODER @@ -141,8 +133,7 @@ const FFCodec ff_mp3on4_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush_mp3on4, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c index ba8c49a3b4..05e2e399e4 100644 --- a/libavcodec/mpegaudiodec_float.c +++ b/libavcodec/mpegaudiodec_float.c @@ -85,9 +85,7 @@ const FFCodec ff_mp1float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP2FLOAT_DECODER @@ -102,9 +100,7 @@ const FFCodec ff_mp2float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP3FLOAT_DECODER @@ -119,9 +115,7 @@ const FFCodec ff_mp3float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP3ADUFLOAT_DECODER @@ -136,9 +130,7 @@ const FFCodec ff_mp3adufloat_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif #if CONFIG_MP3ON4FLOAT_DECODER @@ -154,8 +146,7 @@ const FFCodec ff_mp3on4float_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .flush = flush_mp3on4, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c index c73b1e0054..d7c5210eb8 100644 --- a/libavcodec/mpegaudiodec_template.c +++ b/libavcodec/mpegaudiodec_template.c @@ -1770,7 +1770,7 @@ static av_cold int decode_init_mp3on4(AVCodecContext * avctx) else s->syncword = 0xfff00000; - /* Init the first mp3 decoder in standard way, so that all tables get builded + /* Init the first mp3 decoder in standard way, so that all tables get built * We replace avctx->priv_data with the context of the first decoder so that * decode_init() does not have to be changed. * Other decoders will be initialized here copying data from the first context diff --git a/libavcodec/mpegaudiodsp_template.c b/libavcodec/mpegaudiodsp_template.c index fbbd94e486..6e8b84664e 100644 --- a/libavcodec/mpegaudiodsp_template.c +++ b/libavcodec/mpegaudiodsp_template.c @@ -369,4 +369,3 @@ void RENAME(ff_imdct36_blocks)(INTFLOAT *out, INTFLOAT *buf, INTFLOAT *in, out++; } } - diff --git a/libavcodec/mpegaudioenc_template.c b/libavcodec/mpegaudioenc.c similarity index 81% rename from libavcodec/mpegaudioenc_template.c rename to libavcodec/mpegaudioenc.c index 396e8a4899..9727c3819d 100644 --- a/libavcodec/mpegaudioenc_template.c +++ b/libavcodec/mpegaudioenc.c @@ -24,9 +24,14 @@ * The simplest mpeg audio layer 2 encoder. */ +#include "config.h" +#include "config_components.h" + +#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "avcodec.h" +#include "codec_internal.h" #include "encode.h" #include "put_bits.h" @@ -45,12 +50,12 @@ #define SAMPLES_BUF_SIZE 4096 typedef struct MpegAudioContext { - PutBitContext pb; int nb_channels; int lsf; /* 1 if mpeg2 low bitrate selected */ int bitrate_index; /* bit rate */ int freq_index; int frame_size; /* frame size, in bits, without padding */ + int is_fixed; /* padding computation */ int frame_frac, frame_frac_incr, do_padding; short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */ @@ -64,16 +69,19 @@ typedef struct MpegAudioContext { int16_t filter_bank[512]; int scale_factor_table[64]; unsigned char scale_diff_table[128]; -#if USE_FLOATS - float scale_factor_inv_table[64]; -#else - int8_t scale_factor_shift[64]; - unsigned short scale_factor_mult[64]; -#endif + union { + float scale_factor_inv_table[64]; + struct { + int8_t scale_factor_shift[64]; + unsigned short scale_factor_mult[64]; + }; + }; unsigned short total_quant_bits[17]; /* total number of bits per allocation group */ } MpegAudioContext; -static av_cold int MPA_encode_init(AVCodecContext *avctx) +#define IS_FIXED(s) (CONFIG_MP2_ENCODER && CONFIG_MP2FIXED_ENCODER ? (s)->is_fixed : CONFIG_MP2FIXED_ENCODER) + +static av_cold int mpa_encode_init(AVCodecContext *avctx) { MpegAudioContext *s = avctx->priv_data; int freq = avctx->sample_rate; @@ -89,7 +97,8 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) /* encoding freq */ s->lsf = 0; - for(i=0;i<3;i++) { + for (i = 0;; i++) { + av_assert1(i < 3); if (ff_mpa_freq_tab[i] == freq) break; if ((ff_mpa_freq_tab[i] / 2) == freq) { @@ -97,10 +106,6 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) break; } } - if (i == 3){ - av_log(avctx, AV_LOG_ERROR, "Sampling rate %d is not allowed in mp2\n", freq); - return AVERROR(EINVAL); - } s->freq_index = i; /* encoding bitrate & frequency */ @@ -159,13 +164,13 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx) if (v <= 0) v = 1; s->scale_factor_table[i] = v; -#if USE_FLOATS - s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20); -#else + if (IS_FIXED(s)) { #define P 15 - s->scale_factor_shift[i] = 21 - P - (i / 3); - s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0); -#endif + s->scale_factor_shift[i] = 21 - P - (i / 3); + s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0); + } else { + s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20); + } } for(i=0;i<128;i++) { v = i - 64; @@ -502,7 +507,7 @@ static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT]) /* Try to maximize the smr while using a number of bits inferior to the frame size. I tried to make the code simpler, faster and smaller than other encoders :-) */ -static void compute_bit_allocation(MpegAudioContext *s, +static unsigned compute_bit_allocation(MpegAudioContext *s, short smr1[MPA_MAX_CHANNELS][SBLIMIT], unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], int *padding) @@ -592,20 +597,86 @@ static void compute_bit_allocation(MpegAudioContext *s, } *padding = max_frame_size - current_frame_size; av_assert0(*padding >= 0); + return max_frame_size / 8U; +} + +/// Quantization & write sub band samples +static av_always_inline void encode_subbands(MpegAudioContext *const s, + PutBitContext *const p, + const uint8_t bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], + int is_fixed) +{ + for (int k = 0; k < 3; ++k) { + for (int l = 0; l < 12; l += 3) { + for (int i = 0, j = 0; i < s->sblimit; ++i) { + const int bit_alloc_bits = s->alloc_table[j]; + for (int ch = 0; ch < s->nb_channels; ++ch) { + const int b = bit_alloc[ch][i]; + if (b) { + /* we encode 3 sub band samples of the same sub band at a time */ + const int qindex = s->alloc_table[j + b]; + const int steps = ff_mpa_quant_steps[qindex]; + int q[3]; + + for (int m = 0; m < 3; ++m) { + const int sample = s->sb_samples[ch][k][l + m][i]; + /* divide by scale factor */ + if (!is_fixed) { + float a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]]; + q[m] = (int)((a + 1.0) * steps * 0.5); + } else { + const int e = s->scale_factors[ch][i][k]; + const int shift = s->scale_factor_shift[e]; + const int mult = s->scale_factor_mult[e]; + int q1; + + /* normalize to P bits */ + if (shift < 0) + q1 = sample * (1 << -shift); + else + q1 = sample >> shift; + q1 = (q1 * mult) >> P; + q1 += 1 << P; + if (q1 < 0) + q1 = 0; + q[m] = (q1 * (unsigned)steps) >> (P + 1); + } + if (q[m] >= steps) + q[m] = steps - 1; + av_assert2(q[m] >= 0 && q[m] < steps); + } + const int bits = ff_mpa_quant_bits[qindex]; + if (bits < 0) { + /* group the 3 values to save bits */ + put_bits(p, -bits, + q[0] + steps * (q[1] + steps * q[2])); + } else { + put_bits(p, bits, q[0]); + put_bits(p, bits, q[1]); + put_bits(p, bits, q[2]); + } + } + } + /* next subband in alloc table */ + j += 1 << bit_alloc_bits; + } + } + } } /* * Output the MPEG audio layer 2 frame. Note how the code is small * compared to other encoders :-) */ -static void encode_frame(MpegAudioContext *s, +static void encode_frame(MpegAudioContext *s, uint8_t *buf, unsigned buf_size, unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT], int padding) { - int i, j, k, l, bit_alloc_bits, b, ch; + int i, j, bit_alloc_bits, ch; unsigned char *sf; - int q[3]; - PutBitContext *p = &s->pb; + PutBitContext p0, *p = &p0; + + init_put_bits(p, buf, buf_size); /* header */ @@ -648,14 +719,11 @@ static void encode_frame(MpegAudioContext *s, sf = &s->scale_factors[ch][i][0]; switch(s->scale_code[ch][i]) { case 0: - put_bits(p, 6, sf[0]); - put_bits(p, 6, sf[1]); - put_bits(p, 6, sf[2]); + put_bits(p, 18, sf[0] << 12 | sf[1] << 6 | sf[2]); break; case 3: case 1: - put_bits(p, 6, sf[0]); - put_bits(p, 6, sf[2]); + put_bits(p, 12, sf[0] << 6 | sf[2]); break; case 2: put_bits(p, 6, sf[0]); @@ -665,76 +733,26 @@ static void encode_frame(MpegAudioContext *s, } } - /* quantization & write sub band samples */ - - for(k=0;k<3;k++) { - for(l=0;l<12;l+=3) { - j = 0; - for(i=0;isblimit;i++) { - bit_alloc_bits = s->alloc_table[j]; - for(ch=0;chnb_channels;ch++) { - b = bit_alloc[ch][i]; - if (b) { - int qindex, steps, m, sample, bits; - /* we encode 3 sub band samples of the same sub band at a time */ - qindex = s->alloc_table[j+b]; - steps = ff_mpa_quant_steps[qindex]; - for(m=0;m<3;m++) { - sample = s->sb_samples[ch][k][l + m][i]; - /* divide by scale factor */ -#if USE_FLOATS - { - float a; - a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]]; - q[m] = (int)((a + 1.0) * steps * 0.5); - } +#if CONFIG_SMALL + encode_subbands(s, p, bit_alloc, IS_FIXED(s)); #else - { - int q1, e, shift, mult; - e = s->scale_factors[ch][i][k]; - shift = s->scale_factor_shift[e]; - mult = s->scale_factor_mult[e]; - - /* normalize to P bits */ - if (shift < 0) - q1 = sample * (1 << -shift); - else - q1 = sample >> shift; - q1 = (q1 * mult) >> P; - q1 += 1 << P; - if (q1 < 0) - q1 = 0; - q[m] = (q1 * (unsigned)steps) >> (P + 1); - } + if (IS_FIXED(s)) + encode_subbands(s, p, bit_alloc, 1); + else + encode_subbands(s, p, bit_alloc, 0); #endif - if (q[m] >= steps) - q[m] = steps - 1; - av_assert2(q[m] >= 0 && q[m] < steps); - } - bits = ff_mpa_quant_bits[qindex]; - if (bits < 0) { - /* group the 3 values to save bits */ - put_bits(p, -bits, - q[0] + steps * (q[1] + steps * q[2])); - } else { - put_bits(p, bits, q[0]); - put_bits(p, bits, q[1]); - put_bits(p, bits, q[2]); - } - } - } - /* next subband in alloc table */ - j += 1 << bit_alloc_bits; - } - } - } + + av_assert1(put_bits_left(p) == padding); + + /* flush */ + flush_put_bits(p); /* padding */ - for(i=0;ipriv_data; @@ -754,18 +772,13 @@ static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, for(i=0;inb_channels;i++) { psycho_acoustic_model(s, smr[i]); } - compute_bit_allocation(s, smr, bit_alloc, &padding); + unsigned frame_size = compute_bit_allocation(s, smr, bit_alloc, &padding); - if ((ret = ff_alloc_packet(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0) + ret = ff_get_encode_buffer(avctx, avpkt, frame_size, 0); + if (ret < 0) return ret; - init_put_bits(&s->pb, avpkt->data, avpkt->size); - - encode_frame(s, bit_alloc, padding); - - /* flush */ - flush_put_bits(&s->pb); - avpkt->size = put_bytes_output(&s->pb); + encode_frame(s, avpkt->data, frame_size, bit_alloc, padding); if (frame->pts != AV_NOPTS_VALUE) avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); @@ -779,3 +792,44 @@ static const FFCodecDefault mp2_defaults[] = { { NULL }, }; +#if CONFIG_MP2_ENCODER +const FFCodec ff_mp2_encoder = { + .p.name = "mp2", + CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_MP2, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MpegAudioContext), + .init = mpa_encode_init, + FF_CODEC_ENCODE_CB(mpa_encode_frame), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + .defaults = mp2_defaults, +}; +#endif + +#if CONFIG_MP2FIXED_ENCODER +static av_cold int mpa_fixed_encode_init(AVCodecContext *avctx) +{ + MpegAudioContext *s = avctx->priv_data; + + s->is_fixed = 1; + return mpa_encode_init(avctx); +} + +const FFCodec ff_mp2fixed_encoder = { + .p.name = "mp2fixed", + CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_MP2, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MpegAudioContext), + .init = mpa_fixed_encode_init, + FF_CODEC_ENCODE_CB(mpa_encode_frame), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + .defaults = mp2_defaults, +}; +#endif diff --git a/libavcodec/mpegaudioenc_fixed.c b/libavcodec/mpegaudioenc_fixed.c deleted file mode 100644 index cdfc0b9958..0000000000 --- a/libavcodec/mpegaudioenc_fixed.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * The simplest mpeg audio layer 2 encoder - * Copyright (c) 2000, 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/channel_layout.h" -#include "codec_internal.h" -#include "mpegaudioenc_template.c" - -const FFCodec ff_mp2fixed_encoder = { - .p.name = "mp2fixed", - CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_MP2, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegAudioContext), - .init = MPA_encode_init, - FF_CODEC_ENCODE_CB(MPA_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ - 44100, 48000, 32000, 22050, 24000, 16000, 0 - }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .defaults = mp2_defaults, -}; diff --git a/libavcodec/mpegaudioenc_float.c b/libavcodec/mpegaudioenc_float.c deleted file mode 100644 index f94ab54e89..0000000000 --- a/libavcodec/mpegaudioenc_float.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * The simplest mpeg audio layer 2 encoder - * Copyright (c) 2000, 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/channel_layout.h" -#define USE_FLOATS 1 -#include "codec_internal.h" -#include "mpegaudioenc_template.c" - -const FFCodec ff_mp2_encoder = { - .p.name = "mp2", - CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_MP2, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegAudioContext), - .init = MPA_encode_init, - FF_CODEC_ENCODE_CB(MPA_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ - 44100, 48000, 32000, 22050, 24000, 16000, 0 - }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .defaults = mp2_defaults, -}; diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index cde060aa1f..6e96389c34 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -26,24 +26,24 @@ #include "avcodec.h" #include "mpegpicture.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" -static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) +static void mpv_pic_reset(AVRefStructOpaque unused, void *obj) { MPVPicture *pic = obj; av_frame_unref(pic->f); ff_thread_progress_reset(&pic->progress); - ff_refstruct_unref(&pic->hwaccel_picture_private); + av_refstruct_unref(&pic->hwaccel_picture_private); - ff_refstruct_unref(&pic->mbskip_table); - ff_refstruct_unref(&pic->qscale_table_base); - ff_refstruct_unref(&pic->mb_type_base); + av_refstruct_unref(&pic->mbskip_table); + av_refstruct_unref(&pic->qscale_table_base); + av_refstruct_unref(&pic->mb_type_base); for (int i = 0; i < 2; i++) { - ff_refstruct_unref(&pic->motion_val_base[i]); - ff_refstruct_unref(&pic->ref_index[i]); + av_refstruct_unref(&pic->motion_val_base[i]); + av_refstruct_unref(&pic->ref_index[i]); pic->motion_val[i] = NULL; } @@ -64,7 +64,7 @@ static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) pic->coded_picture_number = 0; } -static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) +static int av_cold mpv_pic_init(AVRefStructOpaque opaque, void *obj) { MPVPicture *pic = obj; int ret, init_progress = (uintptr_t)opaque.nc; @@ -79,7 +79,7 @@ static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) return 0; } -static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) +static void av_cold mpv_pic_free(AVRefStructOpaque unused, void *obj) { MPVPicture *pic = obj; @@ -87,17 +87,17 @@ static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) av_frame_free(&pic->f); } -av_cold FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) +av_cold AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) { - return ff_refstruct_pool_alloc_ext(sizeof(MPVPicture), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, + return av_refstruct_pool_alloc_ext(sizeof(MPVPicture), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, (void*)(uintptr_t)init_progress, mpv_pic_init, mpv_pic_reset, mpv_pic_free, NULL); } void ff_mpv_unref_picture(MPVWorkPicture *pic) { - ff_refstruct_unref(&pic->ptr); + av_refstruct_unref(&pic->ptr); memset(pic, 0, sizeof(*pic)); } @@ -121,13 +121,13 @@ static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic) void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src) { av_assert1(dst != src); - ff_refstruct_replace(&dst->ptr, src->ptr); + av_refstruct_replace(&dst->ptr, src->ptr); memcpy(dst, src, sizeof(*dst)); } void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic) { - ff_refstruct_replace(&wpic->ptr, pic); + av_refstruct_replace(&wpic->ptr, pic); if (!pic) { memset(wpic, 0, sizeof(*wpic)); return; @@ -207,7 +207,7 @@ static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic, int mb_height) { #define GET_BUFFER(name, buf_suffix, idx_suffix) do { \ - pic->name ## buf_suffix idx_suffix = ff_refstruct_pool_get(pools->name ## _pool); \ + pic->name ## buf_suffix idx_suffix = av_refstruct_pool_get(pools->name ## _pool); \ if (!pic->name ## buf_suffix idx_suffix) \ return AVERROR(ENOMEM); \ } while (0) diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h index 196aa9b744..d24093656a 100644 --- a/libavcodec/mpegpicture.h +++ b/libavcodec/mpegpicture.h @@ -42,11 +42,11 @@ typedef struct ScratchpadContext { } ScratchpadContext; typedef struct BufferPoolContext { - struct FFRefStructPool *mbskip_table_pool; - struct FFRefStructPool *qscale_table_pool; - struct FFRefStructPool *mb_type_pool; - struct FFRefStructPool *motion_val_pool; - struct FFRefStructPool *ref_index_pool; + struct AVRefStructPool *mbskip_table_pool; + struct AVRefStructPool *qscale_table_pool; + struct AVRefStructPool *mb_type_pool; + struct AVRefStructPool *motion_val_pool; + struct AVRefStructPool *ref_index_pool; int alloc_mb_width; ///< mb_width used to allocate tables int alloc_mb_height; ///< mb_height used to allocate tables int alloc_mb_stride; ///< mb_stride used to allocate tables @@ -114,7 +114,7 @@ typedef struct MPVWorkPicture { /** * Allocate a pool of MPVPictures. */ -struct FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress); +struct AVRefStructPool *ff_mpv_alloc_pic_pool(int init_progress); /** * Allocate an MPVPicture's accessories (but not the AVFrame's buffer itself) diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index e4ce26d299..9967762a79 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -33,7 +33,6 @@ #define PICT_FRAME 3 #define MAX_MB_BYTES (30 * 16 * 16 * 3 / 8 + 120) -#define MAX_FCODE 7 /* MB types */ #define MB_TYPE_INTRA4x4 (1 << 0) diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 01e310e483..a137fe31db 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -31,6 +31,7 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "avcodec.h" @@ -41,220 +42,8 @@ #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodata.h" -#include "refstruct.h" - -static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - /* XXX: only MPEG-1 */ - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 3; - level = (level - 1) | 1; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 3; - level = (level - 1) | 1; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - nCoeffs= s->block_last_index[n]; - - quant_matrix = s->inter_matrix; - for(i=0; i<=nCoeffs; i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 4; - level = (level - 1) | 1; - level = -level; - } else { - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 4; - level = (level - 1) | 1; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 4; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 4; - } - block[j] = level; - } - } -} - -static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - int sum=-1; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - sum += block[0]; - quant_matrix = s->intra_matrix; - for(i=1;i<=nCoeffs;i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (int)(level * qscale * quant_matrix[j]) >> 4; - level = -level; - } else { - level = (int)(level * qscale * quant_matrix[j]) >> 4; - } - block[j] = level; - sum+=level; - } - } - block[63]^=sum&1; -} - -static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, nCoeffs; - const uint16_t *quant_matrix; - int sum=-1; - - if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; - else qscale <<= 1; - - nCoeffs= s->block_last_index[n]; - - quant_matrix = s->inter_matrix; - for(i=0; i<=nCoeffs; i++) { - int j= s->intra_scantable.permutated[i]; - level = block[j]; - if (level) { - if (level < 0) { - level = -level; - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 5; - level = -level; - } else { - level = (((level << 1) + 1) * qscale * - ((int) (quant_matrix[j]))) >> 5; - } - block[j] = level; - sum+=level; - } - } - block[63]^=sum&1; -} - -static void dct_unquantize_h263_intra_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, qmul, qadd; - int nCoeffs; - - av_assert2(s->block_last_index[n]>=0 || s->h263_aic); - - qmul = qscale << 1; - - if (!s->h263_aic) { - block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; - qadd = (qscale - 1) | 1; - }else{ - qadd = 0; - } - if(s->ac_pred) - nCoeffs=63; - else - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; - - for(i=1; i<=nCoeffs; i++) { - level = block[i]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[i] = level; - } - } -} - -static void dct_unquantize_h263_inter_c(MpegEncContext *s, - int16_t *block, int n, int qscale) -{ - int i, level, qmul, qadd; - int nCoeffs; - - av_assert2(s->block_last_index[n]>=0); - - qadd = (qscale - 1) | 1; - qmul = qscale << 1; - - nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; - - for(i=0; i<=nCoeffs; i++) { - level = block[i]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[i] = level; - } - } -} +#include "mpegvideo_unquantize.h" +#include "libavutil/refstruct.h" static void gray16(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h) @@ -324,78 +113,17 @@ av_cold void ff_mpv_idct_init(MpegEncContext *s) s->idsp.idct_permutation); ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, s->idsp.idct_permutation); - - s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c; - s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c; - s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c; - s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c; - s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c; - if (s->avctx->flags & AV_CODEC_FLAG_BITEXACT) - s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact; - s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c; - -#if HAVE_INTRINSICS_NEON - ff_mpv_common_init_neon(s); -#endif - -#if ARCH_ARM - ff_mpv_common_init_arm(s); -#elif ARCH_PPC - ff_mpv_common_init_ppc(s); -#elif ARCH_X86 - ff_mpv_common_init_x86(s); -#elif ARCH_MIPS - ff_mpv_common_init_mips(s); -#endif } -static int init_duplicate_context(MpegEncContext *s) +av_cold int ff_mpv_init_duplicate_contexts(MpegEncContext *s) { - if (s->encoding) { - s->me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*s->me.map)); - if (!s->me.map) - return AVERROR(ENOMEM); - s->me.score_map = s->me.map + ME_MAP_SIZE; + const int nb_slices = s->slice_context_count; + const size_t slice_size = s->slice_ctx_size; - if (s->noise_reduction) { - if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_error_sum, 2)) - return AVERROR(ENOMEM); - } - } - if (!FF_ALLOCZ_TYPED_ARRAY(s->blocks, 1 + s->encoding)) - return AVERROR(ENOMEM); - s->block = s->blocks[0]; - - if (s->out_format == FMT_H263) { - int mb_height = s->msmpeg4_version == MSMP4_VC1 ? - FFALIGN(s->mb_height, 2) : s->mb_height; - int y_size = s->b8_stride * (2 * mb_height + 1); - int c_size = s->mb_stride * (mb_height + 1); - int yc_size = y_size + 2 * c_size; - /* ac values */ - if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, yc_size)) - return AVERROR(ENOMEM); - s->ac_val[0] = s->ac_val_base + s->b8_stride + 1; - s->ac_val[1] = s->ac_val_base + y_size + s->mb_stride + 1; - s->ac_val[2] = s->ac_val[1] + c_size; - } - - return 0; -} - -int ff_mpv_init_duplicate_contexts(MpegEncContext *s) -{ - int nb_slices = s->slice_context_count, ret; - - /* We initialize the copies before the original so that - * fields allocated in init_duplicate_context are NULL after - * copying. This prevents double-frees upon allocation error. */ for (int i = 1; i < nb_slices; i++) { - s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); + s->thread_context[i] = av_memdup(s, slice_size); if (!s->thread_context[i]) return AVERROR(ENOMEM); - if ((ret = init_duplicate_context(s->thread_context[i])) < 0) - return ret; s->thread_context[i]->start_mb_y = (s->mb_height * (i ) + nb_slices / 2) / nb_slices; s->thread_context[i]->end_mb_y = @@ -404,29 +132,21 @@ int ff_mpv_init_duplicate_contexts(MpegEncContext *s) s->start_mb_y = 0; s->end_mb_y = nb_slices > 1 ? (s->mb_height + nb_slices / 2) / nb_slices : s->mb_height; - return init_duplicate_context(s); + return 0; } -static void free_duplicate_context(MpegEncContext *s) +static av_cold void free_duplicate_context(MpegEncContext *s) { if (!s) return; av_freep(&s->sc.edge_emu_buffer); av_freep(&s->sc.scratchpad_buf); - s->me.temp = s->me.scratchpad = s->sc.obmc_scratchpad = NULL; s->sc.linesize = 0; - - av_freep(&s->dct_error_sum); - av_freep(&s->me.map); - s->me.score_map = NULL; - av_freep(&s->blocks); - av_freep(&s->ac_val_base); - s->block = NULL; } -static void free_duplicate_contexts(MpegEncContext *s) +static av_cold void free_duplicate_contexts(MpegEncContext *s) { for (int i = 1; i < s->slice_context_count; i++) { free_duplicate_context(s->thread_context[i]); @@ -435,35 +155,22 @@ static void free_duplicate_contexts(MpegEncContext *s) free_duplicate_context(s); } -static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) -{ -#define COPY(a) bak->a = src->a - COPY(sc); - COPY(me.map); - COPY(me.score_map); - COPY(blocks); - COPY(block); - COPY(start_mb_y); - COPY(end_mb_y); - COPY(me.map_generation); - COPY(dct_error_sum); - COPY(dct_count[0]); - COPY(dct_count[1]); - COPY(ac_val_base); - COPY(ac_val[0]); - COPY(ac_val[1]); - COPY(ac_val[2]); -#undef COPY -} - int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src) { - MpegEncContext bak; +#define COPY(M) \ + M(ScratchpadContext, sc) \ + M(int, start_mb_y) \ + M(int, end_mb_y) \ + M(int16_t*, dc_val) \ + M(void*, ac_val) + int ret; // FIXME copy only needed parts - backup_duplicate_context(&bak, dst); +#define BACKUP(T, member) T member = dst->member; + COPY(BACKUP) memcpy(dst, src, sizeof(MpegEncContext)); - backup_duplicate_context(dst, &bak); +#define RESTORE(T, member) dst->member = member; + COPY(RESTORE) ret = ff_mpv_framesize_alloc(dst->avctx, &dst->sc, dst->linesize); if (ret < 0) { @@ -480,44 +187,56 @@ int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src) * The changed fields will not depend upon the * prior state of the MpegEncContext. */ -void ff_mpv_common_defaults(MpegEncContext *s) +av_cold void ff_mpv_common_defaults(MpegEncContext *s) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; s->chroma_qscale_table = ff_default_chroma_qscale_table; s->progressive_frame = 1; s->progressive_sequence = 1; s->picture_structure = PICT_FRAME; - s->picture_number = 0; - - s->f_code = 1; - s->b_code = 1; - s->slice_context_count = 1; } -static void free_buffer_pools(BufferPoolContext *pools) +static av_cold void free_buffer_pools(BufferPoolContext *pools) { - ff_refstruct_pool_uninit(&pools->mbskip_table_pool); - ff_refstruct_pool_uninit(&pools->qscale_table_pool); - ff_refstruct_pool_uninit(&pools->mb_type_pool); - ff_refstruct_pool_uninit(&pools->motion_val_pool); - ff_refstruct_pool_uninit(&pools->ref_index_pool); + av_refstruct_pool_uninit(&pools->mbskip_table_pool); + av_refstruct_pool_uninit(&pools->qscale_table_pool); + av_refstruct_pool_uninit(&pools->mb_type_pool); + av_refstruct_pool_uninit(&pools->motion_val_pool); + av_refstruct_pool_uninit(&pools->ref_index_pool); pools->alloc_mb_height = pools->alloc_mb_width = pools->alloc_mb_stride = 0; } -int ff_mpv_init_context_frame(MpegEncContext *s) +av_cold int ff_mpv_init_context_frame(MpegEncContext *s) { + int nb_slices = (HAVE_THREADS && + s->avctx->active_thread_type & FF_THREAD_SLICE) ? + s->avctx->thread_count : 1; BufferPoolContext *const pools = &s->buffer_pools; - int y_size, c_size, yc_size, i, mb_array_size, mv_table_size, x, y; + int y_size, c_size, yc_size, mb_array_size, mv_table_size, x, y; int mb_height; + if (s->encoding && s->avctx->slices) + nb_slices = s->avctx->slices; + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) s->mb_height = (s->height + 31) / 32 * 2; else s->mb_height = (s->height + 15) / 16; + if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { + int max_slices; + if (s->mb_height) + max_slices = FFMIN(MAX_THREADS, s->mb_height); + else + max_slices = MAX_THREADS; + av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d)," + " reducing to %d\n", nb_slices, max_slices); + nb_slices = max_slices; + } + + s->slice_context_count = nb_slices; + /* VC-1 can change from being progressive to interlaced on a per-frame * basis. We therefore allocate certain buffers so big that they work * in both instances. */ @@ -557,7 +276,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) s->mb_index2xy[s->mb_height * s->mb_width] = (s->mb_height - 1) * s->mb_stride + s->mb_width; // FIXME really needed? #define ALLOC_POOL(name, size, flags) do { \ - pools->name ##_pool = ff_refstruct_pool_alloc((size), (flags)); \ + pools->name ##_pool = av_refstruct_pool_alloc((size), (flags)); \ if (!pools->name ##_pool) \ return AVERROR(ENOMEM); \ } while (0) @@ -578,7 +297,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) } if (s->codec_id == AV_CODEC_ID_MPEG4) { ALLOC_POOL(mbskip_table, mb_array_size + 2, - !s->encoding ? FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME : 0); + !s->encoding ? AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME : 0); if (!s->encoding) { /* cbp, pred_dir */ if (!(s->cbp_table = av_mallocz(mb_array_size)) || @@ -595,24 +314,39 @@ int ff_mpv_init_context_frame(MpegEncContext *s) s->coded_block = s->coded_block_base + s->b8_stride + 1; } - if (s->h263_pred || s->h263_plus || !s->encoding) { + if (s->h263_pred || s->h263_aic || !s->encoding) { + // When encoding, each slice (and therefore each thread) + // gets its own ac_val and dc_val buffers in order to avoid + // races. + size_t allslice_yc_size = yc_size * (s->encoding ? nb_slices : 1); + if (s->out_format == FMT_H263) { + /* ac values */ + if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, allslice_yc_size)) + return AVERROR(ENOMEM); + s->ac_val = s->ac_val_base + s->b8_stride + 1; + } + /* dc values */ // MN: we need these for error resilience of intra-frames - if (!FF_ALLOCZ_TYPED_ARRAY(s->dc_val_base, yc_size)) + // Allocating them unconditionally for decoders also means + // that we don't need to reinitialize when e.g. h263_aic changes. + + // y_size and therefore yc_size is always odd; allocate one element + // more for each encoder slice in order to be able to align each slice's + // dc_val to four in order to use aligned stores when cleaning dc_val. + allslice_yc_size += s->encoding * nb_slices; + if (!FF_ALLOC_TYPED_ARRAY(s->dc_val_base, allslice_yc_size)) return AVERROR(ENOMEM); - s->dc_val[0] = s->dc_val_base + s->b8_stride + 1; - s->dc_val[1] = s->dc_val_base + y_size + s->mb_stride + 1; - s->dc_val[2] = s->dc_val[1] + c_size; - for (i = 0; i < yc_size; i++) + s->dc_val = s->dc_val_base + s->b8_stride + 1; + for (size_t i = 0; i < allslice_yc_size; ++i) s->dc_val_base[i] = 1024; } // Note the + 1 is for a quicker MPEG-4 slice_end detection if (!(s->mbskip_table = av_mallocz(mb_array_size + 2)) || /* which mb is an intra block, init macroblock skip table */ - !(s->mbintra_table = av_malloc(mb_array_size))) + !(s->mbintra_table = av_mallocz(mb_array_size))) return AVERROR(ENOMEM); - memset(s->mbintra_table, 1, mb_array_size); ALLOC_POOL(qscale_table, mv_table_size, 0); ALLOC_POOL(mb_type, mv_table_size * sizeof(uint32_t), 0); @@ -626,7 +360,7 @@ int ff_mpv_init_context_frame(MpegEncContext *s) /* FIXME: The output of H.263 with OBMC depends upon * the earlier content of the buffer; therefore we set * the flags to always reset returned buffers here. */ - ALLOC_POOL(motion_val, mv_size, FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + ALLOC_POOL(motion_val, mv_size, AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); ALLOC_POOL(ref_index, ref_index_size, 0); } #undef ALLOC_POOL @@ -637,65 +371,14 @@ int ff_mpv_init_context_frame(MpegEncContext *s) return !CONFIG_MPEGVIDEODEC || s->encoding ? 0 : ff_mpeg_er_init(s); } -static void clear_context(MpegEncContext *s) -{ - memset(&s->buffer_pools, 0, sizeof(s->buffer_pools)); - memset(&s->next_pic, 0, sizeof(s->next_pic)); - memset(&s->last_pic, 0, sizeof(s->last_pic)); - memset(&s->cur_pic, 0, sizeof(s->cur_pic)); - - memset(s->thread_context, 0, sizeof(s->thread_context)); - - s->me.map = NULL; - s->me.score_map = NULL; - s->dct_error_sum = NULL; - s->block = NULL; - s->blocks = NULL; - s->ac_val_base = NULL; - s->ac_val[0] = - s->ac_val[1] = - s->ac_val[2] =NULL; - s->me.scratchpad = NULL; - s->me.temp = NULL; - memset(&s->sc, 0, sizeof(s->sc)); - - - s->bitstream_buffer = NULL; - s->allocated_bitstream_buffer_size = 0; - s->p_field_mv_table_base = NULL; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - s->p_field_mv_table[i][j] = NULL; - - s->dc_val_base = NULL; - s->coded_block_base = NULL; - s->mbintra_table = NULL; - s->cbp_table = NULL; - s->pred_dir_table = NULL; - - s->mbskip_table = NULL; - - s->er.error_status_table = NULL; - s->er.er_temp_buffer = NULL; - s->mb_index2xy = NULL; -} - /** * init common structure for both encoder and decoder. * this assumes that some variables like width/height are already set */ av_cold int ff_mpv_common_init(MpegEncContext *s) { - int nb_slices = (HAVE_THREADS && - s->avctx->active_thread_type & FF_THREAD_SLICE) ? - s->avctx->thread_count : 1; int ret; - clear_context(s); - - if (s->encoding && s->avctx->slices) - nb_slices = s->avctx->slices; - if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) { av_log(s->avctx, AV_LOG_ERROR, "decoding to AV_PIX_FMT_NONE is not supported.\n"); @@ -718,26 +401,15 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if ((ret = ff_mpv_init_context_frame(s))) goto fail; - if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { - int max_slices; - if (s->mb_height) - max_slices = FFMIN(MAX_THREADS, s->mb_height); - else - max_slices = MAX_THREADS; - av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d)," - " reducing to %d\n", nb_slices, max_slices); - nb_slices = max_slices; - } - s->context_initialized = 1; - memset(s->thread_context, 0, sizeof(s->thread_context)); s->thread_context[0] = s; - s->slice_context_count = nb_slices; // if (s->width && s->height) { - ret = ff_mpv_init_duplicate_contexts(s); - if (ret < 0) - goto fail; + if (!s->encoding) { + ret = ff_mpv_init_duplicate_contexts(s); + if (ret < 0) + goto fail; + } // } return 0; @@ -746,7 +418,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) return ret; } -void ff_mpv_free_context_frame(MpegEncContext *s) +av_cold void ff_mpv_free_context_frame(MpegEncContext *s) { free_duplicate_contexts(s); @@ -756,6 +428,7 @@ void ff_mpv_free_context_frame(MpegEncContext *s) for (int j = 0; j < 2; j++) s->p_field_mv_table[i][j] = NULL; + av_freep(&s->ac_val_base); av_freep(&s->dc_val_base); av_freep(&s->coded_block_base); av_freep(&s->mbintra_table); @@ -771,15 +444,12 @@ void ff_mpv_free_context_frame(MpegEncContext *s) s->linesize = s->uvlinesize = 0; } -void ff_mpv_common_end(MpegEncContext *s) +av_cold void ff_mpv_common_end(MpegEncContext *s) { ff_mpv_free_context_frame(s); if (s->slice_context_count > 1) s->slice_context_count = 1; - av_freep(&s->bitstream_buffer); - s->allocated_bitstream_buffer_size = 0; - ff_mpv_unref_picture(&s->last_pic); ff_mpv_unref_picture(&s->cur_pic); ff_mpv_unref_picture(&s->next_pic); @@ -797,24 +467,25 @@ void ff_clean_intra_table_entries(MpegEncContext *s) { int wrap = s->b8_stride; int xy = s->block_index[0]; - - s->dc_val[0][xy ] = - s->dc_val[0][xy + 1 ] = - s->dc_val[0][xy + wrap] = - s->dc_val[0][xy + 1 + wrap] = 1024; - /* ac pred */ - memset(s->ac_val[0][xy ], 0, 32 * sizeof(int16_t)); - memset(s->ac_val[0][xy + wrap], 0, 32 * sizeof(int16_t)); /* chroma */ - wrap = s->mb_stride; - xy = s->mb_x + s->mb_y * wrap; - s->dc_val[1][xy] = - s->dc_val[2][xy] = 1024; - /* ac pred */ - memset(s->ac_val[1][xy], 0, 16 * sizeof(int16_t)); - memset(s->ac_val[2][xy], 0, 16 * sizeof(int16_t)); + unsigned uxy = s->block_index[4]; + unsigned vxy = s->block_index[5]; + int16_t *dc_val = s->dc_val; - s->mbintra_table[xy]= 0; + AV_WN32A(dc_val + xy, 1024 << 16 | 1024); + AV_WN32 (dc_val + xy + wrap, 1024 << 16 | 1024); + dc_val[uxy] = + dc_val[vxy] = 1024; + /* ac pred */ + int16_t (*ac_val)[16] = s->ac_val; + av_assume(!((uintptr_t)ac_val & 0xF)); + // Don't reset the upper-left luma block, as it will only ever be + // referenced by blocks from the same macroblock. + memset(ac_val[xy + 1], 0, sizeof(*ac_val)); + memset(ac_val[xy + wrap], 0, 2 * sizeof(*ac_val)); + /* ac pred */ + memset(ac_val[uxy], 0, sizeof(*ac_val)); + memset(ac_val[vxy], 0, sizeof(*ac_val)); } void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 8083299b66..4a30986eac 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -30,26 +30,16 @@ #include "blockdsp.h" #include "error_resilience.h" -#include "fdctdsp.h" -#include "get_bits.h" #include "h264chroma.h" #include "h263dsp.h" #include "hpeldsp.h" #include "idctdsp.h" -#include "me_cmp.h" -#include "motion_est.h" #include "mpegpicture.h" -#include "mpegvideoencdsp.h" -#include "pixblockdsp.h" -#include "put_bits.h" -#include "ratecontrol.h" #include "qpeldsp.h" #include "videodsp.h" #define MAX_THREADS 32 -#define MAX_B_FRAMES 16 - /** * Scantable. */ @@ -94,33 +84,17 @@ typedef struct MpegEncContext { void *private_ctx; /* the following parameters must be initialized before encoding */ int width, height;///< picture size. must be a multiple of 16 - int gop_size; - int intra_only; ///< if true, only intra pictures are generated - int64_t bit_rate; ///< wanted bit rate enum OutputFormat out_format; ///< output format int h263_pred; ///< use MPEG-4/H.263 ac/dc predictions - int pb_frame; ///< PB-frame mode (0 = none, 1 = base, 2 = improved) - -/* the following codec id fields are deprecated in favor of codec_id */ - int h263_plus; ///< H.263+ headers - int h263_flv; ///< use flv H.263 header enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ - int fixed_qscale; ///< fixed qscale if non zero int encoding; ///< true if we are encoding (vs decoding) - int max_b_frames; ///< max number of B-frames for encoding - int luma_elim_threshold; - int chroma_elim_threshold; int workaround_bugs; ///< workaround bugs in encoders which cannot be detected automatically int codec_tag; ///< internal codec_tag upper case converted from avctx codec_tag /* the following fields are managed internally by the encoder */ /* sequence parameters */ int context_initialized; - int input_picture_number; ///< used to set pic->display_picture_number, should not be used for/by anything else - int coded_picture_number; ///< used to set pic->coded_picture_number, should not be used for/by anything else - int picture_number; //FIXME remove, unclear definition - int picture_in_gop_number; ///< 0-> first pic in gop, ... int mb_width, mb_height; ///< number of MBs horizontally & vertically int mb_stride; ///< mb_width+1 used for some arrays to allow simple addressing of left & top MBs without sig11 int b8_stride; ///< 2*mb_width+1 used for some 8x8 block arrays to allow simple addressing @@ -128,28 +102,17 @@ typedef struct MpegEncContext { int mb_num; ///< number of MBs of a picture ptrdiff_t linesize; ///< line size, in bytes, may be different from width ptrdiff_t uvlinesize; ///< line size, for chroma in bytes, may be different from width - struct FFRefStructPool *picture_pool; ///< Pool for MPVPictures - MPVPicture **input_picture;///< next pictures on display order for encoding - MPVPicture **reordered_input_picture; ///< pointer to the next pictures in coded order for encoding + struct AVRefStructPool *picture_pool; ///< Pool for MPVPictures BufferPoolContext buffer_pools; - int64_t user_specified_pts; ///< last non-zero pts from AVFrame which was passed into avcodec_send_frame() - /** - * pts difference between the first and second input frame, used for - * calculating dts of the first frame when there's a delay */ - int64_t dts_delta; - /** - * reordered pts to be used as dts for the next output frame when there's - * a delay */ - int64_t reordered_pts; - - /** bit output */ - PutBitContext pb; - int start_mb_y; ///< start mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) int end_mb_y; ///< end mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) - struct MpegEncContext *thread_context[MAX_THREADS]; + union { + struct MpegEncContext *thread_context[MAX_THREADS]; + struct Mpeg12SliceContext *mpeg12_contexts[MAX_THREADS]; + struct MPVEncContext *enc_contexts[MAX_THREADS]; + }; int slice_context_count; ///< number of used thread_contexts /** @@ -164,29 +127,22 @@ typedef struct MpegEncContext { */ MPVWorkPicture next_pic; - /** - * Reference to the source picture for encoding. - * note, linesize & data, might not match the source picture (for field pictures) - */ - AVFrame *new_pic; - /** * copy of the current picture structure. * note, linesize & data, might not match the current picture (for field pictures) */ MPVWorkPicture cur_pic; - int skipped_last_frame; int last_dc[3]; ///< last DC values for MPEG-1 int16_t *dc_val_base; - int16_t *dc_val[3]; ///< used for MPEG-4 DC prediction, all 3 arrays must be continuous const uint8_t *y_dc_scale_table; ///< qscale -> y_dc_scale table const uint8_t *c_dc_scale_table; ///< qscale -> c_dc_scale table const uint8_t *chroma_qscale_table; ///< qscale -> chroma_qscale (H.263) uint8_t *coded_block_base; uint8_t *coded_block; ///< used for coded block pattern prediction (msmpeg4v3, wmv1) int16_t (*ac_val_base)[16]; - int16_t (*ac_val[3])[16]; ///< used for MPEG-4 AC prediction, all 3 arrays must be continuous + int16_t *dc_val; ///< used for H.263 AIC/MPEG-4 DC prediction and ER + int16_t (*ac_val)[16]; ///< used for H.263 AIC, MPEG-4 AC prediction int mb_skipped; ///< MUST BE SET only during DECODING uint8_t *mbskip_table; /**< used to avoid copy if macroblock skipped (for black regions for example) and used for B-frame encoding & decoding (contains skip table of next P-frame) */ @@ -198,65 +154,19 @@ typedef struct MpegEncContext { int qscale; ///< QP int chroma_qscale; ///< chroma QP - unsigned int lambda; ///< Lagrange multiplier used in rate distortion - unsigned int lambda2; ///< (lambda*lambda) >> FF_LAMBDA_SHIFT - int *lambda_table; - int adaptive_quant; ///< use adaptive quantization - int dquant; ///< qscale difference to prev qscale int pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ... - int vbv_delay; - int last_pict_type; //FIXME removes - int last_non_b_pict_type; ///< used for MPEG-4 gmc B-frames & ratecontrol int droppable; - int last_lambda_for[5]; ///< last lambda for a specific pict type - int skipdct; ///< skip dct and code zero residual - - /* motion compensation */ - int unrestricted_mv; ///< mv can point outside of the coded picture - int h263_long_vectors; ///< use horrible H.263v1 long vector mode BlockDSPContext bdsp; - FDCTDSPContext fdsp; H264ChromaContext h264chroma; HpelDSPContext hdsp; IDCTDSPContext idsp; - MpegvideoEncDSPContext mpvencdsp; - PixblockDSPContext pdsp; QpelDSPContext qdsp; VideoDSPContext vdsp; H263DSPContext h263dsp; - int f_code; ///< forward MV resolution - int b_code; ///< backward MV resolution for B-frames (MPEG-4) - int16_t (*p_mv_table_base)[2]; - int16_t (*b_forw_mv_table_base)[2]; - int16_t (*b_back_mv_table_base)[2]; - int16_t (*b_bidir_forw_mv_table_base)[2]; - int16_t (*b_bidir_back_mv_table_base)[2]; - int16_t (*b_direct_mv_table_base)[2]; int16_t (*p_field_mv_table_base)[2]; - int16_t (*b_field_mv_table_base)[2]; - int16_t (*p_mv_table)[2]; ///< MV table (1MV per MB) P-frame encoding - int16_t (*b_forw_mv_table)[2]; ///< MV table (1MV per MB) forward mode B-frame encoding - int16_t (*b_back_mv_table)[2]; ///< MV table (1MV per MB) backward mode B-frame encoding - int16_t (*b_bidir_forw_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding - int16_t (*b_bidir_back_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding - int16_t (*b_direct_mv_table)[2]; ///< MV table (1MV per MB) direct mode B-frame encoding int16_t (*p_field_mv_table[2][2])[2]; ///< MV table (2MV per MB) interlaced P-frame encoding - int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame encoding - uint8_t (*p_field_select_table[2]); ///< Only the first element is allocated - uint8_t (*b_field_select_table[2][2]); ///< Only the first element is allocated - /* The following fields are encoder-only */ - uint16_t *mb_var; ///< Table for MB variances - uint16_t *mc_mb_var; ///< Table for motion compensated MB variances - uint8_t *mb_mean; ///< Table for MB luminance - int64_t mb_var_sum; ///< sum of MB variance for current frame - int64_t mc_mb_var_sum; ///< motion compensated MB variance for current frame - uint64_t encoding_error[MPV_MAX_PLANES]; - - int motion_est; ///< ME algorithm - int me_penalty_compensation; - int me_pre; ///< prepass for motion estimation int mv_dir; #define MV_DIR_FORWARD 1 #define MV_DIR_BACKWARD 2 @@ -275,19 +185,14 @@ typedef struct MpegEncContext { int mv[2][4][2]; int field_select[2][2]; int last_mv[2][2][2]; ///< last MV, used for MV prediction in MPEG-1 & B-frame MPEG-4 - const uint8_t *fcode_tab; ///< smallest fcode needed for each MV int16_t direct_scale_mv[2][64]; ///< precomputed to avoid divisions in ff_mpeg4_set_direct_mv - MotionEstContext me; - int no_rounding; /**< apply no rounding to motion compensation (MPEG-4, msmpeg4, ...) for B-frames rounding mode is always 0 */ /* macroblock layer */ int mb_x, mb_y; - int mb_skip_run; int mb_intra; - uint16_t *mb_type; ///< Table for candidate MB types for encoding (defines in mpegvideoenc.h) int block_index[6]; ///< index to current MB in block based arrays with edges int block_wrap[6]; @@ -301,80 +206,18 @@ typedef struct MpegEncContext { uint16_t inter_matrix[64]; uint16_t chroma_inter_matrix[64]; - int intra_quant_bias; ///< bias for the quantizer - int inter_quant_bias; ///< bias for the quantizer - int min_qcoeff; ///< minimum encodable coefficient - int max_qcoeff; ///< maximum encodable coefficient - int ac_esc_length; ///< num of bits needed to encode the longest esc - uint8_t *intra_ac_vlc_length; - uint8_t *intra_ac_vlc_last_length; - uint8_t *intra_chroma_ac_vlc_length; - uint8_t *intra_chroma_ac_vlc_last_length; - uint8_t *inter_ac_vlc_length; - uint8_t *inter_ac_vlc_last_length; - uint8_t *luma_dc_vlc_length; - - int coded_score[12]; - - /** precomputed matrix (combine qscale and DCT renorm) */ - int (*q_intra_matrix)[64]; - int (*q_chroma_intra_matrix)[64]; - int (*q_inter_matrix)[64]; - /** identical to the above but for MMX & these are not permutated, second 64 entries are bias*/ - uint16_t (*q_intra_matrix16)[2][64]; - uint16_t (*q_chroma_intra_matrix16)[2][64]; - uint16_t (*q_inter_matrix16)[2][64]; - - /* noise reduction */ - int (*dct_error_sum)[64]; - int dct_count[2]; - uint16_t (*dct_offset)[64]; - - /* bit rate control */ - int64_t total_bits; - int frame_bits; ///< bits used for the current frame - int stuffing_bits; ///< bits used for stuffing - int next_lambda; ///< next lambda used for retrying to encode a frame - RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c - - /* statistics, used for 2-pass encoding */ - int mv_bits; - int header_bits; - int i_tex_bits; - int p_tex_bits; - int i_count; - int misc_bits; ///< cbp, mb_type - int last_bits; ///< temp var used for calculating the above vars - /* error concealment / resync */ int resync_mb_x; ///< x position of last resync marker int resync_mb_y; ///< y position of last resync marker - GetBitContext last_resync_gb; ///< used to search for the next resync marker - int mb_num_left; ///< number of MBs left in this video packet (for partitioned Slices only) /* H.263 specific */ - int gob_index; int obmc; ///< overlapped block motion compensation - int mb_info; ///< interval for outputting info about mb offsets as side data - int prev_mb_info, last_mb_info; - uint8_t *mb_info_ptr; - int mb_info_size; - int ehc_mode; /* H.263+ specific */ - int umvplus; ///< == H.263+ && unrestricted_mv int h263_aic_dir; ///< AIC direction: 0 = left, 1 = top - int h263_slice_structured; - int alt_inter_vlc; ///< alternative inter vlc - int modified_quant; - int loop_filter; - int custom_pcf; /* MPEG-4 specific */ int studio_profile; - int dct_precision; - ///< number of bits to represent the fractional part of time (encoder only) - int time_increment_bits; int last_time_base; int time_base; ///< time in seconds of last I,P,S Frame int64_t time; ///< time of current frame @@ -385,37 +228,10 @@ typedef struct MpegEncContext { uint16_t pb_field_time; ///< like above, just for interlaced int mcsel; int quarter_sample; ///< 1->qpel, 0->half pel ME/MC - int data_partitioning; ///< data partitioning flag from header - int partitioned_frame; ///< is current frame partitioned int low_delay; ///< no reordering needed / has no B-frames - PutBitContext tex_pb; ///< used for data partitioned VOPs - PutBitContext pb2; ///< used for data partitioned VOPs - int mpeg_quant; - int padding_bug_score; ///< used to detect the VERY common padding bug in MPEG-4 - - /* divx specific, used to workaround (many) bugs in divx5 */ - int divx_packed; - uint8_t *bitstream_buffer; //Divx 5.01 puts several frames in a single one, this is used to reorder them - int bitstream_buffer_size; - unsigned int allocated_bitstream_buffer_size; - - /* RV10 specific */ - int rv10_version; ///< RV10 version: 0 or 3 - int rv10_first_dc_coded[3]; - - /* MJPEG specific */ - struct MJpegContext *mjpeg_ctx; - int esc_pos; /* MSMPEG4 specific */ - int mv_table_index; - int rl_table_index; - int rl_chroma_table_index; - int dc_table_index; - int use_skip_mb_code; - int slice_height; ///< in macroblocks int first_slice_line; ///< used in MPEG-4 too to handle resync markers - int flipflop_rounding; enum { MSMP4_UNUSED, MSMP4_V1, @@ -425,19 +241,9 @@ typedef struct MpegEncContext { MSMP4_WMV2, MSMP4_VC1, ///< for VC1 (image), WMV3 (image) and MSS2. } msmpeg4_version; - int per_mb_rl_table; - int esc3_level_length; - int esc3_run_length; int inter_intra_pred; int mspel; - /* decompression specific */ - GetBitContext gb; - - /* MPEG-1 specific */ - int last_mv_dir; ///< last mv_dir, used for B-frame encoding - int vbv_delay_pos; ///< offset of vbv_delay in the bitstream - /* MPEG-2-specific - I wished not to have to support this mess. */ int progressive_sequence; int mpeg_f_code[2][2]; @@ -450,7 +256,6 @@ typedef struct MpegEncContext { int top_field_first; int concealment_motion_vectors; int q_scale_type; - int brd_scale; int intra_vlc_format; int alternate_scan; int repeat_first_field; @@ -467,93 +272,22 @@ typedef struct MpegEncContext { int interlaced_dct; int first_field; ///< is 1 for the first field of a field picture 0 otherwise - /* RTP specific */ - int rtp_mode; - int rtp_payload_size; - - uint8_t *ptr_lastgob; - - int16_t (*block)[64]; ///< points to one of the following blocks - int16_t (*blocks)[12][64]; // for HQ mode we need to keep the best block - int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() - -#define SLICE_OK 0 -#define SLICE_ERROR -1 -#define SLICE_END -2 /// clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. - */ - float rc_qsquish; - float rc_qmod_amp; - int rc_qmod_freq; - float rc_initial_cplx; - float rc_buffer_aggressivity; - float border_masking; - int lmin, lmax; - int vbv_ignore_qmax; - - char *rc_eq; - - /* temp buffers for rate control */ - float *cplx_tab, *bits_tab; /* flag to indicate a reinitialization is required, e.g. after * a frame size change */ int context_reinit; + /// If set, ff_mpv_common_init() will allocate slice contexts of this size + unsigned slice_ctx_size; + ERContext er; - - int error_rate; - - /* temporary frames used by b_frame_strategy = 2 */ - AVFrame *tmp_frames[MAX_B_FRAMES + 2]; - int b_frame_strategy; - int b_sensitivity; - - /* frame skip options for encoding */ - int frame_skip_threshold; - int frame_skip_factor; - int frame_skip_exp; - int frame_skip_cmp; - me_cmp_func frame_skip_cmp_fn; - - int scenechange_threshold; - int noise_reduction; - - int intra_penalty; } MpegEncContext; +typedef MpegEncContext MPVContext; /** * Set the given MpegEncContext to common defaults (same for encoding @@ -563,12 +297,6 @@ typedef struct MpegEncContext { void ff_mpv_common_defaults(MpegEncContext *s); int ff_mpv_common_init(MpegEncContext *s); -void ff_mpv_common_init_arm(MpegEncContext *s); -void ff_mpv_common_init_axp(MpegEncContext *s); -void ff_mpv_common_init_neon(MpegEncContext *s); -void ff_mpv_common_init_ppc(MpegEncContext *s); -void ff_mpv_common_init_x86(MpegEncContext *s); -void ff_mpv_common_init_mips(MpegEncContext *s); /** * Initialize an MpegEncContext's thread contexts. Presumes that * slice_context_count is already set and that all the fields diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c index 1cab108935..85e24c667e 100644 --- a/libavcodec/mpegvideo_dec.c +++ b/libavcodec/mpegvideo_dec.c @@ -32,18 +32,19 @@ #include "avcodec.h" #include "decode.h" +#include "h263.h" #include "h264chroma.h" #include "internal.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "mpeg4videodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" #include "wmv2dec.h" -int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) +av_cold int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) { enum ThreadingStatus thread_status; @@ -79,44 +80,23 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, { MpegEncContext *const s1 = src->priv_data; MpegEncContext *const s = dst->priv_data; - int ret; + int ret = 0; if (dst == src) return 0; av_assert0(s != s1); - // FIXME can parameters change on I-frames? - // in that case dst may need a reinit - if (!s->context_initialized) { - void *private_ctx = s->private_ctx; - int err; - memcpy(s, s1, sizeof(*s)); - - s->context_initialized = 0; - s->context_reinit = 0; - s->avctx = dst; - s->private_ctx = private_ctx; - s->bitstream_buffer = NULL; - s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0; - - if (s1->context_initialized) { - if ((err = ff_mpv_common_init(s)) < 0) - return err; - } - } - if (s->height != s1->height || s->width != s1->width || s->context_reinit) { s->height = s1->height; s->width = s1->width; if ((ret = ff_mpv_common_frame_size_change(s)) < 0) return ret; + ret = 1; } s->quarter_sample = s1->quarter_sample; - s->picture_number = s1->picture_number; - ff_mpv_replace_picture(&s->cur_pic, &s1->cur_pic); ff_mpv_replace_picture(&s->last_pic, &s1->last_pic); ff_mpv_replace_picture(&s->next_pic, &s1->next_pic); @@ -126,7 +106,6 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, // Error/bug resilience s->workaround_bugs = s1->workaround_bugs; - s->padding_bug_score = s1->padding_bug_score; // MPEG-4 timing info memcpy(&s->last_time_base, &s1->last_time_base, @@ -134,42 +113,25 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, (char *) &s1->last_time_base); // B-frame info - s->max_b_frames = s1->max_b_frames; s->low_delay = s1->low_delay; - // DivX handling (doesn't work) - s->divx_packed = s1->divx_packed; - - if (s1->bitstream_buffer) { - av_fast_padded_malloc(&s->bitstream_buffer, - &s->allocated_bitstream_buffer_size, - s1->bitstream_buffer_size); - if (!s->bitstream_buffer) { - s->bitstream_buffer_size = 0; - return AVERROR(ENOMEM); - } - s->bitstream_buffer_size = s1->bitstream_buffer_size; - memcpy(s->bitstream_buffer, s1->bitstream_buffer, - s1->bitstream_buffer_size); - } - // MPEG-2/interlacing info memcpy(&s->progressive_sequence, &s1->progressive_sequence, - (char *) &s1->rtp_mode - (char *) &s1->progressive_sequence); + (char *) &s1->first_field + sizeof(s1->first_field) - (char *) &s1->progressive_sequence); - return 0; + return ret; } -int ff_mpv_decode_close(AVCodecContext *avctx) +av_cold int ff_mpv_decode_close(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - ff_refstruct_pool_uninit(&s->picture_pool); + av_refstruct_pool_uninit(&s->picture_pool); ff_mpv_common_end(s); return 0; } -int ff_mpv_common_frame_size_change(MpegEncContext *s) +av_cold int ff_mpv_common_frame_size_change(MpegEncContext *s) { int err = 0; @@ -216,7 +178,7 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) static int alloc_picture(MpegEncContext *s, MPVWorkPicture *dst, int reference) { AVCodecContext *avctx = s->avctx; - MPVPicture *pic = ff_refstruct_pool_get(s->picture_pool); + MPVPicture *pic = av_refstruct_pool_get(s->picture_pool); int ret; if (!pic) @@ -404,7 +366,7 @@ void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame * { ff_print_debug_info2(s->avctx, pict, p->mb_type, p->qscale_table, p->motion_val, - s->mb_width, s->mb_height, s->mb_stride, s->quarter_sample); + p->mb_width, p->mb_height, p->mb_stride, s->quarter_sample); } int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, @@ -446,7 +408,7 @@ void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h) s->first_field, s->low_delay); } -void ff_mpeg_flush(AVCodecContext *avctx) +av_cold void ff_mpeg_flush(AVCodecContext *avctx) { MpegEncContext *const s = avctx->priv_data; @@ -456,17 +418,9 @@ void ff_mpeg_flush(AVCodecContext *avctx) s->mb_x = s->mb_y = 0; - s->bitstream_buffer_size = 0; s->pp_time = 0; } -void ff_mpv_report_decode_progress(MpegEncContext *s) -{ - if (s->pict_type != AV_PICTURE_TYPE_B && !s->partitioned_frame && !s->er.error_occurred) - ff_thread_progress_report(&s->cur_pic.ptr->progress, s->mb_y); -} - - static inline int hpel_motion_lowres(MpegEncContext *s, uint8_t *dest, const uint8_t *src, int field_based, int field_select, @@ -603,7 +557,7 @@ static av_always_inline void mpeg_motion_lowres(MpegEncContext *s, ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x; if ((unsigned) src_x > FFMAX( h_edge_pos - (!!sx) - 2 * block_s, 0) || uvsrc_y<0 || - (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - FFMAX(h, hc<chroma_y_shift), 0)) { + (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - FFMAX(h, field_select + hc<chroma_y_shift), 0)) { s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr_y, linesize >> field_based, linesize >> field_based, 17, 17 + field_based, @@ -853,7 +807,7 @@ static inline void MPV_motion_lowres(MpegEncContext *s, } break; default: - av_assert2(0); + av_unreachable("No other mpegvideo MV types exist"); } } @@ -897,29 +851,255 @@ unhandled: /* add block[] to dest[] */ static inline void add_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size) + int16_t block[][64], int i, uint8_t *dest, int line_size) { if (s->block_last_index[i] >= 0) { - s->idsp.idct_add(dest, line_size, block); + s->idsp.idct_add(dest, line_size, block[i]); } } -#define IS_ENCODER 0 -#include "mpv_reconstruct_mb_template.c" - -void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) +/* put block[] to dest[] */ +static inline void put_dct(MpegEncContext *s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) { - if (s->avctx->debug & FF_DEBUG_DCT_COEFF) { - /* print DCT coefficients */ - av_log(s->avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 64; j++) { - av_log(s->avctx, AV_LOG_DEBUG, "%5d", - block[i][s->idsp.idct_permutation[j]]); - } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); - } + s->dct_unquantize_intra(s, block, i, qscale); + s->idsp.idct_put(dest, line_size, block); +} + +static inline void add_dequant_dct(MpegEncContext *s, + int16_t block[][64], int i, uint8_t *dest, int line_size, int qscale) +{ + if (s->block_last_index[i] >= 0) { + s->dct_unquantize_inter(s, block[i], i, qscale); + + s->idsp.idct_add(dest, line_size, block[i]); } +} + +#define NOT_MPEG12_H261 0 +#define MAY_BE_MPEG12_H261 1 +#define DEFINITELY_MPEG12_H261 2 + +/* generic function called after a macroblock has been parsed by the decoder. + + Important variables used: + s->mb_intra : true if intra macroblock + s->mv_dir : motion vector direction + s->mv_type : motion vector type + s->mv : motion vector + s->interlaced_dct : true if interlaced dct used (mpeg2) + */ +static av_always_inline +void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], + int lowres_flag, int is_mpeg12) +{ +#define IS_MPEG12_H261(s) (is_mpeg12 == MAY_BE_MPEG12_H261 ? ((s)->out_format <= FMT_H261) : is_mpeg12) + uint8_t *dest_y = s->dest[0], *dest_cb = s->dest[1], *dest_cr = s->dest[2]; + int dct_linesize, dct_offset; + const int linesize = s->cur_pic.linesize[0]; //not s->linesize as this would be wrong for field pics + const int uvlinesize = s->cur_pic.linesize[1]; + const int block_size = lowres_flag ? 8 >> s->avctx->lowres : 8; + + dct_linesize = linesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? linesize : linesize * block_size; + + if (!s->mb_intra) { + /* motion handling */ + if (HAVE_THREADS && is_mpeg12 != DEFINITELY_MPEG12_H261 && + s->avctx->active_thread_type & FF_THREAD_FRAME) { + if (s->mv_dir & MV_DIR_FORWARD) { + ff_thread_progress_await(&s->last_pic.ptr->progress, + lowest_referenced_row(s, 0)); + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_thread_progress_await(&s->next_pic.ptr->progress, + lowest_referenced_row(s, 1)); + } + } + + if (lowres_flag) { + const h264_chroma_mc_func *op_pix = s->h264chroma.put_h264_chroma_pixels_tab; + + if (s->mv_dir & MV_DIR_FORWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix); + op_pix = s->h264chroma.avg_h264_chroma_pixels_tab; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix); + } + } else { + const op_pixels_func (*op_pix)[4]; + const qpel_mc_func (*op_qpix)[16]; + + if ((is_mpeg12 == DEFINITELY_MPEG12_H261 || !s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { + op_pix = s->hdsp.put_pixels_tab; + op_qpix = s->qdsp.put_qpel_pixels_tab; + } else { + op_pix = s->hdsp.put_no_rnd_pixels_tab; + op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; + } + if (s->mv_dir & MV_DIR_FORWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix, op_qpix); + op_pix = s->hdsp.avg_pixels_tab; + op_qpix = s->qdsp.avg_qpel_pixels_tab; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix, op_qpix); + } + } + + /* skip dequant / idct if we are really late ;) */ + if (s->avctx->skip_idct) { + if ( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) + ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) + || s->avctx->skip_idct >= AVDISCARD_ALL) + return; + } + + /* add dct residue */ + if (is_mpeg12 != DEFINITELY_MPEG12_H261 && s->dct_unquantize_inter) { + // H.263, H.263+, H.263I, FLV, RV10, RV20 and MPEG-4 with MPEG-2 quantization + add_dequant_dct(s, block, 0, dest_y , dct_linesize, s->qscale); + add_dequant_dct(s, block, 1, dest_y + block_size, dct_linesize, s->qscale); + add_dequant_dct(s, block, 2, dest_y + dct_offset , dct_linesize, s->qscale); + add_dequant_dct(s, block, 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + av_assert2(s->chroma_y_shift); + add_dequant_dct(s, block, 4, dest_cb, uvlinesize, s->chroma_qscale); + add_dequant_dct(s, block, 5, dest_cr, uvlinesize, s->chroma_qscale); + } + } else if (is_mpeg12 == DEFINITELY_MPEG12_H261 || lowres_flag || (s->codec_id != AV_CODEC_ID_WMV2)) { + // H.261, MPEG-1, MPEG-2, MPEG-4 with H.263 quantization, + // MSMP4V1-3 and WMV1. + // Also RV30, RV40 and the VC-1 family when performing error resilience, + // but all blocks are skipped in this case. + add_dct(s, block, 0, dest_y , dct_linesize); + add_dct(s, block, 1, dest_y + block_size, dct_linesize); + add_dct(s, block, 2, dest_y + dct_offset , dct_linesize); + add_dct(s, block, 3, dest_y + dct_offset + block_size, dct_linesize); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) {//Chroma420 + add_dct(s, block, 4, dest_cb, uvlinesize); + add_dct(s, block, 5, dest_cr, uvlinesize); + } else { + //chroma422 + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + add_dct(s, block, 4, dest_cb, dct_linesize); + add_dct(s, block, 5, dest_cr, dct_linesize); + add_dct(s, block, 6, dest_cb + dct_offset, dct_linesize); + add_dct(s, block, 7, dest_cr + dct_offset, dct_linesize); + if (!s->chroma_x_shift) {//Chroma444 + add_dct(s, block, 8, dest_cb + block_size, dct_linesize); + add_dct(s, block, 9, dest_cr + block_size, dct_linesize); + add_dct(s, block, 10, dest_cb + block_size + dct_offset, dct_linesize); + add_dct(s, block, 11, dest_cr + block_size + dct_offset, dct_linesize); + } + } + } //fi gray + } else if (CONFIG_WMV2_DECODER) { + 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 (is_mpeg12 != DEFINITELY_MPEG12_H261 && CONFIG_MPEG4_DECODER && + /* s->codec_id == AV_CODEC_ID_MPEG4 && */ + s->avctx->bits_per_raw_sample > 8) { + ff_mpeg4_decode_studio(s, dest_y, dest_cb, dest_cr, block_size, + uvlinesize, dct_linesize, dct_offset); + } else if (!IS_MPEG12_H261(s)) { + /* dct only in intra block */ + put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); + put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); + put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); + put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) { + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + } else { + dct_offset >>= 1; + dct_linesize >>= 1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } + } + } else { + s->idsp.idct_put(dest_y, dct_linesize, block[0]); + s->idsp.idct_put(dest_y + block_size, dct_linesize, block[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, block[2]); + s->idsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift) { + s->idsp.idct_put(dest_cb, uvlinesize, block[4]); + s->idsp.idct_put(dest_cr, uvlinesize, block[5]); + } else { + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, block[4]); + s->idsp.idct_put(dest_cr, dct_linesize, block[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); + if (!s->chroma_x_shift) { //Chroma444 + s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]); + s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]); + s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]); + s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]); + } + } + } //gray + } + } +} + +static av_cold void debug_dct_coeffs(MPVContext *s, const int16_t block[][64]) +{ + if (!block) // happens when called via error resilience + return; + + void *const logctx = s->avctx; + const uint8_t *const idct_permutation = s->idsp.idct_permutation; + + /* print DCT coefficients */ + av_log(logctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 64; j++) { + av_log(logctx, AV_LOG_DEBUG, "%5d", + block[i][idct_permutation[j]]); + } + av_log(logctx, AV_LOG_DEBUG, "\n"); + } +} + +void ff_mpv_reconstruct_mb(MPVContext *s, int16_t block[][64]) +{ + const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; + + s->cur_pic.qscale_table[mb_xy] = s->qscale; + + /* avoid copy if macroblock skipped in last frame too */ + if (s->mb_skipped) { + s->mb_skipped = 0; + av_assert2(s->pict_type != AV_PICTURE_TYPE_I); + *mbskip_ptr = 1; + } else if (!s->cur_pic.reference) { + *mbskip_ptr = 1; + } else{ + *mbskip_ptr = 0; /* not skipped */ + } + + if (s->avctx->debug & FF_DEBUG_DCT_COEFF) + debug_dct_coeffs(s, block); av_assert2((s->out_format <= FMT_H261) == (s->out_format == FMT_H261 || s->out_format == FMT_MPEG1)); if (!s->avctx->lowres) { diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index a332edd1ae..dbf4d25136 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -33,6 +33,7 @@ #include "config_components.h" +#include #include #include "libavutil/emms.h" @@ -59,6 +60,7 @@ #include "mjpegenc_common.h" #include "mathops.h" #include "mpegutils.h" +#include "mpegvideo_unquantize.h" #include "mjpegenc.h" #include "speedhqenc.h" #include "msmpeg4enc.h" @@ -66,16 +68,14 @@ #include "qpeldsp.h" #include "faandct.h" #include "aandcttab.h" -#include "flvenc.h" #include "mpeg4video.h" #include "mpeg4videodata.h" #include "mpeg4videoenc.h" #include "internal.h" #include "bytestream.h" -#include "wmv2enc.h" #include "rv10enc.h" #include "packet_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include #include "sp5x.h" @@ -84,16 +84,15 @@ #define QMAT_SHIFT_MMX 16 #define QMAT_SHIFT 21 -static int encode_picture(MpegEncContext *s, const AVPacket *pkt); -static int dct_quantize_refine(MpegEncContext *s, int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale); -static int sse_mb(MpegEncContext *s); -static void denoise_dct_c(MpegEncContext *s, int16_t *block); -static int dct_quantize_c(MpegEncContext *s, +static int encode_picture(MPVMainEncContext *const s, const AVPacket *pkt); +static int dct_quantize_refine(MPVEncContext *const s, int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale); +static int sse_mb(MPVEncContext *const s); +static void denoise_dct_c(MPVEncContext *const s, int16_t *block); +static int dct_quantize_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow); -static int dct_quantize_trellis_c(MpegEncContext *s, int16_t *block, int n, int qscale, int *overflow); +static int dct_quantize_trellis_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow); -static uint8_t default_mv_penalty[MAX_FCODE + 1][MAX_DMV * 2 + 1]; static uint8_t default_fcode_tab[MAX_MV * 2 + 1]; static const AVOption mpv_generic_options[] = { @@ -109,7 +108,7 @@ const AVClass ff_mpv_enc_class = { .version = LIBAVUTIL_VERSION_INT, }; -void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], +void ff_convert_matrix(MPVEncContext *const s, int (*qmat)[64], uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix, int bias, int qmin, int qmax, int intra) @@ -122,7 +121,7 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], int i; int qscale2; - if (s->q_scale_type) qscale2 = ff_mpeg2_non_linear_qscale[qscale]; + if (s->c.q_scale_type) qscale2 = ff_mpeg2_non_linear_qscale[qscale]; else qscale2 = qscale << 1; if (fdsp->fdct == ff_jpeg_fdct_islow_8 || @@ -131,40 +130,43 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], #endif /* CONFIG_FAANDCT */ fdsp->fdct == ff_jpeg_fdct_islow_10) { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = (int64_t) qscale2 * quant_matrix[j]; - /* 16 <= qscale * quant_matrix[i] <= 7905 - * Assume x = ff_aanscales[i] * qscale * quant_matrix[i] - * 19952 <= x <= 249205026 - * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026 - * 3444240 >= (1 << 36) / (x) >= 275 */ + /* 1 * 1 <= qscale2 * quant_matrix[j] <= 112 * 255 + * Assume x = qscale2 * quant_matrix[j] + * 1 <= x <= 28560 + * (1 << 22) / 1 >= (1 << 22) / (x) >= (1 << 22) / 28560 + * 4194304 >= (1 << 22) / (x) >= 146 */ qmat[qscale][i] = (int)((UINT64_C(2) << QMAT_SHIFT) / den); } } else if (fdsp->fdct == ff_fdct_ifast) { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = ff_aanscales[i] * (int64_t) qscale2 * quant_matrix[j]; - /* 16 <= qscale * quant_matrix[i] <= 7905 - * Assume x = ff_aanscales[i] * qscale * quant_matrix[i] - * 19952 <= x <= 249205026 - * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026 - * 3444240 >= (1 << 36) / (x) >= 275 */ + /* 1247 * 1 * 1 <= ff_aanscales[i] * qscale2 * quant_matrix[j] <= 31521 * 112 * 255 + * Assume x = ff_aanscales[i] * qscale2 * quant_matrix[j] + * 1247 <= x <= 900239760 + * (1 << 36) / 1247 >= (1 << 36) / (x) >= (1 << 36) / 900239760 + * 55107840 >= (1 << 36) / (x) >= 76 */ qmat[qscale][i] = (int)((UINT64_C(2) << (QMAT_SHIFT + 14)) / den); } } else { for (i = 0; i < 64; i++) { - const int j = s->idsp.idct_permutation[i]; + const int j = s->c.idsp.idct_permutation[i]; int64_t den = (int64_t) qscale2 * quant_matrix[j]; - /* We can safely suppose that 16 <= quant_matrix[i] <= 255 - * Assume x = qscale * quant_matrix[i] - * So 16 <= x <= 7905 - * so (1 << 19) / 16 >= (1 << 19) / (x) >= (1 << 19) / 7905 - * so 32768 >= (1 << 19) / (x) >= 67 */ + /* 1 * 1 <= qscale2 * quant_matrix[j] <= 112 * 255 + * Assume x = qscale2 * quant_matrix[j] + * 1 <= x <= 28560 + * (1 << 22) / 1 >= (1 << 22) / (x) >= (1 << 22) / 28560 + * 4194304 >= (1 << 22) / (x) >= 146 + * + * 1 <= x <= 28560 + * (1 << 17) / 1 >= (1 << 17) / (x) >= (1 << 17) / 28560 + * 131072 >= (1 << 17) / (x) >= 4 */ + qmat[qscale][i] = (int)((UINT64_C(2) << QMAT_SHIFT) / den); - //qmat [qscale][i] = (1 << QMAT_SHIFT_MMX) / - // (qscale * quant_matrix[i]); qmat16[qscale][0][i] = (2 << QMAT_SHIFT_MMX) / den; if (qmat16[qscale][0][i] == 0 || @@ -187,34 +189,36 @@ void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], } } if (shift) { - av_log(s->avctx, AV_LOG_INFO, + av_log(s->c.avctx, AV_LOG_INFO, "Warning, QMAT_SHIFT is larger than %d, overflows possible\n", QMAT_SHIFT - shift); } } -static inline void update_qscale(MpegEncContext *s) +static inline void update_qscale(MPVMainEncContext *const m) { - if (s->q_scale_type == 1 && 0) { + MPVEncContext *const s = &m->s; + + if (s->c.q_scale_type == 1 && 0) { int i; int bestdiff=INT_MAX; int best = 1; for (i = 0 ; ilambda * 139); - if (ff_mpeg2_non_linear_qscale[i] < s->avctx->qmin || - (ff_mpeg2_non_linear_qscale[i] > s->avctx->qmax && !s->vbv_ignore_qmax)) + if (ff_mpeg2_non_linear_qscale[i] < s->c.avctx->qmin || + (ff_mpeg2_non_linear_qscale[i] > s->c.avctx->qmax && !m->vbv_ignore_qmax)) continue; if (diff < bestdiff) { bestdiff = diff; best = i; } } - s->qscale = best; + s->c.qscale = best; } else { - s->qscale = (s->lambda * 139 + FF_LAMBDA_SCALE * 64) >> + s->c.qscale = (s->lambda * 139 + FF_LAMBDA_SCALE * 64) >> (FF_LAMBDA_SHIFT + 7); - s->qscale = av_clip(s->qscale, s->avctx->qmin, s->vbv_ignore_qmax ? 31 : s->avctx->qmax); + s->c.qscale = av_clip(s->c.qscale, s->c.avctx->qmin, m->vbv_ignore_qmax ? 31 : s->c.avctx->qmax); } s->lambda2 = (s->lambda * s->lambda + FF_LAMBDA_SCALE / 2) >> @@ -235,63 +239,66 @@ void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix) } /** - * init s->cur_pic.qscale_table from s->lambda_table + * init s->c.cur_pic.qscale_table from s->lambda_table */ -static void init_qscale_tab(MpegEncContext *s) +static void init_qscale_tab(MPVEncContext *const s) { - int8_t * const qscale_table = s->cur_pic.qscale_table; - int i; + int8_t *const qscale_table = s->c.cur_pic.qscale_table; - for (i = 0; i < s->mb_num; i++) { - unsigned int lam = s->lambda_table[s->mb_index2xy[i]]; + for (int i = 0; i < s->c.mb_num; i++) { + unsigned int lam = s->lambda_table[s->c.mb_index2xy[i]]; int qp = (lam * 139 + FF_LAMBDA_SCALE * 64) >> (FF_LAMBDA_SHIFT + 7); - qscale_table[s->mb_index2xy[i]] = av_clip(qp, s->avctx->qmin, - s->avctx->qmax); + qscale_table[s->c.mb_index2xy[i]] = av_clip(qp, s->c.avctx->qmin, + s->c.avctx->qmax); } } -static void update_duplicate_context_after_me(MpegEncContext *dst, - const MpegEncContext *src) +static void update_duplicate_context_after_me(MPVEncContext *const dst, + const MPVEncContext *const src) { -#define COPY(a) dst->a= src->a - COPY(pict_type); +#define COPY(a) dst->a = src->a + COPY(c.pict_type); COPY(f_code); COPY(b_code); - COPY(qscale); + COPY(c.qscale); COPY(lambda); COPY(lambda2); - COPY(frame_pred_frame_dct); // FIXME don't set in encode_header - COPY(progressive_frame); // FIXME don't set in encode_header - COPY(partitioned_frame); // FIXME don't set in encode_header + COPY(c.frame_pred_frame_dct); // FIXME don't set in encode_header + COPY(c.progressive_frame); // FIXME don't set in encode_header + COPY(partitioned_frame); // FIXME don't set in encode_header #undef COPY } -static void mpv_encode_init_static(void) +static av_cold void mpv_encode_init_static(void) { for (int i = -16; i < 16; i++) default_fcode_tab[i + MAX_MV] = 1; } /** - * Set the given MpegEncContext to defaults for encoding. - * the changed fields will not depend upon the prior state of the MpegEncContext. + * Set the given MPVEncContext to defaults for encoding. */ -static void mpv_encode_defaults(MpegEncContext *s) +static av_cold void mpv_encode_defaults(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; static AVOnce init_static_once = AV_ONCE_INIT; - ff_mpv_common_defaults(s); + ff_mpv_common_defaults(&s->c); - ff_thread_once(&init_static_once, mpv_encode_init_static); + s->f_code = 1; + s->b_code = 1; - s->me.mv_penalty = default_mv_penalty; - s->fcode_tab = default_fcode_tab; - - s->input_picture_number = 0; - s->picture_in_gop_number = 0; + if (!m->fcode_tab) { + m->fcode_tab = default_fcode_tab + MAX_MV; + ff_thread_once(&init_static_once, mpv_encode_init_static); + } + if (!s->c.y_dc_scale_table) { + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; + } } -av_cold void ff_dct_encode_init(MpegEncContext *s) +av_cold void ff_dct_encode_init(MPVEncContext *const s) { s->dct_quantize = dct_quantize_c; s->denoise_dct = denoise_dct_c; @@ -302,12 +309,33 @@ av_cold void ff_dct_encode_init(MpegEncContext *s) ff_dct_encode_init_x86(s); #endif - if (s->avctx->trellis) + if (s->c.avctx->trellis) s->dct_quantize = dct_quantize_trellis_c; } -static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) +static av_cold void init_unquantize(MPVEncContext *const s2, AVCodecContext *avctx) { + MpegEncContext *const s = &s2->c; + MPVUnquantDSPContext unquant_dsp_ctx; + + ff_mpv_unquantize_init(&unquant_dsp_ctx, + avctx->flags & AV_CODEC_FLAG_BITEXACT, s->q_scale_type); + + if (s2->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_mpeg2_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_mpeg2_inter; + } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_h263_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_h263_inter; + } else { + s->dct_unquantize_intra = unquant_dsp_ctx.dct_unquantize_mpeg1_intra; + s->dct_unquantize_inter = unquant_dsp_ctx.dct_unquantize_mpeg1_inter; + } +} + +static av_cold int me_cmp_init(MPVMainEncContext *const m, AVCodecContext *avctx) +{ + MPVEncContext *const s = &m->s; MECmpContext mecc; me_cmp_func me_cmp[6]; int ret; @@ -316,10 +344,10 @@ static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) ret = ff_me_init(&s->me, avctx, &mecc, 1); if (ret < 0) return ret; - ret = ff_set_cmp(&mecc, me_cmp, s->frame_skip_cmp, 1); + ret = ff_set_cmp(&mecc, me_cmp, m->frame_skip_cmp, 1); if (ret < 0) return ret; - s->frame_skip_cmp_fn = me_cmp[1]; + m->frame_skip_cmp_fn = me_cmp[1]; if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { ret = ff_set_cmp(&mecc, me_cmp, avctx->ildct_cmp, 1); if (ret < 0) @@ -347,37 +375,218 @@ static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) return 0; } +#define ALLOCZ_ARRAYS(p, mult, numb) ((p) = av_calloc(numb, mult * sizeof(*(p)))) +static av_cold int init_matrices(MPVMainEncContext *const m, AVCodecContext *avctx) +{ + MPVEncContext *const s = &m->s; + const int nb_matrices = 1 + (s->c.out_format == FMT_MJPEG) + !m->intra_only; + const uint16_t *intra_matrix, *inter_matrix; + int ret; + + if (!ALLOCZ_ARRAYS(s->q_intra_matrix, 32, nb_matrices) || + !ALLOCZ_ARRAYS(s->q_intra_matrix16, 32, nb_matrices)) + return AVERROR(ENOMEM); + + if (s->c.out_format == FMT_MJPEG) { + s->q_chroma_intra_matrix = s->q_intra_matrix + 32; + s->q_chroma_intra_matrix16 = s->q_intra_matrix16 + 32; + // No need to set q_inter_matrix + av_assert1(m->intra_only); + // intra_matrix, chroma_intra_matrix will be set later for MJPEG. + return 0; + } else { + s->q_chroma_intra_matrix = s->q_intra_matrix; + s->q_chroma_intra_matrix16 = s->q_intra_matrix16; + } + if (!m->intra_only) { + s->q_inter_matrix = s->q_intra_matrix + 32; + s->q_inter_matrix16 = s->q_intra_matrix16 + 32; + } + + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4 && + s->mpeg_quant) { + intra_matrix = ff_mpeg4_default_intra_matrix; + inter_matrix = ff_mpeg4_default_non_intra_matrix; + } else if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { + intra_matrix = + inter_matrix = ff_mpeg1_default_non_intra_matrix; + } else { + /* MPEG-1/2, SpeedHQ */ + intra_matrix = ff_mpeg1_default_intra_matrix; + inter_matrix = ff_mpeg1_default_non_intra_matrix; + } + if (avctx->intra_matrix) + intra_matrix = avctx->intra_matrix; + if (avctx->inter_matrix) + inter_matrix = avctx->inter_matrix; + + /* init q matrix */ + for (int i = 0; i < 64; i++) { + int j = s->c.idsp.idct_permutation[i]; + + s->c.intra_matrix[j] = s->c.chroma_intra_matrix[j] = intra_matrix[i]; + s->c.inter_matrix[j] = inter_matrix[i]; + } + + /* precompute matrix */ + ret = ff_check_codec_matrices(avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_INTER, 1, 255); + if (ret < 0) + return ret; + + ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, + s->c.intra_matrix, s->intra_quant_bias, avctx->qmin, + 31, 1); + if (s->q_inter_matrix) + ff_convert_matrix(s, s->q_inter_matrix, s->q_inter_matrix16, + s->c.inter_matrix, s->inter_quant_bias, avctx->qmin, + 31, 0); + + return 0; +} + +static av_cold int init_buffers(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + int has_b_frames = !!m->max_b_frames; + int16_t (*mv_table)[2]; + + /* Allocate MB type table */ + unsigned mb_array_size = s->c.mb_stride * s->c.mb_height; + s->mb_type = av_calloc(mb_array_size, 3 * sizeof(*s->mb_type) + sizeof(*s->mb_mean)); + if (!s->mb_type) + return AVERROR(ENOMEM); + s->mc_mb_var = s->mb_type + mb_array_size; + s->mb_var = s->mc_mb_var + mb_array_size; + s->mb_mean = (uint8_t*)(s->mb_var + mb_array_size); + + if (!FF_ALLOCZ_TYPED_ARRAY(s->lambda_table, mb_array_size)) + return AVERROR(ENOMEM); + + unsigned mv_table_size = (s->c.mb_height + 2) * s->c.mb_stride + 1; + unsigned nb_mv_tables = 1 + 5 * has_b_frames; + if (s->c.codec_id == AV_CODEC_ID_MPEG4 || + (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { + nb_mv_tables += 8 * has_b_frames; + s->p_field_select_table[0] = av_calloc(mv_table_size, 2 * (2 + 4 * has_b_frames)); + if (!s->p_field_select_table[0]) + return AVERROR(ENOMEM); + s->p_field_select_table[1] = s->p_field_select_table[0] + 2 * mv_table_size; + } + + mv_table = av_calloc(mv_table_size, nb_mv_tables * sizeof(*mv_table)); + if (!mv_table) + return AVERROR(ENOMEM); + m->mv_table_base = mv_table; + mv_table += s->c.mb_stride + 1; + + s->p_mv_table = mv_table; + if (has_b_frames) { + s->b_forw_mv_table = mv_table += mv_table_size; + s->b_back_mv_table = mv_table += mv_table_size; + s->b_bidir_forw_mv_table = mv_table += mv_table_size; + s->b_bidir_back_mv_table = mv_table += mv_table_size; + s->b_direct_mv_table = mv_table += mv_table_size; + + if (s->p_field_select_table[1]) { // MPEG-4 or INTERLACED_ME above + uint8_t *field_select = s->p_field_select_table[1]; + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + for (int l = 0; l < 2; l++) + s->b_field_mv_table[j][k][l] = mv_table += mv_table_size; + s->b_field_select_table[j][k] = field_select += 2 * mv_table_size; + } + } + } + } + + return 0; +} + +static av_cold int init_slice_buffers(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + // Align the following per-thread buffers to avoid false sharing. + enum { +#ifndef _MSC_VER + /// The number is supposed to match/exceed the cache-line size. + ALIGN = FFMAX(128, _Alignof(max_align_t)), +#else + ALIGN = 128, +#endif + DCT_ERROR_SIZE = FFALIGN(2 * sizeof(*s->dct_error_sum), ALIGN), + }; + static_assert(DCT_ERROR_SIZE * MAX_THREADS + ALIGN - 1 <= SIZE_MAX, + "Need checks for potential overflow."); + unsigned nb_slices = s->c.slice_context_count; + char *dct_error = NULL; + + if (m->noise_reduction) { + if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2)) + return AVERROR(ENOMEM); + dct_error = av_mallocz(ALIGN - 1 + nb_slices * DCT_ERROR_SIZE); + if (!dct_error) + return AVERROR(ENOMEM); + m->dct_error_sum_base = dct_error; + dct_error += FFALIGN((uintptr_t)dct_error, ALIGN) - (uintptr_t)dct_error; + } + + const int y_size = s->c.b8_stride * (2 * s->c.mb_height + 1); + const int c_size = s->c.mb_stride * (s->c.mb_height + 1); + const int yc_size = y_size + 2 * c_size; + ptrdiff_t offset = 0; + + for (unsigned i = 0; i < nb_slices; ++i) { + MPVEncContext *const s2 = s->c.enc_contexts[i]; + + s2->block = s2->blocks[0]; + + if (dct_error) { + s2->dct_offset = s->dct_offset; + s2->dct_error_sum = (void*)dct_error; + dct_error += DCT_ERROR_SIZE; + } + + if (s2->c.ac_val) { + s2->c.dc_val += offset + i; + s2->c.ac_val += offset; + offset += yc_size; + } + } + return 0; +} + /* init video encoder */ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; AVCPBProperties *cpb_props; - int i, ret; - int mb_array_size, mv_table_size; + int gcd, ret; - mpv_encode_defaults(s); + mpv_encode_defaults(m); switch (avctx->pix_fmt) { case AV_PIX_FMT_YUVJ444P: case AV_PIX_FMT_YUV444P: - s->chroma_format = CHROMA_444; + s->c.chroma_format = CHROMA_444; break; case AV_PIX_FMT_YUVJ422P: case AV_PIX_FMT_YUV422P: - s->chroma_format = CHROMA_422; + s->c.chroma_format = CHROMA_422; break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); case AV_PIX_FMT_YUVJ420P: case AV_PIX_FMT_YUV420P: - default: - s->chroma_format = CHROMA_420; + s->c.chroma_format = CHROMA_420; break; } avctx->bits_per_raw_sample = av_clip(avctx->bits_per_raw_sample, 0, 8); - s->bit_rate = avctx->bit_rate; - s->width = avctx->width; - s->height = avctx->height; + m->bit_rate = avctx->bit_rate; + s->c.width = avctx->width; + s->c.height = avctx->height; if (avctx->gop_size > 600 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { av_log(avctx, AV_LOG_WARNING, @@ -385,65 +594,65 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->gop_size, 600); avctx->gop_size = 600; } - s->gop_size = avctx->gop_size; - s->avctx = avctx; - if (avctx->max_b_frames > MAX_B_FRAMES) { + m->gop_size = avctx->gop_size; + s->c.avctx = avctx; + if (avctx->max_b_frames > MPVENC_MAX_B_FRAMES) { av_log(avctx, AV_LOG_ERROR, "Too many B-frames requested, maximum " - "is %d.\n", MAX_B_FRAMES); - avctx->max_b_frames = MAX_B_FRAMES; + "is " AV_STRINGIFY(MPVENC_MAX_B_FRAMES) ".\n"); + avctx->max_b_frames = MPVENC_MAX_B_FRAMES; } else if (avctx->max_b_frames < 0) { av_log(avctx, AV_LOG_ERROR, "max b frames must be 0 or positive for mpegvideo based encoders\n"); return AVERROR(EINVAL); } - s->max_b_frames = avctx->max_b_frames; - s->codec_id = avctx->codec->id; - if (s->max_b_frames && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) { + m->max_b_frames = avctx->max_b_frames; + s->c.codec_id = avctx->codec->id; + if (m->max_b_frames && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) { av_log(avctx, AV_LOG_ERROR, "B-frames not supported by codec\n"); return AVERROR(EINVAL); } - s->quarter_sample = (avctx->flags & AV_CODEC_FLAG_QPEL) != 0; + s->c.quarter_sample = (avctx->flags & AV_CODEC_FLAG_QPEL) != 0; s->rtp_mode = !!s->rtp_payload_size; - s->intra_dc_precision = avctx->intra_dc_precision; + s->c.intra_dc_precision = avctx->intra_dc_precision; // workaround some differences between how applications specify dc precision - if (s->intra_dc_precision < 0) { - s->intra_dc_precision += 8; - } else if (s->intra_dc_precision >= 8) - s->intra_dc_precision -= 8; + if (s->c.intra_dc_precision < 0) { + s->c.intra_dc_precision += 8; + } else if (s->c.intra_dc_precision >= 8) + s->c.intra_dc_precision -= 8; - if (s->intra_dc_precision < 0) { + if (s->c.intra_dc_precision < 0) { av_log(avctx, AV_LOG_ERROR, "intra dc precision must be positive, note some applications use" " 0 and some 8 as base meaning 8bit, the value must not be smaller than that\n"); return AVERROR(EINVAL); } - if (s->intra_dc_precision > (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 3 : 0)) { + if (s->c.intra_dc_precision > (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 3 : 0)) { av_log(avctx, AV_LOG_ERROR, "intra dc precision too large\n"); return AVERROR(EINVAL); } - s->user_specified_pts = AV_NOPTS_VALUE; + m->user_specified_pts = AV_NOPTS_VALUE; - if (s->gop_size <= 1) { - s->intra_only = 1; - s->gop_size = 12; + if (m->gop_size <= 1) { + m->intra_only = 1; + m->gop_size = 12; } else { - s->intra_only = 0; + m->intra_only = 0; } /* Fixed QSCALE */ - s->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); + m->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); s->adaptive_quant = (avctx->lumi_masking || avctx->dark_masking || avctx->temporal_cplx_masking || avctx->spatial_cplx_masking || avctx->p_masking || - s->border_masking || + m->border_masking || (s->mpv_flags & FF_MPV_FLAG_QP_RD)) && - !s->fixed_qscale; + !m->fixed_qscale; s->loop_filter = !!(avctx->flags & AV_CODEC_FLAG_LOOP_FILTER); @@ -507,7 +716,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (!s->fixed_qscale && + if (!m->fixed_qscale && avctx->bit_rate * av_q2d(avctx->time_base) > avctx->bit_rate_tolerance) { double nbt = avctx->bit_rate * av_q2d(avctx->time_base) * 5; @@ -519,38 +728,27 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->bit_rate_tolerance = INT_MAX; } - if (avctx->rc_max_rate && - avctx->rc_min_rate == avctx->rc_max_rate && - (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || - s->codec_id == AV_CODEC_ID_MPEG2VIDEO) && - 90000LL * (avctx->rc_buffer_size - 1) > - avctx->rc_max_rate * 0xFFFFLL) { - av_log(avctx, AV_LOG_INFO, - "Warning vbv_delay will be set to 0xFFFF (=VBR) as the " - "specified vbv buffer is too large for the given bitrate!\n"); - } - - if ((avctx->flags & AV_CODEC_FLAG_4MV) && s->codec_id != AV_CODEC_ID_MPEG4 && - s->codec_id != AV_CODEC_ID_H263 && s->codec_id != AV_CODEC_ID_H263P && - s->codec_id != AV_CODEC_ID_FLV1) { + if ((avctx->flags & AV_CODEC_FLAG_4MV) && s->c.codec_id != AV_CODEC_ID_MPEG4 && + s->c.codec_id != AV_CODEC_ID_H263 && s->c.codec_id != AV_CODEC_ID_H263P && + s->c.codec_id != AV_CODEC_ID_FLV1) { av_log(avctx, AV_LOG_ERROR, "4MV not supported by codec\n"); return AVERROR(EINVAL); } - if (s->obmc && avctx->mb_decision != FF_MB_DECISION_SIMPLE) { + if (s->c.obmc && avctx->mb_decision != FF_MB_DECISION_SIMPLE) { av_log(avctx, AV_LOG_ERROR, "OBMC is only supported with simple mb decision\n"); return AVERROR(EINVAL); } - if (s->quarter_sample && s->codec_id != AV_CODEC_ID_MPEG4) { + if (s->c.quarter_sample && s->c.codec_id != AV_CODEC_ID_MPEG4) { av_log(avctx, AV_LOG_ERROR, "qpel not supported by codec\n"); return AVERROR(EINVAL); } - if ((s->codec_id == AV_CODEC_ID_MPEG4 || - s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P) && + if ((s->c.codec_id == AV_CODEC_ID_MPEG4 || + s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P) && (avctx->sample_aspect_ratio.num > 255 || avctx->sample_aspect_ratio.den > 255)) { av_log(avctx, AV_LOG_WARNING, @@ -560,38 +758,44 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 255); } - if ((s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P) && + if ((s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P) && (avctx->width > 2048 || avctx->height > 1152 )) { av_log(avctx, AV_LOG_ERROR, "H.263 does not support resolutions above 2048x1152\n"); return AVERROR(EINVAL); } - if ((s->codec_id == AV_CODEC_ID_H263 || - s->codec_id == AV_CODEC_ID_H263P || - s->codec_id == AV_CODEC_ID_RV20) && + if (s->c.codec_id == AV_CODEC_ID_FLV1 && + (avctx->width > 65535 || + avctx->height > 65535 )) { + av_log(avctx, AV_LOG_ERROR, "FLV does not support resolutions above 16bit\n"); + return AVERROR(EINVAL); + } + if ((s->c.codec_id == AV_CODEC_ID_H263 || + s->c.codec_id == AV_CODEC_ID_H263P || + s->c.codec_id == AV_CODEC_ID_RV20) && ((avctx->width &3) || (avctx->height&3) )) { av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 4\n"); return AVERROR(EINVAL); } - if (s->codec_id == AV_CODEC_ID_RV10 && + if (s->c.codec_id == AV_CODEC_ID_RV10 && (avctx->width &15 || avctx->height&15 )) { av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 16\n"); return AVERROR(EINVAL); } - if ((s->codec_id == AV_CODEC_ID_WMV1 || - s->codec_id == AV_CODEC_ID_WMV2) && + if ((s->c.codec_id == AV_CODEC_ID_WMV1 || + s->c.codec_id == AV_CODEC_ID_WMV2) && avctx->width & 1) { av_log(avctx, AV_LOG_ERROR, "width must be multiple of 2\n"); return AVERROR(EINVAL); } if ((avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME)) && - s->codec_id != AV_CODEC_ID_MPEG4 && s->codec_id != AV_CODEC_ID_MPEG2VIDEO) { + s->c.codec_id != AV_CODEC_ID_MPEG4 && s->c.codec_id != AV_CODEC_ID_MPEG2VIDEO) { av_log(avctx, AV_LOG_ERROR, "interlacing not supported by codec\n"); return AVERROR(EINVAL); } @@ -607,7 +811,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (s->scenechange_threshold < 1000000000 && + if (m->scenechange_threshold < 1000000000 && (avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)) { av_log(avctx, AV_LOG_ERROR, "closed gop with scene change detection are not supported yet, " @@ -616,49 +820,41 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) } if (avctx->flags & AV_CODEC_FLAG_LOW_DELAY) { - if (s->codec_id != AV_CODEC_ID_MPEG2VIDEO && + if (s->c.codec_id != AV_CODEC_ID_MPEG2VIDEO && avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) { av_log(avctx, AV_LOG_ERROR, "low delay forcing is only available for mpeg2, " "set strict_std_compliance to 'unofficial' or lower in order to allow it\n"); return AVERROR(EINVAL); } - if (s->max_b_frames != 0) { + if (m->max_b_frames != 0) { av_log(avctx, AV_LOG_ERROR, "B-frames cannot be used with low delay\n"); return AVERROR(EINVAL); } } - if (s->q_scale_type == 1) { - if (avctx->qmax > 28) { - av_log(avctx, AV_LOG_ERROR, - "non linear quant only supports qmax <= 28 currently\n"); - return AVERROR_PATCHWELCOME; - } - } - if (avctx->slices > 1 && !(avctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)) { av_log(avctx, AV_LOG_ERROR, "Multiple slices are not supported by this codec\n"); return AVERROR(EINVAL); } - if (s->b_frame_strategy && (avctx->flags & AV_CODEC_FLAG_PASS2)) { + if (m->b_frame_strategy && (avctx->flags & AV_CODEC_FLAG_PASS2)) { av_log(avctx, AV_LOG_INFO, "notice: b_frame_strategy only affects the first pass\n"); - s->b_frame_strategy = 0; + m->b_frame_strategy = 0; } - i = av_gcd(avctx->time_base.den, avctx->time_base.num); - if (i > 1) { + gcd = av_gcd(avctx->time_base.den, avctx->time_base.num); + if (gcd > 1) { av_log(avctx, AV_LOG_INFO, "removing common factors from framerate\n"); - avctx->time_base.den /= i; - avctx->time_base.num /= i; + avctx->time_base.den /= gcd; + avctx->time_base.num /= gcd; //return -1; } - if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id == AV_CODEC_ID_AMV || s->codec_id == AV_CODEC_ID_SPEEDHQ) { + if (s->mpeg_quant || s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO || s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO || s->c.codec_id == AV_CODEC_ID_MJPEG || s->c.codec_id == AV_CODEC_ID_AMV || s->c.codec_id == AV_CODEC_ID_SPEEDHQ) { // (a + x * 3 / 8) / x s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3); s->inter_quant_bias = 0; @@ -675,340 +871,238 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) 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 && - avctx->time_base.den > (1 << 16) - 1) { - av_log(avctx, AV_LOG_ERROR, - "timebase %d/%d not supported by MPEG 4 standard, " - "the maximum admitted value for the timebase denominator " - "is %d\n", avctx->time_base.num, avctx->time_base.den, - (1 << 16) - 1); - return AVERROR(EINVAL); - } - s->time_increment_bits = av_log2(avctx->time_base.den - 1) + 1; - switch (avctx->codec->id) { #if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER case AV_CODEC_ID_MPEG2VIDEO: s->rtp_mode = 1; /* fallthrough */ case AV_CODEC_ID_MPEG1VIDEO: - s->out_format = FMT_MPEG1; - s->low_delay = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY); - avctx->delay = s->low_delay ? 0 : (s->max_b_frames + 1); + s->c.out_format = FMT_MPEG1; + s->c.low_delay = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY); + avctx->delay = s->c.low_delay ? 0 : (m->max_b_frames + 1); ff_mpeg1_encode_init(s); break; #endif #if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER case AV_CODEC_ID_MJPEG: case AV_CODEC_ID_AMV: - s->out_format = FMT_MJPEG; - s->intra_only = 1; /* force intra only for jpeg */ - if ((ret = ff_mjpeg_encode_init(s)) < 0) - return ret; + s->c.out_format = FMT_MJPEG; + m->intra_only = 1; /* force intra only for jpeg */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; #endif case AV_CODEC_ID_SPEEDHQ: - s->out_format = FMT_SPEEDHQ; - s->intra_only = 1; /* force intra only for SHQ */ - if (!CONFIG_SPEEDHQ_ENCODER) - return AVERROR_ENCODER_NOT_FOUND; - if ((ret = ff_speedhq_encode_init(s)) < 0) - return ret; + s->c.out_format = FMT_SPEEDHQ; + m->intra_only = 1; /* force intra only for SHQ */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_H261: - if (!CONFIG_H261_ENCODER) - return AVERROR_ENCODER_NOT_FOUND; - ret = ff_h261_encode_init(s); - if (ret < 0) - return ret; - s->out_format = FMT_H261; + s->c.out_format = FMT_H261; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; s->rtp_mode = 0; /* Sliced encoding not supported */ break; case AV_CODEC_ID_H263: if (!CONFIG_H263_ENCODER) return AVERROR_ENCODER_NOT_FOUND; if (ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format), - s->width, s->height) == 8) { + s->c.width, s->c.height) == 8) { av_log(avctx, AV_LOG_ERROR, "The specified picture size of %dx%d is not valid for " "the H.263 codec.\nValid sizes are 128x96, 176x144, " "352x288, 704x576, and 1408x1152. " - "Try H.263+.\n", s->width, s->height); + "Try H.263+.\n", s->c.width, s->c.height); return AVERROR(EINVAL); } - s->out_format = FMT_H263; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_H263P: - s->out_format = FMT_H263; - s->h263_plus = 1; + s->c.out_format = FMT_H263; /* Fx */ - s->h263_aic = (avctx->flags & AV_CODEC_FLAG_AC_PRED) ? 1 : 0; - s->modified_quant = s->h263_aic; - s->loop_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; - s->unrestricted_mv = s->obmc || s->loop_filter || s->umvplus; + s->c.h263_aic = (avctx->flags & AV_CODEC_FLAG_AC_PRED) ? 1 : 0; + s->modified_quant = s->c.h263_aic; + s->loop_filter = !!(avctx->flags & AV_CODEC_FLAG_LOOP_FILTER); + s->me.unrestricted_mv = s->c.obmc || s->loop_filter || s->umvplus; s->flipflop_rounding = 1; /* /Fx */ /* These are just to be sure */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_FLV1: - s->out_format = FMT_H263; - s->h263_flv = 2; /* format = 1; 11-bit codes */ - s->unrestricted_mv = 1; + s->c.out_format = FMT_H263; + s->me.unrestricted_mv = 1; s->rtp_mode = 0; /* don't allow GOB */ avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; +#if CONFIG_RV10_ENCODER case AV_CODEC_ID_RV10: - s->out_format = FMT_H263; + m->encode_picture_header = ff_rv10_encode_picture_header; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; +#endif +#if CONFIG_RV20_ENCODER case AV_CODEC_ID_RV20: - s->out_format = FMT_H263; + m->encode_picture_header = ff_rv20_encode_picture_header; + s->c.out_format = FMT_H263; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; s->modified_quant = 1; - s->h263_aic = 1; - s->h263_plus = 1; + // Set here to force allocation of dc_val; + // will be set later on a per-frame basis. + s->c.h263_aic = 1; s->loop_filter = 1; - s->unrestricted_mv = 0; + s->me.unrestricted_mv = 0; break; +#endif case AV_CODEC_ID_MPEG4: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; s->flipflop_rounding = 1; - s->low_delay = s->max_b_frames ? 0 : 1; - avctx->delay = s->low_delay ? 0 : (s->max_b_frames + 1); + s->c.low_delay = m->max_b_frames ? 0 : 1; + avctx->delay = s->c.low_delay ? 0 : (m->max_b_frames + 1); break; case AV_CODEC_ID_MSMPEG4V2: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_V2; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_V2; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_MSMPEG4V3: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_V3; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_V3; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_WMV1: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_WMV1; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_WMV1; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; case AV_CODEC_ID_WMV2: - s->out_format = FMT_H263; - s->h263_pred = 1; - s->unrestricted_mv = 1; - s->msmpeg4_version = MSMP4_WMV2; + s->c.out_format = FMT_H263; + s->c.h263_pred = 1; + s->me.unrestricted_mv = 1; + s->c.msmpeg4_version = MSMP4_WMV2; s->flipflop_rounding = 1; avctx->delay = 0; - s->low_delay = 1; + s->c.low_delay = 1; break; default: - return AVERROR(EINVAL); + av_unreachable("List contains all codecs using ff_mpv_encode_init()"); } - avctx->has_b_frames = !s->low_delay; + avctx->has_b_frames = !s->c.low_delay; - s->encoding = 1; + s->c.encoding = 1; - s->progressive_frame = - s->progressive_sequence = !(avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | - AV_CODEC_FLAG_INTERLACED_ME) || - s->alternate_scan); + s->c.progressive_frame = + s->c.progressive_sequence = !(avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | + AV_CODEC_FLAG_INTERLACED_ME) || + s->c.alternate_scan); - if (s->lmin > s->lmax) { - av_log(avctx, AV_LOG_WARNING, "Clipping lmin value to %d\n", s->lmax); - s->lmin = s->lmax; + if (avctx->flags & AV_CODEC_FLAG_PSNR || avctx->mb_decision == FF_MB_DECISION_RD || + m->frame_skip_threshold || m->frame_skip_factor) { + s->frame_reconstruction_bitfield = (1 << AV_PICTURE_TYPE_I) | + (1 << AV_PICTURE_TYPE_P) | + (1 << AV_PICTURE_TYPE_B); + } else if (!m->intra_only) { + s->frame_reconstruction_bitfield = (1 << AV_PICTURE_TYPE_I) | + (1 << AV_PICTURE_TYPE_P); + } else { + s->frame_reconstruction_bitfield = 0; } - /* init */ - ff_mpv_idct_init(s); - if ((ret = ff_mpv_common_init(s)) < 0) - return ret; + if (m->lmin > m->lmax) { + av_log(avctx, AV_LOG_WARNING, "Clipping lmin value to %d\n", m->lmax); + m->lmin = m->lmax; + } + /* ff_mpv_init_duplicate_contexts() will copy (memdup) the contents of the + * main slice to the slice contexts, so we initialize various fields of it + * before calling ff_mpv_init_duplicate_contexts(). */ + s->parent = m; + ff_mpv_idct_init(&s->c); + init_unquantize(s, avctx); ff_fdctdsp_init(&s->fdsp, avctx); ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx); - ff_pixblockdsp_init(&s->pdsp, avctx); - ret = me_cmp_init(s, avctx); + ff_pixblockdsp_init(&s->pdsp, 8); + ret = me_cmp_init(m, avctx); if (ret < 0) return ret; if (!(avctx->stats_out = av_mallocz(256)) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix16, 32) || - !FF_ALLOCZ_TYPED_ARRAY(s->input_picture, MAX_B_FRAMES + 1) || - !FF_ALLOCZ_TYPED_ARRAY(s->reordered_input_picture, MAX_B_FRAMES + 1) || !(s->new_pic = av_frame_alloc()) || - !(s->picture_pool = ff_mpv_alloc_pic_pool(0))) + !(s->c.picture_pool = ff_mpv_alloc_pic_pool(0))) return AVERROR(ENOMEM); - /* Allocate MV tables; the MV and MB tables will be copied - * to slice contexts by ff_update_duplicate_context(). */ - mv_table_size = (s->mb_height + 2) * s->mb_stride + 1; - if (!FF_ALLOCZ_TYPED_ARRAY(s->p_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_forw_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_back_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_forw_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_back_mv_table_base, mv_table_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->b_direct_mv_table_base, mv_table_size)) - return AVERROR(ENOMEM); - s->p_mv_table = s->p_mv_table_base + s->mb_stride + 1; - s->b_forw_mv_table = s->b_forw_mv_table_base + s->mb_stride + 1; - s->b_back_mv_table = s->b_back_mv_table_base + s->mb_stride + 1; - s->b_bidir_forw_mv_table = s->b_bidir_forw_mv_table_base + s->mb_stride + 1; - s->b_bidir_back_mv_table = s->b_bidir_back_mv_table_base + s->mb_stride + 1; - s->b_direct_mv_table = s->b_direct_mv_table_base + s->mb_stride + 1; - - /* Allocate MB type table */ - mb_array_size = s->mb_stride * s->mb_height; - if (!FF_ALLOCZ_TYPED_ARRAY(s->mb_type, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->lambda_table, mb_array_size) || - !FF_ALLOC_TYPED_ARRAY (s->cplx_tab, mb_array_size) || - !FF_ALLOC_TYPED_ARRAY (s->bits_tab, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->mc_mb_var, mb_array_size) || - !FF_ALLOCZ_TYPED_ARRAY(s->mb_var, mb_array_size) || - !(s->mb_mean = av_mallocz(mb_array_size))) - return AVERROR(ENOMEM); - -#define ALLOCZ_ARRAYS(p, mult, numb) ((p) = av_calloc(numb, mult * sizeof(*(p)))) - if (s->codec_id == AV_CODEC_ID_MPEG4 || - (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { - int16_t (*tmp1)[2]; - uint8_t *tmp2; - if (!(tmp1 = ALLOCZ_ARRAYS(s->b_field_mv_table_base, 8, mv_table_size)) || - !(tmp2 = ALLOCZ_ARRAYS(s->b_field_select_table[0][0], 2 * 4, mv_table_size)) || - !ALLOCZ_ARRAYS(s->p_field_select_table[0], 2 * 2, mv_table_size)) - return AVERROR(ENOMEM); - - s->p_field_select_table[1] = s->p_field_select_table[0] + 2 * mv_table_size; - tmp1 += s->mb_stride + 1; - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - s->b_field_mv_table[i][j][k] = tmp1; - tmp1 += mv_table_size; - } - s->b_field_select_table[i][j] = tmp2; - tmp2 += 2 * mv_table_size; - } - } - } - - if (s->noise_reduction) { - if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2)) - return AVERROR(ENOMEM); - } + ret = init_matrices(m, avctx); + if (ret < 0) + return ret; ff_dct_encode_init(s); - if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra; - s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter; - } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { - s->dct_unquantize_intra = s->dct_unquantize_h263_intra; - s->dct_unquantize_inter = s->dct_unquantize_h263_inter; - } else { - s->dct_unquantize_intra = s->dct_unquantize_mpeg1_intra; - s->dct_unquantize_inter = s->dct_unquantize_mpeg1_inter; - } - - if ((CONFIG_H263P_ENCODER || CONFIG_RV20_ENCODER) && s->modified_quant) - s->chroma_qscale_table = ff_h263_chroma_qscale_table; - - if (s->slice_context_count > 1) { - s->rtp_mode = 1; - - if (avctx->codec_id == AV_CODEC_ID_H263P) - s->h263_slice_structured = 1; - } - - if (CONFIG_H263_ENCODER && s->out_format == FMT_H263) { - ff_h263_encode_init(s); + if (CONFIG_H263_ENCODER && s->c.out_format == FMT_H263) { + ff_h263_encode_init(m); #if CONFIG_MSMPEG4ENC - if (s->msmpeg4_version != MSMP4_UNUSED) - ff_msmpeg4_encode_init(s); + if (s->c.msmpeg4_version != MSMP4_UNUSED) + ff_msmpeg4_encode_init(m); #endif } - /* init q matrix */ - for (i = 0; i < 64; i++) { - int j = s->idsp.idct_permutation[i]; - if (CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4 && - s->mpeg_quant) { - s->intra_matrix[j] = ff_mpeg4_default_intra_matrix[i]; - s->inter_matrix[j] = ff_mpeg4_default_non_intra_matrix[i]; - } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { - s->intra_matrix[j] = - s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; - } else if (CONFIG_SPEEDHQ_ENCODER && s->codec_id == AV_CODEC_ID_SPEEDHQ) { - s->intra_matrix[j] = - s->inter_matrix[j] = ff_mpeg1_default_intra_matrix[i]; - } else { - /* MPEG-1/2 */ - s->chroma_intra_matrix[j] = - s->intra_matrix[j] = ff_mpeg1_default_intra_matrix[i]; - s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; - } - if (avctx->intra_matrix) - s->intra_matrix[j] = avctx->intra_matrix[i]; - if (avctx->inter_matrix) - s->inter_matrix[j] = avctx->inter_matrix[i]; + s->c.slice_ctx_size = sizeof(*s); + ret = ff_mpv_common_init(&s->c); + if (ret < 0) + return ret; + ret = init_buffers(m); + if (ret < 0) + return ret; + if (s->c.slice_context_count > 1) { + s->rtp_mode = 1; + if (avctx->codec_id == AV_CODEC_ID_H263P) + s->h263_slice_structured = 1; } - - /* precompute matrix */ - /* for mjpeg, we do include qscale in the matrix */ - if (s->out_format != FMT_MJPEG) { - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, avctx->qmin, - 31, 1); - ff_convert_matrix(s, s->q_inter_matrix, s->q_inter_matrix16, - s->inter_matrix, s->inter_quant_bias, avctx->qmin, - 31, 0); - } - - if ((ret = ff_rate_control_init(s)) < 0) + ret = ff_mpv_init_duplicate_contexts(&s->c); + if (ret < 0) return ret; - if (s->b_frame_strategy == 2) { - for (i = 0; i < s->max_b_frames + 2; i++) { - s->tmp_frames[i] = av_frame_alloc(); - if (!s->tmp_frames[i]) + ret = init_slice_buffers(m); + if (ret < 0) + return ret; + + ret = ff_rate_control_init(m); + if (ret < 0) + return ret; + + if (m->b_frame_strategy == 2) { + for (int i = 0; i < m->max_b_frames + 2; i++) { + m->tmp_frames[i] = av_frame_alloc(); + if (!m->tmp_frames[i]) return AVERROR(ENOMEM); - s->tmp_frames[i]->format = AV_PIX_FMT_YUV420P; - s->tmp_frames[i]->width = s->width >> s->brd_scale; - s->tmp_frames[i]->height = s->height >> s->brd_scale; + m->tmp_frames[i]->format = AV_PIX_FMT_YUV420P; + m->tmp_frames[i]->width = s->c.width >> m->brd_scale; + m->tmp_frames[i]->height = s->c.height >> m->brd_scale; - ret = av_frame_get_buffer(s->tmp_frames[i], 0); + ret = av_frame_get_buffer(m->tmp_frames[i], 0); if (ret < 0) return ret; } @@ -1027,79 +1121,126 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) av_cold int ff_mpv_encode_end(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; - int i; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; - ff_rate_control_uninit(&s->rc_context); + ff_rate_control_uninit(&m->rc_context); - ff_mpv_common_end(s); - ff_refstruct_pool_uninit(&s->picture_pool); + ff_mpv_common_end(&s->c); + av_refstruct_pool_uninit(&s->c.picture_pool); - if (s->input_picture && s->reordered_input_picture) { - for (int i = 0; i < MAX_B_FRAMES + 1; i++) { - ff_refstruct_unref(&s->input_picture[i]); - ff_refstruct_unref(&s->reordered_input_picture[i]); - } + for (int i = 0; i < MPVENC_MAX_B_FRAMES + 1; i++) { + av_refstruct_unref(&m->input_picture[i]); + av_refstruct_unref(&m->reordered_input_picture[i]); } - for (i = 0; i < FF_ARRAY_ELEMS(s->tmp_frames); i++) - av_frame_free(&s->tmp_frames[i]); + for (int i = 0; i < FF_ARRAY_ELEMS(m->tmp_frames); i++) + av_frame_free(&m->tmp_frames[i]); av_frame_free(&s->new_pic); av_freep(&avctx->stats_out); - av_freep(&s->p_mv_table_base); - av_freep(&s->b_forw_mv_table_base); - av_freep(&s->b_back_mv_table_base); - av_freep(&s->b_bidir_forw_mv_table_base); - av_freep(&s->b_bidir_back_mv_table_base); - av_freep(&s->b_direct_mv_table_base); - av_freep(&s->b_field_mv_table_base); - av_freep(&s->b_field_select_table[0][0]); + av_freep(&m->mv_table_base); av_freep(&s->p_field_select_table[0]); + av_freep(&m->dct_error_sum_base); av_freep(&s->mb_type); av_freep(&s->lambda_table); - av_freep(&s->cplx_tab); - av_freep(&s->bits_tab); - - if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix); - if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16); - s->q_chroma_intra_matrix= NULL; - s->q_chroma_intra_matrix16= NULL; av_freep(&s->q_intra_matrix); - av_freep(&s->q_inter_matrix); av_freep(&s->q_intra_matrix16); - av_freep(&s->q_inter_matrix16); - av_freep(&s->input_picture); - av_freep(&s->reordered_input_picture); av_freep(&s->dct_offset); - av_freep(&s->mb_var); - av_freep(&s->mc_mb_var); - av_freep(&s->mb_mean); return 0; } -#define IS_ENCODER 1 -#include "mpv_reconstruct_mb_template.c" - -static void mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) +/* put block[] to dest[] */ +static inline void put_dct(MPVEncContext *const s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) { - if (s->avctx->debug & FF_DEBUG_DCT_COEFF) { + s->c.dct_unquantize_intra(&s->c, block, i, qscale); + s->c.idsp.idct_put(dest, line_size, block); +} + +static inline void add_dequant_dct(MPVEncContext *const s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) +{ + if (s->c.block_last_index[i] >= 0) { + s->c.dct_unquantize_inter(&s->c, block, i, qscale); + + s->c.idsp.idct_add(dest, line_size, block); + } +} + +/** + * Performs dequantization and IDCT (if necessary) + */ +static void mpv_reconstruct_mb(MPVEncContext *const s, int16_t block[12][64]) +{ + if (s->c.avctx->debug & FF_DEBUG_DCT_COEFF) { /* print DCT coefficients */ - av_log(s->avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); + av_log(s->c.avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->c.mb_x, s->c.mb_y); for (int i = 0; i < 6; i++) { for (int j = 0; j < 64; j++) { - av_log(s->avctx, AV_LOG_DEBUG, "%5d", - block[i][s->idsp.idct_permutation[j]]); + av_log(s->c.avctx, AV_LOG_DEBUG, "%5d", + block[i][s->c.idsp.idct_permutation[j]]); } - av_log(s->avctx, AV_LOG_DEBUG, "\n"); + av_log(s->c.avctx, AV_LOG_DEBUG, "\n"); } } - mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12_H261); + if ((1 << s->c.pict_type) & s->frame_reconstruction_bitfield) { + uint8_t *dest_y = s->c.dest[0], *dest_cb = s->c.dest[1], *dest_cr = s->c.dest[2]; + int dct_linesize, dct_offset; + const int linesize = s->c.cur_pic.linesize[0]; + const int uvlinesize = s->c.cur_pic.linesize[1]; + const int block_size = 8; + + dct_linesize = linesize << s->c.interlaced_dct; + dct_offset = s->c.interlaced_dct ? linesize : linesize * block_size; + + if (!s->c.mb_intra) { + /* No MC, as that was already done otherwise */ + add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->c.qscale); + add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->c.qscale); + add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->c.qscale); + add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->c.qscale); + + if (!CONFIG_GRAY || !(s->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->c.chroma_y_shift) { + add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->c.chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->c.chroma_qscale); + } else { + dct_linesize >>= 1; + dct_offset >>= 1; + add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->c.chroma_qscale); + add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->c.chroma_qscale); + } + } + } else { + /* dct only in intra block */ + put_dct(s, block[0], 0, dest_y , dct_linesize, s->c.qscale); + put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->c.qscale); + put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->c.qscale); + put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->c.qscale); + + if (!CONFIG_GRAY || !(s->c.avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->c.chroma_y_shift) { + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->c.chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->c.chroma_qscale); + } else { + dct_offset >>= 1; + dct_linesize >>= 1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->c.chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->c.chroma_qscale); + } + } + } + } } static int get_sae(const uint8_t *src, int ref, int stride) @@ -1116,14 +1257,14 @@ static int get_sae(const uint8_t *src, int ref, int stride) return acc; } -static int get_intra_count(MpegEncContext *s, const uint8_t *src, +static int get_intra_count(MPVEncContext *const s, const uint8_t *src, const uint8_t *ref, int stride) { int x, y, w, h; int acc = 0; - w = s->width & ~15; - h = s->height & ~15; + w = s->c.width & ~15; + h = s->c.height & ~15; for (y = 0; y < h; y += 16) { for (x = 0; x < w; x += 16) { @@ -1143,9 +1284,9 @@ static int get_intra_count(MpegEncContext *s, const uint8_t *src, * Allocates new buffers for an AVFrame and copies the properties * from another AVFrame. */ -static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_frame) +static int prepare_picture(MPVEncContext *const s, AVFrame *f, const AVFrame *props_frame) { - AVCodecContext *avctx = s->avctx; + AVCodecContext *avctx = s->c.avctx; int ret; f->width = avctx->width + 2 * EDGE_WIDTH; @@ -1155,14 +1296,14 @@ static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_f if (ret < 0) return ret; - ret = ff_mpv_pic_check_linesize(avctx, f, &s->linesize, &s->uvlinesize); + ret = ff_mpv_pic_check_linesize(avctx, f, &s->c.linesize, &s->c.uvlinesize); if (ret < 0) return ret; for (int i = 0; f->data[i]; i++) { - int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) * + int offset = (EDGE_WIDTH >> (i ? s->c.chroma_y_shift : 0)) * f->linesize[i] + - (EDGE_WIDTH >> (i ? s->chroma_x_shift : 0)); + (EDGE_WIDTH >> (i ? s->c.chroma_x_shift : 0)); f->data[i] += offset; } f->width = avctx->width; @@ -1175,42 +1316,43 @@ static int prepare_picture(MpegEncContext *s, AVFrame *f, const AVFrame *props_f return 0; } -static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) +static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg) { + MPVEncContext *const s = &m->s; MPVPicture *pic = NULL; int64_t pts; int display_picture_number = 0, ret; - int encoding_delay = s->max_b_frames ? s->max_b_frames - : (s->low_delay ? 0 : 1); + int encoding_delay = m->max_b_frames ? m->max_b_frames + : (s->c.low_delay ? 0 : 1); int flush_offset = 1; int direct = 1; - av_assert1(!s->input_picture[0]); + av_assert1(!m->input_picture[0]); if (pic_arg) { pts = pic_arg->pts; - display_picture_number = s->input_picture_number++; + display_picture_number = m->input_picture_number++; if (pts != AV_NOPTS_VALUE) { - if (s->user_specified_pts != AV_NOPTS_VALUE) { - int64_t last = s->user_specified_pts; + if (m->user_specified_pts != AV_NOPTS_VALUE) { + int64_t last = m->user_specified_pts; if (pts <= last) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(s->c.avctx, AV_LOG_ERROR, "Invalid pts (%"PRId64") <= last (%"PRId64")\n", pts, last); return AVERROR(EINVAL); } - if (!s->low_delay && display_picture_number == 1) - s->dts_delta = pts - last; + if (!s->c.low_delay && display_picture_number == 1) + m->dts_delta = pts - last; } - s->user_specified_pts = pts; + m->user_specified_pts = pts; } else { - if (s->user_specified_pts != AV_NOPTS_VALUE) { - s->user_specified_pts = - pts = s->user_specified_pts + 1; - av_log(s->avctx, AV_LOG_INFO, + if (m->user_specified_pts != AV_NOPTS_VALUE) { + m->user_specified_pts = + pts = m->user_specified_pts + 1; + av_log(s->c.avctx, AV_LOG_INFO, "Warning: AVFrame.pts=? trying to guess (%"PRId64")\n", pts); } else { @@ -1218,21 +1360,21 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) } } - if (pic_arg->linesize[0] != s->linesize || - pic_arg->linesize[1] != s->uvlinesize || - pic_arg->linesize[2] != s->uvlinesize) + if (pic_arg->linesize[0] != s->c.linesize || + pic_arg->linesize[1] != s->c.uvlinesize || + pic_arg->linesize[2] != s->c.uvlinesize) direct = 0; - if ((s->width & 15) || (s->height & 15)) + if ((s->c.width & 15) || (s->c.height & 15)) direct = 0; if (((intptr_t)(pic_arg->data[0])) & (STRIDE_ALIGN-1)) direct = 0; - if (s->linesize & (STRIDE_ALIGN-1)) + if (s->c.linesize & (STRIDE_ALIGN-1)) direct = 0; - ff_dlog(s->avctx, "%d %d %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"\n", pic_arg->linesize[0], - pic_arg->linesize[1], s->linesize, s->uvlinesize); + ff_dlog(s->c.avctx, "%d %d %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"\n", pic_arg->linesize[0], + pic_arg->linesize[1], s->c.linesize, s->c.uvlinesize); - pic = ff_refstruct_pool_get(s->picture_pool); + pic = av_refstruct_pool_get(s->c.picture_pool); if (!pic) return AVERROR(ENOMEM); @@ -1247,21 +1389,21 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) for (int i = 0; i < 3; i++) { ptrdiff_t src_stride = pic_arg->linesize[i]; - ptrdiff_t dst_stride = i ? s->uvlinesize : s->linesize; - int h_shift = i ? s->chroma_x_shift : 0; - int v_shift = i ? s->chroma_y_shift : 0; - int w = AV_CEIL_RSHIFT(s->width , h_shift); - int h = AV_CEIL_RSHIFT(s->height, v_shift); + ptrdiff_t dst_stride = i ? s->c.uvlinesize : s->c.linesize; + int h_shift = i ? s->c.chroma_x_shift : 0; + int v_shift = i ? s->c.chroma_y_shift : 0; + int w = AV_CEIL_RSHIFT(s->c.width , h_shift); + int h = AV_CEIL_RSHIFT(s->c.height, v_shift); const uint8_t *src = pic_arg->data[i]; uint8_t *dst = pic->f->data[i]; int vpad = 16; - if ( s->codec_id == AV_CODEC_ID_MPEG2VIDEO - && !s->progressive_sequence - && FFALIGN(s->height, 32) - s->height > 16) + if ( s->c.codec_id == AV_CODEC_ID_MPEG2VIDEO + && !s->c.progressive_sequence + && FFALIGN(s->c.height, 32) - s->c.height > 16) vpad = 32; - if (!s->avctx->rc_buffer_size) + if (!s->c.avctx->rc_buffer_size) dst += INPLACE_OFFSET; if (src_stride == dst_stride) @@ -1275,7 +1417,7 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) src += src_stride; } } - if ((s->width & 15) || (s->height & (vpad-1))) { + if ((s->c.width & 15) || (s->c.height & (vpad-1))) { s->mpvencdsp.draw_edges(dst, dst_stride, w, h, 16 >> h_shift, @@ -1288,50 +1430,51 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) pic->display_picture_number = display_picture_number; pic->f->pts = pts; // we set this here to avoid modifying pic_arg - } else if (!s->reordered_input_picture[1]) { + } else if (!m->reordered_input_picture[1]) { /* Flushing: When the above check is true, the encoder is about to run * out of frames to encode. Check if there are input_pictures left; - * if so, ensure s->input_picture[0] contains the first picture. + * if so, ensure m->input_picture[0] contains the first picture. * A flush_offset != 1 will only happen if we did not receive enough * input frames. */ for (flush_offset = 0; flush_offset < encoding_delay + 1; flush_offset++) - if (s->input_picture[flush_offset]) + if (m->input_picture[flush_offset]) break; encoding_delay -= flush_offset - 1; } /* shift buffer entries */ - for (int i = flush_offset; i <= MAX_B_FRAMES; i++) - s->input_picture[i - flush_offset] = s->input_picture[i]; - for (int i = MAX_B_FRAMES + 1 - flush_offset; i <= MAX_B_FRAMES; i++) - s->input_picture[i] = NULL; + for (int i = flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) + m->input_picture[i - flush_offset] = m->input_picture[i]; + for (int i = MPVENC_MAX_B_FRAMES + 1 - flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) + m->input_picture[i] = NULL; - s->input_picture[encoding_delay] = pic; + m->input_picture[encoding_delay] = pic; return 0; fail: - ff_refstruct_unref(&pic); + av_refstruct_unref(&pic); return ret; } -static int skip_check(MpegEncContext *s, const MPVPicture *p, const MPVPicture *ref) +static int skip_check(MPVMainEncContext *const m, + const MPVPicture *p, const MPVPicture *ref) { - int x, y, plane; + MPVEncContext *const s = &m->s; int score = 0; int64_t score64 = 0; - for (plane = 0; plane < 3; plane++) { + for (int plane = 0; plane < 3; plane++) { const int stride = p->f->linesize[plane]; const int bw = plane ? 1 : 2; - for (y = 0; y < s->mb_height * bw; y++) { - for (x = 0; x < s->mb_width * bw; x++) { + for (int y = 0; y < s->c.mb_height * bw; y++) { + for (int x = 0; x < s->c.mb_width * bw; x++) { int off = p->shared ? 0 : 16; const uint8_t *dptr = p->f->data[plane] + 8 * (x + y * stride) + off; const uint8_t *rptr = ref->f->data[plane] + 8 * (x + y * stride); - int v = s->frame_skip_cmp_fn(s, dptr, rptr, stride, 8); + int v = m->frame_skip_cmp_fn(s, dptr, rptr, stride, 8); - switch (FFABS(s->frame_skip_exp)) { + switch (FFABS(m->frame_skip_exp)) { case 0: score = FFMAX(score, v); break; case 1: score += FFABS(v); break; case 2: score64 += v * (int64_t)v; break; @@ -1345,13 +1488,13 @@ static int skip_check(MpegEncContext *s, const MPVPicture *p, const MPVPicture * if (score) score64 = score; - if (s->frame_skip_exp < 0) - score64 = pow(score64 / (double)(s->mb_width * s->mb_height), - -1.0/s->frame_skip_exp); + if (m->frame_skip_exp < 0) + score64 = pow(score64 / (double)(s->c.mb_width * s->c.mb_height), + -1.0/m->frame_skip_exp); - if (score64 < s->frame_skip_threshold) + if (score64 < m->frame_skip_threshold) return 1; - if (score64 < ((s->frame_skip_factor * (int64_t) s->lambda) >> 8)) + if (score64 < ((m->frame_skip_factor * (int64_t) s->lambda) >> 8)) return 1; return 0; } @@ -1377,13 +1520,14 @@ static int encode_frame(AVCodecContext *c, const AVFrame *frame, AVPacket *pkt) return size; } -static int estimate_best_b_count(MpegEncContext *s) +static int estimate_best_b_count(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; AVPacket *pkt; - const int scale = s->brd_scale; - int width = s->width >> scale; - int height = s->height >> scale; - int i, j, out_size, p_lambda, b_lambda, lambda2; + const int scale = m->brd_scale; + int width = s->c.width >> scale; + int height = s->c.height >> scale; + int out_size, p_lambda, b_lambda, lambda2; int64_t best_rd = INT64_MAX; int best_b_count = -1; int ret = 0; @@ -1395,17 +1539,17 @@ static int estimate_best_b_count(MpegEncContext *s) return AVERROR(ENOMEM); //emms_c(); - p_lambda = s->last_lambda_for[AV_PICTURE_TYPE_P]; - //p_lambda * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset; - b_lambda = s->last_lambda_for[AV_PICTURE_TYPE_B]; + p_lambda = m->last_lambda_for[AV_PICTURE_TYPE_P]; + //p_lambda * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset; + b_lambda = m->last_lambda_for[AV_PICTURE_TYPE_B]; if (!b_lambda) // FIXME we should do this somewhere else b_lambda = p_lambda; lambda2 = (b_lambda * b_lambda + (1 << FF_LAMBDA_SHIFT) / 2) >> FF_LAMBDA_SHIFT; - for (i = 0; i < s->max_b_frames + 2; i++) { - const MPVPicture *pre_input_ptr = i ? s->input_picture[i - 1] : - s->next_pic.ptr; + for (int i = 0; i < m->max_b_frames + 2; i++) { + const MPVPicture *pre_input_ptr = i ? m->input_picture[i - 1] : + s->c.next_pic.ptr; if (pre_input_ptr) { const uint8_t *data[4]; @@ -1417,29 +1561,29 @@ static int estimate_best_b_count(MpegEncContext *s) data[2] += INPLACE_OFFSET; } - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[0], - s->tmp_frames[i]->linesize[0], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[0], + m->tmp_frames[i]->linesize[0], data[0], pre_input_ptr->f->linesize[0], width, height); - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[1], - s->tmp_frames[i]->linesize[1], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[1], + m->tmp_frames[i]->linesize[1], data[1], pre_input_ptr->f->linesize[1], width >> 1, height >> 1); - s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[2], - s->tmp_frames[i]->linesize[2], + s->mpvencdsp.shrink[scale](m->tmp_frames[i]->data[2], + m->tmp_frames[i]->linesize[2], data[2], pre_input_ptr->f->linesize[2], width >> 1, height >> 1); } } - for (j = 0; j < s->max_b_frames + 1; j++) { + for (int j = 0; j < m->max_b_frames + 1; j++) { AVCodecContext *c; int64_t rd = 0; - if (!s->input_picture[j]) + if (!m->input_picture[j]) break; c = avcodec_alloc_context3(NULL); @@ -1451,24 +1595,24 @@ static int estimate_best_b_count(MpegEncContext *s) c->width = width; c->height = height; c->flags = AV_CODEC_FLAG_QSCALE | AV_CODEC_FLAG_PSNR; - c->flags |= s->avctx->flags & AV_CODEC_FLAG_QPEL; - c->mb_decision = s->avctx->mb_decision; - c->me_cmp = s->avctx->me_cmp; - c->mb_cmp = s->avctx->mb_cmp; - c->me_sub_cmp = s->avctx->me_sub_cmp; + c->flags |= s->c.avctx->flags & AV_CODEC_FLAG_QPEL; + c->mb_decision = s->c.avctx->mb_decision; + c->me_cmp = s->c.avctx->me_cmp; + c->mb_cmp = s->c.avctx->mb_cmp; + c->me_sub_cmp = s->c.avctx->me_sub_cmp; c->pix_fmt = AV_PIX_FMT_YUV420P; - c->time_base = s->avctx->time_base; - c->max_b_frames = s->max_b_frames; + c->time_base = s->c.avctx->time_base; + c->max_b_frames = m->max_b_frames; - ret = avcodec_open2(c, s->avctx->codec, NULL); + ret = avcodec_open2(c, s->c.avctx->codec, NULL); if (ret < 0) goto fail; - s->tmp_frames[0]->pict_type = AV_PICTURE_TYPE_I; - s->tmp_frames[0]->quality = 1 * FF_QP2LAMBDA; + m->tmp_frames[0]->pict_type = AV_PICTURE_TYPE_I; + m->tmp_frames[0]->quality = 1 * FF_QP2LAMBDA; - out_size = encode_frame(c, s->tmp_frames[0], pkt); + out_size = encode_frame(c, m->tmp_frames[0], pkt); if (out_size < 0) { ret = out_size; goto fail; @@ -1476,14 +1620,14 @@ static int estimate_best_b_count(MpegEncContext *s) //rd += (out_size * lambda2) >> FF_LAMBDA_SHIFT; - for (i = 0; i < s->max_b_frames + 1; i++) { - int is_p = i % (j + 1) == j || i == s->max_b_frames; + for (int i = 0; i < m->max_b_frames + 1; i++) { + int is_p = i % (j + 1) == j || i == m->max_b_frames; - s->tmp_frames[i + 1]->pict_type = is_p ? + m->tmp_frames[i + 1]->pict_type = is_p ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_B; - s->tmp_frames[i + 1]->quality = is_p ? p_lambda : b_lambda; + m->tmp_frames[i + 1]->quality = is_p ? p_lambda : b_lambda; - out_size = encode_frame(c, s->tmp_frames[i + 1], pkt); + out_size = encode_frame(c, m->tmp_frames[i + 1], pkt); if (out_size < 0) { ret = out_size; goto fail; @@ -1529,85 +1673,86 @@ fail: * input_picture[0] is always NULL when exiting this function, even on error; * reordered_input_picture[0] is always NULL when exiting this function on error. */ -static int set_bframe_chain_length(MpegEncContext *s) +static int set_bframe_chain_length(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; + /* Either nothing to do or can't do anything */ - if (s->reordered_input_picture[0] || !s->input_picture[0]) + if (m->reordered_input_picture[0] || !m->input_picture[0]) return 0; /* set next picture type & ordering */ - if (s->frame_skip_threshold || s->frame_skip_factor) { - if (s->picture_in_gop_number < s->gop_size && - s->next_pic.ptr && - skip_check(s, s->input_picture[0], s->next_pic.ptr)) { + if (m->frame_skip_threshold || m->frame_skip_factor) { + if (m->picture_in_gop_number < m->gop_size && + s->c.next_pic.ptr && + skip_check(m, m->input_picture[0], s->c.next_pic.ptr)) { // FIXME check that the gop check above is +-1 correct - ff_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); - ff_vbv_update(s, 0); + ff_vbv_update(m, 0); return 0; } } - if (/*s->picture_in_gop_number >= s->gop_size ||*/ - !s->next_pic.ptr || s->intra_only) { - s->reordered_input_picture[0] = s->input_picture[0]; - s->input_picture[0] = NULL; - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; - s->reordered_input_picture[0]->coded_picture_number = - s->coded_picture_number++; + if (/* m->picture_in_gop_number >= m->gop_size || */ + !s->c.next_pic.ptr || m->intra_only) { + m->reordered_input_picture[0] = m->input_picture[0]; + m->input_picture[0] = NULL; + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; + m->reordered_input_picture[0]->coded_picture_number = + m->coded_picture_number++; } else { int b_frames = 0; - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { - for (int i = 0; i < s->max_b_frames + 1; i++) { - int pict_num = s->input_picture[0]->display_picture_number + i; + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { + for (int i = 0; i < m->max_b_frames + 1; i++) { + int pict_num = m->input_picture[0]->display_picture_number + i; - if (pict_num >= s->rc_context.num_entries) + if (pict_num >= m->rc_context.num_entries) break; - if (!s->input_picture[i]) { - s->rc_context.entry[pict_num - 1].new_pict_type = AV_PICTURE_TYPE_P; + if (!m->input_picture[i]) { + m->rc_context.entry[pict_num - 1].new_pict_type = AV_PICTURE_TYPE_P; break; } - s->input_picture[i]->f->pict_type = - s->rc_context.entry[pict_num].new_pict_type; + m->input_picture[i]->f->pict_type = + m->rc_context.entry[pict_num].new_pict_type; } } - if (s->b_frame_strategy == 0) { - b_frames = s->max_b_frames; - while (b_frames && !s->input_picture[b_frames]) + if (m->b_frame_strategy == 0) { + b_frames = m->max_b_frames; + while (b_frames && !m->input_picture[b_frames]) b_frames--; - } else if (s->b_frame_strategy == 1) { - int i; - for (i = 1; i < s->max_b_frames + 1; i++) { - if (s->input_picture[i] && - s->input_picture[i]->b_frame_score == 0) { - s->input_picture[i]->b_frame_score = + } else if (m->b_frame_strategy == 1) { + for (int i = 1; i < m->max_b_frames + 1; i++) { + if (m->input_picture[i] && + m->input_picture[i]->b_frame_score == 0) { + m->input_picture[i]->b_frame_score = get_intra_count(s, - s->input_picture[i ]->f->data[0], - s->input_picture[i - 1]->f->data[0], - s->linesize) + 1; + m->input_picture[i ]->f->data[0], + m->input_picture[i - 1]->f->data[0], + s->c.linesize) + 1; } } - for (i = 0; i < s->max_b_frames + 1; i++) { - if (!s->input_picture[i] || - s->input_picture[i]->b_frame_score - 1 > - s->mb_num / s->b_sensitivity) + for (int i = 0;; i++) { + if (i >= m->max_b_frames + 1 || + !m->input_picture[i] || + m->input_picture[i]->b_frame_score - 1 > + s->c.mb_num / m->b_sensitivity) { + b_frames = FFMAX(0, i - 1); break; + } } - b_frames = FFMAX(0, i - 1); - /* reset scores */ - for (i = 0; i < b_frames + 1; i++) { - s->input_picture[i]->b_frame_score = 0; - } - } else if (s->b_frame_strategy == 2) { - b_frames = estimate_best_b_count(s); + for (int i = 0; i < b_frames + 1; i++) + m->input_picture[i]->b_frame_score = 0; + } else if (m->b_frame_strategy == 2) { + b_frames = estimate_best_b_count(m); if (b_frames < 0) { - ff_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); return b_frames; } } @@ -1615,132 +1760,133 @@ static int set_bframe_chain_length(MpegEncContext *s) emms_c(); for (int i = b_frames - 1; i >= 0; i--) { - int type = s->input_picture[i]->f->pict_type; + int type = m->input_picture[i]->f->pict_type; if (type && type != AV_PICTURE_TYPE_B) b_frames = i; } - if (s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && - b_frames == s->max_b_frames) { - av_log(s->avctx, AV_LOG_ERROR, + if (m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && + b_frames == m->max_b_frames) { + av_log(s->c.avctx, AV_LOG_ERROR, "warning, too many B-frames in a row\n"); } - if (s->picture_in_gop_number + b_frames >= s->gop_size) { + if (m->picture_in_gop_number + b_frames >= m->gop_size) { if ((s->mpv_flags & FF_MPV_FLAG_STRICT_GOP) && - s->gop_size > s->picture_in_gop_number) { - b_frames = s->gop_size - s->picture_in_gop_number - 1; + m->gop_size > m->picture_in_gop_number) { + b_frames = m->gop_size - m->picture_in_gop_number - 1; } else { - if (s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) + if (s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) b_frames = 0; - s->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; + m->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; } } - if ((s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) && b_frames && - s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) + if ((s->c.avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) && b_frames && + m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) b_frames--; - s->reordered_input_picture[0] = s->input_picture[b_frames]; - s->input_picture[b_frames] = NULL; - if (s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; - s->reordered_input_picture[0]->coded_picture_number = - s->coded_picture_number++; + m->reordered_input_picture[0] = m->input_picture[b_frames]; + m->input_picture[b_frames] = NULL; + if (m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; + m->reordered_input_picture[0]->coded_picture_number = + m->coded_picture_number++; for (int i = 0; i < b_frames; i++) { - s->reordered_input_picture[i + 1] = s->input_picture[i]; - s->input_picture[i] = NULL; - s->reordered_input_picture[i + 1]->f->pict_type = + m->reordered_input_picture[i + 1] = m->input_picture[i]; + m->input_picture[i] = NULL; + m->reordered_input_picture[i + 1]->f->pict_type = AV_PICTURE_TYPE_B; - s->reordered_input_picture[i + 1]->coded_picture_number = - s->coded_picture_number++; + m->reordered_input_picture[i + 1]->coded_picture_number = + m->coded_picture_number++; } } return 0; } -static int select_input_picture(MpegEncContext *s) +static int select_input_picture(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int ret; - av_assert1(!s->reordered_input_picture[0]); + av_assert1(!m->reordered_input_picture[0]); - for (int i = 1; i <= MAX_B_FRAMES; i++) - s->reordered_input_picture[i - 1] = s->reordered_input_picture[i]; - s->reordered_input_picture[MAX_B_FRAMES] = NULL; + for (int i = 1; i <= MPVENC_MAX_B_FRAMES; i++) + m->reordered_input_picture[i - 1] = m->reordered_input_picture[i]; + m->reordered_input_picture[MPVENC_MAX_B_FRAMES] = NULL; - ret = set_bframe_chain_length(s); - av_assert1(!s->input_picture[0]); + ret = set_bframe_chain_length(m); + av_assert1(!m->input_picture[0]); if (ret < 0) return ret; av_frame_unref(s->new_pic); - if (s->reordered_input_picture[0]) { - s->reordered_input_picture[0]->reference = - s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; + if (m->reordered_input_picture[0]) { + m->reordered_input_picture[0]->reference = + m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; - if (s->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) { + if (m->reordered_input_picture[0]->shared || s->c.avctx->rc_buffer_size) { // input is a shared pix, so we can't modify it -> allocate a new - // one & ensure that the shared one is reuseable - av_frame_move_ref(s->new_pic, s->reordered_input_picture[0]->f); + // one & ensure that the shared one is reusable + av_frame_move_ref(s->new_pic, m->reordered_input_picture[0]->f); - ret = prepare_picture(s, s->reordered_input_picture[0]->f, s->new_pic); + ret = prepare_picture(s, m->reordered_input_picture[0]->f, s->new_pic); if (ret < 0) goto fail; } else { // input is not a shared pix -> reuse buffer for current_pix - ret = av_frame_ref(s->new_pic, s->reordered_input_picture[0]->f); + ret = av_frame_ref(s->new_pic, m->reordered_input_picture[0]->f); if (ret < 0) goto fail; - for (int i = 0; i < MPV_MAX_PLANES; i++) { - if (s->new_pic->data[i]) - s->new_pic->data[i] += INPLACE_OFFSET; - } + for (int i = 0; i < MPV_MAX_PLANES; i++) + s->new_pic->data[i] += INPLACE_OFFSET; } - s->cur_pic.ptr = s->reordered_input_picture[0]; - s->reordered_input_picture[0] = NULL; - av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); - av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height); - av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); - ret = ff_mpv_alloc_pic_accessories(s->avctx, &s->cur_pic, - &s->sc, &s->buffer_pools, s->mb_height); + s->c.cur_pic.ptr = m->reordered_input_picture[0]; + m->reordered_input_picture[0] = NULL; + av_assert1(s->c.mb_width == s->c.buffer_pools.alloc_mb_width); + av_assert1(s->c.mb_height == s->c.buffer_pools.alloc_mb_height); + av_assert1(s->c.mb_stride == s->c.buffer_pools.alloc_mb_stride); + ret = ff_mpv_alloc_pic_accessories(s->c.avctx, &s->c.cur_pic, + &s->c.sc, &s->c.buffer_pools, s->c.mb_height); if (ret < 0) { - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); return ret; } - s->picture_number = s->cur_pic.ptr->display_picture_number; + s->picture_number = s->c.cur_pic.ptr->display_picture_number; } return 0; fail: - ff_refstruct_unref(&s->reordered_input_picture[0]); + av_refstruct_unref(&m->reordered_input_picture[0]); return ret; } -static void frame_end(MpegEncContext *s) +static void frame_end(MPVMainEncContext *const m) { - if (s->unrestricted_mv && - s->cur_pic.reference && - !s->intra_only) { - int hshift = s->chroma_x_shift; - int vshift = s->chroma_y_shift; - s->mpvencdsp.draw_edges(s->cur_pic.data[0], - s->cur_pic.linesize[0], - s->h_edge_pos, s->v_edge_pos, + MPVEncContext *const s = &m->s; + + if (s->me.unrestricted_mv && + s->c.cur_pic.reference && + !m->intra_only) { + int hshift = s->c.chroma_x_shift; + int vshift = s->c.chroma_y_shift; + s->mpvencdsp.draw_edges(s->c.cur_pic.data[0], + s->c.cur_pic.linesize[0], + s->c.h_edge_pos, s->c.v_edge_pos, EDGE_WIDTH, EDGE_WIDTH, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->cur_pic.data[1], - s->cur_pic.linesize[1], - s->h_edge_pos >> hshift, - s->v_edge_pos >> vshift, + s->mpvencdsp.draw_edges(s->c.cur_pic.data[1], + s->c.cur_pic.linesize[1], + s->c.h_edge_pos >> hshift, + s->c.v_edge_pos >> vshift, EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->cur_pic.data[2], - s->cur_pic.linesize[2], - s->h_edge_pos >> hshift, - s->v_edge_pos >> vshift, + s->mpvencdsp.draw_edges(s->c.cur_pic.data[2], + s->c.cur_pic.linesize[2], + s->c.h_edge_pos >> hshift, + s->c.v_edge_pos >> vshift, EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift, EDGE_TOP | EDGE_BOTTOM); @@ -1748,14 +1894,15 @@ static void frame_end(MpegEncContext *s) emms_c(); - s->last_pict_type = s->pict_type; - s->last_lambda_for [s->pict_type] = s->cur_pic.ptr->f->quality; - if (s->pict_type!= AV_PICTURE_TYPE_B) - s->last_non_b_pict_type = s->pict_type; + m->last_pict_type = s->c.pict_type; + m->last_lambda_for[s->c.pict_type] = s->c.cur_pic.ptr->f->quality; + if (s->c.pict_type != AV_PICTURE_TYPE_B) + m->last_non_b_pict_type = s->c.pict_type; } -static void update_noise_reduction(MpegEncContext *s) +static void update_noise_reduction(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int intra, i; for (intra = 0; intra < 2; intra++) { @@ -1767,7 +1914,7 @@ static void update_noise_reduction(MpegEncContext *s) } for (i = 0; i < 64; i++) { - s->dct_offset[intra][i] = (s->noise_reduction * + s->dct_offset[intra][i] = (m->noise_reduction * s->dct_count[intra] + s->dct_error_sum[intra][i] / 2) / (s->dct_error_sum[intra][i] + 1); @@ -1775,45 +1922,49 @@ static void update_noise_reduction(MpegEncContext *s) } } -static void frame_start(MpegEncContext *s) +static void frame_start(MPVMainEncContext *const m) { - s->cur_pic.ptr->f->pict_type = s->pict_type; + MPVEncContext *const s = &m->s; - if (s->pict_type != AV_PICTURE_TYPE_B) { - ff_mpv_replace_picture(&s->last_pic, &s->next_pic); - ff_mpv_replace_picture(&s->next_pic, &s->cur_pic); + s->c.cur_pic.ptr->f->pict_type = s->c.pict_type; + + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + ff_mpv_replace_picture(&s->c.last_pic, &s->c.next_pic); + ff_mpv_replace_picture(&s->c.next_pic, &s->c.cur_pic); } + av_assert2(!!m->noise_reduction == !!s->dct_error_sum); if (s->dct_error_sum) { - av_assert2(s->noise_reduction && s->encoding); - update_noise_reduction(s); + update_noise_reduction(m); } } int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic_arg, int *got_packet) { - MpegEncContext *s = avctx->priv_data; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; int stuffing_count, ret; - int context_count = s->slice_context_count; + int context_count = s->c.slice_context_count; - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); - s->vbv_ignore_qmax = 0; + m->vbv_ignore_qmax = 0; - s->picture_in_gop_number++; + m->picture_in_gop_number++; - if (load_input_picture(s, pic_arg) < 0) - return -1; + ret = load_input_picture(m, pic_arg); + if (ret < 0) + return ret; - if (select_input_picture(s) < 0) { - return -1; - } + ret = select_input_picture(m); + if (ret < 0) + return ret; /* output? */ if (s->new_pic->data[0]) { int growing_buffer = context_count == 1 && !s->data_partitioning; - size_t pkt_size = 10000 + s->mb_width * s->mb_height * + size_t pkt_size = 10000 + s->c.mb_width * s->c.mb_height * (growing_buffer ? 64 : (MAX_MB_BYTES + 100)); if (CONFIG_MJPEG_ENCODER && avctx->codec_id == AV_CODEC_ID_MJPEG) { ret = ff_mjpeg_add_icc_profile_size(avctx, s->new_pic, &pkt_size); @@ -1826,17 +1977,17 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, if (s->mb_info) { s->mb_info_ptr = av_packet_new_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, - s->mb_width*s->mb_height*12); + s->c.mb_width*s->c.mb_height*12); if (!s->mb_info_ptr) return AVERROR(ENOMEM); s->prev_mb_info = s->last_mb_info = s->mb_info_size = 0; } - s->pict_type = s->new_pic->pict_type; + s->c.pict_type = s->new_pic->pict_type; //emms_c(); - frame_start(s); + frame_start(m); vbv_retry: - ret = encode_picture(s, pkt); + ret = encode_picture(m, pkt); if (growing_buffer) { av_assert0(s->pb.buf == avctx->internal->byte_buffer); pkt->data = s->pb.buf; @@ -1845,39 +1996,38 @@ vbv_retry: if (ret < 0) return -1; - frame_end(s); + frame_end(m); - if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && s->out_format == FMT_MJPEG) - ff_mjpeg_encode_picture_trailer(&s->pb, s->header_bits); + if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && s->c.out_format == FMT_MJPEG) + ff_mjpeg_encode_picture_trailer(&s->pb, m->header_bits); if (avctx->rc_buffer_size) { - RateControlContext *rcc = &s->rc_context; + RateControlContext *rcc = &m->rc_context; int max_size = FFMAX(rcc->buffer_index * avctx->rc_max_available_vbv_use, rcc->buffer_index - 500); int hq = (avctx->mb_decision == FF_MB_DECISION_RD || avctx->trellis); int min_step = hq ? 1 : (1<<(FF_LAMBDA_SHIFT + 7))/139; if (put_bits_count(&s->pb) > max_size && - s->lambda < s->lmax) { - s->next_lambda = FFMAX(s->lambda + min_step, s->lambda * - (s->qscale + 1) / s->qscale); + s->lambda < m->lmax) { + m->next_lambda = FFMAX(s->lambda + min_step, s->lambda * + (s->c.qscale + 1) / s->c.qscale); if (s->adaptive_quant) { - int i; - for (i = 0; i < s->mb_height * s->mb_stride; i++) + for (int i = 0; i < s->c.mb_height * s->c.mb_stride; i++) s->lambda_table[i] = FFMAX(s->lambda_table[i] + min_step, - s->lambda_table[i] * (s->qscale + 1) / - s->qscale); + s->lambda_table[i] * (s->c.qscale + 1) / + s->c.qscale); } - s->mb_skipped = 0; // done in frame_start() + s->c.mb_skipped = 0; // done in frame_start() // done in encode_picture() so we must undo it - if (s->pict_type == AV_PICTURE_TYPE_P) { - s->no_rounding ^= s->flipflop_rounding; + if (s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.no_rounding ^= s->flipflop_rounding; } - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->time_base = s->last_time_base; - s->last_non_b_time = s->time - s->pp_time; + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + s->c.time_base = s->c.last_time_base; + s->c.last_non_b_time = s->c.time - s->c.pp_time; } - s->vbv_ignore_qmax = 1; + m->vbv_ignore_qmax = 1; av_log(avctx, AV_LOG_VERBOSE, "reencoding frame due to VBV\n"); goto vbv_retry; } @@ -1886,31 +2036,31 @@ vbv_retry: } if (avctx->flags & AV_CODEC_FLAG_PASS1) - ff_write_pass1_stats(s); + ff_write_pass1_stats(m); for (int i = 0; i < MPV_MAX_PLANES; i++) avctx->error[i] += s->encoding_error[i]; - ff_side_data_set_encoder_stats(pkt, s->cur_pic.ptr->f->quality, + ff_side_data_set_encoder_stats(pkt, s->c.cur_pic.ptr->f->quality, s->encoding_error, (avctx->flags&AV_CODEC_FLAG_PSNR) ? MPV_MAX_PLANES : 0, - s->pict_type); + s->c.pict_type); if (avctx->flags & AV_CODEC_FLAG_PASS1) - assert(put_bits_count(&s->pb) == s->header_bits + s->mv_bits + + assert(put_bits_count(&s->pb) == m->header_bits + s->mv_bits + s->misc_bits + s->i_tex_bits + s->p_tex_bits); flush_put_bits(&s->pb); - s->frame_bits = put_bits_count(&s->pb); + m->frame_bits = put_bits_count(&s->pb); - stuffing_count = ff_vbv_update(s, s->frame_bits); - s->stuffing_bits = 8*stuffing_count; + stuffing_count = ff_vbv_update(m, m->frame_bits); + m->stuffing_bits = 8*stuffing_count; if (stuffing_count) { if (put_bytes_left(&s->pb, 0) < stuffing_count + 50) { av_log(avctx, AV_LOG_ERROR, "stuffing too large\n"); return -1; } - switch (s->codec_id) { + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: while (stuffing_count--) { @@ -1927,16 +2077,16 @@ vbv_retry: break; default: av_log(avctx, AV_LOG_ERROR, "vbv buffer overflow\n"); - s->stuffing_bits = 0; + m->stuffing_bits = 0; } flush_put_bits(&s->pb); - s->frame_bits = put_bits_count(&s->pb); + m->frame_bits = put_bits_count(&s->pb); } /* update MPEG-1/2 vbv_delay for CBR */ if (avctx->rc_max_rate && avctx->rc_min_rate == avctx->rc_max_rate && - s->out_format == FMT_MPEG1 && + s->c.out_format == FMT_MPEG1 && 90000LL * (avctx->rc_buffer_size - 1) <= avctx->rc_max_rate * 0xFFFFLL) { AVCPBProperties *props; @@ -1945,16 +2095,16 @@ vbv_retry: int vbv_delay, min_delay; double inbits = avctx->rc_max_rate * av_q2d(avctx->time_base); - int minbits = s->frame_bits - 8 * - (s->vbv_delay_pos - 1); - double bits = s->rc_context.buffer_index + minbits - inbits; - uint8_t *const vbv_delay_ptr = s->pb.buf + s->vbv_delay_pos; + int minbits = m->frame_bits - 8 * + (m->vbv_delay_pos - 1); + double bits = m->rc_context.buffer_index + minbits - inbits; + uint8_t *const vbv_delay_ptr = s->pb.buf + m->vbv_delay_pos; if (bits < 0) av_log(avctx, AV_LOG_ERROR, "Internal error, negative bits\n"); - av_assert1(s->repeat_first_field == 0); + av_assert1(s->c.repeat_first_field == 0); vbv_delay = bits * 90000 / avctx->rc_max_rate; min_delay = (minbits * 90000LL + avctx->rc_max_rate - 1) / @@ -1982,44 +2132,44 @@ vbv_retry: return ret; } } - s->total_bits += s->frame_bits; + m->total_bits += m->frame_bits; - pkt->pts = s->cur_pic.ptr->f->pts; - pkt->duration = s->cur_pic.ptr->f->duration; - if (!s->low_delay && s->pict_type != AV_PICTURE_TYPE_B) { - if (!s->cur_pic.ptr->coded_picture_number) - pkt->dts = pkt->pts - s->dts_delta; + pkt->pts = s->c.cur_pic.ptr->f->pts; + pkt->duration = s->c.cur_pic.ptr->f->duration; + if (!s->c.low_delay && s->c.pict_type != AV_PICTURE_TYPE_B) { + if (!s->c.cur_pic.ptr->coded_picture_number) + pkt->dts = pkt->pts - m->dts_delta; else - pkt->dts = s->reordered_pts; - s->reordered_pts = pkt->pts; + pkt->dts = m->reordered_pts; + m->reordered_pts = pkt->pts; } else pkt->dts = pkt->pts; // the no-delay case is handled in generic code if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY) { - ret = ff_encode_reordered_opaque(avctx, pkt, s->cur_pic.ptr->f); + ret = ff_encode_reordered_opaque(avctx, pkt, s->c.cur_pic.ptr->f); if (ret < 0) return ret; } - if (s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) + if (s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY; if (s->mb_info) av_packet_shrink_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, s->mb_info_size); } else { - s->frame_bits = 0; + m->frame_bits = 0; } - ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->c.cur_pic); - av_assert1((s->frame_bits & 7) == 0); + av_assert1((m->frame_bits & 7) == 0); - pkt->size = s->frame_bits / 8; + pkt->size = m->frame_bits / 8; *got_packet = !!pkt->size; return 0; } -static inline void dct_single_coeff_elimination(MpegEncContext *s, +static inline void dct_single_coeff_elimination(MPVEncContext *const s, int n, int threshold) { static const char tab[64] = { @@ -2036,7 +2186,7 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, int run = 0; int i; int16_t *block = s->block[n]; - const int last_index = s->block_last_index[n]; + const int last_index = s->c.block_last_index[n]; int skip_dc; if (threshold < 0) { @@ -2050,7 +2200,7 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, return; for (i = 0; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; const int level = FFABS(block[j]); if (level == 1) { if (skip_dc && i == 0) @@ -2066,16 +2216,16 @@ static inline void dct_single_coeff_elimination(MpegEncContext *s, if (score >= threshold) return; for (i = skip_dc; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; block[j] = 0; } if (block[0]) - s->block_last_index[n] = 0; + s->c.block_last_index[n] = 0; else - s->block_last_index[n] = -1; + s->c.block_last_index[n] = -1; } -static inline void clip_coeffs(MpegEncContext *s, int16_t *block, +static inline void clip_coeffs(const MPVEncContext *const s, int16_t block[], int last_index) { int i; @@ -2083,13 +2233,13 @@ static inline void clip_coeffs(MpegEncContext *s, int16_t *block, const int minlevel = s->min_qcoeff; int overflow = 0; - if (s->mb_intra) { + if (s->c.mb_intra) { i = 1; // skip clipping of intra dc } else i = 0; for (; i <= last_index; i++) { - const int j = s->intra_scantable.permutated[i]; + const int j = s->c.intra_scantable.permutated[i]; int level = block[j]; if (level > maxlevel) { @@ -2103,8 +2253,8 @@ static inline void clip_coeffs(MpegEncContext *s, int16_t *block, block[j] = level; } - if (overflow && s->avctx->mb_decision == FF_MB_DECISION_SIMPLE) - av_log(s->avctx, AV_LOG_INFO, + if (overflow && s->c.avctx->mb_decision == FF_MB_DECISION_SIMPLE) + av_log(s->c.avctx, AV_LOG_INFO, "warning, clipping %d dct coefficients to %d..%d\n", overflow, minlevel, maxlevel); } @@ -2133,7 +2283,7 @@ static void get_visual_weight(int16_t *weight, const uint8_t *ptr, int stride) } } -static av_always_inline void encode_mb_internal(MpegEncContext *s, +static av_always_inline void encode_mb_internal(MPVEncContext *const s, int motion_x, int motion_y, int mb_block_height, int mb_block_width, @@ -2145,15 +2295,15 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, /* Interlaced DCT is only possible with MPEG-2 and MPEG-4 * and neither of these encoders currently supports 444. */ #define INTERLACED_DCT(s) ((chroma_format == CHROMA_420 || chroma_format == CHROMA_422) && \ - (s)->avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) + (s)->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) int16_t weight[12][64]; int16_t orig[12][64]; - const int mb_x = s->mb_x; - const int mb_y = s->mb_y; + const int mb_x = s->c.mb_x; + const int mb_y = s->c.mb_y; int i; int skip_dct[12]; - int dct_offset = s->linesize * 8; // default for progressive frames - int uv_dct_offset = s->uvlinesize * 8; + int dct_offset = s->c.linesize * 8; // default for progressive frames + int uv_dct_offset = s->c.uvlinesize * 8; const uint8_t *ptr_y, *ptr_cb, *ptr_cr; ptrdiff_t wrap_y, wrap_c; @@ -2161,37 +2311,37 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, skip_dct[i] = s->skipdct; if (s->adaptive_quant) { - const int last_qp = s->qscale; - const int mb_xy = mb_x + mb_y * s->mb_stride; + const int last_qp = s->c.qscale; + const int mb_xy = mb_x + mb_y * s->c.mb_stride; - s->lambda = s->lambda_table[mb_xy]; + s->lambda = s->lambda_table[mb_xy]; s->lambda2 = (s->lambda * s->lambda + FF_LAMBDA_SCALE / 2) >> - FF_LAMBDA_SHIFT; + FF_LAMBDA_SHIFT; if (!(s->mpv_flags & FF_MPV_FLAG_QP_RD)) { - s->dquant = s->cur_pic.qscale_table[mb_xy] - last_qp; + s->dquant = s->c.cur_pic.qscale_table[mb_xy] - last_qp; - if (s->out_format == FMT_H263) { + if (s->c.out_format == FMT_H263) { s->dquant = av_clip(s->dquant, -2, 2); - if (s->codec_id == AV_CODEC_ID_MPEG4) { - if (!s->mb_intra) { - if (s->pict_type == AV_PICTURE_TYPE_B) { - if (s->dquant & 1 || s->mv_dir & MV_DIRECT) + if (s->c.codec_id == AV_CODEC_ID_MPEG4) { + if (!s->c.mb_intra) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + if (s->dquant & 1 || s->c.mv_dir & MV_DIRECT) s->dquant = 0; } - if (s->mv_type == MV_TYPE_8X8) + if (s->c.mv_type == MV_TYPE_8X8) s->dquant = 0; } } } } - ff_set_qscale(s, last_qp + s->dquant); + ff_set_qscale(&s->c, last_qp + s->dquant); } else if (s->mpv_flags & FF_MPV_FLAG_QP_RD) - ff_set_qscale(s, s->qscale + s->dquant); + ff_set_qscale(&s->c, s->c.qscale + s->dquant); - wrap_y = s->linesize; - wrap_c = s->uvlinesize; + wrap_y = s->c.linesize; + wrap_c = s->c.uvlinesize; ptr_y = s->new_pic->data[0] + (mb_y * 16 * wrap_y) + mb_x * 16; ptr_cb = s->new_pic->data[1] + @@ -2199,22 +2349,23 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, ptr_cr = s->new_pic->data[2] + (mb_y * mb_block_height * wrap_c) + mb_x * mb_block_width; - if((mb_x * 16 + 16 > s->width || mb_y * 16 + 16 > s->height) && s->codec_id != AV_CODEC_ID_AMV){ - uint8_t *ebuf = s->sc.edge_emu_buffer + 38 * wrap_y; - int cw = (s->width + chroma_x_shift) >> chroma_x_shift; - int ch = (s->height + chroma_y_shift) >> chroma_y_shift; - s->vdsp.emulated_edge_mc(ebuf, ptr_y, + if ((mb_x * 16 + 16 > s->c.width || mb_y * 16 + 16 > s->c.height) && + s->c.codec_id != AV_CODEC_ID_AMV) { + uint8_t *ebuf = s->c.sc.edge_emu_buffer + 38 * wrap_y; + int cw = (s->c.width + chroma_x_shift) >> chroma_x_shift; + int ch = (s->c.height + chroma_y_shift) >> chroma_y_shift; + s->c.vdsp.emulated_edge_mc(ebuf, ptr_y, wrap_y, wrap_y, 16, 16, mb_x * 16, mb_y * 16, - s->width, s->height); + s->c.width, s->c.height); ptr_y = ebuf; - s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y, ptr_cb, + s->c.vdsp.emulated_edge_mc(ebuf + 16 * wrap_y, ptr_cb, wrap_c, wrap_c, mb_block_width, mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height, cw, ch); ptr_cb = ebuf + 16 * wrap_y; - s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y + 16, ptr_cr, + s->c.vdsp.emulated_edge_mc(ebuf + 16 * wrap_y + 16, ptr_cr, wrap_c, wrap_c, mb_block_width, mb_block_height, mb_x * mb_block_width, mb_y * mb_block_height, @@ -2222,11 +2373,11 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, ptr_cr = ebuf + 16 * wrap_y + 16; } - if (s->mb_intra) { + if (s->c.mb_intra) { if (INTERLACED_DCT(s)) { int progressive_score, interlaced_score; - s->interlaced_dct = 0; + s->c.interlaced_dct = 0; progressive_score = s->ildct_cmp[1](s, ptr_y, NULL, wrap_y, 8) + s->ildct_cmp[1](s, ptr_y + wrap_y * 8, NULL, wrap_y, 8) - 400; @@ -2237,7 +2388,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->ildct_cmp[1](s, ptr_y + wrap_y, NULL, wrap_y * 2, 8); if (progressive_score > interlaced_score) { - s->interlaced_dct = 1; + s->c.interlaced_dct = 1; dct_offset = wrap_y; uv_dct_offset = wrap_c; @@ -2254,7 +2405,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->pdsp.get_pixels(s->block[2], ptr_y + dct_offset, wrap_y); s->pdsp.get_pixels(s->block[3], ptr_y + dct_offset + 8, wrap_y); - if (s->avctx->flags & AV_CODEC_FLAG_GRAY) { + if (s->c.avctx->flags & AV_CODEC_FLAG_GRAY) { skip_dct[4] = 1; skip_dct[5] = 1; } else { @@ -2277,41 +2428,41 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, qpel_mc_func (*op_qpix)[16]; uint8_t *dest_y, *dest_cb, *dest_cr; - dest_y = s->dest[0]; - dest_cb = s->dest[1]; - dest_cr = s->dest[2]; + dest_y = s->c.dest[0]; + dest_cb = s->c.dest[1]; + dest_cr = s->c.dest[2]; - if ((!s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { - op_pix = s->hdsp.put_pixels_tab; - op_qpix = s->qdsp.put_qpel_pixels_tab; + if ((!s->c.no_rounding) || s->c.pict_type == AV_PICTURE_TYPE_B) { + op_pix = s->c.hdsp.put_pixels_tab; + op_qpix = s->c.qdsp.put_qpel_pixels_tab; } else { - op_pix = s->hdsp.put_no_rnd_pixels_tab; - op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; + op_pix = s->c.hdsp.put_no_rnd_pixels_tab; + op_qpix = s->c.qdsp.put_no_rnd_qpel_pixels_tab; } - if (s->mv_dir & MV_DIR_FORWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, - s->last_pic.data, + if (s->c.mv_dir & MV_DIR_FORWARD) { + ff_mpv_motion(&s->c, dest_y, dest_cb, dest_cr, 0, + s->c.last_pic.data, op_pix, op_qpix); - op_pix = s->hdsp.avg_pixels_tab; - op_qpix = s->qdsp.avg_qpel_pixels_tab; + op_pix = s->c.hdsp.avg_pixels_tab; + op_qpix = s->c.qdsp.avg_qpel_pixels_tab; } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, - s->next_pic.data, + if (s->c.mv_dir & MV_DIR_BACKWARD) { + ff_mpv_motion(&s->c, dest_y, dest_cb, dest_cr, 1, + s->c.next_pic.data, op_pix, op_qpix); } if (INTERLACED_DCT(s)) { int progressive_score, interlaced_score; - s->interlaced_dct = 0; + s->c.interlaced_dct = 0; progressive_score = s->ildct_cmp[0](s, dest_y, ptr_y, wrap_y, 8) + s->ildct_cmp[0](s, dest_y + wrap_y * 8, ptr_y + wrap_y * 8, wrap_y, 8) - 400; - if (s->avctx->ildct_cmp == FF_CMP_VSSE) + if (s->c.avctx->ildct_cmp == FF_CMP_VSSE) progressive_score -= 400; if (progressive_score > 0) { @@ -2322,7 +2473,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, wrap_y * 2, 8); if (progressive_score > interlaced_score) { - s->interlaced_dct = 1; + s->c.interlaced_dct = 1; dct_offset = wrap_y; uv_dct_offset = wrap_c; @@ -2340,7 +2491,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->pdsp.diff_pixels(s->block[3], ptr_y + dct_offset + 8, dest_y + dct_offset + 8, wrap_y); - if (s->avctx->flags & AV_CODEC_FLAG_GRAY) { + if (s->c.avctx->flags & AV_CODEC_FLAG_GRAY) { skip_dct[4] = 1; skip_dct[5] = 1; } else { @@ -2354,30 +2505,30 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } } /* pre quantization */ - if (s->mc_mb_var[s->mb_stride * mb_y + mb_x] < 2 * s->qscale * s->qscale) { + if (s->mc_mb_var[s->c.mb_stride * mb_y + mb_x] < 2 * s->c.qscale * s->c.qscale) { // FIXME optimize - if (s->sad_cmp[1](NULL, ptr_y, dest_y, wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y, dest_y, wrap_y, 8) < 20 * s->c.qscale) skip_dct[0] = 1; - if (s->sad_cmp[1](NULL, ptr_y + 8, dest_y + 8, wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y + 8, dest_y + 8, wrap_y, 8) < 20 * s->c.qscale) skip_dct[1] = 1; if (s->sad_cmp[1](NULL, ptr_y + dct_offset, dest_y + dct_offset, - wrap_y, 8) < 20 * s->qscale) + wrap_y, 8) < 20 * s->c.qscale) skip_dct[2] = 1; if (s->sad_cmp[1](NULL, ptr_y + dct_offset + 8, dest_y + dct_offset + 8, - wrap_y, 8) < 20 * s->qscale) + wrap_y, 8) < 20 * s->c.qscale) skip_dct[3] = 1; - if (s->sad_cmp[1](NULL, ptr_cb, dest_cb, wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cb, dest_cb, wrap_c, 8) < 20 * s->c.qscale) skip_dct[4] = 1; - if (s->sad_cmp[1](NULL, ptr_cr, dest_cr, wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cr, dest_cr, wrap_c, 8) < 20 * s->c.qscale) skip_dct[5] = 1; if (!chroma_y_shift) { /* 422 */ if (s->sad_cmp[1](NULL, ptr_cb + uv_dct_offset, dest_cb + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + wrap_c, 8) < 20 * s->c.qscale) skip_dct[6] = 1; if (s->sad_cmp[1](NULL, ptr_cr + uv_dct_offset, dest_cr + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + wrap_c, 8) < 20 * s->c.qscale) skip_dct[7] = 1; } } @@ -2408,230 +2559,207 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } /* DCT & quantize */ - av_assert2(s->out_format != FMT_MJPEG || s->qscale == 8); + av_assert2(s->c.out_format != FMT_MJPEG || s->c.qscale == 8); { for (i = 0; i < mb_block_count; i++) { if (!skip_dct[i]) { int overflow; - s->block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->qscale, &overflow); + s->c.block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->c.qscale, &overflow); // FIXME we could decide to change to quantizer instead of // clipping // JS: I don't think that would be a good idea it could lower // quality instead of improve it. Just INTRADC clipping // deserves changes in quantizer if (overflow) - clip_coeffs(s, s->block[i], s->block_last_index[i]); + clip_coeffs(s, s->block[i], s->c.block_last_index[i]); } else - s->block_last_index[i] = -1; + s->c.block_last_index[i] = -1; } if (s->quantizer_noise_shaping) { for (i = 0; i < mb_block_count; i++) { if (!skip_dct[i]) { - s->block_last_index[i] = + s->c.block_last_index[i] = dct_quantize_refine(s, s->block[i], weight[i], - orig[i], i, s->qscale); + orig[i], i, s->c.qscale); } } } - if (s->luma_elim_threshold && !s->mb_intra) + if (s->luma_elim_threshold && !s->c.mb_intra) for (i = 0; i < 4; i++) dct_single_coeff_elimination(s, i, s->luma_elim_threshold); - if (s->chroma_elim_threshold && !s->mb_intra) + if (s->chroma_elim_threshold && !s->c.mb_intra) for (i = 4; i < mb_block_count; i++) dct_single_coeff_elimination(s, i, s->chroma_elim_threshold); if (s->mpv_flags & FF_MPV_FLAG_CBP_RD) { for (i = 0; i < mb_block_count; i++) { - if (s->block_last_index[i] == -1) + if (s->c.block_last_index[i] == -1) s->coded_score[i] = INT_MAX / 256; } } } - if ((s->avctx->flags & AV_CODEC_FLAG_GRAY) && s->mb_intra) { - s->block_last_index[4] = - s->block_last_index[5] = 0; + if ((s->c.avctx->flags & AV_CODEC_FLAG_GRAY) && s->c.mb_intra) { + s->c.block_last_index[4] = + s->c.block_last_index[5] = 0; s->block[4][0] = - s->block[5][0] = (1024 + s->c_dc_scale / 2) / s->c_dc_scale; + s->block[5][0] = (1024 + s->c.c_dc_scale / 2) / s->c.c_dc_scale; if (!chroma_y_shift) { /* 422 / 444 */ for (i=6; i<12; i++) { - s->block_last_index[i] = 0; + s->c.block_last_index[i] = 0; s->block[i][0] = s->block[4][0]; } } } // non c quantize code returns incorrect block_last_index FIXME - if (s->alternate_scan && s->dct_quantize != dct_quantize_c) { + if (s->c.alternate_scan && s->dct_quantize != dct_quantize_c) { for (i = 0; i < mb_block_count; i++) { int j; - if (s->block_last_index[i] > 0) { + if (s->c.block_last_index[i] > 0) { for (j = 63; j > 0; j--) { - if (s->block[i][s->intra_scantable.permutated[j]]) + if (s->block[i][s->c.intra_scantable.permutated[j]]) break; } - s->block_last_index[i] = j; + s->c.block_last_index[i] = j; } } } - /* huffman encode */ - switch(s->codec_id){ //FIXME funct ptr could be slightly faster - case AV_CODEC_ID_MPEG1VIDEO: - case AV_CODEC_ID_MPEG2VIDEO: - if (CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER) - ff_mpeg1_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_MPEG4: - if (CONFIG_MPEG4_ENCODER) - ff_mpeg4_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_MSMPEG4V2: - case AV_CODEC_ID_MSMPEG4V3: - case AV_CODEC_ID_WMV1: - if (CONFIG_MSMPEG4ENC) - ff_msmpeg4_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_WMV2: - if (CONFIG_WMV2_ENCODER) - ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_H261: - if (CONFIG_H261_ENCODER) - ff_h261_encode_mb(s, s->block, motion_x, motion_y); - break; - case AV_CODEC_ID_H263: - case AV_CODEC_ID_H263P: - case AV_CODEC_ID_FLV1: - case AV_CODEC_ID_RV10: - case AV_CODEC_ID_RV20: - if (CONFIG_H263_ENCODER) - ff_h263_encode_mb(s, s->block, motion_x, motion_y); - break; -#if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER - case AV_CODEC_ID_MJPEG: - case AV_CODEC_ID_AMV: - ff_mjpeg_encode_mb(s, s->block); - break; -#endif - case AV_CODEC_ID_SPEEDHQ: - if (CONFIG_SPEEDHQ_ENCODER) - ff_speedhq_encode_mb(s, s->block); - break; - default: - av_assert1(0); - } + s->encode_mb(s, s->block, motion_x, motion_y); } -static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) +static void encode_mb(MPVEncContext *const s, int motion_x, int motion_y) { - if (s->chroma_format == CHROMA_420) + if (s->c.chroma_format == CHROMA_420) encode_mb_internal(s, motion_x, motion_y, 8, 8, 6, 1, 1, CHROMA_420); - else if (s->chroma_format == CHROMA_422) + else if (s->c.chroma_format == CHROMA_422) encode_mb_internal(s, motion_x, motion_y, 16, 8, 8, 1, 0, CHROMA_422); else encode_mb_internal(s, motion_x, motion_y, 16, 16, 12, 0, 0, CHROMA_444); } -static inline void copy_context_before_encode(MpegEncContext *d, - const MpegEncContext *s) -{ - int i; +typedef struct MBBackup { + struct { + int mv[2][4][2]; + int last_mv[2][2][2]; + int mv_type, mv_dir; + int last_dc[3]; + int mb_intra, mb_skipped; + int qscale; + int block_last_index[8]; + int interlaced_dct; + } c; + int mb_skip_run; + int mv_bits, i_tex_bits, p_tex_bits, i_count, misc_bits, last_bits; + int dquant; + int esc3_level_length; + int16_t (*block)[64]; + PutBitContext pb, pb2, tex_pb; +} MBBackup; - memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? - - /* MPEG-1 */ - d->mb_skip_run= s->mb_skip_run; - for(i=0; i<3; i++) - d->last_dc[i] = s->last_dc[i]; - - /* statistics */ - d->mv_bits= s->mv_bits; - d->i_tex_bits= s->i_tex_bits; - d->p_tex_bits= s->p_tex_bits; - d->i_count= s->i_count; - d->misc_bits= s->misc_bits; - d->last_bits= 0; - - d->mb_skipped= 0; - d->qscale= s->qscale; - d->dquant= s->dquant; - - d->esc3_level_length= s->esc3_level_length; +#define COPY_CONTEXT(BEFORE, AFTER, DST_TYPE, SRC_TYPE) \ +static inline void BEFORE ##_context_before_encode(DST_TYPE *const d, \ + const SRC_TYPE *const s) \ +{ \ + /* FIXME is memcpy faster than a loop? */ \ + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ + \ + /* MPEG-1 */ \ + d->mb_skip_run = s->mb_skip_run; \ + for (int i = 0; i < 3; i++) \ + d->c.last_dc[i] = s->c.last_dc[i]; \ + \ + /* statistics */ \ + d->mv_bits = s->mv_bits; \ + d->i_tex_bits = s->i_tex_bits; \ + d->p_tex_bits = s->p_tex_bits; \ + d->i_count = s->i_count; \ + d->misc_bits = s->misc_bits; \ + d->last_bits = 0; \ + \ + d->c.mb_skipped = 0; \ + d->c.qscale = s->c.qscale; \ + d->dquant = s->dquant; \ + \ + d->esc3_level_length = s->esc3_level_length; \ +} \ + \ +static inline void AFTER ## _context_after_encode(DST_TYPE *const d, \ + const SRC_TYPE *const s, \ + int data_partitioning) \ +{ \ + /* FIXME is memcpy faster than a loop? */ \ + memcpy(d->c.mv, s->c.mv, 2*4*2*sizeof(int)); \ + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ + \ + /* MPEG-1 */ \ + d->mb_skip_run = s->mb_skip_run; \ + for (int i = 0; i < 3; i++) \ + d->c.last_dc[i] = s->c.last_dc[i]; \ + \ + /* statistics */ \ + d->mv_bits = s->mv_bits; \ + d->i_tex_bits = s->i_tex_bits; \ + d->p_tex_bits = s->p_tex_bits; \ + d->i_count = s->i_count; \ + d->misc_bits = s->misc_bits; \ + \ + d->c.mb_intra = s->c.mb_intra; \ + d->c.mb_skipped = s->c.mb_skipped; \ + d->c.mv_type = s->c.mv_type; \ + d->c.mv_dir = s->c.mv_dir; \ + d->pb = s->pb; \ + if (data_partitioning) { \ + d->pb2 = s->pb2; \ + d->tex_pb = s->tex_pb; \ + } \ + d->block = s->block; \ + for (int i = 0; i < 8; i++) \ + d->c.block_last_index[i] = s->c.block_last_index[i]; \ + d->c.interlaced_dct = s->c.interlaced_dct; \ + d->c.qscale = s->c.qscale; \ + \ + d->esc3_level_length = s->esc3_level_length; \ } -static inline void copy_context_after_encode(MpegEncContext *d, - const MpegEncContext *s) -{ - int i; +COPY_CONTEXT(backup, save, MBBackup, MPVEncContext) +COPY_CONTEXT(reset, store, MPVEncContext, MBBackup) - memcpy(d->mv, s->mv, 2*4*2*sizeof(int)); - memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? - - /* MPEG-1 */ - d->mb_skip_run= s->mb_skip_run; - for(i=0; i<3; i++) - d->last_dc[i] = s->last_dc[i]; - - /* statistics */ - d->mv_bits= s->mv_bits; - d->i_tex_bits= s->i_tex_bits; - d->p_tex_bits= s->p_tex_bits; - d->i_count= s->i_count; - d->misc_bits= s->misc_bits; - - d->mb_intra= s->mb_intra; - d->mb_skipped= s->mb_skipped; - d->mv_type= s->mv_type; - d->mv_dir= s->mv_dir; - d->pb= s->pb; - if(s->data_partitioning){ - d->pb2= s->pb2; - d->tex_pb= s->tex_pb; - } - d->block= s->block; - for(i=0; i<8; i++) - d->block_last_index[i]= s->block_last_index[i]; - d->interlaced_dct= s->interlaced_dct; - d->qscale= s->qscale; - - d->esc3_level_length= s->esc3_level_length; -} - -static void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncContext *best, +static void encode_mb_hq(MPVEncContext *const s, MBBackup *const backup, MBBackup *const best, PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], int *dmin, int *next_block, int motion_x, int motion_y) { int score; uint8_t *dest_backup[3]; - copy_context_before_encode(s, backup); + reset_context_before_encode(s, backup); - s->block= s->blocks[*next_block]; - s->pb= pb[*next_block]; - if(s->data_partitioning){ + s->block = s->blocks[*next_block]; + s->pb = pb[*next_block]; + if (s->data_partitioning) { s->pb2 = pb2 [*next_block]; s->tex_pb= tex_pb[*next_block]; } if(*next_block){ - memcpy(dest_backup, s->dest, sizeof(s->dest)); - s->dest[0] = s->sc.rd_scratchpad; - s->dest[1] = s->sc.rd_scratchpad + 16*s->linesize; - s->dest[2] = s->sc.rd_scratchpad + 16*s->linesize + 8; - av_assert0(s->linesize >= 32); //FIXME + memcpy(dest_backup, s->c.dest, sizeof(s->c.dest)); + s->c.dest[0] = s->c.sc.rd_scratchpad; + s->c.dest[1] = s->c.sc.rd_scratchpad + 16*s->c.linesize; + s->c.dest[2] = s->c.sc.rd_scratchpad + 16*s->c.linesize + 8; + av_assert0(s->c.linesize >= 32); //FIXME } encode_mb(s, motion_x, motion_y); score= put_bits_count(&s->pb); - if(s->data_partitioning){ + if (s->data_partitioning) { score+= put_bits_count(&s->pb2); score+= put_bits_count(&s->tex_pb); } - if(s->avctx->mb_decision == FF_MB_DECISION_RD){ + if (s->c.avctx->mb_decision == FF_MB_DECISION_RD) { mpv_reconstruct_mb(s, s->block); score *= s->lambda2; @@ -2639,18 +2767,19 @@ static void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncConte } if(*next_block){ - memcpy(s->dest, dest_backup, sizeof(s->dest)); + memcpy(s->c.dest, dest_backup, sizeof(s->c.dest)); } if(score<*dmin){ *dmin= score; *next_block^=1; - copy_context_after_encode(best, s); + save_context_after_encode(best, s, s->data_partitioning); } } -static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int w, int h, int stride){ +static int sse(const MPVEncContext *const s, const uint8_t *src1, const uint8_t *src2, int w, int h, int stride) +{ const uint32_t *sq = ff_square_tab + 256; int acc=0; int x,y; @@ -2671,129 +2800,128 @@ static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int return acc; } -static int sse_mb(MpegEncContext *s){ +static int sse_mb(MPVEncContext *const s) +{ int w= 16; int h= 16; - int chroma_mb_w = w >> s->chroma_x_shift; - int chroma_mb_h = h >> s->chroma_y_shift; + int chroma_mb_w = w >> s->c.chroma_x_shift; + int chroma_mb_h = h >> s->c.chroma_y_shift; - if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; - if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; + if (s->c.mb_x*16 + 16 > s->c.width ) w = s->c.width - s->c.mb_x*16; + if (s->c.mb_y*16 + 16 > s->c.height) h = s->c.height- s->c.mb_y*16; if(w==16 && h==16) - return s->n_sse_cmp[0](s, s->new_pic->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, - s->dest[0], s->linesize, 16) + - s->n_sse_cmp[1](s, s->new_pic->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[1], s->uvlinesize, chroma_mb_h) + - s->n_sse_cmp[1](s, s->new_pic->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[2], s->uvlinesize, chroma_mb_h); + return s->n_sse_cmp[0](s, s->new_pic->data[0] + s->c.mb_x * 16 + s->c.mb_y * s->c.linesize * 16, + s->c.dest[0], s->c.linesize, 16) + + s->n_sse_cmp[1](s, s->new_pic->data[1] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[1], s->c.uvlinesize, chroma_mb_h) + + s->n_sse_cmp[1](s, s->new_pic->data[2] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[2], s->c.uvlinesize, chroma_mb_h); else - return sse(s, s->new_pic->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, - s->dest[0], w, h, s->linesize) + - sse(s, s->new_pic->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[1], w >> s->chroma_x_shift, h >> s->chroma_y_shift, s->uvlinesize) + - sse(s, s->new_pic->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[2], w >> s->chroma_x_shift, h >> s->chroma_y_shift, s->uvlinesize); + return sse(s, s->new_pic->data[0] + s->c.mb_x * 16 + s->c.mb_y * s->c.linesize * 16, + s->c.dest[0], w, h, s->c.linesize) + + sse(s, s->new_pic->data[1] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[1], w >> s->c.chroma_x_shift, h >> s->c.chroma_y_shift, s->c.uvlinesize) + + sse(s, s->new_pic->data[2] + s->c.mb_x * chroma_mb_w + s->c.mb_y * s->c.uvlinesize * chroma_mb_h, + s->c.dest[2], w >> s->c.chroma_x_shift, h >> s->c.chroma_y_shift, s->c.uvlinesize); } static int pre_estimate_motion_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; + MPVEncContext *const s = *(void**)arg; - s->me.pre_pass=1; - s->me.dia_size= s->avctx->pre_dia_size; - s->first_slice_line=1; - for(s->mb_y= s->end_mb_y-1; s->mb_y >= s->start_mb_y; s->mb_y--) { - for(s->mb_x=s->mb_width-1; s->mb_x >=0 ;s->mb_x--) { - ff_pre_estimate_p_frame_motion(s, s->mb_x, s->mb_y); - } - s->first_slice_line=0; + s->me.pre_pass = 1; + s->me.dia_size = s->c.avctx->pre_dia_size; + s->c.first_slice_line = 1; + for (s->c.mb_y = s->c.end_mb_y - 1; s->c.mb_y >= s->c.start_mb_y; s->c.mb_y--) { + for (s->c.mb_x = s->c.mb_width - 1; s->c.mb_x >=0 ; s->c.mb_x--) + ff_pre_estimate_p_frame_motion(s, s->c.mb_x, s->c.mb_y); + s->c.first_slice_line = 0; } - s->me.pre_pass=0; + s->me.pre_pass = 0; return 0; } static int estimate_motion_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; + MPVEncContext *const s = *(void**)arg; - s->me.dia_size= s->avctx->dia_size; - s->first_slice_line=1; - for(s->mb_y= s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { - s->mb_x=0; //for block init below - ff_init_block_index(s); - for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { - s->block_index[0]+=2; - s->block_index[1]+=2; - s->block_index[2]+=2; - s->block_index[3]+=2; + s->me.dia_size = s->c.avctx->dia_size; + s->c.first_slice_line = 1; + for (s->c.mb_y = s->c.start_mb_y; s->c.mb_y < s->c.end_mb_y; s->c.mb_y++) { + s->c.mb_x = 0; //for block init below + ff_init_block_index(&s->c); + for (s->c.mb_x = 0; s->c.mb_x < s->c.mb_width; s->c.mb_x++) { + s->c.block_index[0] += 2; + s->c.block_index[1] += 2; + s->c.block_index[2] += 2; + s->c.block_index[3] += 2; /* compute motion vector & mb_type and store in context */ - if(s->pict_type==AV_PICTURE_TYPE_B) - ff_estimate_b_frame_motion(s, s->mb_x, s->mb_y); + if (s->c.pict_type == AV_PICTURE_TYPE_B) + ff_estimate_b_frame_motion(s, s->c.mb_x, s->c.mb_y); else - ff_estimate_p_frame_motion(s, s->mb_x, s->mb_y); + ff_estimate_p_frame_motion(s, s->c.mb_x, s->c.mb_y); } - s->first_slice_line=0; + s->c.first_slice_line = 0; } return 0; } static int mb_var_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; - int mb_x, mb_y; + MPVEncContext *const s = *(void**)arg; - for(mb_y=s->start_mb_y; mb_y < s->end_mb_y; mb_y++) { - for(mb_x=0; mb_x < s->mb_width; mb_x++) { + for (int mb_y = s->c.start_mb_y; mb_y < s->c.end_mb_y; mb_y++) { + for (int mb_x = 0; mb_x < s->c.mb_width; mb_x++) { int xx = mb_x * 16; int yy = mb_y * 16; - const uint8_t *pix = s->new_pic->data[0] + (yy * s->linesize) + xx; + const uint8_t *pix = s->new_pic->data[0] + (yy * s->c.linesize) + xx; int varc; - int sum = s->mpvencdsp.pix_sum(pix, s->linesize); + int sum = s->mpvencdsp.pix_sum(pix, s->c.linesize); - varc = (s->mpvencdsp.pix_norm1(pix, s->linesize) - + varc = (s->mpvencdsp.pix_norm1(pix, s->c.linesize) - (((unsigned) sum * sum) >> 8) + 500 + 128) >> 8; - s->mb_var [s->mb_stride * mb_y + mb_x] = varc; - s->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; + s->mb_var [s->c.mb_stride * mb_y + mb_x] = varc; + s->mb_mean[s->c.mb_stride * mb_y + mb_x] = (sum+128)>>8; s->me.mb_var_sum_temp += varc; } } return 0; } -static void write_slice_end(MpegEncContext *s){ - if(CONFIG_MPEG4_ENCODER && s->codec_id==AV_CODEC_ID_MPEG4){ - if(s->partitioned_frame){ +static void write_slice_end(MPVEncContext *const s) +{ + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) { + if (s->partitioned_frame) ff_mpeg4_merge_partitions(s); - } ff_mpeg4_stuffing(&s->pb); } else if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && - s->out_format == FMT_MJPEG) { + s->c.out_format == FMT_MJPEG) { ff_mjpeg_encode_stuffing(s); - } else if (CONFIG_SPEEDHQ_ENCODER && s->out_format == FMT_SPEEDHQ) { + } else if (CONFIG_SPEEDHQ_ENCODER && s->c.out_format == FMT_SPEEDHQ) { ff_speedhq_end_slice(s); } flush_put_bits(&s->pb); - if ((s->avctx->flags & AV_CODEC_FLAG_PASS1) && !s->partitioned_frame) + if ((s->c.avctx->flags & AV_CODEC_FLAG_PASS1) && !s->partitioned_frame) s->misc_bits+= get_bits_diff(s); } -static void write_mb_info(MpegEncContext *s) +static void write_mb_info(MPVEncContext *const s) { uint8_t *ptr = s->mb_info_ptr + s->mb_info_size - 12; int offset = put_bits_count(&s->pb); - int mba = s->mb_x + s->mb_width * (s->mb_y % s->gob_index); - int gobn = s->mb_y / s->gob_index; + int mba = s->c.mb_x + s->c.mb_width * (s->c.mb_y % s->gob_index); + int gobn = s->c.mb_y / s->gob_index; int pred_x, pred_y; if (CONFIG_H263_ENCODER) - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); bytestream_put_le32(&ptr, offset); - bytestream_put_byte(&ptr, s->qscale); + bytestream_put_byte(&ptr, s->c.qscale); bytestream_put_byte(&ptr, gobn); bytestream_put_le16(&ptr, mba); bytestream_put_byte(&ptr, pred_x); /* hmv1 */ @@ -2803,7 +2931,7 @@ static void write_mb_info(MpegEncContext *s) bytestream_put_byte(&ptr, 0); /* vmv2 */ } -static void update_mb_info(MpegEncContext *s, int startcode) +static void update_mb_info(MPVEncContext *const s, int startcode) { if (!s->mb_info) return; @@ -2826,32 +2954,32 @@ static void update_mb_info(MpegEncContext *s, int startcode) write_mb_info(s); } -int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase) +int ff_mpv_reallocate_putbitbuffer(MPVEncContext *const s, size_t threshold, size_t size_increase) { if (put_bytes_left(&s->pb, 0) < threshold - && s->slice_context_count == 1 - && s->pb.buf == s->avctx->internal->byte_buffer) { + && s->c.slice_context_count == 1 + && s->pb.buf == s->c.avctx->internal->byte_buffer) { int lastgob_pos = s->ptr_lastgob - s->pb.buf; uint8_t *new_buffer = NULL; int new_buffer_size = 0; - if ((s->avctx->internal->byte_buffer_size + size_increase) >= INT_MAX/8) { - av_log(s->avctx, AV_LOG_ERROR, "Cannot reallocate putbit buffer\n"); + if ((s->c.avctx->internal->byte_buffer_size + size_increase) >= INT_MAX/8) { + av_log(s->c.avctx, AV_LOG_ERROR, "Cannot reallocate putbit buffer\n"); return AVERROR(ENOMEM); } emms_c(); av_fast_padded_malloc(&new_buffer, &new_buffer_size, - s->avctx->internal->byte_buffer_size + size_increase); + s->c.avctx->internal->byte_buffer_size + size_increase); if (!new_buffer) return AVERROR(ENOMEM); - memcpy(new_buffer, s->avctx->internal->byte_buffer, s->avctx->internal->byte_buffer_size); - av_free(s->avctx->internal->byte_buffer); - s->avctx->internal->byte_buffer = new_buffer; - s->avctx->internal->byte_buffer_size = new_buffer_size; + memcpy(new_buffer, s->c.avctx->internal->byte_buffer, s->c.avctx->internal->byte_buffer_size); + av_free(s->c.avctx->internal->byte_buffer); + s->c.avctx->internal->byte_buffer = new_buffer; + s->c.avctx->internal->byte_buffer_size = new_buffer_size; rebase_put_bits(&s->pb, new_buffer, new_buffer_size); s->ptr_lastgob = s->pb.buf + lastgob_pos; } @@ -2861,20 +2989,20 @@ int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t s } static int encode_thread(AVCodecContext *c, void *arg){ - MpegEncContext *s= *(void**)arg; - int mb_x, mb_y, mb_y_order; - int chr_h= 16>>s->chroma_y_shift; - int i, j; - MpegEncContext best_s = { 0 }, backup_s; + MPVEncContext *const s = *(void**)arg; + int chr_h = 16 >> s->c.chroma_y_shift; + int i; + MBBackup best_s = { 0 }, backup_s; uint8_t bit_buf[2][MAX_MB_BYTES]; - uint8_t bit_buf2[2][MAX_MB_BYTES]; - uint8_t bit_buf_tex[2][MAX_MB_BYTES]; + // + 2 because ff_copy_bits() overreads + uint8_t bit_buf2[2][MAX_PB2_MB_SIZE + 2]; + uint8_t bit_buf_tex[2][MAX_AC_TEX_MB_SIZE + 2]; PutBitContext pb[2], pb2[2], tex_pb[2]; for(i=0; i<2; i++){ init_put_bits(&pb [i], bit_buf [i], MAX_MB_BYTES); - init_put_bits(&pb2 [i], bit_buf2 [i], MAX_MB_BYTES); - init_put_bits(&tex_pb[i], bit_buf_tex[i], MAX_MB_BYTES); + init_put_bits(&pb2 [i], bit_buf2 [i], MAX_PB2_MB_SIZE); + init_put_bits(&tex_pb[i], bit_buf_tex[i], MAX_AC_TEX_MB_SIZE); } s->last_bits= put_bits_count(&s->pb); @@ -2887,84 +3015,75 @@ static int encode_thread(AVCodecContext *c, void *arg){ for(i=0; i<3; i++){ /* init last dc values */ /* note: quant matrix value (8) is implied here */ - s->last_dc[i] = 128 << s->intra_dc_precision; + s->c.last_dc[i] = 128 << s->c.intra_dc_precision; s->encoding_error[i] = 0; } - if(s->codec_id==AV_CODEC_ID_AMV){ - s->last_dc[0] = 128*8/13; - s->last_dc[1] = 128*8/14; - s->last_dc[2] = 128*8/14; + if (s->c.codec_id == AV_CODEC_ID_AMV) { + s->c.last_dc[0] = 128 * 8 / 13; + s->c.last_dc[1] = 128 * 8 / 14; + s->c.last_dc[2] = 128 * 8 / 14; +#if CONFIG_MPEG4_ENCODER + } else if (s->partitioned_frame) { + av_assert1(s->c.codec_id == AV_CODEC_ID_MPEG4); + ff_mpeg4_init_partitions(s); +#endif } s->mb_skip_run = 0; - memset(s->last_mv, 0, sizeof(s->last_mv)); + memset(s->c.last_mv, 0, sizeof(s->c.last_mv)); s->last_mv_dir = 0; - switch(s->codec_id){ - case AV_CODEC_ID_H263: - case AV_CODEC_ID_H263P: - case AV_CODEC_ID_FLV1: - if (CONFIG_H263_ENCODER) - s->gob_index = H263_GOB_HEIGHT(s->height); - break; - case AV_CODEC_ID_MPEG4: - if(CONFIG_MPEG4_ENCODER && s->partitioned_frame) - ff_mpeg4_init_partitions(s); - break; - } - - s->resync_mb_x=0; - s->resync_mb_y=0; - s->first_slice_line = 1; + s->c.resync_mb_x = 0; + s->c.resync_mb_y = 0; + s->c.first_slice_line = 1; s->ptr_lastgob = s->pb.buf; - for (mb_y_order = s->start_mb_y; mb_y_order < s->end_mb_y; mb_y_order++) { - if (CONFIG_SPEEDHQ_ENCODER && s->codec_id == AV_CODEC_ID_SPEEDHQ) { + for (int mb_y_order = s->c.start_mb_y; mb_y_order < s->c.end_mb_y; mb_y_order++) { + int mb_y; + if (CONFIG_SPEEDHQ_ENCODER && s->c.codec_id == AV_CODEC_ID_SPEEDHQ) { int first_in_slice; - mb_y = ff_speedhq_mb_y_order_to_mb(mb_y_order, s->mb_height, &first_in_slice); - if (first_in_slice && mb_y_order != s->start_mb_y) + mb_y = ff_speedhq_mb_y_order_to_mb(mb_y_order, s->c.mb_height, &first_in_slice); + if (first_in_slice && mb_y_order != s->c.start_mb_y) ff_speedhq_end_slice(s); - s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 1024 << s->intra_dc_precision; + s->c.last_dc[0] = s->c.last_dc[1] = s->c.last_dc[2] = 1024 << s->c.intra_dc_precision; } else { mb_y = mb_y_order; } - s->mb_x=0; - s->mb_y= mb_y; + s->c.mb_x = 0; + s->c.mb_y = mb_y; - ff_set_qscale(s, s->qscale); - ff_init_block_index(s); + ff_set_qscale(&s->c, s->c.qscale); + ff_init_block_index(&s->c); - for(mb_x=0; mb_x < s->mb_width; mb_x++) { - int xy= mb_y*s->mb_stride + mb_x; // removed const, H261 needs to adjust this - int mb_type= s->mb_type[xy]; + for (int mb_x = 0; mb_x < s->c.mb_width; mb_x++) { + int mb_type, xy; // int d; int dmin= INT_MAX; int dir; - int size_increase = s->avctx->internal->byte_buffer_size/4 - + s->mb_width*MAX_MB_BYTES; + int size_increase = s->c.avctx->internal->byte_buffer_size/4 + + s->c.mb_width*MAX_MB_BYTES; ff_mpv_reallocate_putbitbuffer(s, MAX_MB_BYTES, size_increase); if (put_bytes_left(&s->pb, 0) < MAX_MB_BYTES){ - av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "encoded frame too large\n"); return -1; } - if(s->data_partitioning){ + if (s->data_partitioning) { if (put_bytes_left(&s->pb2, 0) < MAX_MB_BYTES || put_bytes_left(&s->tex_pb, 0) < MAX_MB_BYTES) { - av_log(s->avctx, AV_LOG_ERROR, "encoded partitioned frame too large\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "encoded partitioned frame too large\n"); return -1; } } - s->mb_x = mb_x; - s->mb_y = mb_y; // moved into loop, can get changed by H.261 - ff_update_block_index(s, 8, 0, s->chroma_x_shift); + s->c.mb_x = mb_x; + s->c.mb_y = mb_y; // moved into loop, can get changed by H.261 + ff_update_block_index(&s->c, 8, 0, s->c.chroma_x_shift); - if(CONFIG_H261_ENCODER && s->codec_id == AV_CODEC_ID_H261){ + if (CONFIG_H261_ENCODER && s->c.codec_id == AV_CODEC_ID_H261) ff_h261_reorder_mb_index(s); - xy= s->mb_y*s->mb_stride + s->mb_x; - mb_type= s->mb_type[xy]; - } + xy = s->c.mb_y * s->c.mb_stride + s->c.mb_x; + mb_type = s->mb_type[xy]; /* write gob / video packet header */ if(s->rtp_mode){ @@ -2977,38 +3096,39 @@ static int encode_thread(AVCodecContext *c, void *arg){ current_packet_size >= s->rtp_payload_size && mb_y + mb_x > 0; - if(s->start_mb_y == mb_y && mb_y > 0 && mb_x==0) is_gob_start=1; + if (s->c.start_mb_y == mb_y && mb_y > 0 && mb_x == 0) is_gob_start = 1; - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_H263: case AV_CODEC_ID_H263P: - if(!s->h263_slice_structured) - if(s->mb_x || s->mb_y%s->gob_index) is_gob_start=0; + if (!s->h263_slice_structured) + if (s->c.mb_x || s->c.mb_y % s->gob_index) is_gob_start = 0; break; case AV_CODEC_ID_MPEG2VIDEO: - if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1; + if (s->c.mb_x == 0 && s->c.mb_y != 0) is_gob_start = 1; case AV_CODEC_ID_MPEG1VIDEO: - if(s->mb_skip_run) is_gob_start=0; + if (s->c.codec_id == AV_CODEC_ID_MPEG1VIDEO && s->c.mb_y >= 175 || + s->mb_skip_run) + is_gob_start=0; break; case AV_CODEC_ID_MJPEG: - if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1; + if (s->c.mb_x == 0 && s->c.mb_y != 0) is_gob_start = 1; break; } if(is_gob_start){ - if(s->start_mb_y != mb_y || mb_x!=0){ + if (s->c.start_mb_y != mb_y || mb_x != 0) { write_slice_end(s); - if(CONFIG_MPEG4_ENCODER && s->codec_id==AV_CODEC_ID_MPEG4 && s->partitioned_frame){ + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4 && s->partitioned_frame) ff_mpeg4_init_partitions(s); - } } av_assert2((put_bits_count(&s->pb)&7) == 0); current_packet_size= put_bits_ptr(&s->pb) - s->ptr_lastgob; - if (s->error_rate && s->resync_mb_x + s->resync_mb_y > 0) { - int r = put_bytes_count(&s->pb, 0) + s->picture_number + 16 + s->mb_x + s->mb_y; + if (s->error_rate && s->c.resync_mb_x + s->c.resync_mb_y > 0) { + int r = put_bytes_count(&s->pb, 0) + s->picture_number + 16 + s->c.mb_x + s->c.mb_y; int d = 100 / s->error_rate; if(r % d == 0){ current_packet_size=0; @@ -3017,22 +3137,28 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG4: if (CONFIG_MPEG4_ENCODER) { ff_mpeg4_encode_video_packet_header(s); - ff_mpeg4_clean_buffers(s); + ff_mpeg4_clean_buffers(&s->c); + ff_h263_mpeg4_reset_dc(s); } break; case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: if (CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER) { ff_mpeg1_encode_slice_header(s); - ff_mpeg1_clean_buffers(s); + ff_mpeg1_clean_buffers(&s->c); } break; - case AV_CODEC_ID_H263: +#if CONFIG_H263P_ENCODER case AV_CODEC_ID_H263P: + if (s->c.dc_val) + ff_h263_mpeg4_reset_dc(s); + // fallthrough +#endif + case AV_CODEC_ID_H263: if (CONFIG_H263_ENCODER) { update_mb_info(s, 1); ff_h263_encode_gob_header(s, mb_y); @@ -3040,25 +3166,24 @@ static int encode_thread(AVCodecContext *c, void *arg){ break; } - if (s->avctx->flags & AV_CODEC_FLAG_PASS1) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS1) { int bits= put_bits_count(&s->pb); s->misc_bits+= bits - s->last_bits; s->last_bits= bits; } - s->ptr_lastgob += current_packet_size; - s->first_slice_line=1; - s->resync_mb_x=mb_x; - s->resync_mb_y=mb_y; + s->ptr_lastgob += current_packet_size; + s->c.first_slice_line = 1; + s->c.resync_mb_x = mb_x; + s->c.resync_mb_y = mb_y; } } - if( (s->resync_mb_x == s->mb_x) - && s->resync_mb_y+1 == s->mb_y){ - s->first_slice_line=0; - } + if (s->c.resync_mb_x == s->c.mb_x && + s->c.resync_mb_y+1 == s->c.mb_y) + s->c.first_slice_line = 0; - s->mb_skipped=0; + s->c.mb_skipped = 0; s->dquant=0; //only for QP_RD update_mb_info(s, 0); @@ -3067,180 +3192,173 @@ static int encode_thread(AVCodecContext *c, void *arg){ int next_block=0; int pb_bits_count, pb2_bits_count, tex_pb_bits_count; - copy_context_before_encode(&backup_s, s); + backup_context_before_encode(&backup_s, s); backup_s.pb= s->pb; - best_s.data_partitioning= s->data_partitioning; - best_s.partitioned_frame= s->partitioned_frame; - if(s->data_partitioning){ + if (s->data_partitioning) { backup_s.pb2= s->pb2; backup_s.tex_pb= s->tex_pb; } if(mb_type&CANDIDATE_MB_TYPE_INTER){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->p_mv_table[xy][0]; - s->mv[0][0][1] = s->p_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->p_mv_table[xy][0]; + s->c.mv[0][0][1] = s->p_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER_I){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->p_field_select_table[i][xy]; - s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; - s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; + int j = s->c.field_select[0][i] = s->p_field_select_table[i][xy]; + s->c.mv[0][i][0] = s->c.p_field_mv_table[i][j][xy][0]; + s->c.mv[0][i][1] = s->c.p_field_mv_table[i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_SKIPPED){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER4V){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_8X8; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_8X8; + s->c.mb_intra = 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + s->c.mv[0][i][0] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + s->c.mv[0][i][1] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_forw_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); + &dmin, &next_block, s->c.mv[0][0][0], s->c.mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD){ - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[1][0][0] = s->b_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[1][0][0] = s->b_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[1][0][0], s->mv[1][0][1]); + &dmin, &next_block, s->c.mv[1][0][0], s->c.mv[1][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; - s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; + s->c.mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD_I){ - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; - s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; - s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; + int j = s->c.field_select[0][i] = s->b_field_select_table[0][i][xy]; + s->c.mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; + s->c.mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD_I){ - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; - s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; - s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; + int j = s->c.field_select[1][i] = s->b_field_select_table[1][i][xy]; + s->c.mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; + s->c.mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR_I){ - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ - j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; - s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; - s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; + int j = s->c.field_select[dir][i] = s->b_field_select_table[dir][i][xy]; + s->c.mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; + s->c.mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_INTRA){ - s->mv_dir = 0; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= 1; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; + s->c.mv_dir = 0; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = 1; + s->c.mv[0][0][0] = 0; + s->c.mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); - if(s->h263_pred || s->h263_aic){ - if(best_s.mb_intra) - s->mbintra_table[mb_x + mb_y*s->mb_stride]=1; - else - ff_clean_intra_table_entries(s); //old mode? - } + s->c.mbintra_table[xy] = 1; } if ((s->mpv_flags & FF_MPV_FLAG_QP_RD) && dmin < INT_MAX) { - if(best_s.mv_type==MV_TYPE_16X16){ //FIXME move 4mv after QPRD - const int last_qp= backup_s.qscale; + if (best_s.c.mv_type == MV_TYPE_16X16) { //FIXME move 4mv after QPRD + const int last_qp = backup_s.c.qscale; int qpi, qp, dc[6]; int16_t ac[6][16]; - const int mvdir= (best_s.mv_dir&MV_DIR_BACKWARD) ? 1 : 0; + const int mvdir = (best_s.c.mv_dir & MV_DIR_BACKWARD) ? 1 : 0; static const int dquant_tab[4]={-1,1,-2,2}; - int storecoefs = s->mb_intra && s->dc_val[0]; + int storecoefs = s->c.mb_intra && s->c.dc_val; av_assert2(backup_s.dquant == 0); //FIXME intra - s->mv_dir= best_s.mv_dir; - s->mv_type = MV_TYPE_16X16; - s->mb_intra= best_s.mb_intra; - s->mv[0][0][0] = best_s.mv[0][0][0]; - s->mv[0][0][1] = best_s.mv[0][0][1]; - s->mv[1][0][0] = best_s.mv[1][0][0]; - s->mv[1][0][1] = best_s.mv[1][0][1]; + s->c.mv_dir = best_s.c.mv_dir; + s->c.mv_type = MV_TYPE_16X16; + s->c.mb_intra = best_s.c.mb_intra; + s->c.mv[0][0][0] = best_s.c.mv[0][0][0]; + s->c.mv[0][0][1] = best_s.c.mv[0][0][1]; + s->c.mv[1][0][0] = best_s.c.mv[1][0][0]; + s->c.mv[1][0][1] = best_s.c.mv[1][0][1]; - qpi = s->pict_type == AV_PICTURE_TYPE_B ? 2 : 0; + qpi = s->c.pict_type == AV_PICTURE_TYPE_B ? 2 : 0; for(; qpi<4; qpi++){ int dquant= dquant_tab[qpi]; qp= last_qp + dquant; - if(qp < s->avctx->qmin || qp > s->avctx->qmax) + if (qp < s->c.avctx->qmin || qp > s->c.avctx->qmax) continue; backup_s.dquant= dquant; if(storecoefs){ for(i=0; i<6; i++){ - dc[i]= s->dc_val[0][ s->block_index[i] ]; - memcpy(ac[i], s->ac_val[0][s->block_index[i]], sizeof(int16_t)*16); + dc[i] = s->c.dc_val[s->c.block_index[i]]; + memcpy(ac[i], s->c.ac_val[s->c.block_index[i]], sizeof(*s->c.ac_val)); } } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, - &dmin, &next_block, s->mv[mvdir][0][0], s->mv[mvdir][0][1]); - if(best_s.qscale != qp){ + &dmin, &next_block, s->c.mv[mvdir][0][0], s->c.mv[mvdir][0][1]); + if (best_s.c.qscale != qp) { if(storecoefs){ for(i=0; i<6; i++){ - s->dc_val[0][ s->block_index[i] ]= dc[i]; - memcpy(s->ac_val[0][s->block_index[i]], ac[i], sizeof(int16_t)*16); + s->c.dc_val[s->c.block_index[i]] = dc[i]; + memcpy(s->c.ac_val[s->c.block_index[i]], ac[i], sizeof(*s->c.ac_val)); } } } @@ -3252,45 +3370,45 @@ static int encode_thread(AVCodecContext *c, void *arg){ int my= s->b_direct_mv_table[xy][1]; backup_s.dquant = 0; - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, mx, my); + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, mx, my); encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, mx, my); } if(CONFIG_MPEG4_ENCODER && mb_type&CANDIDATE_MB_TYPE_DIRECT0){ backup_s.dquant = 0; - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, 0, 0); + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, 0, 0); encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } - if (!best_s.mb_intra && s->mpv_flags & FF_MPV_FLAG_SKIP_RD) { + if (!best_s.c.mb_intra && s->mpv_flags & FF_MPV_FLAG_SKIP_RD) { int coded=0; for(i=0; i<6; i++) - coded |= s->block_last_index[i]; + coded |= s->c.block_last_index[i]; if(coded){ int mx,my; - memcpy(s->mv, best_s.mv, sizeof(s->mv)); - if(CONFIG_MPEG4_ENCODER && best_s.mv_dir & MV_DIRECT){ + memcpy(s->c.mv, best_s.c.mv, sizeof(s->c.mv)); + if (CONFIG_MPEG4_ENCODER && best_s.c.mv_dir & MV_DIRECT) { mx=my=0; //FIXME find the one we actually used - ff_mpeg4_set_direct_mv(s, mx, my); - }else if(best_s.mv_dir&MV_DIR_BACKWARD){ - mx= s->mv[1][0][0]; - my= s->mv[1][0][1]; + ff_mpeg4_set_direct_mv(&s->c, mx, my); + } else if (best_s.c.mv_dir & MV_DIR_BACKWARD) { + mx = s->c.mv[1][0][0]; + my = s->c.mv[1][0][1]; }else{ - mx= s->mv[0][0][0]; - my= s->mv[0][0][1]; + mx = s->c.mv[0][0][0]; + my = s->c.mv[0][0][1]; } - s->mv_dir= best_s.mv_dir; - s->mv_type = best_s.mv_type; - s->mb_intra= 0; -/* s->mv[0][0][0] = best_s.mv[0][0][0]; - s->mv[0][0][1] = best_s.mv[0][0][1]; - s->mv[1][0][0] = best_s.mv[1][0][0]; - s->mv[1][0][1] = best_s.mv[1][0][1];*/ + s->c.mv_dir = best_s.c.mv_dir; + s->c.mv_type = best_s.c.mv_type; + s->c.mb_intra = 0; +/* s->c.mv[0][0][0] = best_s.mv[0][0][0]; + s->c.mv[0][0][1] = best_s.mv[0][0][1]; + s->c.mv[1][0][0] = best_s.mv[1][0][0]; + s->c.mv[1][0][1] = best_s.mv[1][0][1];*/ backup_s.dquant= 0; s->skipdct=1; encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, @@ -3299,16 +3417,14 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - s->cur_pic.qscale_table[xy] = best_s.qscale; - - copy_context_after_encode(s, &best_s); + store_context_after_encode(s, &best_s, s->data_partitioning); pb_bits_count= put_bits_count(&s->pb); flush_put_bits(&s->pb); ff_copy_bits(&backup_s.pb, bit_buf[next_block^1], pb_bits_count); s->pb= backup_s.pb; - if(s->data_partitioning){ + if (s->data_partitioning) { pb2_bits_count= put_bits_count(&s->pb2); flush_put_bits(&s->pb2); ff_copy_bits(&backup_s.pb2, bit_buf2[next_block^1], pb2_bits_count); @@ -3322,174 +3438,184 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->last_bits= put_bits_count(&s->pb); if (CONFIG_H263_ENCODER && - s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) + s->c.out_format == FMT_H263 && s->c.pict_type != AV_PICTURE_TYPE_B) ff_h263_update_mb(s); if(next_block==0){ //FIXME 16 vs linesize16 - s->hdsp.put_pixels_tab[0][0](s->dest[0], s->sc.rd_scratchpad , s->linesize ,16); - s->hdsp.put_pixels_tab[1][0](s->dest[1], s->sc.rd_scratchpad + 16*s->linesize , s->uvlinesize, 8); - s->hdsp.put_pixels_tab[1][0](s->dest[2], s->sc.rd_scratchpad + 16*s->linesize + 8, s->uvlinesize, 8); + s->c.hdsp.put_pixels_tab[0][0](s->c.dest[0], s->c.sc.rd_scratchpad , s->c.linesize ,16); + s->c.hdsp.put_pixels_tab[1][0](s->c.dest[1], s->c.sc.rd_scratchpad + 16*s->c.linesize , s->c.uvlinesize, 8); + s->c.hdsp.put_pixels_tab[1][0](s->c.dest[2], s->c.sc.rd_scratchpad + 16*s->c.linesize + 8, s->c.uvlinesize, 8); } - if(s->avctx->mb_decision == FF_MB_DECISION_BITS) + if (s->c.avctx->mb_decision == FF_MB_DECISION_BITS) mpv_reconstruct_mb(s, s->block); } else { int motion_x = 0, motion_y = 0; - s->mv_type=MV_TYPE_16X16; + s->c.mv_type = MV_TYPE_16X16; // only one MB-Type possible switch(mb_type){ case CANDIDATE_MB_TYPE_INTRA: - s->mv_dir = 0; - s->mb_intra= 1; - motion_x= s->mv[0][0][0] = 0; - motion_y= s->mv[0][0][1] = 0; + s->c.mv_dir = 0; + s->c.mb_intra = 1; + motion_x= s->c.mv[0][0][0] = 0; + motion_y= s->c.mv[0][0][1] = 0; + s->c.mbintra_table[xy] = 1; break; case CANDIDATE_MB_TYPE_INTER: - s->mv_dir = MV_DIR_FORWARD; - s->mb_intra= 0; - motion_x= s->mv[0][0][0] = s->p_mv_table[xy][0]; - motion_y= s->mv[0][0][1] = s->p_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[0][0][0] = s->p_mv_table[xy][0]; + motion_y= s->c.mv[0][0][1] = s->p_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_INTER_I: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->p_field_select_table[i][xy]; - s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; - s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; + int j = s->c.field_select[0][i] = s->p_field_select_table[i][xy]; + s->c.mv[0][i][0] = s->c.p_field_mv_table[i][j][xy][0]; + s->c.mv[0][i][1] = s->c.p_field_mv_table[i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_INTER4V: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_8X8; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_8X8; + s->c.mb_intra = 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1]; + s->c.mv[0][i][0] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][0]; + s->c.mv[0][i][1] = s->c.cur_pic.motion_val[0][s->c.block_index[i]][1]; } break; case CANDIDATE_MB_TYPE_DIRECT: if (CONFIG_MPEG4_ENCODER) { - s->mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; + s->c.mb_intra = 0; motion_x=s->b_direct_mv_table[xy][0]; motion_y=s->b_direct_mv_table[xy][1]; - ff_mpeg4_set_direct_mv(s, motion_x, motion_y); + ff_mpeg4_set_direct_mv(&s->c, motion_x, motion_y); } break; case CANDIDATE_MB_TYPE_DIRECT0: if (CONFIG_MPEG4_ENCODER) { - s->mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; - s->mb_intra= 0; - ff_mpeg4_set_direct_mv(s, 0, 0); + s->c.mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD|MV_DIRECT; + s->c.mb_intra = 0; + ff_mpeg4_set_direct_mv(&s->c, 0, 0); } break; case CANDIDATE_MB_TYPE_BIDIR: - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mb_intra= 0; - s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; - s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; - s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; - s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mb_intra = 0; + s->c.mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; + s->c.mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; + s->c.mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; + s->c.mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_BACKWARD: - s->mv_dir = MV_DIR_BACKWARD; - s->mb_intra= 0; - motion_x= s->mv[1][0][0] = s->b_back_mv_table[xy][0]; - motion_y= s->mv[1][0][1] = s->b_back_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[1][0][0] = s->b_back_mv_table[xy][0]; + motion_y= s->c.mv[1][0][1] = s->b_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_FORWARD: - s->mv_dir = MV_DIR_FORWARD; - s->mb_intra= 0; - motion_x= s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; - motion_y= s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mb_intra = 0; + motion_x= s->c.mv[0][0][0] = s->b_forw_mv_table[xy][0]; + motion_y= s->c.mv[0][0][1] = s->b_forw_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_FORWARD_I: - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; - s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; - s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; + int j = s->c.field_select[0][i] = s->b_field_select_table[0][i][xy]; + s->c.mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; + s->c.mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_BACKWARD_I: - s->mv_dir = MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(i=0; i<2; i++){ - j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; - s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; - s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; + int j = s->c.field_select[1][i] = s->b_field_select_table[1][i][xy]; + s->c.mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; + s->c.mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } break; case CANDIDATE_MB_TYPE_BIDIR_I: - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - s->mv_type = MV_TYPE_FIELD; - s->mb_intra= 0; + s->c.mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + s->c.mv_type = MV_TYPE_FIELD; + s->c.mb_intra = 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ - j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; - s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; - s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; + int j = s->c.field_select[dir][i] = s->b_field_select_table[dir][i][xy]; + s->c.mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; + s->c.mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } break; default: - av_log(s->avctx, AV_LOG_ERROR, "illegal MB type\n"); + av_unreachable("There is a case for every CANDIDATE_MB_TYPE_* " + "except CANDIDATE_MB_TYPE_SKIPPED which is never " + "the only candidate (always coupled with INTER) " + "so that it never reaches this switch"); } encode_mb(s, motion_x, motion_y); // RAL: Update last macroblock type - s->last_mv_dir = s->mv_dir; + s->last_mv_dir = s->c.mv_dir; if (CONFIG_H263_ENCODER && - s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) + s->c.out_format == FMT_H263 && s->c.pict_type != AV_PICTURE_TYPE_B) ff_h263_update_mb(s); mpv_reconstruct_mb(s, s->block); } + s->c.cur_pic.qscale_table[xy] = s->c.qscale; + /* clean the MV table in IPS frames for direct mode in B-frames */ - if(s->mb_intra /* && I,P,S_TYPE */){ + if (s->c.mb_intra /* && I,P,S_TYPE */) { s->p_mv_table[xy][0]=0; s->p_mv_table[xy][1]=0; +#if CONFIG_H263_ENCODER + } else if (s->c.h263_pred || s->c.h263_aic) { + ff_h263_clean_intra_table_entries(&s->c, xy); +#endif } - if (s->avctx->flags & AV_CODEC_FLAG_PSNR) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PSNR) { int w= 16; int h= 16; - if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; - if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; + if (s->c.mb_x*16 + 16 > s->c.width ) w = s->c.width - s->c.mb_x*16; + if (s->c.mb_y*16 + 16 > s->c.height) h = s->c.height- s->c.mb_y*16; s->encoding_error[0] += sse( - s, s->new_pic->data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, - s->dest[0], w, h, s->linesize); + s, s->new_pic->data[0] + s->c.mb_x*16 + s->c.mb_y*s->c.linesize*16, + s->c.dest[0], w, h, s->c.linesize); s->encoding_error[1] += sse( - s, s->new_pic->data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, - s->dest[1], w>>1, h>>s->chroma_y_shift, s->uvlinesize); + s, s->new_pic->data[1] + s->c.mb_x*8 + s->c.mb_y*s->c.uvlinesize*chr_h, + s->c.dest[1], w>>1, h>>s->c.chroma_y_shift, s->c.uvlinesize); s->encoding_error[2] += sse( - s, s->new_pic->data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, - s->dest[2], w>>1, h>>s->chroma_y_shift, s->uvlinesize); + s, s->new_pic->data[2] + s->c.mb_x*8 + s->c.mb_y*s->c.uvlinesize*chr_h, + s->c.dest[2], w>>1, h>>s->c.chroma_y_shift, s->c.uvlinesize); } - if(s->loop_filter){ - if(CONFIG_H263_ENCODER && s->out_format == FMT_H263) - ff_h263_loop_filter(s); + if (s->loop_filter) { + if (CONFIG_H263_ENCODER && s->c.out_format == FMT_H263) + ff_h263_loop_filter(&s->c); } - ff_dlog(s->avctx, "MB %d %d bits\n", - s->mb_x + s->mb_y * s->mb_stride, put_bits_count(&s->pb)); + ff_dlog(s->c.avctx, "MB %d %d bits\n", + s->c.mb_x + s->c.mb_y * s->c.mb_stride, put_bits_count(&s->pb)); } } #if CONFIG_MSMPEG4ENC //not beautiful here but we must write it before flushing so it has to be here - if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && - s->pict_type == AV_PICTURE_TYPE_I) + if (s->c.msmpeg4_version != MSMP4_UNUSED && s->c.msmpeg4_version < MSMP4_WMV1 && + s->c.pict_type == AV_PICTURE_TYPE_I) ff_msmpeg4_encode_ext_header(s); #endif @@ -3498,28 +3624,31 @@ static int encode_thread(AVCodecContext *c, void *arg){ return 0; } +#define ADD(field) dst->field += src->field; #define MERGE(field) dst->field += src->field; src->field=0 -static void merge_context_after_me(MpegEncContext *dst, MpegEncContext *src){ - MERGE(me.scene_change_score); - MERGE(me.mc_mb_var_sum_temp); - MERGE(me.mb_var_sum_temp); +static void merge_context_after_me(MPVEncContext *const dst, MPVEncContext *const src) +{ + ADD(me.scene_change_score); + ADD(me.mc_mb_var_sum_temp); + ADD(me.mb_var_sum_temp); } -static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src){ +static void merge_context_after_encode(MPVEncContext *const dst, MPVEncContext *const src) +{ int i; MERGE(dct_count[0]); //note, the other dct vars are not part of the context MERGE(dct_count[1]); - MERGE(mv_bits); - MERGE(i_tex_bits); - MERGE(p_tex_bits); - MERGE(i_count); - MERGE(misc_bits); - MERGE(encoding_error[0]); - MERGE(encoding_error[1]); - MERGE(encoding_error[2]); + ADD(mv_bits); + ADD(i_tex_bits); + ADD(p_tex_bits); + ADD(i_count); + ADD(misc_bits); + ADD(encoding_error[0]); + ADD(encoding_error[1]); + ADD(encoding_error[2]); - if (dst->noise_reduction){ + if (dst->dct_error_sum) { for(i=0; i<64; i++){ MERGE(dct_error_sum[0][i]); MERGE(dct_error_sum[1][i]); @@ -3532,21 +3661,24 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src) flush_put_bits(&dst->pb); } -static int estimate_qp(MpegEncContext *s, int dry_run){ - if (s->next_lambda){ - s->cur_pic.ptr->f->quality = s->next_lambda; - if(!dry_run) s->next_lambda= 0; - } else if (!s->fixed_qscale) { - int quality = ff_rate_estimate_qscale(s, dry_run); - s->cur_pic.ptr->f->quality = quality; - if (s->cur_pic.ptr->f->quality < 0) +static int estimate_qp(MPVMainEncContext *const m, int dry_run) +{ + MPVEncContext *const s = &m->s; + + if (m->next_lambda){ + s->c.cur_pic.ptr->f->quality = m->next_lambda; + if(!dry_run) m->next_lambda= 0; + } else if (!m->fixed_qscale) { + int quality = ff_rate_estimate_qscale(m, dry_run); + s->c.cur_pic.ptr->f->quality = quality; + if (s->c.cur_pic.ptr->f->quality < 0) return -1; } if(s->adaptive_quant){ init_qscale_tab(s); - switch(s->codec_id){ + switch (s->c.codec_id) { case AV_CODEC_ID_MPEG4: if (CONFIG_MPEG4_ENCODER) ff_clean_mpeg4_qscales(s); @@ -3559,174 +3691,166 @@ static int estimate_qp(MpegEncContext *s, int dry_run){ break; } - s->lambda= s->lambda_table[0]; + s->lambda = s->lambda_table[0]; //FIXME broken }else - s->lambda = s->cur_pic.ptr->f->quality; - update_qscale(s); + s->lambda = s->c.cur_pic.ptr->f->quality; + update_qscale(m); return 0; } /* must be called before writing the header */ -static void set_frame_distances(MpegEncContext * s){ - av_assert1(s->cur_pic.ptr->f->pts != AV_NOPTS_VALUE); - s->time = s->cur_pic.ptr->f->pts * s->avctx->time_base.num; +static void set_frame_distances(MPVEncContext *const s) +{ + av_assert1(s->c.cur_pic.ptr->f->pts != AV_NOPTS_VALUE); + s->c.time = s->c.cur_pic.ptr->f->pts * s->c.avctx->time_base.num; - if(s->pict_type==AV_PICTURE_TYPE_B){ - s->pb_time= s->pp_time - (s->last_non_b_time - s->time); - av_assert1(s->pb_time > 0 && s->pb_time < s->pp_time); + if (s->c.pict_type == AV_PICTURE_TYPE_B) { + s->c.pb_time = s->c.pp_time - (s->c.last_non_b_time - s->c.time); + av_assert1(s->c.pb_time > 0 && s->c.pb_time < s->c.pp_time); }else{ - s->pp_time= s->time - s->last_non_b_time; - s->last_non_b_time= s->time; - av_assert1(s->picture_number==0 || s->pp_time > 0); + s->c.pp_time = s->c.time - s->c.last_non_b_time; + s->c.last_non_b_time = s->c.time; + av_assert1(s->picture_number == 0 || s->c.pp_time > 0); } } -static int encode_picture(MpegEncContext *s, const AVPacket *pkt) +static int encode_picture(MPVMainEncContext *const m, const AVPacket *pkt) { + MPVEncContext *const s = &m->s; int i, ret; int bits; - int context_count = s->slice_context_count; - - /* Reset the average MB variance */ - s->me.mb_var_sum_temp = - s->me.mc_mb_var_sum_temp = 0; + int context_count = s->c.slice_context_count; /* we need to initialize some time vars before we can encode B-frames */ // RAL: Condition added for MPEG1VIDEO - if (s->out_format == FMT_MPEG1 || (s->h263_pred && s->msmpeg4_version == MSMP4_UNUSED)) + if (s->c.out_format == FMT_MPEG1 || (s->c.h263_pred && s->c.msmpeg4_version == MSMP4_UNUSED)) set_frame_distances(s); - if(CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4) + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) ff_set_mpeg4_time(s); - s->me.scene_change_score=0; +// s->lambda = s->c.cur_pic.ptr->quality; //FIXME qscale / ... stuff for ME rate distortion -// s->lambda= s->cur_pic.ptr->quality; //FIXME qscale / ... stuff for ME rate distortion - - if(s->pict_type==AV_PICTURE_TYPE_I){ - s->no_rounding = s->msmpeg4_version >= MSMP4_V3; - }else if(s->pict_type!=AV_PICTURE_TYPE_B){ - s->no_rounding ^= s->flipflop_rounding; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->c.no_rounding = s->c.msmpeg4_version >= MSMP4_V3; + } else if (s->c.pict_type != AV_PICTURE_TYPE_B) { + s->c.no_rounding ^= s->flipflop_rounding; } - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { - if (estimate_qp(s,1) < 0) - return -1; - ff_get_2pass_fcode(s); - } else if (!(s->avctx->flags & AV_CODEC_FLAG_QSCALE)) { - if(s->pict_type==AV_PICTURE_TYPE_B) - s->lambda= s->last_lambda_for[s->pict_type]; + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { + ret = estimate_qp(m, 1); + if (ret < 0) + return ret; + ff_get_2pass_fcode(m); + } else if (!(s->c.avctx->flags & AV_CODEC_FLAG_QSCALE)) { + if (s->c.pict_type == AV_PICTURE_TYPE_B) + s->lambda = m->last_lambda_for[s->c.pict_type]; else - s->lambda= s->last_lambda_for[s->last_non_b_pict_type]; - update_qscale(s); + s->lambda = m->last_lambda_for[m->last_non_b_pict_type]; + update_qscale(m); } - if (s->out_format != FMT_MJPEG) { - if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix); - if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16); - s->q_chroma_intra_matrix = s->q_intra_matrix; - s->q_chroma_intra_matrix16 = s->q_intra_matrix16; - } - - ff_me_init_pic(s); - - s->mb_intra=0; //for the rate distortion & bit compare functions + s->c.mb_intra = 0; //for the rate distortion & bit compare functions for (int i = 0; i < context_count; i++) { - MpegEncContext *const slice = s->thread_context[i]; - uint8_t *start, *end; - int h; + MPVEncContext *const slice = s->c.enc_contexts[i]; + int h = s->c.mb_height; + uint8_t *start = pkt->data + (int64_t)pkt->size * slice->c.start_mb_y / h; + uint8_t *end = pkt->data + (int64_t)pkt->size * slice->c. end_mb_y / h; + + init_put_bits(&slice->pb, start, end - start); if (i) { - ret = ff_update_duplicate_context(slice, s); + ret = ff_update_duplicate_context(&slice->c, &s->c); if (ret < 0) return ret; + slice->lambda = s->lambda; + slice->lambda2 = s->lambda2; } - slice->me.temp = slice->me.scratchpad = slice->sc.scratchpad_buf; - - h = s->mb_height; - start = pkt->data + (size_t)(((int64_t) pkt->size) * slice->start_mb_y / h); - end = pkt->data + (size_t)(((int64_t) pkt->size) * slice-> end_mb_y / h); - - init_put_bits(&s->thread_context[i]->pb, start, end - start); + slice->me.temp = slice->me.scratchpad = slice->c.sc.scratchpad_buf; + ff_me_init_pic(slice); } /* Estimate motion for every MB */ - if(s->pict_type != AV_PICTURE_TYPE_I){ - s->lambda = (s->lambda * s->me_penalty_compensation + 128) >> 8; - s->lambda2 = (s->lambda2 * (int64_t) s->me_penalty_compensation + 128) >> 8; - if (s->pict_type != AV_PICTURE_TYPE_B) { - if ((s->me_pre && s->last_non_b_pict_type == AV_PICTURE_TYPE_I) || - s->me_pre == 2) { - s->avctx->execute(s->avctx, pre_estimate_motion_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + if (s->c.pict_type != AV_PICTURE_TYPE_I) { + s->lambda = (s->lambda * m->me_penalty_compensation + 128) >> 8; + s->lambda2 = (s->lambda2 * (int64_t) m->me_penalty_compensation + 128) >> 8; + if (s->c.pict_type != AV_PICTURE_TYPE_B) { + if ((m->me_pre && m->last_non_b_pict_type == AV_PICTURE_TYPE_I) || + m->me_pre == 2) { + s->c.avctx->execute(s->c.avctx, pre_estimate_motion_thread, + &s->c.enc_contexts[0], NULL, + context_count, sizeof(void*)); } } - s->avctx->execute(s->avctx, estimate_motion_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); - }else /* if(s->pict_type == AV_PICTURE_TYPE_I) */{ + s->c.avctx->execute(s->c.avctx, estimate_motion_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); + }else /* if (s->c.pict_type == AV_PICTURE_TYPE_I) */{ /* I-Frame */ - for(i=0; imb_stride*s->mb_height; i++) + for (int i = 0; i < s->c.mb_stride * s->c.mb_height; i++) s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; - if(!s->fixed_qscale){ + if (!m->fixed_qscale) { /* finding spatial complexity for I-frame rate control */ - s->avctx->execute(s->avctx, mb_var_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + s->c.avctx->execute(s->c.avctx, mb_var_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); } } for(i=1; ithread_context[i]); + merge_context_after_me(s, s->c.enc_contexts[i]); } - s->mc_mb_var_sum = s->me.mc_mb_var_sum_temp; - s->mb_var_sum = s->me. mb_var_sum_temp; + m->mc_mb_var_sum = s->me.mc_mb_var_sum_temp; + m->mb_var_sum = s->me. mb_var_sum_temp; emms_c(); - if (s->me.scene_change_score > s->scenechange_threshold && - s->pict_type == AV_PICTURE_TYPE_P) { - s->pict_type= AV_PICTURE_TYPE_I; - for(i=0; imb_stride*s->mb_height; i++) - s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; - if (s->msmpeg4_version >= MSMP4_V3) - s->no_rounding=1; - ff_dlog(s, "Scene change detected, encoding as I Frame %"PRId64" %"PRId64"\n", - s->mb_var_sum, s->mc_mb_var_sum); + if (s->me.scene_change_score > m->scenechange_threshold && + s->c.pict_type == AV_PICTURE_TYPE_P) { + s->c.pict_type = AV_PICTURE_TYPE_I; + for (int i = 0; i < s->c.mb_stride * s->c.mb_height; i++) + s->mb_type[i] = CANDIDATE_MB_TYPE_INTRA; + if (s->c.msmpeg4_version >= MSMP4_V3) + s->c.no_rounding = 1; + ff_dlog(s->c.avctx, "Scene change detected, encoding as I Frame %"PRId64" %"PRId64"\n", + m->mb_var_sum, m->mc_mb_var_sum); } - if(!s->umvplus){ - if(s->pict_type==AV_PICTURE_TYPE_P || s->pict_type==AV_PICTURE_TYPE_S) { - s->f_code= ff_get_best_fcode(s, s->p_mv_table, CANDIDATE_MB_TYPE_INTER); + if (!s->umvplus) { + if (s->c.pict_type == AV_PICTURE_TYPE_P || s->c.pict_type == AV_PICTURE_TYPE_S) { + s->f_code = ff_get_best_fcode(m, s->p_mv_table, CANDIDATE_MB_TYPE_INTER); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int a,b; - a= ff_get_best_fcode(s, s->p_field_mv_table[0][0], CANDIDATE_MB_TYPE_INTER_I); //FIXME field_select - b= ff_get_best_fcode(s, s->p_field_mv_table[1][1], CANDIDATE_MB_TYPE_INTER_I); - s->f_code= FFMAX3(s->f_code, a, b); + a = ff_get_best_fcode(m, s->c.p_field_mv_table[0][0], CANDIDATE_MB_TYPE_INTER_I); //FIXME field_select + b = ff_get_best_fcode(m, s->c.p_field_mv_table[1][1], CANDIDATE_MB_TYPE_INTER_I); + s->f_code = FFMAX3(s->f_code, a, b); } ff_fix_long_p_mvs(s, s->intra_penalty ? CANDIDATE_MB_TYPE_INTER : CANDIDATE_MB_TYPE_INTRA); ff_fix_long_mvs(s, NULL, 0, s->p_mv_table, s->f_code, CANDIDATE_MB_TYPE_INTER, !!s->intra_penalty); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int j; for(i=0; i<2; i++){ for(j=0; j<2; j++) ff_fix_long_mvs(s, s->p_field_select_table[i], j, - s->p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, !!s->intra_penalty); + s->c.p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, !!s->intra_penalty); } } - } else if (s->pict_type == AV_PICTURE_TYPE_B) { + } else if (s->c.pict_type == AV_PICTURE_TYPE_B) { int a, b; - a = ff_get_best_fcode(s, s->b_forw_mv_table, CANDIDATE_MB_TYPE_FORWARD); - b = ff_get_best_fcode(s, s->b_bidir_forw_mv_table, CANDIDATE_MB_TYPE_BIDIR); + a = ff_get_best_fcode(m, s->b_forw_mv_table, CANDIDATE_MB_TYPE_FORWARD); + b = ff_get_best_fcode(m, s->b_bidir_forw_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->f_code = FFMAX(a, b); - a = ff_get_best_fcode(s, s->b_back_mv_table, CANDIDATE_MB_TYPE_BACKWARD); - b = ff_get_best_fcode(s, s->b_bidir_back_mv_table, CANDIDATE_MB_TYPE_BIDIR); + a = ff_get_best_fcode(m, s->b_back_mv_table, CANDIDATE_MB_TYPE_BACKWARD); + b = ff_get_best_fcode(m, s->b_bidir_back_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->b_code = FFMAX(a, b); ff_fix_long_mvs(s, NULL, 0, s->b_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_FORWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BACKWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_BIDIR, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BIDIR, 1); - if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { + if (s->c.avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { int dir, j; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ @@ -3742,137 +3866,99 @@ static int encode_picture(MpegEncContext *s, const AVPacket *pkt) } } - if (estimate_qp(s, 0) < 0) - return -1; + ret = estimate_qp(m, 0); + if (ret < 0) + return ret; - if (s->qscale < 3 && s->max_qcoeff <= 128 && - s->pict_type == AV_PICTURE_TYPE_I && - !(s->avctx->flags & AV_CODEC_FLAG_QSCALE)) - s->qscale= 3; //reduce clipping problems + if (s->c.qscale < 3 && s->max_qcoeff <= 128 && + s->c.pict_type == AV_PICTURE_TYPE_I && + !(s->c.avctx->flags & AV_CODEC_FLAG_QSCALE)) + s->c.qscale = 3; //reduce clipping problems - if (s->out_format == FMT_MJPEG) { - const uint16_t * luma_matrix = ff_mpeg1_default_intra_matrix; - const uint16_t *chroma_matrix = ff_mpeg1_default_intra_matrix; + if (s->c.out_format == FMT_MJPEG) { + ret = ff_check_codec_matrices(s->c.avctx, FF_MATRIX_TYPE_INTRA | FF_MATRIX_TYPE_CHROMA_INTRA, + (7 + s->c.qscale) / s->c.qscale, 65535); + if (ret < 0) + return ret; - if (s->avctx->intra_matrix) { - chroma_matrix = - luma_matrix = s->avctx->intra_matrix; - } - if (s->avctx->chroma_intra_matrix) - chroma_matrix = s->avctx->chroma_intra_matrix; + if (s->c.codec_id != AV_CODEC_ID_AMV) { + const uint16_t * luma_matrix = ff_mpeg1_default_intra_matrix; + const uint16_t *chroma_matrix = ff_mpeg1_default_intra_matrix; - /* for mjpeg, we do include qscale in the matrix */ - for(i=1;i<64;i++){ - int j = s->idsp.idct_permutation[i]; + if (s->c.avctx->intra_matrix) { + chroma_matrix = + luma_matrix = s->c.avctx->intra_matrix; + } + if (s->c.avctx->chroma_intra_matrix) + chroma_matrix = s->c.avctx->chroma_intra_matrix; - s->chroma_intra_matrix[j] = av_clip_uint8((chroma_matrix[i] * s->qscale) >> 3); - s-> intra_matrix[j] = av_clip_uint8(( luma_matrix[i] * s->qscale) >> 3); - } - s->y_dc_scale_table= - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[s->intra_dc_precision]; - s->chroma_intra_matrix[0] = - s->intra_matrix[0] = ff_mpeg12_dc_scale_table[s->intra_dc_precision][8]; - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, 8, 8, 1); - ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, - s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); - s->qscale= 8; + /* for mjpeg, we do include qscale in the matrix */ + for (int i = 1; i < 64; i++) { + int j = s->c.idsp.idct_permutation[i]; - if (s->codec_id == AV_CODEC_ID_AMV) { + s->c.chroma_intra_matrix[j] = av_clip_uint8((chroma_matrix[i] * s->c.qscale) >> 3); + s->c. intra_matrix[j] = av_clip_uint8(( luma_matrix[i] * s->c.qscale) >> 3); + } + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[s->c.intra_dc_precision]; + s->c.chroma_intra_matrix[0] = + s->c.intra_matrix[0] = ff_mpeg12_dc_scale_table[s->c.intra_dc_precision][8]; + } else { static const uint8_t y[32] = {13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13}; static const uint8_t c[32] = {14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14}; for (int i = 1; i < 64; i++) { - int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + int j = s->c.idsp.idct_permutation[ff_zigzag_direct[i]]; - s->intra_matrix[j] = sp5x_qscale_five_quant_table[0][i]; - s->chroma_intra_matrix[j] = sp5x_qscale_five_quant_table[1][i]; + s->c.intra_matrix[j] = sp5x_qscale_five_quant_table[0][i]; + s->c.chroma_intra_matrix[j] = sp5x_qscale_five_quant_table[1][i]; } - s->y_dc_scale_table = y; - s->c_dc_scale_table = c; - s->intra_matrix[0] = 13; - s->chroma_intra_matrix[0] = 14; - ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, - s->intra_matrix, s->intra_quant_bias, 8, 8, 1); - ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, - s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); - s->qscale = 8; + s->c.y_dc_scale_table = y; + s->c.c_dc_scale_table = c; + s->c.intra_matrix[0] = 13; + s->c.chroma_intra_matrix[0] = 14; } + ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16, + s->c.intra_matrix, s->intra_quant_bias, 8, 8, 1); + ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16, + s->c.chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); + s->c.qscale = 8; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->c.cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; } else { - s->cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; + s->c.cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; } - s->cur_pic.ptr->f->pict_type = s->pict_type; + s->c.cur_pic.ptr->f->pict_type = s->c.pict_type; - if (s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) - s->picture_in_gop_number=0; + if (s->c.cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) + m->picture_in_gop_number = 0; - s->mb_x = s->mb_y = 0; + s->c.mb_x = s->c.mb_y = 0; s->last_bits= put_bits_count(&s->pb); - switch(s->out_format) { -#if CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER - case FMT_MJPEG: - ff_mjpeg_amv_encode_picture_header(s); - break; -#endif - case FMT_SPEEDHQ: - if (CONFIG_SPEEDHQ_ENCODER) - ff_speedhq_encode_picture_header(s); - break; - case FMT_H261: - if (CONFIG_H261_ENCODER) - ff_h261_encode_picture_header(s); - break; - case FMT_H263: - if (CONFIG_WMV2_ENCODER && s->codec_id == AV_CODEC_ID_WMV2) - ff_wmv2_encode_picture_header(s); -#if CONFIG_MSMPEG4ENC - else if (s->msmpeg4_version != MSMP4_UNUSED) - ff_msmpeg4_encode_picture_header(s); -#endif - else if (CONFIG_MPEG4_ENCODER && s->h263_pred) { - ret = ff_mpeg4_encode_picture_header(s); - if (ret < 0) - return ret; - } else if (CONFIG_RV10_ENCODER && s->codec_id == AV_CODEC_ID_RV10) { - ret = ff_rv10_encode_picture_header(s); - if (ret < 0) - return ret; - } - else if (CONFIG_RV20_ENCODER && s->codec_id == AV_CODEC_ID_RV20) - ff_rv20_encode_picture_header(s); - else if (CONFIG_FLV_ENCODER && s->codec_id == AV_CODEC_ID_FLV1) - ff_flv_encode_picture_header(s); - else if (CONFIG_H263_ENCODER) - ff_h263_encode_picture_header(s); - break; - case FMT_MPEG1: - if (CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER) - ff_mpeg1_encode_picture_header(s); - break; - default: - av_assert0(0); - } + ret = m->encode_picture_header(m); + if (ret < 0) + return ret; bits= put_bits_count(&s->pb); - s->header_bits= bits - s->last_bits; + m->header_bits = bits - s->last_bits; for(i=1; ithread_context[i], s); + update_duplicate_context_after_me(s->c.enc_contexts[i], s); } - s->avctx->execute(s->avctx, encode_thread, &s->thread_context[0], NULL, context_count, sizeof(void*)); + s->c.avctx->execute(s->c.avctx, encode_thread, &s->c.enc_contexts[0], + NULL, context_count, sizeof(void*)); for(i=1; ipb.buf_end == s->thread_context[i]->pb.buf) - set_put_bits_buffer_size(&s->pb, FFMIN(s->thread_context[i]->pb.buf_end - s->pb.buf, INT_MAX/8-BUF_BITS)); - merge_context_after_encode(s, s->thread_context[i]); + if (s->pb.buf_end == s->c.enc_contexts[i]->pb.buf) + set_put_bits_buffer_size(&s->pb, FFMIN(s->c.enc_contexts[i]->pb.buf_end - s->pb.buf, INT_MAX/8-BUF_BITS)); + merge_context_after_encode(s, s->c.enc_contexts[i]); } emms_c(); return 0; } -static void denoise_dct_c(MpegEncContext *s, int16_t *block){ - const int intra= s->mb_intra; +static void denoise_dct_c(MPVEncContext *const s, int16_t *block) +{ + const int intra = s->c.mb_intra; int i; s->dct_count[intra]++; @@ -3895,7 +3981,7 @@ static void denoise_dct_c(MpegEncContext *s, int16_t *block){ } } -static int dct_quantize_trellis_c(MpegEncContext *s, +static int dct_quantize_trellis_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow){ const int *qmat; @@ -3919,7 +4005,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, int qmul, qadd, start_i, last_non_zero, i, dc; const int esc_length= s->ac_esc_length; const uint8_t *length, *last_length; - const int lambda= s->lambda2 >> (FF_LAMBDA_SHIFT - 6); + const int lambda = s->lambda2 >> (FF_LAMBDA_SHIFT - 6); int mpeg2_qscale; s->fdsp.fdct(block); @@ -3929,18 +4015,18 @@ static int dct_quantize_trellis_c(MpegEncContext *s, qmul= qscale*16; qadd= ((qscale-1)|1)*8; - if (s->q_scale_type) mpeg2_qscale = ff_mpeg2_non_linear_qscale[qscale]; + if (s->c.q_scale_type) mpeg2_qscale = ff_mpeg2_non_linear_qscale[qscale]; else mpeg2_qscale = qscale << 1; - if (s->mb_intra) { + if (s->c.mb_intra) { int q; - scantable= s->intra_scantable.scantable; - perm_scantable= s->intra_scantable.permutated; - if (!s->h263_aic) { + scantable = s->c.intra_scantable.scantable; + perm_scantable = s->c.intra_scantable.permutated; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; q = q << 3; } else{ /* For AIC we skip quant/dequant of INTRADC */ @@ -3953,8 +4039,8 @@ static int dct_quantize_trellis_c(MpegEncContext *s, start_i = 1; last_non_zero = 0; qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale]; - matrix = n < 4 ? s->intra_matrix : s->chroma_intra_matrix; - if(s->mpeg_quant || s->out_format == FMT_MPEG1 || s->out_format == FMT_MJPEG) + matrix = n < 4 ? s->c.intra_matrix : s->c.chroma_intra_matrix; + if (s->mpeg_quant || s->c.out_format == FMT_MPEG1 || s->c.out_format == FMT_MJPEG) bias= 1<<(QMAT_SHIFT-1); if (n > 3 && s->intra_chroma_ac_vlc_length) { @@ -3965,12 +4051,12 @@ static int dct_quantize_trellis_c(MpegEncContext *s, last_length= s->intra_ac_vlc_last_length; } } else { - scantable= s->inter_scantable.scantable; - perm_scantable= s->inter_scantable.permutated; + scantable = s->c.inter_scantable.scantable; + perm_scantable = s->c.inter_scantable.permutated; start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; - matrix = s->inter_matrix; + matrix = s->c.inter_matrix; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } @@ -3981,9 +4067,9 @@ static int dct_quantize_trellis_c(MpegEncContext *s, for(i=63; i>=start_i; i--) { const int j = scantable[i]; - int level = block[j] * qmat[j]; + int64_t level = (int64_t)block[j] * qmat[j]; - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ last_non_zero = i; break; } @@ -3991,11 +4077,11 @@ static int dct_quantize_trellis_c(MpegEncContext *s, for(i=start_i; i<=last_non_zero; i++) { const int j = scantable[i]; - int level = block[j] * qmat[j]; + int64_t level = (int64_t)block[j] * qmat[j]; // if( bias+level >= (1<<(QMAT_SHIFT - 3)) // || bias-level >= (1<<(QMAT_SHIFT - 3))){ - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; coeff[0][i]= level; @@ -4044,14 +4130,14 @@ static int dct_quantize_trellis_c(MpegEncContext *s, av_assert2(level); - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { unquant_coeff= alevel*qmul + qadd; - } else if(s->out_format == FMT_MJPEG) { - j = s->idsp.idct_permutation[scantable[i]]; + } else if (s->c.out_format == FMT_MJPEG) { + j = s->c.idsp.idct_permutation[scantable[i]]; unquant_coeff = alevel * matrix[j] * 8; }else{ // MPEG-1 - j = s->idsp.idct_permutation[scantable[i]]; // FIXME: optimize - if(s->mb_intra){ + j = s->c.idsp.idct_permutation[scantable[i]]; // FIXME: optimize + if (s->c.mb_intra) { unquant_coeff = (int)( alevel * mpeg2_qscale * matrix[j]) >> 4; unquant_coeff = (unquant_coeff - 1) | 1; }else{ @@ -4076,7 +4162,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, } } - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distortion + last_length[UNI_AC_ENC_INDEX(run, level)]*lambda; @@ -4102,7 +4188,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, } } - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distortion + score_tab[i-run]; @@ -4135,7 +4221,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, survivor[ survivor_count++ ]= i+1; } - if(s->out_format != FMT_H263 && s->out_format != FMT_H261){ + if (s->c.out_format != FMT_H263 && s->c.out_format != FMT_H261) { last_score= 256*256*256*120; for(i= survivor[0]; i<=last_non_zero + 1; i++){ int score= score_tab[i]; @@ -4169,7 +4255,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, int alevel= FFABS(level); int unquant_coeff, score, distortion; - if(s->out_format == FMT_H263 || s->out_format == FMT_H261){ + if (s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) { unquant_coeff= (alevel*qmul + qadd)>>3; } else{ // MPEG-1 unquant_coeff = ((( alevel << 1) + 1) * mpeg2_qscale * ((int) matrix[0])) >> 5; @@ -4228,7 +4314,7 @@ static void build_basis(uint8_t *perm){ } } -static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? +static int dct_quantize_refine(MPVEncContext *const s, //FIXME breaks denoise? int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale){ int16_t rem[64]; @@ -4244,21 +4330,21 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? const uint8_t *length; const uint8_t *last_length; int lambda; - int rle_index, run, q = 1, sum; //q is only used when s->mb_intra is true + int rle_index, run, q = 1, sum; //q is only used when s->c.mb_intra is true if(basis[0][0] == 0) - build_basis(s->idsp.idct_permutation); + build_basis(s->c.idsp.idct_permutation); qmul= qscale*2; qadd= (qscale-1)|1; - if (s->mb_intra) { - scantable= s->intra_scantable.scantable; - perm_scantable= s->intra_scantable.permutated; - if (!s->h263_aic) { + if (s->c.mb_intra) { + scantable = s->c.intra_scantable.scantable; + perm_scantable = s->c.intra_scantable.permutated; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; } else{ /* For AIC we skip quant/dequant of INTRADC */ q = 1; @@ -4269,7 +4355,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? dc= block[0]*q; // block[0] = (block[0] + (q >> 1)) / q; start_i = 1; -// if(s->mpeg_quant || s->out_format == FMT_MPEG1) +// if (s->mpeg_quant || s->c.out_format == FMT_MPEG1) // bias= 1<<(QMAT_SHIFT-1); if (n > 3 && s->intra_chroma_ac_vlc_length) { length = s->intra_chroma_ac_vlc_length; @@ -4279,14 +4365,14 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? last_length= s->intra_ac_vlc_last_length; } } else { - scantable= s->inter_scantable.scantable; - perm_scantable= s->inter_scantable.permutated; + scantable = s->c.inter_scantable.scantable; + perm_scantable = s->c.inter_scantable.permutated; dc= 0; start_i = 0; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } - last_non_zero = s->block_last_index[n]; + last_non_zero = s->c.block_last_index[n]; dc += (1<<(RECON_SHIFT-1)); for(i=0; i<64; i++){ @@ -4309,7 +4395,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? av_assert2(w<(1<<6)); sum += w*w; } - lambda= sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6); + lambda = sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6); run=0; rle_index=0; @@ -4350,7 +4436,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? const int level= block[0]; int change, old_coeff; - av_assert2(s->mb_intra); + av_assert2(s->c.mb_intra); old_coeff= q*level; @@ -4580,11 +4666,11 @@ void ff_block_permute(int16_t *block, const uint8_t *permutation, } } -static int dct_quantize_c(MpegEncContext *s, +static int dct_quantize_c(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow) { - int i, j, level, last_non_zero, q, start_i; + int i, last_non_zero, q, start_i; const int *qmat; const uint8_t *scantable; int bias; @@ -4596,13 +4682,13 @@ static int dct_quantize_c(MpegEncContext *s, if(s->dct_error_sum) s->denoise_dct(s, block); - if (s->mb_intra) { - scantable= s->intra_scantable.scantable; - if (!s->h263_aic) { + if (s->c.mb_intra) { + scantable = s->c.intra_scantable.scantable; + if (!s->c.h263_aic) { if (n < 4) - q = s->y_dc_scale; + q = s->c.y_dc_scale; else - q = s->c_dc_scale; + q = s->c.c_dc_scale; q = q << 3; } else /* For AIC we skip quant/dequant of INTRADC */ @@ -4615,7 +4701,7 @@ static int dct_quantize_c(MpegEncContext *s, qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale]; bias= s->intra_quant_bias*(1<<(QMAT_SHIFT - QUANT_BIAS_SHIFT)); } else { - scantable= s->inter_scantable.scantable; + scantable = s->c.inter_scantable.scantable; start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; @@ -4624,10 +4710,10 @@ static int dct_quantize_c(MpegEncContext *s, threshold1= (1<=start_i;i--) { - j = scantable[i]; - level = block[j] * qmat[j]; + const int j = scantable[i]; + int64_t level = (int64_t)block[j] * qmat[j]; - if(((unsigned)(level+threshold1))>threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ last_non_zero = i; break; }else{ @@ -4635,12 +4721,12 @@ static int dct_quantize_c(MpegEncContext *s, } } for(i=start_i; i<=last_non_zero; i++) { - j = scantable[i]; - level = block[j] * qmat[j]; + const int j = scantable[i]; + int64_t level = (int64_t)block[j] * qmat[j]; // if( bias+level >= (1<= (1<threshold2){ + if(((uint64_t)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; block[j]= level; @@ -4656,8 +4742,8 @@ static int dct_quantize_c(MpegEncContext *s, *overflow= s->max_qcoeff < max; //overflow might have happened /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ - if (s->idsp.perm_type != FF_IDCT_PERM_NONE) - ff_block_permute(block, s->idsp.idct_permutation, + if (s->c.idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, s->c.idsp.idct_permutation, scantable, last_non_zero); return last_non_zero; diff --git a/libavcodec/mpegvideo_motion.c b/libavcodec/mpegvideo_motion.c index 6e9368dd9c..a48b898dac 100644 --- a/libavcodec/mpegvideo_motion.c +++ b/libavcodec/mpegvideo_motion.c @@ -29,6 +29,7 @@ #include "avcodec.h" #include "h261.h" +#include "h263.h" #include "mpegutils.h" #include "mpegvideo.h" #include "mpeg4videodec.h" @@ -812,7 +813,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, } break; } - default: av_assert2(0); + default: + av_unreachable("No other mpegvideo MV types exist"); } } diff --git a/libavcodec/mpegvideo_parser.c b/libavcodec/mpegvideo_parser.c index 2cd0348317..663399a919 100644 --- a/libavcodec/mpegvideo_parser.c +++ b/libavcodec/mpegvideo_parser.c @@ -147,11 +147,6 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s, pc->frame_rate = avctx->framerate = ff_mpeg12_frame_rate_tab[frame_rate_index]; bit_rate = (buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6); avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } break; case EXT_START_CODE: @@ -181,11 +176,6 @@ FF_ENABLE_DEPRECATION_WARNINGS avctx->framerate.num = pc->frame_rate.num * (frame_rate_ext_n + 1); avctx->framerate.den = pc->frame_rate.den * (frame_rate_ext_d + 1); avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->ticks_per_frame = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } break; case 0x8: /* picture coding extension */ diff --git a/libavcodec/mpegvideo_unquantize.c b/libavcodec/mpegvideo_unquantize.c new file mode 100644 index 0000000000..213e37a514 --- /dev/null +++ b/libavcodec/mpegvideo_unquantize.c @@ -0,0 +1,274 @@ +/* + * Unquantize functions for mpegvideo + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * 4MV & hq & B-frame encoding stuff by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "avcodec.h" +#include "mpegvideo.h" +#include "mpegvideodata.h" +#include "mpegvideo_unquantize.h" + +static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + /* XXX: only MPEG-1 */ + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + sum += block[0]; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_h263_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0 || s->h263_aic); + + qmul = qscale << 1; + + if (!s->h263_aic) { + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + qadd = (qscale - 1) | 1; + }else{ + qadd = 0; + } + if(s->ac_pred) + nCoeffs=63; + else + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=1; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + +static void dct_unquantize_h263_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0); + + qadd = (qscale - 1) | 1; + qmul = qscale << 1; + + nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=0; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + +av_cold void ff_mpv_unquantize_init(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type) +{ + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c; + s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c; + s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c; + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c; + if (bitexact) + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact; + s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c; + +#if HAVE_INTRINSICS_NEON + ff_mpv_unquantize_init_neon(s, bitexact); +#endif + +#if ARCH_ARM + ff_mpv_unquantize_init_arm(s, bitexact); +#elif ARCH_PPC + ff_mpv_unquantize_init_ppc(s, bitexact); +#elif ARCH_X86 + ff_mpv_unquantize_init_x86(s, bitexact); +#elif ARCH_MIPS + ff_mpv_unquantize_init_mips(s, bitexact, q_scale_type); +#endif +} diff --git a/libavcodec/mpegvideo_unquantize.h b/libavcodec/mpegvideo_unquantize.h new file mode 100644 index 0000000000..3e6d8aedf7 --- /dev/null +++ b/libavcodec/mpegvideo_unquantize.h @@ -0,0 +1,62 @@ +/* + * Unquantize functions for mpegvideo + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * 4MV & hq & B-frame encoding stuff by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGVIDEO_UNQUANTIZE_H +#define AVCODEC_MPEGVIDEO_UNQUANTIZE_H + +#include + +#include "config.h" + +typedef struct MpegEncContext MpegEncContext; + +typedef struct MPVUnquantDSPContext { + void (*dct_unquantize_mpeg1_intra)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg1_inter)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg2_intra)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_mpeg2_inter)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_h263_intra)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); + void (*dct_unquantize_h263_inter)(struct MpegEncContext *s, + int16_t *block/*align 16*/, int n, int qscale); +} MPVUnquantDSPContext; + +#if !ARCH_MIPS +#define ff_mpv_unquantize_init(s, bitexact, q_scale_type) ff_mpv_unquantize_init(s, bitexact) +#endif + +void ff_mpv_unquantize_init(MPVUnquantDSPContext *s, + int bitexact, int q_scale_type); +void ff_mpv_unquantize_init_arm (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_neon(MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_ppc (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_x86 (MPVUnquantDSPContext *s, int bitexact); +void ff_mpv_unquantize_init_mips(MPVUnquantDSPContext *s, int bitexact, + int q_scale_type); + +#endif /* AVCODEC_MPEGVIDEO_UNQUANTIZE_H */ diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h index 6100364715..16b3eb1b17 100644 --- a/libavcodec/mpegvideodec.h +++ b/libavcodec/mpegvideodec.h @@ -56,12 +56,20 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx); * Ensure that the dummy frames are allocated according to pict_type if necessary. */ int ff_mpv_alloc_dummy_frames(MpegEncContext *s); -void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]); -void ff_mpv_report_decode_progress(MpegEncContext *s); +void ff_mpv_reconstruct_mb(MPVContext *s, int16_t block[][64]); void ff_mpv_frame_end(MpegEncContext *s); int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const MPVPicture *p, int qp_type); +/** + * update_thread_context for mpegvideo-based decoders. It updates + * the MPVPictures and generic stream-level parameters. If necessary + * (on dimension changes), it also performs reinitialization. + * + * @retval 1 if a reinitialization happened + * @retval 0 on success if no reinitialization happened + * @retval "<0" error code + */ int ff_mpeg_update_thread_context(AVCodecContext *dst, const AVCodecContext *src); void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h); void ff_mpeg_flush(AVCodecContext *avctx); @@ -69,10 +77,10 @@ int ff_mpv_decode_close(AVCodecContext *avctx); void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame *pict); -static inline int mpeg_get_qscale(MpegEncContext *s) +static inline int mpeg_get_qscale(GetBitContext *const gb, int q_scale_type) { - int qscale = get_bits(&s->gb, 5); - if (s->q_scale_type) + int qscale = get_bits(gb, 5); + if (q_scale_type) return ff_mpeg2_non_linear_qscale[qscale]; else return qscale << 1; diff --git a/libavcodec/mpegvideoenc.h b/libavcodec/mpegvideoenc.h index f5044a0309..ee115c3611 100644 --- a/libavcodec/mpegvideoenc.h +++ b/libavcodec/mpegvideoenc.h @@ -30,9 +30,259 @@ #include +#include "libavutil/avassert.h" +#include "libavutil/mem_internal.h" #include "libavutil/opt.h" +#include "fdctdsp.h" +#include "motion_est.h" #include "mpegvideo.h" +#include "mpegvideoencdsp.h" +#include "pixblockdsp.h" +#include "put_bits.h" +#include "ratecontrol.h" +#define MPVENC_MAX_B_FRAMES 16 + +typedef struct MPVEncContext { + MpegEncContext c; ///< the common base context + + /** bit output */ + PutBitContext pb; + + unsigned int lambda; ///< Lagrange multiplier used in rate distortion + unsigned int lambda2; ///< (lambda*lambda) >> FF_LAMBDA_SHIFT + int *lambda_table; + int adaptive_quant; ///< use adaptive quantization + int dquant; ///< qscale difference to prev qscale + int skipdct; ///< skip dct and code zero residual + + int quantizer_noise_shaping; + + int luma_elim_threshold; + int chroma_elim_threshold; + + int mpv_flags; ///< flags set by private options + /// Bitfield containing information which frames to reconstruct. + int frame_reconstruction_bitfield; + + /** + * Reference to the source picture. + */ + AVFrame *new_pic; + + struct MPVMainEncContext *parent; + + FDCTDSPContext fdsp; + MpegvideoEncDSPContext mpvencdsp; + PixblockDSPContext pdsp; + MotionEstContext me; + + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames + + int16_t (*p_mv_table)[2]; ///< MV table (1MV per MB) P-frame + int16_t (*b_forw_mv_table)[2]; ///< MV table (1MV per MB) forward mode B-frame + int16_t (*b_back_mv_table)[2]; ///< MV table (1MV per MB) backward mode B-frame + int16_t (*b_bidir_forw_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame + int16_t (*b_bidir_back_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame + int16_t (*b_direct_mv_table)[2]; ///< MV table (1MV per MB) direct mode B-frame + int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame + uint8_t (*p_field_select_table[2]); ///< Only the first element is allocated + uint8_t (*b_field_select_table[2][2]); ///< allocated jointly with p_field_select_table + + uint16_t *mb_type; ///< Table for candidate MB types + uint16_t *mb_var; ///< Table for MB variances + uint16_t *mc_mb_var; ///< Table for motion compensated MB variances + uint8_t *mb_mean; ///< Table for MB luminance + uint64_t encoding_error[MPV_MAX_PLANES]; + + int intra_quant_bias; ///< bias for the quantizer + int inter_quant_bias; ///< bias for the quantizer + int min_qcoeff; ///< minimum encodable coefficient + int max_qcoeff; ///< maximum encodable coefficient + int ac_esc_length; ///< num of bits needed to encode the longest esc + const uint8_t *intra_ac_vlc_length; + const uint8_t *intra_ac_vlc_last_length; + const uint8_t *intra_chroma_ac_vlc_length; + const uint8_t *intra_chroma_ac_vlc_last_length; + const uint8_t *inter_ac_vlc_length; + const uint8_t *inter_ac_vlc_last_length; + const uint8_t *luma_dc_vlc_length; + + int coded_score[12]; + + int16_t (*block)[64]; ///< points into blocks below + + /** precomputed matrix (combine qscale and DCT renorm) */ + int (*q_intra_matrix)[64]; + int (*q_chroma_intra_matrix)[64]; + int (*q_inter_matrix)[64]; + /** identical to the above but for MMX & these are not permutated, second 64 entries are bias*/ + uint16_t (*q_intra_matrix16)[2][64]; + uint16_t (*q_chroma_intra_matrix16)[2][64]; + uint16_t (*q_inter_matrix16)[2][64]; + + /* noise reduction */ + void (*denoise_dct)(struct MPVEncContext *s, int16_t *block); + int (*dct_error_sum)[64]; + int dct_count[2]; + uint16_t (*dct_offset)[64]; + + int picture_number; + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int misc_bits; ///< cbp, mb_type + int last_bits; ///< temp var used for calculating the above vars + + int mb_skip_run; + + /* H.263 specific */ + int gob_index; + int mb_info; ///< interval for outputting info about mb offsets as side data + int prev_mb_info, last_mb_info; + int mb_info_size; + uint8_t *mb_info_ptr; + + /* H.263+ specific */ + int umvplus; ///< == H.263+ && unrestricted_mv + int h263_slice_structured; + int alt_inter_vlc; ///< alternative inter vlc + int modified_quant; + int loop_filter; + + /* MJPEG specific */ + struct MJpegContext *mjpeg_ctx; + int esc_pos; + + /* MPEG-1 specific */ + int last_mv_dir; ///< last mv_dir, used for B-frame encoding + + /* MPEG-4 specific */ + int data_partitioning; ///< data partitioning flag, set via option + int partitioned_frame; ///< is current frame partitioned + int mpeg_quant; + PutBitContext tex_pb; ///< used for data partitioned VOPs + PutBitContext pb2; ///< used for data partitioned VOPs + + /* MSMPEG4 specific */ + int slice_height; ///< in macroblocks + int flipflop_rounding; ///< also used for MPEG-4, H.263+ + int esc3_level_length; + + /* RTP specific */ + int rtp_mode; + int rtp_payload_size; + int error_rate; + + uint8_t *ptr_lastgob; + + void (*encode_mb)(struct MPVEncContext *s, int16_t block[][64], + int motion_x, int motion_y); + + int (*dct_quantize)(struct MPVEncContext *s, int16_t *block/*align 16*/, int n, int qscale, int *overflow); + + me_cmp_func ildct_cmp[2]; ///< 0 = intra, 1 = non-intra + me_cmp_func n_sse_cmp[2]; ///< either SSE or NSSE cmp func + me_cmp_func sad_cmp[2]; + me_cmp_func sse_cmp[2]; + int (*sum_abs_dctelem)(const int16_t *block); + + int intra_penalty; + + DECLARE_ALIGNED_32(int16_t, blocks)[2][12][64]; // for HQ mode we need to keep the best block +} MPVEncContext; + +typedef struct MPVMainEncContext { + MPVEncContext s; ///< The main slicecontext + + int intra_only; ///< if true, only intra pictures are generated + int gop_size; + int max_b_frames; ///< max number of B-frames + int picture_in_gop_number; ///< 0-> first pic in gop, ... + int input_picture_number; ///< used to set pic->display_picture_number + int coded_picture_number; ///< used to set pic->coded_picture_number + + MPVPicture *input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in display order + MPVPicture *reordered_input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in coded order + + int64_t user_specified_pts; ///< last non-zero pts from user-supplied AVFrame + /** + * pts difference between the first and second input frame, used for + * calculating dts of the first frame when there's a delay */ + int64_t dts_delta; + /** + * reordered pts to be used as dts for the next output frame when there's + * a delay */ + int64_t reordered_pts; + + /// temporary frames used by b_frame_strategy = 2 + AVFrame *tmp_frames[MPVENC_MAX_B_FRAMES + 2]; + int b_frame_strategy; + int b_sensitivity; + int brd_scale; + + int scenechange_threshold; + + int noise_reduction; + + float border_masking; + int lmin, lmax; + int vbv_ignore_qmax; + + /* MPEG-1/2 specific */ + int vbv_delay_pos; ///< offset of vbv_delay in the bitstream + + const uint8_t *fcode_tab; ///< smallest fcode needed for each MV + + /* frame skip options */ + int frame_skip_threshold; + int frame_skip_factor; + int frame_skip_exp; + int frame_skip_cmp; + me_cmp_func frame_skip_cmp_fn; + + int (*encode_picture_header)(struct MPVMainEncContext *m); + + /* bit rate control */ + int64_t bit_rate; + int64_t total_bits; + int frame_bits; ///< bits used for the current frame + int header_bits; + int stuffing_bits; ///< bits used for stuffing + int next_lambda; ///< next lambda used for retrying to encode a frame + int fixed_qscale; ///< fixed qscale if non zero + int last_lambda_for[5]; ///< last lambda for a specific pict type + int last_pict_type; //FIXME removes + int last_non_b_pict_type; ///< used for MPEG-4 gmc B-frames & ratecontrol + RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c + + int me_penalty_compensation; + int me_pre; ///< prepass for motion estimation + + int64_t mb_var_sum; ///< sum of MB variance for current frame + int64_t mc_mb_var_sum; ///< motion compensated MB variance for current frame + + char *me_map_base; ///< backs MotionEstContext.(map|score_map) + char *dct_error_sum_base; ///< backs dct_error_sum + int16_t (*mv_table_base)[2]; +} MPVMainEncContext; + +static inline const MPVMainEncContext *slice_to_mainenc(const MPVEncContext *s) +{ +#ifdef NO_SLICE_THREADING_HERE + av_assert2(s->c.slice_context_count <= 1 && + !(s->c.avctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)); + return (const MPVMainEncContext*)s; +#else + return s->parent; +#endif +} + +#define MAX_FCODE 7 #define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level)) #define INPLACE_OFFSET 16 @@ -79,7 +329,9 @@ { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ { "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" } -#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) +#define FF_MPV_OFFSET(x) offsetof(MPVEncContext, x) +#define FF_MPV_MAIN_OFFSET(x) offsetof(MPVMainEncContext, x) +#define FF_RC_OFFSET(x) offsetof(MPVMainEncContext, rc_context.x) #define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) #define FF_MPV_COMMON_OPTS \ FF_MPV_OPT_CMP_FUNC, \ @@ -89,7 +341,6 @@ FF_MPV_OPT_CMP_FUNC, \ { "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "naq", "normalize adaptive quantization", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_NAQ }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ -{ "mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_MV0 }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ { "luma_elim_threshold", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)",\ FF_MPV_OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ { "chroma_elim_threshold", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)",\ @@ -98,64 +349,64 @@ FF_MPV_OPT_CMP_FUNC, \ { "error_rate", "Simulate errors in the bitstream to test error concealment.", \ FF_MPV_OFFSET(error_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\ {"qsquish", "how to keep quantizer between qmin and qmax (0 = clip, 1 = use differentiable function)", \ - FF_MPV_OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \ -{"rc_qmod_amp", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"rc_qmod_freq", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \ + FF_RC_OFFSET(qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_amp", "experimental quantizer modulation", FF_RC_OFFSET(qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_freq", "experimental quantizer modulation", FF_RC_OFFSET(qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \ {"rc_eq", "Set rate control equation. When computing the expression, besides the standard functions " \ "defined in the section 'Expression Evaluation', the following functions are available: " \ "bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " \ "fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", \ - FF_MPV_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \ -{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_MPV_OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"rc_buf_aggressivity", "currently useless", FF_MPV_OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ -{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_threshold", "Frame skip threshold", FF_MPV_OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_factor", "Frame skip factor", FF_MPV_OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_exp", "Frame skip exponent", FF_MPV_OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"skip_cmp", "Frame skip compare function", FF_MPV_OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ -{"sc_threshold", "Scene change threshold", FF_MPV_OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"noise_reduction", "Noise reduction", FF_MPV_OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ + FF_RC_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \ +{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_RC_OFFSET(initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_buf_aggressivity", "currently useless", FF_RC_OFFSET(buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_MAIN_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_MAIN_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_MAIN_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_threshold", "Frame skip threshold", FF_MPV_MAIN_OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_factor", "Frame skip factor", FF_MPV_MAIN_OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_exp", "Frame skip exponent", FF_MPV_MAIN_OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_cmp", "Frame skip compare function", FF_MPV_MAIN_OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }, \ +{"noise_reduction", "Noise reduction", FF_MPV_MAIN_OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"ps", "RTP payload size in bytes", FF_MPV_OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ #define FF_MPV_COMMON_BFRAME_OPTS \ -{"b_strategy", "Strategy to choose between I/P/B-frames", FF_MPV_OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FF_MPV_OPT_FLAGS }, \ -{"b_sensitivity", "Adjust sensitivity of b_frame_strategy 1", FF_MPV_OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"brd_scale", "Downscale frames for dynamic B-frame decision", FF_MPV_OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 3, FF_MPV_OPT_FLAGS }, +{"b_strategy", "Strategy to choose between I/P/B-frames", FF_MPV_MAIN_OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FF_MPV_OPT_FLAGS }, \ +{"b_sensitivity", "Adjust sensitivity of b_frame_strategy 1", FF_MPV_MAIN_OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"brd_scale", "Downscale frames for dynamic B-frame decision", FF_MPV_MAIN_OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 3, FF_MPV_OPT_FLAGS }, #define FF_MPV_COMMON_MOTION_EST_OPTS \ -{"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ +{ "mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_MV0 }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "mpv_flags" },\ +{"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(me.motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ { "xone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_XONE }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion_est" }, \ -{"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"mepre", "pre motion estimation", FF_MPV_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_MAIN_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepre", "pre motion estimation", FF_MPV_MAIN_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"intra_penalty", "Penalty for intra blocks in block decision", FF_MPV_OFFSET(intra_penalty), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX/2, FF_MPV_OPT_FLAGS }, \ +{"sc_threshold", "Scene change threshold", FF_MPV_MAIN_OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ extern const AVClass ff_mpv_enc_class; int ff_mpv_encode_init(AVCodecContext *avctx); -void ff_mpv_encode_init_x86(MpegEncContext *s); int ff_mpv_encode_end(AVCodecContext *avctx); int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet); -int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase); +int ff_mpv_reallocate_putbitbuffer(MPVEncContext *s, size_t threshold, size_t size_increase); void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix); -void ff_dct_encode_init(MpegEncContext *s); -void ff_mpvenc_dct_init_mips(MpegEncContext *s); -void ff_dct_encode_init_x86(MpegEncContext *s); +void ff_dct_encode_init(MPVEncContext *s); +void ff_mpvenc_dct_init_mips(MPVEncContext *s); +void ff_dct_encode_init_x86(MPVEncContext *s); -void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], uint16_t (*qmat16)[2][64], +void ff_convert_matrix(MPVEncContext *s, int (*qmat)[64], uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix, int bias, int qmin, int qmax, int intra); void ff_block_permute(int16_t *block, const uint8_t *permutation, const uint8_t *scantable, int last); -static inline int get_bits_diff(MpegEncContext *s) +static inline int get_bits_diff(MPVEncContext *s) { const int bits = put_bits_count(&s->pb); const int last = s->last_bits; diff --git a/libavcodec/mpegvideoencdsp.c b/libavcodec/mpegvideoencdsp.c index 5e4c446d99..b4fd2af915 100644 --- a/libavcodec/mpegvideoencdsp.c +++ b/libavcodec/mpegvideoencdsp.c @@ -25,7 +25,7 @@ #include "libavutil/attributes.h" #include "libavutil/imgutils.h" #include "avcodec.h" -#include "me_cmp.h" +#include "mathops.h" #include "mpegvideoencdsp.h" static int try_8x8basis_c(const int16_t rem[64], const int16_t weight[64], diff --git a/libavcodec/mpv_reconstruct_mb_template.c b/libavcodec/mpv_reconstruct_mb_template.c deleted file mode 100644 index dca982ae0f..0000000000 --- a/libavcodec/mpv_reconstruct_mb_template.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * MPEG macroblock reconstruction - * Copyright (c) 2000,2001 Fabrice Bellard - * Copyright (c) 2002-2004 Michael Niedermayer - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define NOT_MPEG12_H261 0 -#define MAY_BE_MPEG12_H261 1 -#define DEFINITELY_MPEG12_H261 2 - -/* put block[] to dest[] */ -static inline void put_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size, int qscale) -{ - s->dct_unquantize_intra(s, block, i, qscale); - s->idsp.idct_put(dest, line_size, block); -} - -static inline void add_dequant_dct(MpegEncContext *s, - int16_t *block, int i, uint8_t *dest, int line_size, int qscale) -{ - if (s->block_last_index[i] >= 0) { - s->dct_unquantize_inter(s, block, i, qscale); - - s->idsp.idct_add(dest, line_size, block); - } -} - -/* generic function called after a macroblock has been parsed by the - decoder or after it has been encoded by the encoder. - - Important variables used: - s->mb_intra : true if intra macroblock - s->mv_dir : motion vector direction - s->mv_type : motion vector type - s->mv : motion vector - s->interlaced_dct : true if interlaced dct used (mpeg2) - */ -static av_always_inline -void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], - int lowres_flag, int is_mpeg12) -{ -#define IS_MPEG12_H261(s) (is_mpeg12 == MAY_BE_MPEG12_H261 ? ((s)->out_format <= FMT_H261) : is_mpeg12) - const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; - - s->cur_pic.qscale_table[mb_xy] = s->qscale; - - /* update DC predictors for P macroblocks */ - if (!s->mb_intra) { - if (is_mpeg12 != DEFINITELY_MPEG12_H261 && (s->h263_pred || s->h263_aic)) { - if (s->mbintra_table[mb_xy]) - ff_clean_intra_table_entries(s); - } else { - s->last_dc[0] = - s->last_dc[1] = - s->last_dc[2] = 128 << s->intra_dc_precision; - } - } else if (is_mpeg12 != DEFINITELY_MPEG12_H261 && (s->h263_pred || s->h263_aic)) - s->mbintra_table[mb_xy] = 1; - -#if IS_ENCODER - if ((s->avctx->flags & AV_CODEC_FLAG_PSNR) || s->frame_skip_threshold || s->frame_skip_factor || - !((s->intra_only || s->pict_type == AV_PICTURE_TYPE_B) && - s->avctx->mb_decision != FF_MB_DECISION_RD)) // FIXME precalc -#endif /* IS_ENCODER */ - { - uint8_t *dest_y = s->dest[0], *dest_cb = s->dest[1], *dest_cr = s->dest[2]; - int dct_linesize, dct_offset; - const int linesize = s->cur_pic.linesize[0]; //not s->linesize as this would be wrong for field pics - const int uvlinesize = s->cur_pic.linesize[1]; - const int block_size = lowres_flag ? 8 >> s->avctx->lowres : 8; - - /* avoid copy if macroblock skipped in last frame too */ - /* skip only during decoding as we might trash the buffers during encoding a bit */ - if (!IS_ENCODER) { - uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; - - if (s->mb_skipped) { - s->mb_skipped = 0; - av_assert2(s->pict_type!=AV_PICTURE_TYPE_I); - *mbskip_ptr = 1; - } else if (!s->cur_pic.reference) { - *mbskip_ptr = 1; - } else{ - *mbskip_ptr = 0; /* not skipped */ - } - } - - dct_linesize = linesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? linesize : linesize * block_size; - - if (!s->mb_intra) { - /* motion handling */ - /* decoding or more than one mb_type (MC was already done otherwise) */ - -#if !IS_ENCODER - if (HAVE_THREADS && is_mpeg12 != DEFINITELY_MPEG12_H261 && - s->avctx->active_thread_type & FF_THREAD_FRAME) { - if (s->mv_dir & MV_DIR_FORWARD) { - ff_thread_progress_await(&s->last_pic.ptr->progress, - lowest_referenced_row(s, 0)); - } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_thread_progress_await(&s->next_pic.ptr->progress, - lowest_referenced_row(s, 1)); - } - } - - if (lowres_flag) { - const h264_chroma_mc_func *op_pix = s->h264chroma.put_h264_chroma_pixels_tab; - - if (s->mv_dir & MV_DIR_FORWARD) { - MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix); - op_pix = s->h264chroma.avg_h264_chroma_pixels_tab; - } - if (s->mv_dir & MV_DIR_BACKWARD) { - MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix); - } - } else { - const op_pixels_func (*op_pix)[4]; - const qpel_mc_func (*op_qpix)[16]; - - if ((is_mpeg12 == DEFINITELY_MPEG12_H261 || !s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { - op_pix = s->hdsp.put_pixels_tab; - op_qpix = s->qdsp.put_qpel_pixels_tab; - } else { - op_pix = s->hdsp.put_no_rnd_pixels_tab; - op_qpix = s->qdsp.put_no_rnd_qpel_pixels_tab; - } - if (s->mv_dir & MV_DIR_FORWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_pic.data, op_pix, op_qpix); - op_pix = s->hdsp.avg_pixels_tab; - op_qpix = s->qdsp.avg_qpel_pixels_tab; - } - if (s->mv_dir & MV_DIR_BACKWARD) { - ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix, op_qpix); - } - } - - /* skip dequant / idct if we are really late ;) */ - if (s->avctx->skip_idct) { - if( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) - ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) - || s->avctx->skip_idct >= AVDISCARD_ALL) - return; - } - - /* add dct residue */ - if (!(IS_MPEG12_H261(s) || s->msmpeg4_version != MSMP4_UNUSED || - (s->codec_id == AV_CODEC_ID_MPEG4 && !s->mpeg_quant))) -#endif /* !IS_ENCODER */ - { - add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); - add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); - add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); - add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - av_assert2(IS_ENCODER || s->chroma_y_shift); - if (!IS_ENCODER || s->chroma_y_shift) { - add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); - } else { - dct_linesize >>= 1; - dct_offset >>= 1; - add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); - add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); - } - } - } -#if !IS_ENCODER - else if (is_mpeg12 == DEFINITELY_MPEG12_H261 || lowres_flag || (s->codec_id != AV_CODEC_ID_WMV2)) { - add_dct(s, block[0], 0, dest_y , dct_linesize); - add_dct(s, block[1], 1, dest_y + block_size, dct_linesize); - add_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize); - add_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) {//Chroma420 - add_dct(s, block[4], 4, dest_cb, uvlinesize); - add_dct(s, block[5], 5, dest_cr, uvlinesize); - } else { - //chroma422 - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; - - add_dct(s, block[4], 4, dest_cb, dct_linesize); - add_dct(s, block[5], 5, dest_cr, dct_linesize); - add_dct(s, block[6], 6, dest_cb+dct_offset, dct_linesize); - add_dct(s, block[7], 7, dest_cr+dct_offset, dct_linesize); - if (!s->chroma_x_shift) {//Chroma444 - add_dct(s, block[8], 8, dest_cb+block_size, dct_linesize); - add_dct(s, block[9], 9, dest_cr+block_size, dct_linesize); - add_dct(s, block[10], 10, dest_cb+block_size+dct_offset, dct_linesize); - add_dct(s, block[11], 11, dest_cr+block_size+dct_offset, dct_linesize); - } - } - } //fi gray - } else if (CONFIG_WMV2_DECODER) { - ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); - } -#endif /* !IS_ENCODER */ - } else { -#if !IS_ENCODER - /* 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 (is_mpeg12 != DEFINITELY_MPEG12_H261 && CONFIG_MPEG4_DECODER && - /* s->codec_id == AV_CODEC_ID_MPEG4 && */ - s->avctx->bits_per_raw_sample > 8) { - ff_mpeg4_decode_studio(s, dest_y, dest_cb, dest_cr, block_size, - uvlinesize, dct_linesize, dct_offset); - } else if (!IS_MPEG12_H261(s)) -#endif /* !IS_ENCODER */ - { - /* dct only in intra block */ - put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); - put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); - put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); - put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) { - put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); - put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); - } else { - dct_offset >>=1; - dct_linesize >>=1; - put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); - put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); - put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); - put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); - } - } - } -#if !IS_ENCODER - else { - s->idsp.idct_put(dest_y, dct_linesize, block[0]); - s->idsp.idct_put(dest_y + block_size, dct_linesize, block[1]); - s->idsp.idct_put(dest_y + dct_offset, dct_linesize, block[2]); - s->idsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); - - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - if (s->chroma_y_shift) { - s->idsp.idct_put(dest_cb, uvlinesize, block[4]); - s->idsp.idct_put(dest_cr, uvlinesize, block[5]); - } else { - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; - - s->idsp.idct_put(dest_cb, dct_linesize, block[4]); - s->idsp.idct_put(dest_cr, dct_linesize, block[5]); - s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); - s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); - if (!s->chroma_x_shift) { //Chroma444 - s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]); - s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]); - s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]); - s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]); - } - } - } //gray - } -#endif /* !IS_ENCODER */ - } - } -} - diff --git a/libavcodec/mscc.c b/libavcodec/mscc.c index 6d57f1b622..708e84a8e1 100644 --- a/libavcodec/mscc.c +++ b/libavcodec/mscc.c @@ -184,11 +184,6 @@ inflate_error: const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); if (pal && size == AVPALETTE_SIZE) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif for (j = 0; j < 256; j++) s->pal[j] = 0xFF000000 | AV_RL32(pal + j * 4); } else if (pal) { diff --git a/libavcodec/msmpeg4.c b/libavcodec/msmpeg4.c index 872dc8db67..5ceb100333 100644 --- a/libavcodec/msmpeg4.c +++ b/libavcodec/msmpeg4.c @@ -36,6 +36,7 @@ #include "avcodec.h" #include "idctdsp.h" +#include "mathops.h" #include "mpegvideo.h" #include "msmpeg4.h" #include "mpeg4videodata.h" @@ -197,7 +198,7 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, int16_t **dc_val_ptr, int *dir_ptr) { int a, b, c, wrap, pred, scale; - int16_t *dc_val; + int16_t *const dc_val = s->dc_val + s->block_index[n]; /* find prediction */ if (n < 4) { @@ -207,7 +208,6 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, } wrap = s->block_wrap[n]; - dc_val= s->dc_val[0] + s->block_index[n]; /* B C * A X @@ -336,4 +336,3 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, *dc_val_ptr = &dc_val[0]; return pred; } - diff --git a/libavcodec/msmpeg4data.c b/libavcodec/msmpeg4data.c index 65546da66e..b3603f7db1 100644 --- a/libavcodec/msmpeg4data.c +++ b/libavcodec/msmpeg4data.c @@ -481,1144 +481,513 @@ RLTable ff_rl_table[NB_RL_TABLES] = { /* motion vector table 0 */ -static const uint16_t table0_mv_code[1100] = { - 0x0001, 0x0003, 0x0005, 0x0007, 0x0003, 0x0008, 0x000c, 0x0001, - 0x0002, 0x001b, 0x0006, 0x000b, 0x0015, 0x0002, 0x000e, 0x000f, - 0x0014, 0x0020, 0x0022, 0x0025, 0x0027, 0x0029, 0x002d, 0x004b, - 0x004d, 0x0003, 0x0022, 0x0023, 0x0025, 0x0027, 0x0042, 0x0048, - 0x0049, 0x0050, 0x005c, 0x0091, 0x009f, 0x000e, 0x0043, 0x004c, - 0x0054, 0x0056, 0x008c, 0x0098, 0x009a, 0x009b, 0x00b1, 0x00b2, - 0x0120, 0x0121, 0x0126, 0x0133, 0x0139, 0x01a1, 0x01a4, 0x01a5, - 0x01a6, 0x01a7, 0x01ae, 0x01af, 0x000b, 0x0019, 0x0085, 0x0090, - 0x009b, 0x00aa, 0x00af, 0x010c, 0x010e, 0x011c, 0x011e, 0x0133, - 0x0144, 0x0160, 0x0174, 0x0175, 0x0177, 0x0178, 0x0249, 0x024b, - 0x0252, 0x0261, 0x0265, 0x0270, 0x0352, 0x0353, 0x0355, 0x0359, - 0x0010, 0x0011, 0x0013, 0x0034, 0x0035, 0x0036, 0x0037, 0x003d, - 0x003e, 0x0109, 0x0126, 0x0156, 0x021a, 0x021e, 0x023a, 0x023e, - 0x028e, 0x028f, 0x02cf, 0x0491, 0x0494, 0x049f, 0x04a0, 0x04a3, - 0x04a6, 0x04a7, 0x04ad, 0x04ae, 0x04c0, 0x04c4, 0x04c6, 0x04c8, - 0x04c9, 0x04f5, 0x04f6, 0x04f7, 0x0680, 0x0682, 0x0683, 0x0688, - 0x0689, 0x068d, 0x068e, 0x068f, 0x06a2, 0x06a3, 0x06a9, 0x06b0, - 0x06b1, 0x06b4, 0x06b5, 0x0024, 0x0060, 0x0063, 0x0078, 0x0079, - 0x0211, 0x0244, 0x0245, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, - 0x026b, 0x02af, 0x02b8, 0x02bb, 0x0436, 0x0476, 0x0477, 0x047e, - 0x04c8, 0x04c9, 0x04ca, 0x0514, 0x0586, 0x0587, 0x0598, 0x059d, - 0x05d9, 0x05da, 0x0920, 0x0921, 0x093b, 0x093c, 0x093d, 0x0942, - 0x0943, 0x0944, 0x0945, 0x0959, 0x095e, 0x095f, 0x0982, 0x0983, - 0x098e, 0x098f, 0x09c4, 0x09e7, 0x09e8, 0x09e9, 0x0d02, 0x0d17, - 0x0d18, 0x0d19, 0x0d41, 0x0d42, 0x0d43, 0x0d50, 0x0d5f, 0x0d6d, - 0x0d6e, 0x0d6f, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x041e, 0x041f, 0x0420, 0x0421, - 0x048c, 0x048d, 0x04d3, 0x04d4, 0x04d5, 0x055c, 0x055d, 0x0572, - 0x0573, 0x0574, 0x0575, 0x08de, 0x08df, 0x08fe, 0x08ff, 0x0996, - 0x0a36, 0x0a37, 0x0b08, 0x0b09, 0x0b0a, 0x0b0b, 0x0b32, 0x0b33, - 0x0b34, 0x0b35, 0x0b36, 0x0b37, 0x0b38, 0x0b39, 0x0bb0, 0x0bf7, - 0x0bf8, 0x0bf9, 0x0bfa, 0x0bfb, 0x0bfc, 0x0bfd, 0x0bfe, 0x0bff, - 0x1254, 0x1255, 0x1256, 0x1257, 0x1270, 0x1271, 0x1272, 0x1273, - 0x1274, 0x1275, 0x12ab, 0x12ac, 0x12ad, 0x12ae, 0x12af, 0x12b0, - 0x12b1, 0x1315, 0x1316, 0x1317, 0x13bf, 0x13c0, 0x13c1, 0x13c2, - 0x13c3, 0x13c4, 0x13c5, 0x13c6, 0x13c7, 0x13c8, 0x13c9, 0x13ca, - 0x13cb, 0x13cc, 0x13cd, 0x1a06, 0x1a07, 0x1a28, 0x1a29, 0x1a2a, - 0x1a2b, 0x1a2c, 0x1a2d, 0x1a80, 0x1abb, 0x1abc, 0x1abd, 0x1ad8, - 0x1ad9, 0x0094, 0x0095, 0x0096, 0x0097, 0x00a0, 0x00a1, 0x00a2, - 0x00a3, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, 0x0837, - 0x0838, 0x0839, 0x083a, 0x083b, 0x0939, 0x093a, 0x093b, 0x093c, - 0x093d, 0x093e, 0x093f, 0x09a0, 0x09a1, 0x09a2, 0x09a3, 0x09a4, - 0x09a5, 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, - 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, - 0x11bb, 0x132f, 0x1454, 0x1455, 0x1456, 0x1457, 0x1458, 0x1459, - 0x145a, 0x145b, 0x145c, 0x145d, 0x145e, 0x145f, 0x1460, 0x1461, - 0x1462, 0x1463, 0x1464, 0x1465, 0x1466, 0x1467, 0x1468, 0x1469, - 0x146a, 0x146b, 0x17de, 0x17df, 0x17e0, 0x17e1, 0x17e2, 0x17e3, - 0x17e4, 0x17e5, 0x17e6, 0x17e7, 0x17e8, 0x17e9, 0x17ea, 0x17eb, - 0x17ec, 0x17ed, 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, - 0x2546, 0x2547, 0x2548, 0x2549, 0x254a, 0x254b, 0x254c, 0x254d, - 0x254e, 0x254f, 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, - 0x2628, 0x2766, 0x2767, 0x2768, 0x2769, 0x276a, 0x276b, 0x276c, - 0x276d, 0x276e, 0x276f, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, - 0x2775, 0x2776, 0x2777, 0x2778, 0x2779, 0x277a, 0x277b, 0x277c, - 0x277d, 0x3503, 0x3544, 0x3545, 0x3546, 0x3547, 0x3560, 0x3561, - 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567, 0x3568, 0x3569, - 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f, 0x3570, 0x3571, - 0x3572, 0x3573, 0x3574, 0x3575, 0x03f0, 0x103d, 0x103e, 0x103f, - 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, - 0x1048, 0x1049, 0x104a, 0x104b, 0x104c, 0x104d, 0x104e, 0x104f, - 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, - 0x1058, 0x1059, 0x105a, 0x105b, 0x105c, 0x105d, 0x105e, 0x105f, - 0x1060, 0x1061, 0x1270, 0x1271, 0x21b8, 0x21b9, 0x21ba, 0x21bb, - 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x21f0, 0x21f1, 0x21f2, 0x21f3, - 0x21f4, 0x21f5, 0x21f6, 0x21f7, 0x21f8, 0x21f9, 0x21fa, 0x21fb, - 0x21fc, 0x21fd, 0x21fe, 0x21ff, 0x2340, 0x2341, 0x2342, 0x2343, - 0x2344, 0x2345, 0x2346, 0x2347, 0x2348, 0x2349, 0x234a, 0x234b, - 0x234c, 0x234d, 0x234e, 0x234f, 0x2350, 0x2351, 0x2352, 0x2353, - 0x2354, 0x2355, 0x2356, 0x2357, 0x265c, 0x2f88, 0x2f89, 0x2f8a, - 0x2f8b, 0x2f8c, 0x2f8d, 0x2f8e, 0x2f8f, 0x2f90, 0x2f91, 0x2f92, - 0x2f93, 0x2f94, 0x2f95, 0x2f96, 0x2f97, 0x2f98, 0x2f99, 0x2f9a, - 0x2f9b, 0x2f9c, 0x2f9d, 0x2f9e, 0x2f9f, 0x2fa0, 0x2fa1, 0x2fa2, - 0x2fa3, 0x2fa4, 0x2fa5, 0x2fa6, 0x2fa7, 0x2fa8, 0x2fa9, 0x2faa, - 0x2fab, 0x2fac, 0x2fad, 0x2fae, 0x2faf, 0x2fb0, 0x2fb1, 0x2fb2, - 0x2fb3, 0x2fb4, 0x2fb5, 0x2fb6, 0x2fb7, 0x2fb8, 0x2fb9, 0x2fba, - 0x2fbb, 0x4c52, 0x4c53, 0x4e28, 0x4e29, 0x4e2a, 0x4e2b, 0x4e2c, - 0x4e2d, 0x4e2e, 0x4e2f, 0x4e30, 0x4e31, 0x4e32, 0x4e33, 0x4e34, - 0x4e35, 0x4e36, 0x4e37, 0x4e38, 0x4e39, 0x4e3a, 0x4e3b, 0x4e3c, - 0x4e3d, 0x4e3e, 0x4e3f, 0x4e80, 0x4e81, 0x4e82, 0x4e83, 0x4e84, - 0x4e85, 0x4e86, 0x4e87, 0x4e88, 0x4e89, 0x4e8a, 0x4e8b, 0x4e8c, - 0x4e8d, 0x4e8e, 0x4e8f, 0x4e90, 0x4e91, 0x4e92, 0x4e93, 0x4e94, - 0x4e95, 0x4e96, 0x4e97, 0x4e98, 0x4e99, 0x4e9a, 0x4e9b, 0x4e9c, - 0x4e9d, 0x4e9e, 0x4e9f, 0x4ea0, 0x4ea1, 0x4ea2, 0x4ea3, 0x4ea4, - 0x4ea5, 0x4ea6, 0x4ea7, 0x4ea8, 0x4ea9, 0x4eaa, 0x4eab, 0x4eac, - 0x4ead, 0x4eae, 0x4eaf, 0x4eb0, 0x4eb1, 0x4eb2, 0x4eb3, 0x4eb4, - 0x4eb5, 0x4eb6, 0x4eb7, 0x4eb8, 0x4eb9, 0x4eba, 0x4ebb, 0x4ebc, - 0x4ebd, 0x4ebe, 0x4ebf, 0x4ec0, 0x4ec1, 0x4ec2, 0x4ec3, 0x4ec4, - 0x4ec5, 0x4ec6, 0x4ec7, 0x4ec8, 0x4ec9, 0x4eca, 0x4ecb, 0x6a04, - 0x6a05, 0x07e2, 0x07e3, 0x07e4, 0x07e5, 0x07e6, 0x07e7, 0x07e8, - 0x07e9, 0x07ea, 0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, - 0x07f1, 0x07f2, 0x07f3, 0x07f4, 0x07f5, 0x07f6, 0x07f7, 0x07f8, - 0x07f9, 0x07fa, 0x07fb, 0x07fc, 0x07fd, 0x07fe, 0x07ff, 0x2000, - 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, - 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, - 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, - 0x2019, 0x201a, 0x201b, 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, - 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, - 0x2029, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, - 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, - 0x2039, 0x203a, 0x203b, 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, - 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, - 0x2049, 0x204a, 0x204b, 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, - 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, - 0x2059, 0x205a, 0x205b, 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, - 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, - 0x2069, 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, - 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, - 0x2079, 0x4cba, 0x4cbb, 0x5d88, 0x5d89, 0x5d8a, 0x5d8b, 0x5d8c, - 0x5d8d, 0x5d8e, 0x5d8f, 0x5db0, 0x5db1, 0x5db2, 0x5db3, 0x5db4, - 0x5db5, 0x5db6, 0x5db7, 0x5db8, 0x5db9, 0x5dba, 0x5dbb, 0x5dbc, - 0x5dbd, 0x5dbe, 0x5dbf, 0x5e40, 0x5e41, 0x5e42, 0x5e43, 0x5e44, - 0x5e45, 0x5e46, 0x5e47, 0x5e48, 0x5e49, 0x5e4a, 0x5e4b, 0x5e4c, - 0x5e4d, 0x5e4e, 0x5e4f, 0x5e50, 0x5e51, 0x5e52, 0x5e53, 0x5e54, - 0x5e55, 0x5e56, 0x5e57, 0x5e58, 0x5e59, 0x5e5a, 0x5e5b, 0x5e5c, - 0x5e5d, 0x5e5e, 0x5e5f, 0x5e60, 0x5e61, 0x5e62, 0x5e63, 0x5e64, - 0x5e65, 0x5e66, 0x5e67, 0x5e68, 0x5e69, 0x5e6a, 0x5e6b, 0x5e6c, - 0x5e6d, 0x5e6e, 0x5e6f, 0x5e70, 0x5e71, 0x5e72, 0x5e73, 0x5e74, - 0x5e75, 0x5e76, 0x5e77, 0x5e78, 0x5e79, 0x5e7a, 0x5e7b, 0x5e7c, - 0x5e7d, 0x5e7e, 0x5e7f, 0x5e80, 0x5e81, 0x5e82, 0x5e83, 0x5e84, - 0x5e85, 0x5e86, 0x5e87, 0x5e88, 0x5e89, 0x5e8a, 0x5e8b, 0x5e8c, - 0x5e8d, 0x5e8e, 0x5e8f, 0x5e90, 0x5e91, 0x5e92, 0x5e93, 0x5e94, - 0x5e95, 0x5e96, 0x5e97, 0x5e98, 0x5e99, 0x5e9a, 0x5e9b, 0x5e9c, - 0x5e9d, 0x5e9e, 0x5e9f, 0x5ea0, 0x5ea1, 0x5ea2, 0x5ea3, 0x5ea4, - 0x5ea5, 0x5ea6, 0x5ea7, 0x5ea8, 0x5ea9, 0x5eaa, 0x5eab, 0x5eac, - 0x5ead, 0x5eae, 0x5eaf, 0x5eb0, 0x5eb1, 0x5eb2, 0x5eb3, 0x5eb4, - 0x5eb5, 0x5eb6, 0x5eb7, 0x5eb8, 0x5eb9, 0x5eba, 0x5ebb, 0x5ebc, - 0x5ebd, 0x5ebe, 0x5ebf, 0x5ec0, 0x5ec1, 0x5ec2, 0x5ec3, 0x5ec4, - 0x5ec5, 0x5ec6, 0x5ec7, 0x5ec8, 0x5ec9, 0x5eca, 0x5ecb, 0x5ecc, - 0x5ecd, 0x5ece, 0x5ecf, 0x5ed0, 0x5ed1, 0x5ed2, 0x5ed3, 0x5ed4, - 0x5ed5, 0x5ed6, 0x5ed7, 0x5ed8, 0x5ed9, 0x5eda, 0x5edb, 0x5edc, - 0x5edd, 0x5ede, 0x5edf, 0x5ee0, 0x5ee1, 0x5ee2, 0x5ee3, 0x5ee4, - 0x5ee5, 0x5ee6, 0x5ee7, 0x5ee8, 0x5ee9, 0x5eea, 0x5eeb, 0x5eec, - 0x5eed, 0x5eee, 0x5eef, 0x5ef0, 0x5ef1, 0x5ef2, 0x5ef3, 0x5ef4, - 0x5ef5, 0x5ef6, 0x5ef7, 0x5ef8, 0x5ef9, 0x5efa, 0x5efb, 0x5efc, - 0x5efd, 0x5efe, 0x5eff, 0x5f00, 0x5f01, 0x5f02, 0x5f03, 0x5f04, - 0x5f05, 0x5f06, 0x5f07, 0x5f08, 0x5f09, 0x5f0a, 0x5f0b, 0x5f0c, - 0x5f0d, 0x5f0e, 0x5f0f, 0x0000, +#define E(mvx, mvy) ((mvx << 8) | mvy) +#define ESCAPE 0 + +const uint16_t ff_msmp4_mv_table0[MSMPEG4_MV_TABLES_NB_ELEMS] = { + ESCAPE, E(31, 39), E(38, 31), E(24, 32), E(23, 30), E(34, 20), + E(33, 22), E(21, 29), E(28, 34), E(33, 24), E(49, 32), E(27, 41), + E(32, 2), E(40, 33), E(34, 39), E(37, 25), E(29, 26), E(38, 28), + E(43, 31), E(37, 33), E(31, 35), E(32, 35), E(25, 29), E(26, 28), + E(32, 42), E(33, 23), E(42, 31), E(35, 36), E(27, 31), E(36, 30), + E(21, 32), E(23, 32), E(43, 32), E(36, 32), E(39, 29), E(38, 30), + E(36, 34), E(34, 36), E(19, 30), E(20, 38), E(41, 41), E(26, 44), + E(41, 53), E(42, 11), E(42, 20), E(42, 25), E(26, 45), E(26, 46), + E(26, 47), E(26, 48), E( 1, 39), E(26, 52), E(37, 46), E(37, 49), + E(37, 63), E(23, 55), E(34, 44), E(42, 38), E(27, 13), E(43, 13), + E(34, 57), E(27, 22), E(31, 51), E(24, 16), E(33, 12), E(16, 28), + E( 3, 35), E(31, 57), E(24, 25), E(31, 33), E(33, 33), E(34, 32), + E(31, 34), E(34, 31), E(33, 20), E(24, 26), E( 4, 28), E(44, 28), + E(44, 29), E(11, 32), E(44, 31), E(31, 62), E(13, 34), E(13, 35), + E(44, 35), E(45, 19), E(13, 49), E(25, 48), E(22, 39), E(38, 40), + E(26, 18), E(38, 43), E(38, 46), E(39, 11), E(32, 6), E(30, 48), + E(39, 19), E(30, 49), E(22, 41), E(32, 10), E(26, 23), E(30, 58), + E(47, 17), E(47, 21), E(47, 23), E(19, 34), E(47, 30), E(30, 60), + E(31, 0), E(35, 44), E( 8, 34), E(23, 26), E(47, 37), E(47, 46), + E(27, 43), E(35, 49), E(47, 59), E(31, 4), E(48, 34), E(35, 59), + E(19, 37), E(36, 22), E(49, 25), E(49, 28), E(33, 46), E(31, 6), + E(39, 40), E(27, 59), E(39, 42), E(49, 36), E(49, 61), E(50, 28), + E(50, 30), E(50, 31), E(39, 43), E(31, 10), E(51, 22), E(51, 23), + E(39, 47), E(28, 20), E(33, 52), E(33, 55), E(21, 36), E(40, 25), + E(31, 16), E(52, 1), E(53, 11), E(40, 27), E(53, 29), E( 9, 5), + E(33, 63), E(31, 18), E(53, 41), E(54, 31), E(54, 34), E(54, 38), + E(55, 1), E(55, 5), E(34, 13), E(15, 28), E(56, 31), E(25, 17), + E(56, 38), E(21, 39), E(21, 41), E(40, 36), E(40, 37), E(25, 22), + E(40, 39), E(58, 33), E(36, 43), E( 5, 43), E(41, 15), E(41, 17), + E(12, 49), E(60, 30), E(41, 21), E(41, 22), E(37, 20), E(22, 10), + E(61, 17), E(18, 25), E(29, 54), E(29, 57), E(30, 3), E(61, 34), + E(30, 8), E(61, 36), E(62, 25), E(62, 31), E(30, 14), E(30, 15), + E(63, 19), E(18, 29), E(13, 25), E(30, 18), E(45, 30), E( 1, 63), + E(34, 16), E(31, 42), E(22, 28), E(35, 13), E(15, 33), E(46, 33), + E(46, 35), E(35, 19), E(31, 46), E(28, 43), E(29, 17), E(29, 19), + E(23, 36), E(41, 39), E(27, 24), E(14, 31), E(53, 32), E(53, 33), + E(27, 26), E(24, 28), E(32, 62), E(57, 33), E(32, 63), E(17, 33), + E(42, 39), E(37, 19), E(29, 49), E(33, 17), E( 1, 31), E(25, 43), + E(32, 13), E(32, 15), E(63, 29), E(26, 25), E(40, 35), E(23, 34), + E(27, 25), E(22, 33), E(24, 29), E(22, 31), E(39, 39), E(43, 35), + E(27, 36), E(37, 24), E( 6, 32), E(42, 30), E(24, 33), E(40, 31), + E(28, 39), E(32, 1), E(32, 41), E(41, 32), E(36, 31), E(28, 32), + E(35, 31), E(29, 31), E(38, 32), E(23, 31), E(27, 30), E(32, 59), + E(32, 22), E(32, 21), E(30, 39), E(35, 25), E(26, 34), E(34, 38), + E(30, 28), E(44, 33), E(36, 23), E(47, 33), E(26, 27), E(30, 44), + E(31, 60), E(41, 30), E(39, 36), E(33, 19), E(33, 29), E(32, 36), + E(22, 34), E(45, 31), E(36, 24), E(32, 16), E(45, 35), E(19, 32), + E(36, 27), E(32, 4), E(43, 33), E(60, 32), E(37, 31), E(35, 33), + E(35, 32), E(34, 29), E(33, 28), E(25, 33), E(25, 34), E(21, 33), + E(36, 35), E(37, 32), E(29, 39), E(31, 24), E(30, 41), E(31, 3), + E(41, 35), E(22, 32), E(32, 39), E(32, 30), E(33, 32), E(32, 29), + E(33, 35), E(31, 28), E(28, 30), E(26, 33), E(31, 49), E(39, 41), + E(20, 28), E(20, 29), E(44, 34), E(23, 38), E(33, 7), E(34, 61), + E(29, 29), E(31, 38), E(35, 11), E(33, 50), E(33, 13), E(28, 41), + E(41, 19), E(23, 47), E(41, 25), E(41, 26), E(29, 15), E(25, 42), + E(26, 41), E(49, 29), E(29, 45), E(24, 27), E(37, 17), E(49, 35), + E(34, 33), E(30, 35), E(50, 32), E(51, 29), E(51, 32), E(26, 24), + E(39, 13), E(25, 26), E(26, 26), E(15, 31), E(39, 24), E(18, 33), + E(42, 28), E(17, 30), E( 4, 31), E(31, 11), E(32, 45), E(32, 46), + E(60, 33), E( 1, 33), E(42, 35), E(32, 57), E( 0, 32), E(12, 32), + E(19, 35), E(35, 45), E(22, 38), E(30, 21), E( 5, 33), E( 5, 31), + E(17, 31), E(29, 21), E(22, 35), E(31, 5), E(31, 17), E(43, 29), + E(37, 38), E(27, 38), E(32, 18), E(32, 58), E(32, 19), E(33, 43), + E(29, 41), E(33, 41), E(31, 37), E(30, 37), E(41, 33), E( 7, 32), + E(28, 31), E(34, 27), E(30, 27), E(37, 28), E(26, 36), E(34, 30), + E(31, 29), E(33, 30), E(27, 32), E(38, 29), E(30, 25), E(36, 28), + E(37, 36), E(21, 34), E(23, 39), E(19, 53), E(34, 41), E(36, 33), + E(32, 28), E(25, 32), E(29, 32), E(29, 33), E(33, 27), E(29, 27), + E(43, 30), E(35, 41), E(29, 43), E(26, 39), E(22, 29), E(32, 7), + E(19, 29), E(32, 17), E(25, 28), E(31, 19), E(41, 28), E(49, 31), + E(28, 25), E(34, 19), E(28, 40), E(39, 26), E(34, 21), E(19, 33), + E(37, 39), E(38, 23), E(29, 40), E(21, 30), E(36, 39), E(42, 34), + E(27, 28), E(59, 33), E(38, 33), E(35, 28), E(33, 34), E(30, 32), + E(30, 36), E(23, 35), E(33, 21), E(35, 23), E(31, 21), E(30, 26), + E(41, 31), E(39, 32), E(32, 27), E(26, 30), E(31, 22), E(37, 37), + E(38, 27), E(39, 27), E(32, 43), E(23, 29), E(32, 60), E(27, 39), + E(25, 35), E(61, 32), E(30, 33), E(30, 34), E(34, 28), E(33, 36), + E(37, 27), E(20, 22), E(20, 27), E(41, 20), E(13, 29), E( 2, 33), + E( 5, 41), E( 5, 42), E( 1, 35), E(32, 24), E(34, 24), E( 5, 62), + E(32, 50), E( 6, 29), E(32, 53), E(35, 50), E(20, 35), E(35, 55), + E(27, 42), E(35, 61), E(35, 63), E(36, 4), E(36, 7), E(13, 42), + E(36, 21), E(41, 46), E(41, 47), E(33, 37), E(28, 33), E(41, 49), + E( 3, 27), E(30, 46), E(42, 17), E(27, 55), E(20, 41), E(30, 50), + E(27, 63), E(28, 4), E(30, 56), E(21, 18), E(33, 8), E(33, 10), + E(14, 18), E(24, 51), E(30, 63), E(42, 36), E(24, 55), E(33, 18), + E(25, 5), E(42, 55), E(43, 9), E(14, 29), E(43, 17), E(43, 21), + E(14, 30), E(43, 27), E( 7, 1), E(36, 59), E(37, 7), E(37, 11), + E(37, 12), E(37, 15), E( 7, 5), E(14, 42), E(25, 24), E(43, 41), + E(43, 43), E(44, 7), E(15, 27), E(37, 22), E( 7, 25), E( 7, 31), + E( 3, 30), E( 1, 37), E( 8, 22), E(15, 39), E(15, 53), E( 8, 29), + E(44, 36), E(44, 37), E(44, 48), E(45, 0), E(45, 5), E(45, 13), + E(45, 17), E( 8, 31), E( 8, 32), E(45, 26), E(21, 46), E(45, 28), + E(28, 44), E(28, 45), E(28, 46), E(21, 53), E(28, 49), E(28, 51), + E(22, 3), E(37, 41), E(46, 3), E(46, 22), E(37, 42), E( 8, 33), + E(29, 5), E(37, 45), E(29, 7), E(22, 22), E(46, 40), E(37, 53), + E(22, 24), E(29, 14), E(47, 25), E(47, 27), E(38, 10), E(38, 12), + E(16, 34), E(38, 16), E(38, 17), E(33, 53), E(38, 20), E(22, 26), + E(47, 39), E(47, 45), E(29, 18), E(25, 45), E(16, 35), E( 0, 33), + E(48, 31), E( 1, 49), E(34, 4), E(48, 39), E(48, 42), E(34, 11), + E(25, 51), E(26, 5), E(26, 13), E(49, 26), E(49, 27), E(26, 17), + E( 1, 52), E(49, 30), E( 4, 0), E(26, 22), E( 4, 12), E(49, 34), + E( 1, 62), E( 9, 36), E(49, 38), E(49, 41), E(49, 47), E(10, 30), + E(49, 63), E(17, 38), E(38, 41), E(17, 43), E(17, 59), E(50, 33), + E(38, 45), E(50, 37), E(50, 38), E(22, 40), E(38, 47), E(51, 24), + E(38, 48), E(38, 49), E(51, 30), E(39, 1), E(39, 10), E(18, 22), + E(22, 49), E(39, 15), E(51, 39), E(22, 59), E(52, 31), E(52, 32), + E(52, 33), E(39, 18), E(53, 13), E(53, 15), E(10, 31), E(23, 21), + E(18, 27), E(29, 44), E(10, 42), E(53, 39), E(29, 46), E(54, 17), + E(11, 26), E(54, 32), E(11, 30), E(11, 31), E(55, 0), E( 1, 30), + E(18, 34), E(55, 9), E(55, 12), E(55, 13), E(55, 25), E(55, 31), + E(55, 32), E(29, 55), E(34, 43), E(18, 35), E(29, 61), E(56, 33), + E(56, 35), E(34, 46), E(57, 25), E(34, 47), E(34, 48), E(29, 62), + E(29, 63), E(57, 38), E(57, 61), E(35, 1), E(35, 2), E(35, 5), + E(35, 7), E(35, 9), E(39, 46), E(35, 10), E(59, 34), E(59, 35), + E(18, 36), E(59, 55), E(39, 51), E(30, 7), E(18, 40), E(40, 23), + E(60, 34), E(60, 37), E(61, 5), E(30, 13), E(18, 42), E(61, 18), + E(61, 25), E(19, 27), E(19, 28), E(41, 11), E(17, 37), E(26, 42), + E(20, 39), E(45, 37), E(46, 31), E(32, 49), E(37, 21), E(22, 27), + E(47, 29), E(29, 47), E(31, 53), E(27, 40), E(29, 51), E(30, 16), + E(21, 26), E(33, 1), E(35, 40), E(18, 30), E(25, 41), E(33, 44), + E(50, 34), E(51, 25), E(42, 27), E( 2, 31), E(15, 35), E(51, 35), + E(53, 31), E(33, 15), E(25, 49), E(29, 1), E(55, 35), E(37, 40), + E(38, 5), E(33, 58), E(38, 21), E(59, 29), E(38, 22), E(33, 59), + E(39, 45), E(13, 31), E(32, 9), E(40, 26), E(61, 9), E(61, 29), + E(32, 11), E( 9, 32), E(44, 30), E( 3, 3), E(31, 13), E(29, 20), + E(25, 18), E(24, 35), E(48, 32), E(16, 32), E(28, 24), E(49, 33), + E(22, 30), E(34, 40), E(31, 47), E(38, 39), E(39, 37), E(44, 32), + E(11, 33), E(35, 24), E(30, 23), E(33, 45), E(33, 47), E(36, 25), + E(31, 59), E(40, 34), E(25, 27), E(27, 27), E(38, 26), E(31, 40), + E(36, 37), E(28, 27), E(32, 31), E(31, 31), E(34, 35), E(32, 37), + E(34, 34), E(24, 31), E(39, 34), E(34, 37), E(27, 33), E(28, 35), + E(31, 61), E(36, 26), E(25, 39), E(45, 33), E(25, 31), E(35, 34), + E( 3, 31), E(34, 22), E(38, 37), E(39, 25), E(40, 30), E(38, 25), + E( 1, 32), E(25, 30), E(39, 35), E(30, 38), E(37, 29), E(32, 40), + E(28, 28), E(29, 38), E(32, 5), E(37, 34), E(31, 27), E(35, 27), + E(27, 29), E(23, 27), E(28, 23), E(33, 42), E(46, 32), E(15, 32), + E(13, 33), E(24, 36), E(41, 37), E(24, 37), E(34, 17), E(34, 18), + E(30, 22), E(26, 40), E(24, 38), E(14, 32), E(60, 31), E(21, 35), + E(29, 24), E(39, 17), E(23, 25), E(35, 17), E(37, 23), E(30, 24), + E(32, 61), E(19, 31), E(24, 34), E(25, 25), E(26, 38), E(45, 32), + E(38, 35), E(36, 29), E( 3, 32), E(26, 29), E(36, 36), E(30, 31), + E(59, 32), E(28, 36), E(63, 32), E(26, 32), E(38, 34), E(63, 33), + E(31, 20), E(27, 11), E(20, 32), E(24, 30), E(33, 3), E(37, 35), + E(28, 38), E(39, 30), E(32, 3), E(31, 26), E(39, 31), E(35, 29), + E(31, 30), E(32, 38), E(23, 33), E(23, 3), E( 9, 29), E(25, 40), + E( 9, 31), E(29, 53), E(20, 30), E(30, 17), E(30, 20), E(42, 37), + E(18, 31), E(28, 42), E(25, 47), E(28, 47), E(28, 54), E(21, 38), + E(29, 9), E(43, 34), E(29, 13), E(43, 37), E(26, 21), E(44, 25), + E(44, 27), E(21, 43), E(38, 42), E(35, 30), E(21, 45), E(24, 40), + E(45, 25), E(45, 27), E(35, 46), E(39, 22), E(22, 25), E(35, 53), + E(36, 20), E(34, 2), E(34, 14), E(45, 39), E(34, 15), E(29, 22), + E(31, 44), E(46, 34), E(25, 21), E(46, 38), E(16, 33), E(17, 27), + E(31, 48), E(20, 34), E(32, 52), E(47, 35), E(47, 47), E(47, 49), + E(32, 54), E(49, 2), E(49, 13), E(49, 23), E(31, 52), E( 1, 29), + E(27, 45), E(28, 22), E(39, 49), E(39, 54), E(21, 21), E(36, 40), + E(23, 42), E(51, 31), E( 2, 30), E(40, 29), E(51, 34), E(32, 0), + E(53, 25), E(24, 23), E(30, 51), E(24, 24), E(30, 59), E(21, 28), + E(40, 38), E(57, 29), E(57, 31), E(31, 2), E(41, 13), E(58, 31), + E(32, 8), E(12, 31), E( 4, 33), E(32, 12), E(34, 45), E(59, 41), + E(31, 7), E(32, 14), E(13, 30), E( 9, 25), E(35, 18), E(26, 43), + E(35, 20), E(37, 43), E(61, 35), E(37, 44), E(63, 1), E(26, 49), + E(29, 42), E(41, 42), E(45, 34), E(33, 51), E(34, 42), E(47, 31), + E(41, 36), E(22, 36), E(42, 29), E(35, 21), E(35, 22), E(23, 37), + E(32, 44), E(35, 43), E(43, 25), E(32, 47), E( 7, 33), E(31, 45), + E(41, 27), E(20, 31), E(31, 58), E(16, 31), E(13, 32), E(63, 31), + E(25, 38), E(30, 43), E(33, 61), E(31, 43), E(41, 29), E(34, 23), + E(39, 28), E(47, 32), E(40, 28), E(58, 32), E(59, 31), E(41, 34), + E(33, 5), E( 3, 33), E(17, 32), E(61, 33), E(42, 33), E(21, 31), + E(26, 35), E(35, 26), E(29, 36), E(26, 31), E(33, 38), E(30, 30), + E(31, 32), E(33, 31), E(37, 30), E(31, 23), E(30, 42), E(26, 37), + E(33, 26), E(27, 35), E(31, 36), E(27, 34), E(35, 37), E(29, 23), + E(36, 38), E(61, 31), E(33, 40), E(37, 26), E(62, 32), E(35, 38), + E(57, 32), E(31, 41), E(34, 26), E(34, 25), E(40, 32), E(35, 35), + E(29, 34), E(32, 25), E(29, 30), E(28, 26), E(38, 18), E(23, 41), + E(32, 20), E(29, 28), E(29, 25), E(28, 37), E(42, 32), E(33, 39), + E(32, 26), E(31, 25), E(30, 40), E(35, 47), E(30, 45), E(30, 54), + E(31, 1), E(32, 23), E(33, 25), E(42, 26), E(47, 34), E(39, 38), + E(38, 14), E(40, 22), E(40, 24), E(51, 33), E(55, 34), E(56, 32), + E(18, 32), E(21, 37), E(39, 21), E(39, 23), E(33, 49), E(17, 35), + E(41, 23), E(23, 28), E(24, 39), E(43, 39), E(25, 23), E(31, 55), + E(20, 33), E(25, 37), E(38, 38), E(25, 36), E(27, 37), E(29, 37), + E( 4, 32), E(39, 33), E( 5, 32), E(28, 29), E(38, 24), E(17, 29), + E(35, 39), E( 2, 32), E(38, 36), E(30, 29), E(29, 35), E(32, 34), + E(32, 33), E(32, 32), }; -static const uint8_t table0_mv_bits[1100] = { - 1, 4, 4, 4, 5, 5, 5, 6, - 6, 6, 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, 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, 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, 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, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 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, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 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, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 8, -}; - -static const uint8_t table0_mvx[1099] = { - 32, 32, 31, 32, 33, 31, 33, 31, - 33, 32, 34, 32, 30, 32, 31, 34, - 35, 32, 34, 33, 29, 33, 30, 30, - 31, 31, 35, 29, 33, 35, 33, 34, - 31, 29, 30, 34, 30, 36, 28, 32, - 34, 37, 30, 27, 32, 25, 39, 32, - 34, 32, 35, 35, 35, 31, 35, 29, - 32, 29, 30, 29, 37, 27, 36, 38, - 37, 33, 32, 31, 29, 31, 28, 36, - 33, 30, 34, 33, 33, 28, 27, 25, - 31, 26, 39, 32, 32, 31, 33, 39, - 31, 38, 28, 36, 21, 23, 43, 36, - 34, 41, 30, 25, 28, 31, 30, 34, - 38, 35, 61, 34, 28, 30, 37, 37, - 35, 27, 36, 3, 59, 38, 37, 32, - 31, 29, 26, 33, 37, 33, 27, 27, - 35, 34, 34, 40, 42, 33, 32, 29, - 4, 5, 28, 24, 25, 35, 39, 38, - 32, 23, 27, 32, 30, 35, 26, 34, - 60, 36, 29, 22, 26, 41, 7, 30, - 38, 30, 36, 29, 30, 41, 26, 25, - 32, 34, 24, 39, 1, 25, 39, 32, - 28, 29, 32, 38, 26, 36, 28, 63, - 28, 39, 23, 21, 26, 35, 31, 35, - 57, 31, 29, 29, 28, 30, 27, 35, - 2, 38, 40, 34, 37, 29, 38, 43, - 26, 32, 33, 42, 24, 40, 28, 32, - 32, 32, 36, 32, 43, 25, 21, 31, - 30, 31, 41, 29, 33, 37, 26, 37, - 27, 59, 23, 33, 35, 31, 31, 37, - 38, 39, 32, 23, 32, 27, 37, 36, - 31, 40, 25, 27, 38, 31, 36, 28, - 31, 36, 25, 45, 3, 34, 38, 39, - 40, 38, 30, 32, 19, 24, 25, 26, - 45, 20, 24, 33, 33, 31, 41, 34, - 39, 47, 40, 58, 59, 41, 33, 3, - 17, 61, 42, 30, 26, 29, 36, 61, - 33, 37, 62, 28, 25, 38, 25, 38, - 17, 23, 34, 33, 21, 33, 49, 27, - 32, 23, 27, 22, 24, 22, 39, 43, - 27, 37, 6, 42, 47, 26, 30, 31, - 41, 39, 33, 22, 45, 36, 32, 45, - 19, 22, 30, 5, 5, 17, 29, 22, - 31, 31, 43, 37, 27, 32, 32, 32, - 33, 34, 43, 35, 29, 26, 22, 32, - 19, 32, 25, 31, 41, 49, 28, 34, - 28, 39, 34, 19, 37, 38, 29, 21, - 36, 42, 24, 48, 16, 28, 49, 22, - 34, 31, 38, 39, 44, 11, 35, 30, - 33, 33, 23, 28, 33, 46, 15, 13, - 24, 41, 24, 34, 34, 30, 26, 24, - 14, 60, 21, 29, 39, 23, 35, 37, - 63, 45, 33, 34, 47, 41, 22, 42, - 35, 35, 23, 32, 35, 43, 32, 7, - 31, 41, 20, 31, 16, 13, 63, 25, - 30, 32, 35, 30, 30, 31, 42, 47, - 39, 38, 40, 40, 51, 55, 56, 18, - 21, 39, 39, 33, 17, 41, 23, 24, - 43, 25, 31, 20, 19, 45, 1, 34, - 31, 22, 35, 15, 46, 46, 35, 31, - 28, 29, 29, 23, 41, 27, 14, 53, - 53, 27, 24, 32, 57, 32, 17, 42, - 37, 29, 33, 1, 25, 32, 32, 63, - 26, 40, 44, 36, 31, 39, 20, 20, - 44, 23, 33, 34, 35, 33, 33, 28, - 41, 23, 41, 41, 29, 25, 26, 49, - 29, 24, 37, 49, 50, 51, 51, 26, - 39, 25, 26, 15, 39, 18, 42, 17, - 4, 31, 32, 32, 60, 1, 42, 32, - 0, 12, 19, 35, 21, 41, 17, 26, - 20, 45, 46, 32, 37, 22, 47, 29, - 31, 27, 29, 30, 21, 33, 35, 18, - 25, 33, 50, 51, 42, 2, 15, 51, - 53, 33, 25, 29, 55, 37, 38, 33, - 38, 59, 38, 33, 39, 13, 32, 40, - 61, 61, 32, 9, 44, 3, 31, 29, - 25, 31, 27, 23, 9, 25, 9, 29, - 20, 30, 30, 42, 18, 28, 25, 28, - 28, 21, 29, 43, 29, 43, 26, 44, - 44, 21, 38, 21, 24, 45, 45, 35, - 39, 22, 35, 36, 34, 34, 45, 34, - 29, 31, 46, 25, 46, 16, 17, 31, - 20, 32, 47, 47, 47, 32, 49, 49, - 49, 31, 1, 27, 28, 39, 39, 21, - 36, 23, 51, 2, 40, 51, 32, 53, - 24, 30, 24, 30, 21, 40, 57, 57, - 31, 41, 58, 32, 12, 4, 32, 34, - 59, 31, 32, 13, 9, 35, 26, 35, - 37, 61, 37, 63, 26, 29, 41, 38, - 23, 20, 41, 26, 41, 42, 42, 42, - 26, 26, 26, 26, 1, 26, 37, 37, - 37, 23, 34, 42, 27, 43, 34, 27, - 31, 24, 33, 16, 3, 31, 24, 33, - 24, 4, 44, 44, 11, 44, 31, 13, - 13, 44, 45, 13, 25, 22, 38, 26, - 38, 38, 39, 32, 30, 39, 30, 22, - 32, 26, 30, 47, 47, 47, 19, 47, - 30, 31, 35, 8, 23, 47, 47, 27, - 35, 47, 31, 48, 35, 19, 36, 49, - 49, 33, 31, 39, 27, 39, 49, 49, - 50, 50, 50, 39, 31, 51, 51, 39, - 28, 33, 33, 21, 40, 31, 52, 53, - 40, 53, 9, 33, 31, 53, 54, 54, - 54, 55, 55, 34, 15, 56, 25, 56, - 21, 21, 40, 40, 25, 40, 58, 36, - 5, 41, 41, 12, 60, 41, 41, 37, - 22, 61, 18, 29, 29, 30, 61, 30, - 61, 62, 62, 30, 30, 63, 18, 13, - 30, 23, 19, 20, 20, 41, 13, 2, - 5, 5, 1, 5, 32, 6, 32, 35, - 20, 35, 27, 35, 35, 36, 36, 13, - 36, 41, 41, 41, 3, 30, 42, 27, - 20, 30, 27, 28, 30, 21, 33, 33, - 14, 24, 30, 42, 24, 33, 25, 42, - 43, 14, 43, 43, 14, 43, 7, 36, - 37, 37, 37, 37, 7, 14, 25, 43, - 43, 44, 15, 37, 7, 7, 3, 1, - 8, 15, 15, 8, 44, 44, 44, 45, - 45, 45, 45, 8, 8, 45, 21, 45, - 28, 28, 28, 21, 28, 28, 22, 37, - 46, 46, 37, 8, 29, 37, 29, 22, - 46, 37, 22, 29, 47, 47, 38, 38, - 16, 38, 38, 33, 38, 22, 47, 47, - 29, 25, 16, 0, 48, 1, 34, 48, - 48, 34, 25, 26, 26, 49, 49, 26, - 1, 49, 4, 26, 4, 49, 1, 9, - 49, 49, 49, 10, 49, 17, 38, 17, - 17, 50, 38, 50, 50, 22, 38, 51, - 38, 38, 51, 39, 39, 18, 22, 39, - 51, 22, 52, 52, 52, 39, 53, 53, - 10, 23, 18, 29, 10, 53, 29, 54, - 11, 54, 11, 11, 55, 1, 18, 55, - 55, 55, 55, 55, 55, 29, 34, 18, - 29, 56, 56, 34, 57, 34, 34, 29, - 29, 57, 57, 35, 35, 35, 35, 35, - 39, 35, 59, 59, 18, 59, 39, 30, - 18, 40, 60, 60, 61, 30, 18, 61, - 61, 19, 19, -}; - -static const uint8_t table0_mvy[1099] = { - 32, 31, 32, 33, 32, 31, 31, 33, - 33, 34, 32, 30, 32, 35, 34, 31, - 32, 29, 33, 30, 32, 34, 33, 31, - 30, 35, 31, 31, 29, 33, 35, 30, - 29, 33, 34, 34, 30, 32, 32, 36, - 29, 32, 35, 32, 28, 32, 32, 27, - 35, 37, 34, 29, 30, 36, 35, 34, - 25, 30, 29, 35, 33, 31, 31, 32, - 31, 28, 39, 28, 29, 37, 31, 33, - 27, 36, 28, 36, 37, 33, 33, 31, - 27, 32, 31, 38, 26, 25, 25, 33, - 39, 31, 34, 30, 32, 32, 32, 34, - 36, 32, 28, 33, 30, 38, 37, 27, - 33, 28, 32, 37, 35, 38, 29, 34, - 27, 29, 29, 32, 32, 34, 35, 3, - 26, 36, 31, 38, 30, 26, 35, 34, - 37, 26, 25, 32, 32, 39, 23, 37, - 32, 32, 29, 32, 29, 36, 29, 30, - 41, 31, 30, 21, 39, 25, 34, 38, - 32, 35, 39, 32, 33, 33, 32, 27, - 29, 25, 28, 27, 26, 31, 30, 35, - 24, 24, 31, 34, 32, 30, 35, 40, - 28, 38, 5, 35, 29, 36, 36, 32, - 38, 30, 33, 31, 35, 26, 23, 38, - 32, 41, 28, 25, 37, 40, 37, 39, - 32, 36, 33, 39, 25, 26, 28, 31, - 28, 42, 23, 31, 33, 31, 39, 1, - 59, 22, 27, 4, 33, 34, 33, 24, - 41, 3, 35, 41, 41, 28, 36, 36, - 28, 33, 35, 21, 23, 21, 22, 37, - 27, 27, 43, 29, 60, 39, 27, 25, - 59, 34, 27, 27, 26, 40, 37, 27, - 61, 26, 39, 33, 31, 22, 37, 25, - 30, 25, 24, 61, 31, 34, 25, 38, - 32, 32, 30, 3, 61, 43, 29, 23, - 28, 32, 28, 32, 31, 34, 5, 33, - 32, 33, 33, 42, 37, 23, 38, 31, - 40, 26, 32, 26, 37, 38, 36, 24, - 29, 30, 20, 22, 29, 24, 32, 41, - 2, 34, 25, 33, 29, 31, 39, 35, - 36, 24, 32, 30, 33, 27, 44, 60, - 30, 36, 19, 34, 31, 24, 16, 35, - 32, 38, 21, 33, 31, 31, 21, 35, - 5, 17, 29, 38, 38, 18, 58, 19, - 43, 41, 30, 41, 43, 39, 29, 7, - 29, 17, 28, 19, 28, 31, 25, 19, - 40, 26, 21, 33, 39, 23, 40, 30, - 39, 34, 35, 32, 32, 24, 33, 30, - 40, 47, 39, 37, 32, 33, 24, 23, - 45, 47, 27, 23, 42, 32, 32, 33, - 36, 37, 37, 17, 18, 22, 40, 38, - 32, 31, 35, 24, 17, 25, 17, 23, - 33, 34, 51, 42, 31, 36, 36, 29, - 21, 22, 37, 44, 43, 25, 47, 33, - 45, 27, 31, 58, 31, 32, 31, 38, - 43, 20, 47, 45, 54, 1, 26, 34, - 38, 14, 22, 24, 33, 34, 32, 32, - 37, 21, 23, 49, 35, 23, 28, 39, - 39, 23, 55, 33, 30, 30, 63, 16, - 42, 28, 13, 33, 33, 35, 19, 46, - 43, 17, 19, 36, 39, 24, 31, 32, - 33, 26, 28, 62, 33, 63, 33, 39, - 19, 49, 17, 31, 43, 13, 15, 29, - 25, 35, 33, 23, 49, 41, 28, 29, - 34, 38, 7, 61, 11, 50, 13, 41, - 19, 47, 25, 26, 15, 42, 41, 29, - 45, 27, 17, 35, 32, 29, 32, 24, - 13, 26, 26, 31, 24, 33, 28, 30, - 31, 11, 45, 46, 33, 33, 35, 57, - 32, 32, 35, 45, 34, 11, 37, 42, - 39, 37, 31, 49, 21, 27, 29, 47, - 53, 40, 51, 16, 26, 1, 40, 30, - 41, 44, 34, 25, 27, 31, 35, 35, - 31, 15, 49, 1, 35, 40, 5, 58, - 21, 29, 22, 59, 45, 31, 9, 26, - 9, 29, 11, 32, 30, 3, 13, 20, - 18, 20, 11, 3, 29, 40, 31, 53, - 30, 17, 20, 37, 31, 42, 47, 47, - 54, 38, 9, 34, 13, 37, 21, 25, - 27, 43, 42, 45, 40, 25, 27, 46, - 22, 25, 53, 20, 2, 14, 39, 15, - 22, 44, 34, 21, 38, 33, 27, 48, - 34, 52, 35, 47, 49, 54, 2, 13, - 23, 52, 29, 45, 22, 49, 54, 21, - 40, 42, 31, 30, 29, 34, 0, 25, - 23, 51, 24, 59, 28, 38, 29, 31, - 2, 13, 31, 8, 31, 33, 12, 45, - 41, 7, 14, 30, 25, 18, 43, 20, - 43, 35, 44, 1, 49, 42, 42, 18, - 41, 38, 41, 44, 53, 11, 20, 25, - 45, 46, 47, 48, 39, 52, 46, 49, - 63, 55, 44, 38, 13, 13, 57, 22, - 51, 16, 12, 28, 35, 57, 25, 20, - 26, 28, 28, 29, 32, 31, 62, 34, - 35, 35, 19, 49, 48, 39, 40, 18, - 43, 46, 11, 6, 48, 19, 49, 41, - 10, 23, 58, 17, 21, 23, 34, 30, - 60, 0, 44, 34, 26, 37, 46, 43, - 49, 59, 4, 34, 59, 37, 22, 25, - 28, 46, 6, 40, 59, 42, 36, 61, - 28, 30, 31, 43, 10, 22, 23, 47, - 20, 52, 55, 36, 25, 16, 1, 11, - 27, 29, 5, 63, 18, 41, 31, 34, - 38, 1, 5, 13, 28, 31, 17, 38, - 39, 41, 36, 37, 22, 39, 33, 43, - 43, 15, 17, 49, 30, 21, 22, 20, - 10, 17, 25, 54, 57, 3, 34, 8, - 36, 25, 31, 14, 15, 19, 29, 25, - 18, 39, 53, 22, 27, 20, 29, 33, - 41, 42, 35, 62, 50, 29, 53, 50, - 35, 55, 42, 61, 63, 4, 7, 42, - 21, 46, 47, 49, 27, 46, 17, 55, - 41, 50, 63, 4, 56, 18, 8, 10, - 18, 51, 63, 36, 55, 18, 5, 55, - 9, 29, 17, 21, 30, 27, 1, 59, - 7, 11, 12, 15, 5, 42, 24, 41, - 43, 7, 27, 22, 25, 31, 30, 37, - 22, 39, 53, 29, 36, 37, 48, 0, - 5, 13, 17, 31, 32, 26, 46, 28, - 44, 45, 46, 53, 49, 51, 3, 41, - 3, 22, 42, 33, 5, 45, 7, 22, - 40, 53, 24, 14, 25, 27, 10, 12, - 34, 16, 17, 53, 20, 26, 39, 45, - 18, 45, 35, 33, 31, 49, 4, 39, - 42, 11, 51, 5, 13, 26, 27, 17, - 52, 30, 0, 22, 12, 34, 62, 36, - 38, 41, 47, 30, 63, 38, 41, 43, - 59, 33, 45, 37, 38, 40, 47, 24, - 48, 49, 30, 1, 10, 22, 49, 15, - 39, 59, 31, 32, 33, 18, 13, 15, - 31, 21, 27, 44, 42, 39, 46, 17, - 26, 32, 30, 31, 0, 30, 34, 9, - 12, 13, 25, 31, 32, 55, 43, 35, - 61, 33, 35, 46, 25, 47, 48, 62, - 63, 38, 61, 1, 2, 5, 7, 9, - 46, 10, 34, 35, 36, 55, 51, 7, - 40, 23, 34, 37, 5, 13, 42, 18, - 25, 27, 28, +const uint8_t ff_msmp4_mv_table0_lens[MSMPEG4_MV_TABLES_NB_ELEMS] = { + 8, 12, 12, 13, 15, 15, 15, 15, 12, 15, 15, 15, 15, 14, 14, 14, 14, 14, + 14, 11, 9, 8, 13, 14, 14, 14, 14, 13, 11, 12, 12, 12, 12, 10, 13, 13, + 12, 12, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 6, 6, 7, + 8, 8, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 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, 13, 12, 11, 10, + 9, 9, 11, 13, 13, 14, 14, 13, 13, 13, 13, 13, 12, 16, 16, 15, 15, 15, + 15, 15, 15, 15, 9, 10, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 11, 9, + 8, 10, 11, 12, 14, 14, 13, 10, 13, 14, 14, 14, 14, 13, 11, 7, 5, 8, + 9, 11, 12, 13, 16, 16, 16, 16, 16, 16, 16, 16, 11, 12, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 10, 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, 11, 12, 13, 13, 11, 12, 13, 14, 14, 9, 9, 8, 10, 13, 13, 13, + 14, 16, 17, 17, 15, 11, 10, 10, 8, 9, 11, 13, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 12, 12, 8, 7, 11, 14, 14, 14, 14, 13, 13, 10, 10, 13, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 12, 8, 9, 11, 11, 14, 17, 17, 17, 17, 17, + 17, 17, 17, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 11, 11, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 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, 4, 5, 10, 10, 9, 13, 13, 12, 11, 12, 14, 14, 14, 14, 11, 10, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 13, 13, 13, 13, 12, 11, 12, + 12, 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, 13, 12, 12, 13, 13, 8, + 12, 13, 13, 11, 12, 15, 16, 16, 14, 14, 14, 12, 13, 13, 12, 12, 11, 10, + 8, 11, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 10, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 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, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 12, 12, 12, 9, 4, 5, 12, 13, 14, 14, 12, 12, 10, 12, 12, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 10, 10, 10, 10, 14, 16, 16, + 15, 13, 13, 13, 12, 12, 11, 11, 13, 15, 15, 15, 15, 12, 11, 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, 13, 12, 12, 11, 12, 12, 14, 14, 13, 13, 13, 10, 10, 6, + 4, 1, }; /* motion vector table 1 */ -static const uint16_t table1_mv_code[1100] = { - 0x0000, 0x0007, 0x0009, 0x000f, 0x000a, 0x0011, 0x001a, 0x001c, - 0x0011, 0x0031, 0x0025, 0x002d, 0x002f, 0x006f, 0x0075, 0x0041, - 0x004c, 0x004e, 0x005c, 0x0060, 0x0062, 0x0066, 0x0068, 0x0069, - 0x006b, 0x00a6, 0x00c1, 0x00cb, 0x00cc, 0x00ce, 0x00da, 0x00e8, - 0x00ee, 0x0087, 0x0090, 0x009e, 0x009f, 0x00ba, 0x00ca, 0x00d8, - 0x00db, 0x00df, 0x0104, 0x0109, 0x010c, 0x0143, 0x0145, 0x014a, - 0x0156, 0x015c, 0x01b3, 0x01d3, 0x01da, 0x0103, 0x0109, 0x010b, - 0x0122, 0x0127, 0x0134, 0x0161, 0x0164, 0x0176, 0x0184, 0x018d, - 0x018e, 0x018f, 0x0190, 0x0193, 0x0196, 0x019d, 0x019e, 0x019f, - 0x01a9, 0x01b2, 0x01b4, 0x01ba, 0x01bb, 0x01bc, 0x0201, 0x0202, - 0x0205, 0x0207, 0x020d, 0x0210, 0x0211, 0x0215, 0x021b, 0x021f, - 0x0281, 0x0285, 0x0290, 0x029c, 0x029d, 0x02a2, 0x02a7, 0x02a8, - 0x02aa, 0x02b0, 0x02b1, 0x02b4, 0x02bc, 0x02bf, 0x0320, 0x0326, - 0x0327, 0x0329, 0x032a, 0x0336, 0x0360, 0x0362, 0x0363, 0x0372, - 0x03b2, 0x03bc, 0x03bd, 0x0203, 0x0205, 0x021a, 0x0249, 0x024a, - 0x024c, 0x02c7, 0x02ca, 0x02ce, 0x02ef, 0x030d, 0x0322, 0x0325, - 0x0338, 0x0373, 0x037a, 0x0409, 0x0415, 0x0416, 0x0418, 0x0428, - 0x042d, 0x042f, 0x0434, 0x0508, 0x0509, 0x0510, 0x0511, 0x051c, - 0x051e, 0x0524, 0x0541, 0x0543, 0x0546, 0x0547, 0x054d, 0x0557, - 0x055f, 0x056a, 0x056c, 0x056d, 0x056f, 0x0576, 0x0577, 0x057a, - 0x057b, 0x057c, 0x057d, 0x0600, 0x0601, 0x0603, 0x0614, 0x0616, - 0x0617, 0x061c, 0x061f, 0x0642, 0x0648, 0x0649, 0x064a, 0x064b, - 0x0657, 0x0668, 0x0669, 0x066b, 0x066e, 0x067f, 0x06c2, 0x06c8, - 0x06cb, 0x06de, 0x06df, 0x06e2, 0x06e3, 0x06ef, 0x0748, 0x074b, - 0x076e, 0x076f, 0x077c, 0x0409, 0x0423, 0x0428, 0x0429, 0x042a, - 0x042b, 0x0432, 0x0433, 0x0496, 0x049a, 0x04d5, 0x04db, 0x0581, - 0x0582, 0x058b, 0x058c, 0x058d, 0x0598, 0x0599, 0x059a, 0x059e, - 0x05dd, 0x0619, 0x0632, 0x0633, 0x0648, 0x0672, 0x06a1, 0x06a2, - 0x06a3, 0x06af, 0x06e2, 0x06e3, 0x06e4, 0x0800, 0x0801, 0x0802, - 0x0803, 0x081a, 0x081b, 0x0829, 0x082f, 0x0832, 0x083e, 0x083f, - 0x0852, 0x0853, 0x0858, 0x086b, 0x0877, 0x0878, 0x0879, 0x087a, - 0x087b, 0x0a00, 0x0a01, 0x0a0d, 0x0a0e, 0x0a0f, 0x0a24, 0x0a37, - 0x0a3a, 0x0a3b, 0x0a3e, 0x0a46, 0x0a47, 0x0a4a, 0x0a4b, 0x0a5f, - 0x0a79, 0x0a7a, 0x0a7b, 0x0a80, 0x0a81, 0x0a84, 0x0a85, 0x0a99, - 0x0aa5, 0x0aa6, 0x0ab8, 0x0aba, 0x0abb, 0x0abc, 0x0abd, 0x0ac8, - 0x0ace, 0x0acf, 0x0ad7, 0x0adc, 0x0aeb, 0x0c04, 0x0c25, 0x0c26, - 0x0c27, 0x0c2a, 0x0c2b, 0x0c3a, 0x0c3b, 0x0c3c, 0x0c3d, 0x0ca0, - 0x0cad, 0x0cd4, 0x0cd5, 0x0cfc, 0x0cfd, 0x0d86, 0x0d92, 0x0d93, - 0x0d94, 0x0d95, 0x0db0, 0x0db8, 0x0db9, 0x0dba, 0x0dbb, 0x0dc0, - 0x0dc2, 0x0dc3, 0x0dda, 0x0ddb, 0x0ddc, 0x0ddd, 0x0e92, 0x0e93, - 0x0e94, 0x0e95, 0x0ec7, 0x0ecc, 0x0ece, 0x0ecf, 0x0ed8, 0x0ed9, - 0x0eda, 0x0edb, 0x0808, 0x0809, 0x080a, 0x0810, 0x0811, 0x0844, - 0x0845, 0x0861, 0x0862, 0x0863, 0x086c, 0x0922, 0x0923, 0x092e, - 0x092f, 0x0936, 0x0937, 0x09b1, 0x09b2, 0x09b3, 0x09b4, 0x09b5, - 0x09b8, 0x09b9, 0x09ba, 0x09bb, 0x09bc, 0x09bd, 0x09be, 0x09bf, - 0x0b00, 0x0b15, 0x0b2c, 0x0b2d, 0x0b2e, 0x0b2f, 0x0b36, 0x0bb9, - 0x0c28, 0x0c2a, 0x0c2b, 0x0c2c, 0x0c2d, 0x0c2e, 0x0c2f, 0x0c30, - 0x0c31, 0x0c38, 0x0c60, 0x0c61, 0x0c62, 0x0c63, 0x0c8d, 0x0c8e, - 0x0c8f, 0x0c92, 0x0cbe, 0x0cbf, 0x0ce6, 0x0ce7, 0x0d40, 0x0d41, - 0x0d57, 0x0d58, 0x0d59, 0x0d5a, 0x0d5b, 0x0d5c, 0x0d5d, 0x0d98, - 0x0d99, 0x0d9a, 0x0d9b, 0x0d9c, 0x0d9d, 0x0dad, 0x0dae, 0x0daf, - 0x0dc0, 0x0dc1, 0x0dc2, 0x0dc3, 0x0dca, 0x0dcb, 0x0dec, 0x0ded, - 0x0dee, 0x0def, 0x1018, 0x1022, 0x1023, 0x1030, 0x1031, 0x1032, - 0x1033, 0x1050, 0x1051, 0x105c, 0x1074, 0x1075, 0x1076, 0x1077, - 0x1078, 0x1079, 0x107a, 0x107b, 0x10b2, 0x10b3, 0x10b8, 0x10b9, - 0x10ba, 0x10bb, 0x10d4, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x1404, - 0x1405, 0x1406, 0x1407, 0x1410, 0x1411, 0x1412, 0x1413, 0x1414, - 0x1415, 0x1416, 0x1417, 0x1418, 0x1419, 0x1466, 0x1467, 0x1468, - 0x1469, 0x146a, 0x146b, 0x146c, 0x146d, 0x147e, 0x147f, 0x1488, - 0x1489, 0x148a, 0x148b, 0x14b6, 0x14b7, 0x14b8, 0x14b9, 0x14ba, - 0x14bb, 0x14bc, 0x14bd, 0x14f0, 0x14f1, 0x14f8, 0x14f9, 0x14fa, - 0x14fb, 0x14fc, 0x14fd, 0x14fe, 0x14ff, 0x152a, 0x152b, 0x152c, - 0x152d, 0x152e, 0x152f, 0x1530, 0x1531, 0x1548, 0x1549, 0x154e, - 0x154f, 0x1558, 0x1559, 0x155a, 0x155b, 0x1572, 0x159a, 0x159b, - 0x15ac, 0x15ba, 0x15bb, 0x15d0, 0x15d1, 0x15d2, 0x15d3, 0x15d4, - 0x15d5, 0x181d, 0x181e, 0x181f, 0x1840, 0x1841, 0x1842, 0x1843, - 0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x1861, 0x1862, - 0x1863, 0x1864, 0x1865, 0x1866, 0x1867, 0x1868, 0x1869, 0x186a, - 0x186b, 0x186c, 0x186d, 0x186e, 0x191b, 0x191c, 0x191d, 0x191e, - 0x191f, 0x1942, 0x1943, 0x1944, 0x1945, 0x1946, 0x1947, 0x1958, - 0x1959, 0x19ed, 0x19ee, 0x19ef, 0x19f0, 0x19f1, 0x19f2, 0x19f3, - 0x19f4, 0x19f5, 0x19f6, 0x19f7, 0x1b0e, 0x1b0f, 0x1b62, 0x1b63, - 0x1b64, 0x1b65, 0x1b66, 0x1b67, 0x1b68, 0x1b69, 0x1b6a, 0x1b6b, - 0x1b6c, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b82, 0x1ba8, 0x1ba9, 0x1baa, - 0x1bab, 0x1bac, 0x1bad, 0x1bae, 0x1baf, 0x1bb0, 0x1bb1, 0x1bb2, - 0x1bb3, 0x1d80, 0x1d81, 0x1d82, 0x1d83, 0x1d84, 0x1d85, 0x1d86, - 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, 0x1d8c, 0x1d8d, 0x1007, - 0x1008, 0x1009, 0x100a, 0x100b, 0x100c, 0x100d, 0x100e, 0x100f, - 0x1016, 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, - 0x1087, 0x10c0, 0x123a, 0x123b, 0x123c, 0x123d, 0x123e, 0x123f, - 0x1240, 0x1241, 0x1242, 0x1243, 0x1350, 0x1352, 0x1353, 0x1358, - 0x1359, 0x135a, 0x135b, 0x135c, 0x135d, 0x135e, 0x135f, 0x1360, - 0x1361, 0x1602, 0x1603, 0x160c, 0x160d, 0x160e, 0x160f, 0x1620, - 0x1621, 0x1622, 0x1623, 0x1624, 0x1625, 0x1626, 0x1627, 0x1628, - 0x1629, 0x166e, 0x166f, 0x167c, 0x167d, 0x167e, 0x167f, 0x1770, - 0x1771, 0x1852, 0x1853, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, - 0x1877, 0x1878, 0x1879, 0x187a, 0x187b, 0x187c, 0x187d, 0x187e, - 0x187f, 0x1918, 0x1919, 0x1926, 0x1927, 0x1970, 0x1971, 0x1972, - 0x1973, 0x1974, 0x1975, 0x1976, 0x1977, 0x1978, 0x1979, 0x197a, - 0x197b, 0x1aa0, 0x1aa1, 0x1aa2, 0x1aa3, 0x1aa4, 0x1aa5, 0x1aa6, - 0x1aa7, 0x1aa8, 0x1aa9, 0x1aaa, 0x1aab, 0x1aac, 0x1aad, 0x1b3c, - 0x1b3d, 0x1b3e, 0x1b3f, 0x1b50, 0x1b51, 0x1b52, 0x1b53, 0x1b54, - 0x1b55, 0x1b56, 0x1b57, 0x1b58, 0x1b59, 0x2032, 0x2033, 0x2034, - 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, 0x203c, - 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, 0x20ba, - 0x20bb, 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20e0, 0x20e1, 0x20e2, - 0x20e3, 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x21aa, 0x21ab, 0x21c0, - 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, 0x21c8, - 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, 0x21d0, - 0x21d1, 0x21d2, 0x21d3, 0x2894, 0x2895, 0x2896, 0x2897, 0x2898, - 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28c0, - 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7, 0x28c8, - 0x28c9, 0x28ca, 0x28cb, 0x2930, 0x2931, 0x2932, 0x2933, 0x2934, - 0x2935, 0x2936, 0x2937, 0x2938, 0x2939, 0x293a, 0x293b, 0x293c, - 0x293d, 0x293e, 0x293f, 0x2960, 0x2961, 0x2962, 0x2963, 0x2964, - 0x2965, 0x2966, 0x2967, 0x2968, 0x2969, 0x296a, 0x296b, 0x2a40, - 0x2a41, 0x2a42, 0x2a43, 0x2a44, 0x2a45, 0x2a46, 0x2a47, 0x2a48, - 0x2a49, 0x2a4a, 0x2a4b, 0x2a4c, 0x2a4d, 0x2a4e, 0x2a4f, 0x2a50, - 0x2a51, 0x2a52, 0x2a53, 0x2ae6, 0x2ae7, 0x2b24, 0x2b25, 0x2b26, - 0x2b27, 0x2b28, 0x2b29, 0x2b2a, 0x2b2b, 0x2b2c, 0x2b2d, 0x2b2e, - 0x2b2f, 0x2b30, 0x2b31, 0x2b32, 0x2b33, 0x2b5a, 0x2b5b, 0x3014, - 0x3015, 0x3016, 0x3017, 0x3020, 0x3021, 0x3022, 0x3023, 0x3024, - 0x3025, 0x3026, 0x3027, 0x3028, 0x3029, 0x302a, 0x302b, 0x302c, - 0x302d, 0x302e, 0x302f, 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, - 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, 0x30c0, 0x30c1, 0x30de, - 0x30df, 0x3218, 0x3219, 0x321a, 0x321b, 0x321c, 0x321d, 0x321e, - 0x321f, 0x3220, 0x3221, 0x3222, 0x3223, 0x3224, 0x3225, 0x3226, - 0x3227, 0x3228, 0x3229, 0x322a, 0x322b, 0x322c, 0x322d, 0x322e, - 0x322f, 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3378, - 0x3379, 0x337a, 0x337b, 0x337c, 0x337d, 0x337e, 0x337f, 0x33c0, - 0x33c1, 0x33c2, 0x33c3, 0x33c4, 0x33c5, 0x33c6, 0x33c7, 0x33c8, - 0x33c9, 0x33ca, 0x33cb, 0x33cc, 0x33cd, 0x33ce, 0x33cf, 0x33d0, - 0x33d1, 0x33d2, 0x33d3, 0x33d4, 0x33d5, 0x33d6, 0x33d7, 0x33d8, - 0x33d9, 0x3706, 0x3707, 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, - 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, 0x373a, 0x373b, 0x373c, - 0x373d, 0x373e, 0x373f, 0x3740, 0x3741, 0x3742, 0x3743, 0x3744, - 0x3745, 0x3746, 0x3747, 0x3748, 0x3749, 0x374a, 0x374b, 0x374c, - 0x374d, 0x374e, 0x374f, 0x3b34, 0x3b35, 0x3b36, 0x3b37, 0x3be8, - 0x3be9, 0x3bea, 0x3beb, 0x3bec, 0x3bed, 0x3bee, 0x3bef, 0x3bf0, - 0x3bf1, 0x3bf2, 0x3bf3, 0x3bf4, 0x3bf5, 0x3bf6, 0x3bf7, 0x3bf8, - 0x3bf9, 0x3bfa, 0x3bfb, 0x3bfc, 0x3bfd, 0x3bfe, 0x3bff, 0x2000, - 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, - 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x202e, 0x202f, 0x2182, - 0x2183, 0x21b4, 0x21b5, 0x21b6, 0x21b7, 0x21b8, 0x21b9, 0x21ba, - 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x2460, 0x2461, 0x2462, - 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246a, - 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x2470, 0x2471, 0x2472, - 0x2473, 0x26a2, 0x26a3, 0x000b, + +const uint16_t ff_msmp4_mv_table1[MSMPEG4_MV_TABLES_NB_ELEMS] = { + E(32, 32), E(42, 39), E(35, 53), E( 3, 28), E(51, 39), E(35, 57), + E(16, 46), E(35, 10), E(30, 52), E(63, 27), E(57, 35), E(39, 42), + E(39, 45), E(25, 59), E(35, 15), E(51, 34), E(31, 9), E(48, 34), + E( 2, 33), E( 6, 31), E(34, 49), E(30, 43), E(28, 42), E(33, 51), + E(39, 27), E(33, 42), E(37, 25), E(60, 34), E(38, 60), E( 9, 38), + E(38, 33), E(51, 32), E(30, 22), E(33, 23), E(32, 24), E(32, 26), + E(32, 29), E(40, 29), E(27, 23), E(46, 29), E(31, 14), E( 9, 30), + E(35, 45), E(29, 49), E(31, 11), E(47, 32), E(32, 48), E(39, 35), + E(37, 31), E(25, 34), E(30, 25), E(24, 30), E(35, 25), E(61, 32), + E(39, 24), E(16, 24), E(36, 23), E(50, 32), E(32, 45), E(19, 33), + E(59, 33), E(29, 25), E(30, 36), E(63, 33), E(45, 39), E(31, 12), + E(60, 29), E(14, 24), E(34, 0), E(42, 20), E(24, 16), E( 0, 28), + E(37, 43), E(18, 35), E(61, 28), E(57, 1), E(30, 30), E(31, 33), + E(31, 35), E(26, 32), E(37, 49), E(28, 4), E(53, 21), E(20, 42), + E(46, 39), E(14, 29), E(47, 3), E(38, 44), E(38, 21), E(38, 53), + E( 9, 55), E(34, 11), E(39, 5), E(43, 3), E(17, 39), E(39, 53), + E(59, 28), E( 5, 25), E(27, 19), E( 0, 34), E(55, 31), E(46, 28), + E(19, 35), E(37, 41), E(62, 30), E(34, 44), E(30, 18), E(16, 29), + E(19, 34), E(49, 35), E(30, 41), E(25, 27), E(43, 32), E( 4, 32), + E(34, 25), E(27, 25), E(33, 19), E(32, 41), E(25, 29), E(62, 31), + E(24, 35), E(32, 38), E(30, 32), E(34, 33), E(34, 29), E(41, 36), + E(12, 28), E(27, 21), E(41, 25), E(39, 26), E(30, 24), E(37, 21), + E(14, 31), E( 5, 30), E(13, 34), E(35, 19), E(55, 34), E(30, 44), + E(40, 36), E(40, 38), E(42, 25), E(31, 19), E(27, 36), E(30, 42), + E(37, 27), E(31, 17), E(21, 33), E(45, 31), E(32, 44), E(39, 28), + E(20, 33), E(46, 33), E(47, 31), E(35, 23), E(19, 31), E(33, 30), + E(28, 32), E(36, 32), E(33, 32), E(34, 40), E( 8, 31), E(20, 28), + E(35, 39), E(43, 33), E(25, 23), E(45, 37), E(35, 3), E(33, 55), + E(35, 29), E(36, 41), E(54, 30), E(38, 22), E(27, 41), E(37, 24), + E(62, 33), E(40, 26), E(15, 35), E(59, 35), E(49, 30), E( 1, 33), + E(40, 33), E(32, 0), E(29, 37), E(32, 2), E( 3, 32), E(42, 32), + E(49, 31), E(21, 34), E(21, 30), E(14, 32), E( 5, 31), E(28, 36), + E(31, 21), E(51, 33), E(31, 55), E(29, 51), E(31, 38), E(62, 32), + E(34, 47), E(34, 48), E(39, 38), E(24, 24), E(32, 30), E(29, 32), + E(30, 34), E(35, 34), E(29, 15), E(25, 21), E(26, 36), E(33, 61), + E(31, 26), E(32, 34), E(30, 33), E(27, 31), E(23, 35), E(29, 50), + E(21, 25), E(31, 47), E(36, 37), E(35, 41), E(58, 31), E(29, 23), + E(29, 41), E(21, 29), E(20, 30), E(33, 24), E(32, 22), E(42, 35), + E(29, 46), E(10, 30), E(61, 29), E(33, 10), E(49, 34), E(35, 42), + E(34, 45), E( 3, 29), E(38, 42), E(39, 22), E(29, 3), E( 7, 33), + E(41, 27), E( 1, 34), E(30, 31), E(13, 32), E(28, 25), E(12, 32), + E(40, 28), E(25, 35), E(31, 61), E(28, 31), E(29, 34), E(34, 35), + E(28, 33), E(26, 33), E(35, 1), E( 4, 34), E(31, 58), E(33, 2), + E(39, 37), E(21, 31), E(60, 33), E(23, 28), E(15, 34), E(38, 30), + E(37, 33), E(34, 34), E(31, 28), E(23, 36), E(11, 35), E(37, 23), + E(28, 23), E(35, 13), E(30, 58), E(30, 3), E(24, 26), E( 1, 63), + E(43, 25), E(56, 31), E( 8, 34), E(32, 14), E(44, 33), E(32, 35), + E(26, 31), E(31, 5), E(33, 49), E(31, 20), E(36, 33), E(32, 1), + E(27, 33), E(31, 34), E(31, 30), E(28, 39), E(37, 36), E(43, 31), + E(31, 59), E(34, 39), E(31, 27), E(34, 61), E(42, 38), E(24, 39), + E(45, 25), E(30, 61), E(20, 29), E(23, 37), E( 8, 30), E(38, 41), + E(22, 26), E(33, 48), E(17, 28), E(52, 33), E(34, 50), E(29, 21), + E(32, 9), E(30, 23), E(49, 33), E(43, 35), E(28, 24), E(39, 39), + E(33, 21), E(33, 34), E(32, 28), E(30, 29), E(25, 37), E(32, 11), + E(48, 33), E( 2, 30), E(15, 31), E(20, 31), E(22, 35), E(53, 30), + E(43, 37), E(44, 29), E(29, 30), E( 1, 29), E(27, 40), E(31, 6), + E(41, 39), E(43, 28), E(41, 28), E(30, 19), E(31, 8), E(36, 22), + E(30, 45), E(25, 28), E(31, 51), E(28, 40), E(32, 25), E(21, 35), + E(24, 29), E(25, 25), E(15, 33), E(20, 32), E(40, 30), E(39, 34), + E(31, 46), E(17, 35), E(22, 32), E(39, 31), E(33, 28), E(29, 29), + E(21, 32), E(37, 37), E(43, 30), E(18, 30), E(32, 8), E(37, 32), + E(31, 32), E(31, 22), E(31, 40), E(57, 32), E(38, 29), E(33, 37), + E(35, 35), E(33, 63), E( 5, 34), E(55, 35), E(31, 10), E(33, 58), + E(30, 17), E(40, 37), E(23, 39), E(15, 30), E(29, 18), E(34, 54), + E(34, 14), E(59, 29), E(34, 16), E(30, 59), E(11, 30), E(13, 35), + E(38, 23), E( 5, 35), E(24, 28), E(33, 15), E(37, 30), E(25, 31), + E(36, 40), E(13, 33), E(33, 45), E(31, 49), E(32, 16), E(42, 31), + E(25, 33), E(32, 36), E(39, 25), E(11, 32), E(33, 5), E(61, 31), + E(63, 32), E(31, 4), E( 0, 30), E(30, 47), E(32, 62), E(37, 29), + E(31, 2), E(42, 36), E( 5, 29), E(30, 55), E(29, 20), E(29, 35), + E(34, 12), E(10, 31), E(44, 35), E(30, 14), E(63, 29), E(35, 18), + E(12, 34), E( 3, 34), E(33, 47), E(32, 51), E(39, 36), E(37, 39), + E(32, 53), E(32, 10), E(29, 24), E(17, 29), E(32, 20), E(29, 39), + E(33, 27), E(31, 36), E(32, 27), E(31, 3), E(30, 39), E(44, 32), + E(31, 37), E( 5, 33), E(44, 30), E(46, 31), E(32, 40), E(36, 25), + E(35, 40), E(26, 38), E(37, 38), E(33, 38), E(25, 32), E( 2, 32), + E(58, 33), E(26, 24), E(15, 29), E(31, 1), E(31, 25), E(17, 26), + E(25, 22), E(34, 2), E(43, 27), E(39, 23), E(34, 8), E(56, 30), + E(29, 55), E(23, 38), E(30, 60), E(12, 31), E(30, 4), E(10, 34), + E(35, 49), E( 9, 34), E(24, 27), E(58, 34), E(10, 33), E(12, 30), + E(54, 31), E(32, 56), E(34, 23), E(38, 27), E( 8, 32), E(22, 31), + E(34, 24), E(36, 36), E(17, 32), E(38, 36), E(33, 25), E(32, 33), + E(32, 31), E(58, 32), E(38, 28), E(38, 37), E(38, 26), E(22, 29), + E(29, 43), E(32, 61), E(25, 36), E(16, 33), E(35, 24), E(32, 55), + E(35, 43), E(33, 9), E(43, 29), E(18, 34), E(46, 34), E(38, 24), + E(35, 26), E(32, 6), E(60, 31), E( 1, 32), E(23, 33), E(30, 35), + E(27, 32), E(33, 26), E(41, 31), E(35, 38), E(33, 54), E(37, 42), + E(20, 35), E(41, 38), E(35, 46), E(29, 44), E(18, 26), E(61, 27), + E(30, 9), E(40, 39), E(24, 25), E(39, 21), E(39, 32), E(53, 29), + E(62, 28), E(26, 42), E(29, 13), E(33, 0), E(34, 5), E(53, 34), + E(49, 37), E(21, 28), E(27, 24), E(11, 29), E(63, 63), E(50, 33), + E(33, 18), E(18, 33), E(53, 33), E(60, 30), E(13, 31), E(32, 50), + E(36, 24), E(24, 34), E(27, 34), E(32, 58), E(38, 35), E(35, 28), + E(16, 32), E(33, 60), E(51, 30), E(32, 4), E(36, 39), E(43, 34), + E(45, 30), E(27, 39), E(45, 33), E(42, 33), E(30, 38), E(32, 17), + E(31, 43), E(20, 26), E(26, 22), E(23, 27), E( 7, 29), E(13, 25), + E( 6, 33), E(47, 25), E(29, 61), E(30, 0), E( 9, 35), E(51, 25), + E(22, 36), E(34, 15), E(21, 27), E(25, 40), E(33, 53), E(32, 37), + E(56, 33), E(57, 3), E(30, 10), E(38, 16), E(51, 37), E(51, 38), + E(38, 18), E(63, 30), E(28, 46), E(40, 27), E(35, 9), E(33, 6), + E(42, 28), E(29, 22), E(24, 38), E(30, 2), E(25, 26), E(31, 63), + E(52, 32), E(31, 57), E(29, 26), E(35, 31), E(32, 5), E(41, 32), + E(35, 21), E(38, 39), E( 4, 31), E(30, 40), E(17, 31), E( 9, 33), + E(22, 28), E(34, 18), E( 4, 30), E(17, 34), E(28, 22), E(55, 33), + E(42, 29), E(40, 34), E(46, 32), E(38, 34), E(48, 32), E(63, 31), + E(23, 31), E(39, 33), E(33, 3), E( 3, 31), E(18, 29), E(33, 62), + E(33, 8), E(24, 42), E(58, 28), E(58, 29), E(34, 3), E(49, 25), + E(29, 16), E(43, 26), E( 4, 29), E( 1, 35), E( 4, 28), E(42, 27), + E(35, 51), E(35, 61), E(30, 48), E(17, 37), E( 5, 9), E(56, 34), + E(25, 41), E(17, 30), E(20, 34), E(47, 35), E(34, 21), E(33, 13), + E(16, 34), E(40, 35), E(32, 19), E(28, 35), E(33, 36), E(36, 30), + E(25, 39), E(16, 30), E(42, 30), E(19, 32), E(30, 46), E(53, 32), + E(32, 23), E(29, 42), E(10, 32), E(11, 31), E(14, 33), E(34, 38), + E(32, 39), E(41, 29), E(26, 26), E(61, 7), E(25, 49), E(22, 33), + E(28, 38), E(36, 38), E(45, 32), E(34, 27), E(28, 30), E(34, 28), + E(33, 59), E(37, 45), E(36, 20), E(55, 29), E(28, 21), E(35, 5), + E(29, 5), E(50, 29), E(48, 28), E(52, 34), E( 2, 29), E(42, 24), + E(34, 10), E(40, 24), E(46, 35), E(46, 36), E(43, 38), E(33, 11), + E( 4, 33), E(33, 40), E(32, 18), E(36, 34), E(27, 35), E(35, 22), + E(35, 55), E(29, 11), E(29, 38), E(41, 33), E(29, 28), E( 7, 32), + E(44, 31), E(26, 25), E(39, 29), E(32, 3), E(16, 31), E(31, 53), + E(26, 27), E(34, 43), E(38, 25), E(29, 40), E(41, 35), E(35, 27), + E(36, 29), E(38, 31), E(29, 27), E(32, 43), E(27, 29), E(30, 37), + E(24, 32), ESCAPE, E(32, 63), E(24, 31), E(42, 34), E(48, 36), + E(20, 38), E(29, 53), E(31, 54), E(61, 33), E(41, 26), E( 7, 30), + E(30, 49), E(35, 20), E(19, 27), E(14, 30), E(21, 39), E( 8, 33), + E(39, 41), E(39, 49), E(40, 22), E(46, 38), E(55, 38), E(34, 4), + E( 6, 30), E(30, 8), E(34, 9), E(37, 3), E(25, 24), E(37, 22), + E(33, 50), E(22, 37), E(44, 36), E(52, 31), E(17, 27), E(35, 2), + E(31, 50), E(30, 21), E(24, 36), E(35, 33), E(22, 38), E(61, 30), + E(32, 12), E( 9, 31), E(45, 34), E(34, 20), E(31, 15), E(19, 29), + E( 9, 32), E(31, 62), E(18, 32), E(33, 17), E(33, 1), E(37, 34), + E(32, 15), E(22, 30), E(26, 30), E(59, 31), E(29, 9), E(36, 42), + E(46, 30), E(31, 13), E(35, 17), E(54, 32), E(29, 19), E(57, 31), + E(30, 20), E(50, 31), E( 3, 30), E(31, 7), E(63, 1), E(34, 17), + E(47, 34), E(41, 37), E(35, 63), E(40, 25), E(25, 30), E(37, 28), + E( 1, 31), E(26, 28), E(22, 34), E(35, 37), E(34, 32), E(60, 32), + E(27, 30), E(37, 19), E(28, 44), E(30, 1), E(50, 28), E(14, 28), + E(28, 48), E(55, 30), E( 6, 34), E(23, 41), E(19, 41), E(14, 38), + E(30, 12), E( 3, 27), E(30, 15), E(28, 0), E(28, 16), E(61, 34), + E(61, 35), E(47, 38), E(45, 28), E(48, 29), E(40, 40), E(40, 42), + E(34, 51), E(34, 52), E(25, 45), E(30, 54), E(29, 59), E(35, 59), + E( 4, 42), E(51, 31), E(18, 31), E(31, 44), E(14, 34), E(37, 26), + E(36, 35), E(37, 35), E(30, 26), E(31, 41), E(31, 39), E(23, 32), + E(23, 29), E(38, 40), E(31, 16), E(24, 37), E(32, 52), E(31, 48), + E(50, 30), E(28, 34), E(32, 21), E(33, 20), E(31, 18), E(49, 32), + E(34, 37), E(33, 29), E(31, 29), E(40, 31), E( 3, 33), E(28, 27), + E(26, 35), E(28, 28), E(33, 39), E(34, 26), E(26, 44), E(53, 37), + E(50, 26), E(26, 46), E(41, 24), E(27, 15), E(59, 39), E(27, 22), + E(29, 31), E(38, 46), E(39, 19), E( 3, 35), E(50, 38), E(43, 17), + E(47, 37), E(23, 23), E(33, 52), E(55, 55), E(35, 50), E(21, 37), + E(23, 26), E(35, 11), E(61, 37), E(33, 12), E(46, 24), E(52, 30), + E(35, 16), E(34, 13), E(24, 22), E(30, 13), E(43, 36), E(16, 35), + E(37, 40), E(21, 41), E( 2, 34), E(54, 33), E(27, 38), E( 9, 29), + E(33, 7), E(23, 25), E(19, 30), E(32, 54), E(29, 45), E(29, 47), + E(33, 46), E(28, 41), E(27, 27), E(32, 49), E(39, 30), E(33, 31), + E(59, 32), E(32, 42), E(33, 22), E(47, 29), E(49, 29), E(32, 59), + E(40, 32), E(31, 24), E(27, 37), E(23, 34), E(28, 37), E(36, 26), + E(32, 7), E(38, 32), E(29, 33), E(15, 32), E(30, 16), E(47, 30), + E(33, 14), E(27, 26), E(25, 38), E(54, 34), E(44, 34), E(45, 29), + E(50, 34), E(58, 30), E(51, 29), E(48, 30), E(33, 57), E(59, 30), + E( 6, 32), E(34, 22), E(27, 28), E(31, 45), E(30, 27), E(24, 33), + E(26, 29), E(33, 4), E(24, 41), E(45, 26), E(23, 30), E( 2, 31), + E(28, 29), E(35, 36), E(30, 28), E(34, 53), E(30, 51), E(55, 5), + E(55, 21), E( 1, 30), E(29, 2), E(29, 63), E(26, 41), E(28, 20), + E(25, 1), E(31, 56), E(36, 21), E(22, 24), E(17, 25), E(30, 5), + E(52, 28), E( 2, 35), E(44, 26), E(44, 28), E(57, 30), E(26, 18), + E(62, 29), E(41, 23), E(39, 40), E(57, 34), E(26, 20), E(46, 42), + E(49, 39), E(11, 34), E(16, 28), E(19, 61), E( 5, 38), E(34, 46), + E(57, 33), E(13, 29), E(26, 39), E(33, 44), E(13, 30), E(48, 31), + E(30, 50), E(11, 33), E( 7, 31), E(56, 32), E(34, 19), E(33, 43), + E(32, 46), E(34, 41), E(41, 30), E(36, 28), E(34, 31), E(33, 33), + E(33, 35), E(26, 34), E(28, 26), E(32, 13), E(41, 34), E( 0, 32), + E(32, 57), E(35, 30), E(35, 32), E(55, 32), E(26, 40), E( 0, 31), + E(26, 37), E(35, 47), E( 1, 1), E(51, 35), E(33, 16), E(53, 31), + E(31, 0), E(45, 35), E(12, 33), E(29, 1), E(29, 17), E(36, 27), + E( 5, 32), E(38, 38), E(59, 27), E(38, 62), E(39, 9), E(58, 36), + E(34, 42), E(31, 42), E(36, 31), E(47, 33), E(32, 47), E(17, 33), + E(31, 60), E(31, 23), E(33, 41), E(34, 30), E(34, 36), E(32, 60), + E(29, 36), E(38, 17), E(25, 9), E(49, 49), E(50, 24), E(22, 25), + E(28, 54), E(59, 34), E( 9, 39), E(59, 37), E( 7, 3), E(28, 1), + E(55, 25), E(17, 38), E( 4, 38), E(35, 44), E(50, 35), E(21, 36), + E(29, 12), E(44, 60), E(47, 36), E(18, 38), E(24, 40), E(19, 25), + E(25, 43), E(31, 31), }; -static const uint8_t table1_mv_bits[1100] = { - 2, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 7, 7, 7, 7, 7, 8, - 8, 8, 8, 8, 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, 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, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, - 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, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 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, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 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, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 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, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 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, 4, -}; - -static const uint8_t table1_mvx[1099] = { - 32, 31, 32, 31, 33, 32, 33, 33, - 31, 34, 30, 32, 32, 34, 35, 32, - 34, 33, 29, 30, 30, 32, 31, 31, - 33, 35, 35, 33, 31, 29, 29, 33, - 34, 30, 31, 28, 36, 30, 34, 32, - 32, 37, 32, 32, 25, 27, 39, 32, - 32, 32, 38, 35, 36, 32, 37, 61, - 26, 32, 34, 35, 3, 35, 27, 28, - 29, 34, 28, 37, 31, 36, 32, 27, - 31, 30, 29, 39, 33, 29, 33, 35, - 25, 25, 29, 33, 31, 31, 31, 33, - 32, 30, 32, 32, 41, 39, 33, 36, - 32, 28, 34, 36, 38, 24, 60, 31, - 23, 28, 32, 33, 59, 32, 40, 30, - 5, 34, 32, 38, 32, 30, 43, 4, - 32, 32, 42, 31, 31, 32, 26, 38, - 26, 22, 21, 37, 61, 63, 37, 31, - 32, 33, 2, 1, 23, 33, 41, 27, - 35, 30, 38, 23, 33, 3, 28, 34, - 34, 27, 41, 29, 39, 35, 36, 29, - 32, 27, 30, 32, 24, 61, 37, 26, - 59, 25, 35, 27, 36, 37, 30, 31, - 34, 40, 3, 28, 34, 39, 32, 31, - 32, 30, 24, 28, 35, 36, 26, 32, - 31, 33, 29, 33, 39, 25, 30, 24, - 35, 59, 29, 34, 25, 30, 21, 35, - 43, 40, 32, 29, 5, 28, 31, 62, - 33, 33, 25, 31, 21, 31, 43, 31, - 34, 33, 20, 40, 39, 31, 31, 57, - 38, 32, 42, 33, 32, 31, 32, 29, - 30, 44, 5, 31, 22, 34, 36, 17, - 38, 58, 38, 35, 32, 60, 35, 24, - 32, 38, 16, 45, 42, 32, 31, 29, - 4, 30, 17, 40, 46, 48, 63, 32, - 42, 19, 41, 22, 28, 36, 45, 33, - 33, 32, 29, 7, 41, 42, 18, 33, - 33, 32, 22, 37, 1, 26, 22, 23, - 49, 28, 26, 27, 32, 33, 27, 23, - 28, 36, 15, 6, 34, 27, 31, 26, - 23, 2, 33, 32, 34, 41, 28, 32, - 41, 0, 36, 38, 34, 31, 47, 32, - 17, 31, 39, 33, 37, 51, 30, 47, - 32, 50, 32, 19, 63, 30, 25, 27, - 33, 62, 24, 31, 27, 30, 37, 31, - 45, 32, 39, 20, 46, 47, 35, 19, - 34, 1, 49, 21, 21, 14, 51, 26, - 23, 31, 36, 35, 58, 29, 29, 21, - 20, 42, 13, 28, 12, 40, 31, 33, - 39, 60, 32, 44, 33, 31, 28, 37, - 29, 32, 30, 49, 43, 28, 39, 25, - 32, 48, 2, 15, 20, 25, 31, 28, - 21, 24, 25, 15, 31, 17, 37, 43, - 18, 32, 33, 24, 33, 36, 13, 33, - 31, 39, 11, 31, 33, 32, 39, 37, - 32, 32, 29, 17, 44, 46, 36, 35, - 26, 37, 58, 32, 34, 38, 8, 38, - 38, 22, 29, 25, 16, 35, 32, 35, - 33, 43, 18, 46, 38, 50, 33, 18, - 53, 60, 13, 32, 36, 33, 51, 36, - 43, 45, 27, 42, 29, 24, 30, 25, - 31, 52, 31, 35, 38, 9, 22, 34, - 4, 17, 28, 55, 42, 25, 17, 20, - 47, 34, 33, 16, 40, 25, 16, 30, - 53, 29, 10, 11, 14, 26, 33, 4, - 35, 44, 26, 16, 31, 26, 34, 38, - 29, 31, 30, 24, 22, 61, 32, 9, - 45, 34, 31, 19, 9, 31, 46, 31, - 35, 54, 29, 57, 30, 50, 3, 31, - 63, 34, 47, 41, 51, 18, 31, 14, - 37, 38, 31, 24, 32, 31, 50, 33, - 31, 54, 27, 9, 33, 23, 19, 32, - 29, 29, 33, 28, 47, 49, 30, 47, - 33, 27, 25, 54, 44, 45, 50, 58, - 51, 48, 33, 59, 33, 34, 57, 13, - 26, 33, 13, 48, 30, 11, 7, 56, - 34, 55, 26, 0, 26, 35, 1, 51, - 33, 53, 31, 45, 12, 29, 29, 51, - 31, 48, 2, 6, 34, 30, 28, 33, - 60, 40, 27, 46, 31, 9, 35, 29, - 31, 39, 55, 46, 19, 37, 62, 34, - 30, 16, 19, 49, 41, 41, 39, 37, - 14, 5, 13, 35, 55, 30, 40, 40, - 42, 8, 20, 25, 45, 35, 33, 36, - 54, 38, 27, 37, 62, 40, 15, 59, - 49, 31, 29, 34, 34, 39, 24, 29, - 25, 29, 21, 29, 10, 61, 33, 49, - 35, 34, 3, 38, 39, 29, 7, 41, - 1, 35, 4, 23, 15, 23, 11, 37, - 28, 35, 30, 30, 24, 1, 43, 56, - 8, 34, 42, 24, 45, 30, 20, 23, - 8, 38, 22, 33, 17, 52, 34, 22, - 53, 43, 44, 1, 27, 31, 41, 43, - 41, 30, 31, 36, 30, 5, 55, 31, - 33, 30, 40, 23, 15, 29, 34, 34, - 59, 34, 30, 11, 13, 38, 5, 0, - 30, 42, 5, 30, 29, 34, 10, 44, - 30, 63, 35, 12, 3, 26, 15, 17, - 25, 34, 43, 39, 34, 56, 29, 23, - 30, 12, 30, 10, 35, 9, 24, 58, - 10, 12, 54, 33, 37, 20, 41, 35, - 29, 18, 61, 30, 40, 24, 39, 53, - 62, 26, 29, 33, 34, 53, 49, 21, - 27, 11, 63, 20, 26, 23, 7, 13, - 6, 47, 29, 30, 9, 51, 22, 34, - 21, 25, 33, 56, 57, 30, 38, 51, - 51, 38, 63, 28, 40, 35, 33, 18, - 33, 33, 24, 58, 58, 34, 49, 29, - 43, 4, 1, 4, 42, 35, 35, 30, - 17, 5, 56, 61, 25, 37, 36, 55, - 28, 35, 29, 50, 48, 52, 2, 42, - 34, 40, 46, 46, 43, 35, 29, 48, - 20, 29, 31, 41, 7, 30, 35, 19, - 14, 21, 8, 39, 39, 40, 46, 55, - 34, 6, 30, 34, 37, 25, 37, 33, - 22, 44, 52, 17, 35, 29, 36, 35, - 40, 37, 28, 30, 50, 14, 28, 55, - 6, 23, 19, 14, 30, 3, 30, 28, - 28, 61, 61, 47, 45, 48, 40, 40, - 34, 34, 25, 30, 29, 35, 4, 26, - 53, 50, 26, 41, 27, 59, 27, 38, - 39, 3, 50, 43, 47, 23, 33, 55, - 35, 21, 23, 35, 61, 33, 46, 52, - 35, 34, 24, 30, 43, 16, 37, 21, - 2, 24, 45, 34, 30, 55, 55, 1, - 29, 29, 26, 28, 25, 31, 36, 22, - 17, 30, 52, 2, 44, 44, 57, 26, - 62, 41, 39, 57, 26, 46, 49, 11, - 16, 19, 5, 59, 38, 39, 58, 38, - 25, 49, 50, 22, 28, 59, 9, 59, - 7, 28, 55, 17, 4, 35, 50, 21, - 29, 44, 47, 18, 24, 19, 25, 42, - 35, 3, 51, 35, 16, 35, 30, 63, - 57, 39, 39, 25, 35, 38, 9, 16, - 36, 45, 31, 60, 14, 34, 42, 24, - 0, 37, 18, 61, 57, 37, 28, 53, - 20, 46, 14, 47, 38, 38, 38, 9, - 34, 39, 43, 17, 39, 59, 5, 27, - 0, 12, 27, -}; - -static const uint8_t table1_mvy[1099] = { - 32, 32, 31, 31, 32, 33, 31, 33, - 33, 32, 32, 30, 34, 31, 32, 29, - 33, 30, 32, 33, 31, 35, 34, 30, - 34, 31, 33, 29, 29, 31, 33, 35, - 30, 30, 35, 32, 32, 34, 34, 28, - 25, 32, 36, 27, 32, 32, 32, 37, - 39, 3, 32, 30, 31, 26, 31, 32, - 32, 38, 29, 29, 32, 34, 31, 31, - 34, 35, 33, 33, 28, 33, 1, 33, - 27, 29, 30, 31, 28, 29, 37, 35, - 31, 33, 35, 27, 36, 37, 25, 25, - 61, 35, 4, 5, 32, 33, 36, 30, - 23, 30, 28, 34, 31, 32, 32, 39, - 32, 34, 21, 39, 32, 59, 32, 28, - 32, 36, 60, 33, 24, 36, 32, 32, - 41, 2, 32, 38, 26, 22, 33, 30, - 31, 32, 32, 30, 31, 32, 29, 3, - 40, 38, 32, 32, 33, 26, 31, 34, - 28, 38, 34, 31, 3, 31, 35, 38, - 27, 35, 33, 28, 29, 27, 29, 27, - 43, 29, 37, 63, 31, 33, 34, 30, - 31, 30, 37, 30, 35, 35, 26, 41, - 37, 31, 33, 28, 26, 30, 42, 24, - 7, 27, 33, 29, 36, 28, 34, 57, - 23, 41, 36, 23, 35, 34, 25, 30, - 25, 33, 25, 25, 29, 24, 33, 39, - 33, 33, 0, 37, 31, 36, 21, 32, - 61, 24, 35, 61, 31, 5, 31, 59, - 39, 21, 32, 30, 34, 22, 40, 32, - 29, 16, 31, 5, 62, 2, 20, 39, - 39, 32, 33, 1, 31, 24, 36, 32, - 36, 32, 28, 26, 6, 31, 38, 34, - 58, 35, 32, 33, 33, 17, 43, 26, - 31, 40, 31, 34, 32, 32, 31, 19, - 30, 32, 29, 33, 38, 38, 32, 59, - 40, 18, 38, 32, 35, 34, 32, 17, - 1, 15, 30, 28, 31, 28, 34, 29, - 32, 27, 35, 27, 49, 22, 37, 34, - 37, 26, 32, 32, 22, 28, 45, 29, - 30, 31, 43, 46, 41, 30, 26, 13, - 34, 32, 27, 38, 42, 42, 33, 47, - 33, 60, 27, 42, 25, 32, 22, 32, - 48, 32, 45, 33, 33, 41, 27, 25, - 19, 31, 35, 19, 36, 42, 27, 17, - 31, 44, 28, 33, 33, 31, 23, 31, - 40, 33, 31, 34, 30, 32, 33, 36, - 35, 47, 37, 41, 31, 23, 41, 29, - 30, 35, 32, 25, 32, 28, 58, 2, - 37, 33, 14, 33, 49, 20, 39, 36, - 21, 9, 23, 33, 35, 24, 39, 37, - 11, 33, 30, 31, 31, 28, 51, 40, - 35, 29, 25, 33, 46, 35, 37, 30, - 30, 8, 63, 28, 15, 40, 33, 45, - 49, 25, 32, 4, 47, 51, 36, 39, - 53, 10, 24, 29, 30, 31, 25, 40, - 38, 38, 33, 56, 23, 27, 32, 37, - 26, 29, 43, 36, 33, 24, 55, 43, - 9, 29, 34, 34, 24, 33, 18, 33, - 33, 30, 31, 50, 24, 60, 30, 39, - 34, 30, 39, 28, 22, 38, 2, 26, - 63, 32, 57, 21, 39, 33, 28, 18, - 30, 34, 22, 33, 29, 41, 30, 34, - 35, 21, 13, 34, 35, 39, 30, 46, - 32, 42, 32, 31, 33, 26, 11, 33, - 22, 31, 25, 31, 53, 27, 43, 25, - 40, 50, 21, 36, 38, 30, 12, 31, - 34, 20, 15, 29, 32, 62, 30, 13, - 17, 32, 19, 31, 20, 31, 30, 7, - 1, 17, 34, 37, 31, 31, 44, 34, - 26, 40, 16, 37, 52, 48, 30, 20, - 18, 33, 38, 29, 7, 25, 30, 54, - 45, 47, 46, 41, 29, 29, 16, 30, - 14, 26, 38, 34, 34, 29, 34, 30, - 29, 30, 57, 30, 4, 46, 33, 29, - 39, 44, 30, 31, 50, 33, 31, 32, - 19, 32, 40, 31, 37, 47, 1, 35, - 16, 31, 0, 35, 33, 1, 17, 34, - 9, 34, 33, 31, 49, 43, 42, 51, - 34, 29, 23, 29, 14, 30, 45, 49, - 11, 24, 31, 28, 35, 41, 30, 44, - 18, 29, 34, 35, 36, 25, 26, 21, - 31, 30, 34, 19, 34, 44, 36, 38, - 25, 31, 28, 23, 37, 3, 55, 41, - 30, 22, 41, 24, 33, 26, 35, 35, - 30, 55, 51, 47, 48, 38, 24, 15, - 21, 50, 25, 46, 30, 29, 10, 34, - 42, 45, 29, 42, 22, 3, 33, 27, - 34, 1, 34, 28, 34, 36, 35, 23, - 23, 13, 58, 3, 26, 63, 25, 31, - 34, 61, 38, 39, 25, 61, 29, 37, - 30, 41, 26, 48, 28, 33, 50, 35, - 30, 37, 29, 29, 40, 6, 39, 28, - 28, 19, 8, 22, 45, 34, 35, 10, - 58, 17, 37, 39, 30, 18, 54, 14, - 29, 16, 59, 30, 35, 23, 35, 30, - 47, 36, 29, 55, 20, 12, 31, 35, - 14, 29, 18, 34, 34, 24, 29, 26, - 22, 2, 27, 23, 8, 30, 55, 38, - 60, 31, 4, 34, 49, 34, 27, 34, - 33, 30, 31, 54, 42, 35, 38, 46, - 44, 26, 27, 9, 39, 25, 21, 29, - 28, 42, 13, 0, 5, 34, 37, 28, - 24, 29, 63, 26, 22, 27, 29, 25, - 33, 25, 61, 0, 35, 25, 36, 15, - 27, 40, 53, 33, 3, 10, 16, 37, - 38, 18, 30, 46, 27, 9, 6, 29, - 62, 8, 42, 28, 29, 3, 25, 16, - 26, 29, 35, 28, 27, 51, 61, 48, - 37, 9, 34, 7, 49, 45, 20, 29, - 21, 5, 5, 29, 28, 34, 29, 24, - 10, 24, 35, 36, 38, 55, 11, 36, - 38, 53, 54, 26, 30, 49, 20, 27, - 30, 39, 33, 41, 49, 22, 38, 38, - 4, 30, 8, 9, 3, 24, 22, 50, - 37, 36, 31, 27, 2, 9, 42, 63, - 25, 19, 44, 1, 28, 28, 48, 30, - 34, 41, 41, 38, 12, 27, 15, 0, - 16, 34, 35, 38, 28, 29, 40, 42, - 51, 52, 45, 54, 59, 59, 42, 44, - 37, 26, 46, 24, 15, 39, 22, 46, - 19, 35, 38, 17, 37, 23, 52, 55, - 50, 37, 26, 11, 37, 12, 24, 30, - 16, 13, 22, 13, 36, 35, 40, 41, - 34, 41, 26, 53, 51, 5, 21, 30, - 2, 63, 41, 20, 1, 56, 21, 24, - 25, 5, 28, 35, 26, 28, 30, 18, - 29, 23, 40, 34, 20, 42, 39, 34, - 28, 61, 38, 27, 62, 9, 36, 17, - 9, 49, 24, 25, 54, 34, 39, 37, - 3, 1, 25, 38, 38, 44, 35, 36, - 12, 60, 36, 38, 40, 25, 43, 39, - 53, 28, 39, 57, 46, 10, 52, 27, - 35, 42, 45, 59, 15, 60, 38, 24, - 23, 39, 12, 29, 24, 0, 20, 16, - 28, 43, 35, 28, 1, 49, 4, 21, - 42, 39, 29, 3, 44, 21, 53, 55, - 11, 5, 3, 39, 53, 28, 25, 19, - 34, 28, 21, -}; - -MVTable ff_mv_tables[2] = { - { table0_mv_code, - table0_mv_bits, - table0_mvx, - table0_mvy, }, - { table1_mv_code, - table1_mv_bits, - table1_mvx, - table1_mvy, } +const uint8_t ff_msmp4_mv_table1_lens[MSMPEG4_MV_TABLES_NB_ELEMS] = { + 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 14, 15, 15, 11, 13, 13, 12, 11, 10, + 8, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 12, 10, 12, 12, 12, 12, 10, + 14, 15, 15, 13, 13, 13, 12, 12, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 9, 6, 9, 10, 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, 11, 11, 12, 13, 13, 11, 12, 13, 13, 10, 7, 8, 10, 14, + 15, 15, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 12, 13, 13, 13, 13, 13, 13, 13, 13, 8, 9, 9, 5, 13, 14, 14, + 12, 12, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 12, 12, 12, 11, 10, 11, 13, 13, 13, 13, 12, 12, 12, 13, 14, 14, 11, 12, + 14, 14, 14, 14, 7, 8, 9, 10, 14, 14, 13, 12, 11, 7, 8, 10, 13, 14, + 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 13, 13, 13, 13, 12, 12, 10, 10, 10, + 10, 11, 14, 14, 13, 13, 13, 12, 13, 14, 14, 11, 10, 9, 10, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 8, 11, 12, 13, 13, 10, 10, + 10, 8, 8, 13, 13, 12, 12, 12, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 8, 9, 10, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 9, 13, 13, 13, 13, 12, 12, 12, 13, 13, 11, 10, 10, 10, + 11, 13, 13, 13, 13, 9, 4, 12, 12, 12, 12, 10, 10, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 11, 10, + 13, 13, 13, 13, 12, 12, 10, 9, 13, 13, 12, 11, 11, 13, 14, 14, 12, 11, + 12, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 13, 13, 12, 12, 10, 10, 9, 11, 12, 12, 10, 12, 13, 13, 11, 13, + 13, 13, 13, 11, 9, 11, 13, 14, 14, 12, 10, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 10, 5, 4, 12, 12, 13, 13, 13, 13, 10, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 12, 12, 12, 11, 11, 10, 9, 11, 11, 12, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 11, 12, 12, 11, + 12, 13, 13, 10, 13, 13, 13, 13, 12, 12, 11, 12, 12, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 8, 10, 10, + 13, 13, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 12, 12, + 11, 10, 11, 11, 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, 12, 11, 10, 10, + 13, 13, 12, 12, 13, 13, 10, 13, 13, 13, 13, 11, 9, 12, 13, 14, 14, 12, + 12, 12, 12, 11, 10, 10, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 12, 12, 10, 11, 13, 14, 14, 12, 11, 11, 12, + 13, 13, 11, 9, 13, 13, 13, 13, 13, 13, 12, 11, 11, 10, 11, 11, 11, 11, + 10, 4, 11, 11, 12, 14, 14, 14, 14, 11, 14, 14, 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, 8, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 11, + 12, 12, 11, 11, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 11, 12, 12, 12, 12, 11, 6, 10, 11, 14, 14, 14, 14, 14, + 14, 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, 11, 11, 11, 11, 10, 10, + 12, 13, 13, 13, 13, 13, 13, 10, 10, 13, 13, 12, 11, 8, 8, 11, 11, 12, + 12, 11, 10, 11, 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 14, 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, 12, 12, 11, 5, + 10, 11, 12, 13, 13, 10, 10, 11, 12, 12, 12, 12, 11, 9, 8, 12, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, + 12, 13, 14, 14, 12, 12, 11, 11, 10, 14, 14, 14, 14, 14, 14, 14, 14, 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, 12, + 12, 12, 12, 11, 7, 5, 8, 11, 12, 12, 12, 12, 11, 9, 7, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 10, 12, 14, 14, 14, 14, + 12, 12, 9, 12, 12, 12, 12, 11, 11, 8, 10, 10, 11, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 4, }; const uint8_t ff_v2_mb_type[8][2] = { diff --git a/libavcodec/msmpeg4data.h b/libavcodec/msmpeg4data.h index aa4ca86a05..13267d25c1 100644 --- a/libavcodec/msmpeg4data.h +++ b/libavcodec/msmpeg4data.h @@ -35,17 +35,6 @@ #include "libavutil/attributes_internal.h" #include "rl.h" -#include "vlc.h" - -/* motion vector table */ -typedef struct MVTable { - const uint16_t *table_mv_code; - const uint8_t *table_mv_bits; - const uint8_t *table_mvx; - const uint8_t *table_mvy; - uint16_t *table_mv_index; /* encoding: convert mv to index in table_mv */ - const VLCElem *vlc; /* decoding: vlc */ -} MVTable; FF_VISIBILITY_PUSH_HIDDEN #define NB_RL_TABLES 6 @@ -59,8 +48,12 @@ extern const uint8_t ff_wmv1_y_dc_scale_table[32]; extern const uint8_t ff_wmv1_c_dc_scale_table[32]; extern const uint8_t ff_old_ff_y_dc_scale_table[32]; -#define MSMPEG4_MV_TABLES_NB_ELEMS 1099 -extern MVTable ff_mv_tables[2]; +#define MSMPEG4_MV_TABLES_NB_ELEMS 1100 +/// The entries are of the form (8 << mvx) | mvy. Escape value is zero. +extern const uint16_t ff_msmp4_mv_table0[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint8_t ff_msmp4_mv_table0_lens[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint16_t ff_msmp4_mv_table1[MSMPEG4_MV_TABLES_NB_ELEMS]; +extern const uint8_t ff_msmp4_mv_table1_lens[MSMPEG4_MV_TABLES_NB_ELEMS]; extern const uint8_t ff_v2_mb_type[8][2]; extern const uint8_t ff_v2_intra_cbpc[4][2]; diff --git a/libavcodec/msmpeg4dec.c b/libavcodec/msmpeg4dec.c index 12bef4f506..d2249559c9 100644 --- a/libavcodec/msmpeg4dec.c +++ b/libavcodec/msmpeg4dec.c @@ -46,6 +46,8 @@ #define DEFAULT_INTER_INDEX 3 +static const VLCElem *mv_tables[2]; + static inline int msmpeg4v1_pred_dc(MpegEncContext * s, int n, int32_t **dc_val_ptr) { @@ -72,23 +74,24 @@ static VLCElem v2_mb_type_vlc[128]; VLCElem ff_inter_intra_vlc[8]; /* This is identical to H.263 except that its range is multiplied by 2. */ -static int msmpeg4v2_decode_motion(MpegEncContext * s, int pred, int f_code) +static int msmpeg4v2_decode_motion(H263DecContext *const h, int pred, int f_code) { int code, val, sign, shift; - code = get_vlc2(&s->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); - ff_dlog(s, "MV code %d at %d %d pred: %d\n", code, s->mb_x,s->mb_y, pred); + code = get_vlc2(&h->gb, ff_h263_mv_vlc, H263_MV_VLC_BITS, 2); + ff_dlog(h->c.avctx, "MV code %d at %d %d pred: %d\n", + code, h->c.mb_x,h->c.mb_y, pred); if (code < 0) return 0xffff; if (code == 0) return pred; - sign = get_bits1(&s->gb); + sign = get_bits1(&h->gb); shift = f_code - 1; val = code; if (shift) { val = (val - 1) << shift; - val |= get_bits(&s->gb, shift); + val |= get_bits(&h->gb, shift); val++; } if (sign) @@ -103,149 +106,155 @@ static int msmpeg4v2_decode_motion(MpegEncContext * s, int pred, int f_code) return val; } -static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int msmpeg4v12_decode_mb(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int cbp, code, i; - uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &h->c.cur_pic.mb_type[h->c.mb_x + h->c.mb_y*h->c.mb_stride]; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->use_skip_mb_code) { - if (get_bits1(&s->gb)) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (ms->use_skip_mb_code) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } } - if (s->msmpeg4_version == MSMP4_V2) - code = get_vlc2(&s->gb, v2_mb_type_vlc, V2_MB_TYPE_VLC_BITS, 1); + if (h->c.msmpeg4_version == MSMP4_V2) + code = get_vlc2(&h->gb, v2_mb_type_vlc, V2_MB_TYPE_VLC_BITS, 1); else - code = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); + code = get_vlc2(&h->gb, ff_h263_inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 2); if(code<0 || code>7){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", code, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", + code, h->c.mb_x, h->c.mb_y); return -1; } - s->mb_intra = code >>2; + h->c.mb_intra = code >>2; cbp = code & 0x3; } else { - s->mb_intra = 1; - if (s->msmpeg4_version == MSMP4_V2) - cbp = get_vlc2(&s->gb, v2_intra_cbpc_vlc, V2_INTRA_CBPC_VLC_BITS, 1); + h->c.mb_intra = 1; + if (h->c.msmpeg4_version == MSMP4_V2) + cbp = get_vlc2(&h->gb, v2_intra_cbpc_vlc, V2_INTRA_CBPC_VLC_BITS, 1); else - cbp = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); + cbp = get_vlc2(&h->gb, ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 2); if(cbp<0 || cbp>3){ - av_log(s->avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpc %d invalid at %d %d\n", + cbp, h->c.mb_x, h->c.mb_y); return -1; } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my, cbpy; - cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + cbpy = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if(cbpy<0){ - av_log(s->avctx, AV_LOG_ERROR, "cbpy %d invalid at %d %d\n", cbp, s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy %d invalid at %d %d\n", + cbp, h->c.mb_x, h->c.mb_y); return -1; } cbp|= cbpy<<2; - if (s->msmpeg4_version == MSMP4_V1 || (cbp&3) != 3) + if (h->c.msmpeg4_version == MSMP4_V1 || (cbp&3) != 3) cbp ^= 0x3C; - ff_h263_pred_motion(s, 0, 0, &mx, &my); - mx= msmpeg4v2_decode_motion(s, mx, 1); - my= msmpeg4v2_decode_motion(s, my, 1); + ff_h263_pred_motion(&h->c, 0, 0, &mx, &my); + mx = msmpeg4v2_decode_motion(h, mx, 1); + my = msmpeg4v2_decode_motion(h, my, 1); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; *mb_type_ptr = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int v; - if (s->msmpeg4_version == MSMP4_V2) { - s->ac_pred = get_bits1(&s->gb); - v = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + if (h->c.msmpeg4_version == MSMP4_V2) { + h->c.ac_pred = get_bits1(&h->gb); + v = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (v < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); return -1; } cbp|= v<<2; } else{ - s->ac_pred = 0; - v = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); + h->c.ac_pred = 0; + v = get_vlc2(&h->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (v < 0) { - av_log(s->avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "cbpy vlc invalid\n"); return -1; } cbp|= v<<2; - if(s->pict_type==AV_PICTURE_TYPE_P) cbp^=0x3C; + if (h->c.pict_type==AV_PICTURE_TYPE_P) cbp^=0x3C; } *mb_type_ptr = MB_TYPE_INTRA; } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) + if (ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i); + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", + h->c.mb_x, h->c.mb_y, i); return -1; } } return 0; } -static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int msmpeg4v34_decode_mb(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int cbp, code, i; uint8_t *coded_val; - uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &h->c.cur_pic.mb_type[h->c.mb_x + h->c.mb_y*h->c.mb_stride]; - if (get_bits_left(&s->gb) <= 0) + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->use_skip_mb_code) { - if (get_bits1(&s->gb)) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (ms->use_skip_mb_code) { + if (get_bits1(&h->gb)) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for(i=0;i<6;i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } } - code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[DEFAULT_INTER_INDEX], MB_NON_INTRA_VLC_BITS, 3); - //s->mb_intra = (code & 0x40) ? 0 : 1; - s->mb_intra = (~code & 0x40) >> 6; + code = get_vlc2(&h->gb, ff_mb_non_intra_vlc[DEFAULT_INTER_INDEX], MB_NON_INTRA_VLC_BITS, 3); + //h->c.mb_intra = (code & 0x40) ? 0 : 1; + h->c.mb_intra = (~code & 0x40) >> 6; cbp = code & 0x3f; } else { - s->mb_intra = 1; - code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); + h->c.mb_intra = 1; + code = get_vlc2(&h->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); /* predict coded block pattern */ cbp = 0; for(i=0;i<6;i++) { int val = ((code >> (5 - i)) & 1); if (i < 4) { - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_val); + int pred = ff_msmpeg4_coded_block_pred(&h->c, i, &coded_val); val = val ^ pred; *coded_val = val; } @@ -253,41 +262,42 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my; - if(s->per_mb_rl_table && cbp){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } - ff_h263_pred_motion(s, 0, 0, &mx, &my); - ff_msmpeg4_decode_motion(s, &mx, &my); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + ff_h263_pred_motion(&h->c, 0, 0, &mx, &my); + ff_msmpeg4_decode_motion(ms, &mx, &my); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; *mb_type_ptr = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { - ff_dlog(s, "I at %d %d %d %06X\n", s->mb_x, s->mb_y, + ff_dlog(h->c.avctx, "I at %d %d %d %06X\n", h->c.mb_x, h->c.mb_y, ((cbp & 3) ? 1 : 0) +((cbp & 0x3C)? 2 : 0), - show_bits(&s->gb, 24)); - s->ac_pred = get_bits1(&s->gb); + show_bits(&h->gb, 24)); + h->c.ac_pred = get_bits1(&h->gb); *mb_type_ptr = MB_TYPE_INTRA; - if(s->inter_intra_pred){ - s->h263_aic_dir= get_vlc2(&s->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); - ff_dlog(s, "%d%d %d %d/", - s->ac_pred, s->h263_aic_dir, s->mb_x, s->mb_y); + if (h->c.inter_intra_pred) { + h->c.h263_aic_dir = get_vlc2(&h->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); + ff_dlog(h->c.avctx, "%d%d %d %d/", + h->c.ac_pred, h->c.h263_aic_dir, h->c.mb_x, h->c.mb_y); } - if(s->per_mb_rl_table && cbp){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if (ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) + if (ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i); + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding block: %d x %d (%d)\n", + h->c.mb_x, h->c.mb_y, i); return -1; } } @@ -300,7 +310,6 @@ static av_cold void msmpeg4_decode_init_static(void) { static VLCElem vlc_buf[3714 + 2694 + 1636 + 2648 + 1532 + 2488]; VLCInitState state = VLC_INIT_STATE(vlc_buf); - MVTable *mv; INIT_FIRST_VLC_RL(ff_rl_table[0], 642); INIT_FIRST_VLC_RL(ff_rl_table[1], 1104); @@ -326,18 +335,16 @@ static av_cold void msmpeg4_decode_init_static(void) &ff_v2_mb_type[0][1], 2, 1, &ff_v2_mb_type[0][0], 2, 1, 0); - mv = &ff_mv_tables[0]; - mv->vlc = ff_vlc_init_tables_sparse(&state, MV_VLC_BITS, - MSMPEG4_MV_TABLES_NB_ELEMS + 1, - mv->table_mv_bits, 1, 1, - mv->table_mv_code, 2, 2, - NULL, 0, 0, 0); - mv = &ff_mv_tables[1]; - mv->vlc = ff_vlc_init_tables_sparse(&state, MV_VLC_BITS, - MSMPEG4_MV_TABLES_NB_ELEMS + 1, - mv->table_mv_bits, 1, 1, - mv->table_mv_code, 2, 2, - NULL, 0, 0, 0); + mv_tables[0] = ff_vlc_init_tables_from_lengths(&state, MV_VLC_BITS, + MSMPEG4_MV_TABLES_NB_ELEMS, + ff_msmp4_mv_table0_lens, 1, + ff_msmp4_mv_table0, 2, 2, + 0, 0); + mv_tables[1] = ff_vlc_init_tables_from_lengths(&state, MV_VLC_BITS, + MSMPEG4_MV_TABLES_NB_ELEMS, + ff_msmp4_mv_table1_lens, 1, + ff_msmp4_mv_table1, 2, 2, + 0, 0); for (unsigned i = 0; i < 4; i++) { ff_mb_non_intra_vlc[i] = @@ -353,42 +360,9 @@ static av_cold void msmpeg4_decode_init_static(void) ff_msmp4_vc1_vlcs_init_once(); } -av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - MpegEncContext *s = avctx->priv_data; - int ret; - - if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) - return ret; - - if (ff_h263_decode_init(avctx) < 0) - return -1; - - ff_msmpeg4_common_init(s); - - switch (s->msmpeg4_version) { - case MSMP4_V1: - case MSMP4_V2: - s->decode_mb= msmpeg4v12_decode_mb; - break; - case MSMP4_V3: - case MSMP4_WMV1: - s->decode_mb= msmpeg4v34_decode_mb; - break; - case MSMP4_WMV2: - break; - } - - s->slice_height= s->mb_height; //to avoid 1/0 if the first frame is not a keyframe - - ff_thread_once(&init_static_once, msmpeg4_decode_init_static); - - return 0; -} - -int ff_msmpeg4_decode_picture_header(MpegEncContext * s) +static int msmpeg4_decode_picture_header(H263DecContext *const h) { + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); int code; // at minimum one bit per macroblock is required at least in a valid frame, @@ -396,355 +370,370 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) // smallest "black/skip" frame generally contain not much recoverable content // while at the same time they have the highest computational requirements // per byte - if (get_bits_left(&s->gb) * 8LL < (s->width+15)/16 * ((s->height+15)/16)) + if (get_bits_left(&h->gb) * 8LL < (h->c.width+15)/16 * ((h->c.height+15)/16)) return AVERROR_INVALIDDATA; - if (s->msmpeg4_version == MSMP4_V1) { - int start_code = get_bits_long(&s->gb, 32); + if (h->c.msmpeg4_version == MSMP4_V1) { + int start_code = get_bits_long(&h->gb, 32); if(start_code!=0x00000100){ - av_log(s->avctx, AV_LOG_ERROR, "invalid startcode\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "invalid startcode\n"); return -1; } - skip_bits(&s->gb, 5); // frame number */ + skip_bits(&h->gb, 5); // frame number */ } - s->pict_type = get_bits(&s->gb, 2) + 1; - if (s->pict_type != AV_PICTURE_TYPE_I && - s->pict_type != AV_PICTURE_TYPE_P){ - av_log(s->avctx, AV_LOG_ERROR, "invalid picture type\n"); + h->c.pict_type = get_bits(&h->gb, 2) + 1; + if (h->c.pict_type != AV_PICTURE_TYPE_I && + h->c.pict_type != AV_PICTURE_TYPE_P){ + av_log(h->c.avctx, AV_LOG_ERROR, "invalid picture type\n"); return -1; } - s->chroma_qscale= s->qscale = get_bits(&s->gb, 5); - if(s->qscale==0){ - av_log(s->avctx, AV_LOG_ERROR, "invalid qscale\n"); + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "invalid qscale\n"); return -1; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - code = get_bits(&s->gb, 5); - if (s->msmpeg4_version == MSMP4_V1) { - if(code==0 || code>s->mb_height){ - av_log(s->avctx, AV_LOG_ERROR, "invalid slice height %d\n", code); + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + code = get_bits(&h->gb, 5); + if (h->c.msmpeg4_version == MSMP4_V1) { + if(code==0 || code>h->c.mb_height) { + av_log(h->c.avctx, AV_LOG_ERROR, "invalid slice height %d\n", code); return -1; } - s->slice_height = code; + h->slice_height = code; }else{ /* 0x17: one slice, 0x18: two slices, ... */ if (code < 0x17){ - av_log(s->avctx, AV_LOG_ERROR, "error, slice code was %X\n", code); + av_log(h->c.avctx, AV_LOG_ERROR, "error, slice code was %X\n", code); return -1; } - s->slice_height = s->mb_height / (code - 0x16); + h->slice_height = h->c.mb_height / (code - 0x16); } - switch(s->msmpeg4_version){ + switch (h->c.msmpeg4_version) { case MSMP4_V1: case MSMP4_V2: - s->rl_chroma_table_index = 2; - s->rl_table_index = 2; + ms->rl_chroma_table_index = 2; + ms->rl_table_index = 2; - s->dc_table_index = 0; //not used + ms->dc_table_index = 0; //not used break; case MSMP4_V3: - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); + ms->rl_chroma_table_index = decode012(&h->gb); + ms->rl_table_index = decode012(&h->gb); - s->dc_table_index = get_bits1(&s->gb); + ms->dc_table_index = get_bits1(&h->gb); break; case MSMP4_WMV1: - ff_msmpeg4_decode_ext_header(s, (2+5+5+17+7)/8); + ff_msmpeg4_decode_ext_header(h, (2+5+5+17+7)/8); - if(s->bit_rate > MBAC_BITRATE) s->per_mb_rl_table= get_bits1(&s->gb); - else s->per_mb_rl_table= 0; - - if(!s->per_mb_rl_table){ - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); - } - - s->dc_table_index = get_bits1(&s->gb); - s->inter_intra_pred= 0; - break; - } - s->no_rounding = 1; - if(s->avctx->debug&FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d slice:%d \n", - s->qscale, - s->rl_chroma_table_index, - s->rl_table_index, - s->dc_table_index, - s->per_mb_rl_table, - s->slice_height); - } else { - switch(s->msmpeg4_version){ - case MSMP4_V1: - case MSMP4_V2: - if (s->msmpeg4_version == MSMP4_V1) - s->use_skip_mb_code = 1; + if (ms->bit_rate > MBAC_BITRATE) + ms->per_mb_rl_table = get_bits1(&h->gb); else - s->use_skip_mb_code = get_bits1(&s->gb); - s->rl_table_index = 2; - s->rl_chroma_table_index = s->rl_table_index; - s->dc_table_index = 0; //not used - s->mv_table_index = 0; - break; - case MSMP4_V3: - s->use_skip_mb_code = get_bits1(&s->gb); - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + ms->per_mb_rl_table = 0; - s->dc_table_index = get_bits1(&s->gb); - - s->mv_table_index = get_bits1(&s->gb); - break; - case MSMP4_WMV1: - s->use_skip_mb_code = get_bits1(&s->gb); - - if(s->bit_rate > MBAC_BITRATE) s->per_mb_rl_table= get_bits1(&s->gb); - else s->per_mb_rl_table= 0; - - if(!s->per_mb_rl_table){ - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (!ms->per_mb_rl_table) { + ms->rl_chroma_table_index = decode012(&h->gb); + ms->rl_table_index = decode012(&h->gb); } - s->dc_table_index = get_bits1(&s->gb); - - s->mv_table_index = get_bits1(&s->gb); - s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE); + ms->dc_table_index = get_bits1(&h->gb); + h->c.inter_intra_pred= 0; break; + default: + av_unreachable("msmpeg4_decode_picture_header() only used by MSMP4V1-3, WMV1"); + } + h->c.no_rounding = 1; + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d slice:%d \n", + h->c.qscale, + ms->rl_chroma_table_index, + ms->rl_table_index, + ms->dc_table_index, + ms->per_mb_rl_table, + h->slice_height); + } else { + switch (h->c.msmpeg4_version) { + case MSMP4_V1: + case MSMP4_V2: + if (h->c.msmpeg4_version == MSMP4_V1) + ms->use_skip_mb_code = 1; + else + ms->use_skip_mb_code = get_bits1(&h->gb); + ms->rl_table_index = 2; + ms->rl_chroma_table_index = ms->rl_table_index; + ms->dc_table_index = 0; //not used + ms->mv_table_index = 0; + break; + case MSMP4_V3: + ms->use_skip_mb_code = get_bits1(&h->gb); + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; + + ms->dc_table_index = get_bits1(&h->gb); + + ms->mv_table_index = get_bits1(&h->gb); + break; + case MSMP4_WMV1: + ms->use_skip_mb_code = get_bits1(&h->gb); + + if (ms->bit_rate > MBAC_BITRATE) + ms->per_mb_rl_table = get_bits1(&h->gb); + else + ms->per_mb_rl_table = 0; + + if (!ms->per_mb_rl_table) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; + } + + ms->dc_table_index = get_bits1(&h->gb); + + ms->mv_table_index = get_bits1(&h->gb); + h->c.inter_intra_pred = h->c.width*h->c.height < 320*240 && + ms->bit_rate <= II_BITRATE; + break; + default: + av_unreachable("msmpeg4_decode_picture_header() only used by MSMP4V1-3, WMV1"); } - if(s->avctx->debug&FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, "skip:%d rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d \n", - s->use_skip_mb_code, - s->rl_table_index, - s->rl_chroma_table_index, - s->dc_table_index, - s->mv_table_index, - s->per_mb_rl_table, - s->qscale); + if (h->c.avctx->debug&FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_DEBUG, "skip:%d rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d \n", + ms->use_skip_mb_code, + ms->rl_table_index, + ms->rl_chroma_table_index, + ms->dc_table_index, + ms->mv_table_index, + ms->per_mb_rl_table, + h->c.qscale); - if(s->flipflop_rounding){ - s->no_rounding ^= 1; + if (ms->flipflop_rounding) { + h->c.no_rounding ^= 1; }else{ - s->no_rounding = 0; + h->c.no_rounding = 0; } } - ff_dlog(s->avctx, "%d %"PRId64" %d %d %d\n", s->pict_type, s->bit_rate, - s->inter_intra_pred, s->width, s->height); + ff_dlog(h->c.avctx, "%d %d %d %d %d\n", h->c.pict_type, ms->bit_rate, + h->c.inter_intra_pred, h->c.width, h->c.height); - s->esc3_level_length= 0; - s->esc3_run_length= 0; + ms->esc3_level_length = 0; + ms->esc3_run_length = 0; return 0; } -int ff_msmpeg4_decode_ext_header(MpegEncContext * s, int buf_size) +int ff_msmpeg4_decode_ext_header(H263DecContext *const h, int buf_size) { - int left= buf_size*8 - get_bits_count(&s->gb); - int length = s->msmpeg4_version >= MSMP4_V3 ? 17 : 16; + MSMP4DecContext *const ms = mpv_to_msmpeg4(h); + int left = buf_size*8 - get_bits_count(&h->gb); + int length = h->c.msmpeg4_version >= MSMP4_V3 ? 17 : 16; /* the alt_bitstream reader could read over the end so we need to check it */ if(left>=length && leftgb, 5); /* fps */ - s->bit_rate= get_bits(&s->gb, 11)*1024; - if (s->msmpeg4_version >= MSMP4_V3) - s->flipflop_rounding= get_bits1(&s->gb); + skip_bits(&h->gb, 5); /* fps */ + ms->bit_rate = get_bits(&h->gb, 11) * 1024; + if (h->c.msmpeg4_version >= MSMP4_V3) + ms->flipflop_rounding = get_bits1(&h->gb); else - s->flipflop_rounding= 0; + ms->flipflop_rounding = 0; } else if(leftflipflop_rounding= 0; - if (s->msmpeg4_version != MSMP4_V2) - av_log(s->avctx, AV_LOG_ERROR, "ext header missing, %d left\n", left); + ms->flipflop_rounding = 0; + if (h->c.msmpeg4_version != MSMP4_V2) + av_log(h->c.avctx, AV_LOG_ERROR, "ext header missing, %d left\n", left); } else { - av_log(s->avctx, AV_LOG_ERROR, "I-frame too long, ignoring ext header\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "I-frame too long, ignoring ext header\n"); } return 0; } -static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr) +static int msmpeg4_decode_dc(MSMP4DecContext *const ms, int n, int *dir_ptr) { + H263DecContext *const h = &ms->h; int level, pred; - if (s->msmpeg4_version <= MSMP4_V2) { + if (h->c.msmpeg4_version <= MSMP4_V2) { if (n < 4) { - level = get_vlc2(&s->gb, v2_dc_lum_vlc, MSMP4_DC_VLC_BITS, 3); + level = get_vlc2(&h->gb, v2_dc_lum_vlc, MSMP4_DC_VLC_BITS, 3); } else { - level = get_vlc2(&s->gb, v2_dc_chroma_vlc, MSMP4_DC_VLC_BITS, 3); + level = get_vlc2(&h->gb, v2_dc_chroma_vlc, MSMP4_DC_VLC_BITS, 3); } if (level < 0) { - av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "illegal dc vlc\n"); *dir_ptr = 0; return -1; } level-=256; } else { - level = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + level = get_vlc2(&h->gb, ff_msmp4_dc_vlc[ms->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (level == DC_MAX) { - level = get_bits(&s->gb, 8); - if (get_bits1(&s->gb)) + level = get_bits(&h->gb, 8); + if (get_bits1(&h->gb)) level = -level; } else if (level != 0) { - if (get_bits1(&s->gb)) + if (get_bits1(&h->gb)) level = -level; } } - if (s->msmpeg4_version == MSMP4_V1) { + if (h->c.msmpeg4_version == MSMP4_V1) { int32_t *dc_val; - pred = msmpeg4v1_pred_dc(s, n, &dc_val); + pred = msmpeg4v1_pred_dc(&h->c, n, &dc_val); level += pred; /* update predictor */ *dc_val= level; }else{ int16_t *dc_val; - pred = ff_msmpeg4_pred_dc(s, n, &dc_val, dir_ptr); + pred = ff_msmpeg4_pred_dc(&h->c, n, &dc_val, dir_ptr); level += pred; /* update predictor */ if (n < 4) { - *dc_val = level * s->y_dc_scale; + *dc_val = level * h->c.y_dc_scale; } else { - *dc_val = level * s->c_dc_scale; + *dc_val = level * h->c.c_dc_scale; } } return level; } -int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, +int ff_msmpeg4_decode_block(MSMP4DecContext *const ms, int16_t * block, int n, int coded, const uint8_t *scan_table) { + H263DecContext *const h = &ms->h; int level, i, last, run, run_diff; int dc_pred_dir = -1; //unused but its passed around, so it needs to be initialized const RLTable *rl; const RL_VLC_ELEM *rl_vlc; int qmul, qadd; - if (s->mb_intra) { + if (h->c.mb_intra) { qmul=1; qadd=0; /* DC coef */ - level = msmpeg4_decode_dc(s, n, &dc_pred_dir); + level = msmpeg4_decode_dc(ms, n, &dc_pred_dir); if (level < 0){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow- block: %d qscale: %d//\n", n, s->qscale); - if(s->inter_intra_pred) level=0; + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow- block: %d qscale: %d//\n", n, h->c.qscale); + if (h->c.inter_intra_pred) + level = 0; } if (n < 4) { - rl = &ff_rl_table[s->rl_table_index]; - if(level > 256*s->y_dc_scale){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow+ L qscale: %d//\n", s->qscale); - if(!s->inter_intra_pred) return -1; + rl = &ff_rl_table[ms->rl_table_index]; + if (level > 256 * h->c.y_dc_scale) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow+ L qscale: %d//\n", h->c.qscale); + if (!h->c.inter_intra_pred) + return -1; } } else { - rl = &ff_rl_table[3 + s->rl_chroma_table_index]; - if(level > 256*s->c_dc_scale){ - av_log(s->avctx, AV_LOG_ERROR, "dc overflow+ C qscale: %d//\n", s->qscale); - if(!s->inter_intra_pred) return -1; + rl = &ff_rl_table[3 + ms->rl_chroma_table_index]; + if (level > 256 * h->c.c_dc_scale) { + av_log(h->c.avctx, AV_LOG_ERROR, "dc overflow+ C qscale: %d//\n", h->c.qscale); + if (!h->c.inter_intra_pred) + return -1; } } block[0] = level; - run_diff = s->msmpeg4_version >= MSMP4_WMV1; + run_diff = h->c.msmpeg4_version >= MSMP4_WMV1; i = 0; if (!coded) { goto not_coded; } - if (s->ac_pred) { + if (h->c.ac_pred) { if (dc_pred_dir == 0) - scan_table = s->permutated_intra_v_scantable; /* left */ + scan_table = h->c.permutated_intra_v_scantable; /* left */ else - scan_table = s->permutated_intra_h_scantable; /* top */ + scan_table = h->c.permutated_intra_h_scantable; /* top */ } else { - scan_table = s->intra_scantable.permutated; + scan_table = h->c.intra_scantable.permutated; } rl_vlc= rl->rl_vlc[0]; } else { - qmul = s->qscale << 1; - qadd = (s->qscale - 1) | 1; + qmul = h->c.qscale << 1; + qadd = (h->c.qscale - 1) | 1; i = -1; - rl = &ff_rl_table[3 + s->rl_table_index]; + rl = &ff_rl_table[3 + ms->rl_table_index]; - if (s->msmpeg4_version == MSMP4_V2) + if (h->c.msmpeg4_version == MSMP4_V2) run_diff = 0; else run_diff = 1; if (!coded) { - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } if(!scan_table) - scan_table = s->inter_scantable.permutated; - rl_vlc= rl->rl_vlc[s->qscale]; + scan_table = h->c.inter_scantable.permutated; + rl_vlc= rl->rl_vlc[h->c.qscale]; } { - OPEN_READER(re, &s->gb); + OPEN_READER(re, &h->gb); for(;;) { - UPDATE_CACHE(re, &s->gb); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 0); + UPDATE_CACHE(re, &h->gb); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 0); if (level==0) { int cache; - cache= GET_CACHE(re, &s->gb); + cache= GET_CACHE(re, &h->gb); /* escape */ - if (s->msmpeg4_version == MSMP4_V1 || (cache&0x80000000)==0) { - if (s->msmpeg4_version == MSMP4_V1 || (cache&0x40000000)==0) { + if (h->c.msmpeg4_version == MSMP4_V1 || (cache&0x80000000)==0) { + if (h->c.msmpeg4_version == MSMP4_V1 || (cache&0x40000000)==0) { /* third escape */ - if (s->msmpeg4_version != MSMP4_V1) - LAST_SKIP_BITS(re, &s->gb, 2); - UPDATE_CACHE(re, &s->gb); - if (s->msmpeg4_version <= MSMP4_V3) { - last= SHOW_UBITS(re, &s->gb, 1); SKIP_CACHE(re, &s->gb, 1); - run= SHOW_UBITS(re, &s->gb, 6); SKIP_CACHE(re, &s->gb, 6); - level= SHOW_SBITS(re, &s->gb, 8); - SKIP_COUNTER(re, &s->gb, 1+6+8); + if (h->c.msmpeg4_version != MSMP4_V1) + LAST_SKIP_BITS(re, &h->gb, 2); + UPDATE_CACHE(re, &h->gb); + if (h->c.msmpeg4_version <= MSMP4_V3) { + last = SHOW_UBITS(re, &h->gb, 1); SKIP_CACHE(re, &h->gb, 1); + run = SHOW_UBITS(re, &h->gb, 6); SKIP_CACHE(re, &h->gb, 6); + level = SHOW_SBITS(re, &h->gb, 8); + SKIP_COUNTER(re, &h->gb, 1 + 6 + 8); }else{ int sign; - last= SHOW_UBITS(re, &s->gb, 1); SKIP_BITS(re, &s->gb, 1); - if(!s->esc3_level_length){ + last = SHOW_UBITS(re, &h->gb, 1); SKIP_BITS(re, &h->gb, 1); + if (!ms->esc3_level_length) { int ll; - ff_dlog(s->avctx, "ESC-3 %X at %d %d\n", - show_bits(&s->gb, 24), s->mb_x, s->mb_y); - if(s->qscale<8){ - ll= SHOW_UBITS(re, &s->gb, 3); SKIP_BITS(re, &s->gb, 3); + ff_dlog(h->c.avctx, "ESC-3 %X at %d %d\n", + show_bits(&h->gb, 24), h->c.mb_x, h->c.mb_y); + if (h->c.qscale < 8) { + ll = SHOW_UBITS(re, &h->gb, 3); SKIP_BITS(re, &h->gb, 3); if(ll==0){ - ll= 8+SHOW_UBITS(re, &s->gb, 1); SKIP_BITS(re, &s->gb, 1); + ll = 8+SHOW_UBITS(re, &h->gb, 1); SKIP_BITS(re, &h->gb, 1); } }else{ ll=2; - while(ll<8 && SHOW_UBITS(re, &s->gb, 1)==0){ + while (ll < 8 && SHOW_UBITS(re, &h->gb, 1) == 0) { ll++; - SKIP_BITS(re, &s->gb, 1); + SKIP_BITS(re, &h->gb, 1); } - if(ll<8) SKIP_BITS(re, &s->gb, 1); + if (ll<8) SKIP_BITS(re, &h->gb, 1); } - s->esc3_level_length= ll; - s->esc3_run_length= SHOW_UBITS(re, &s->gb, 2) + 3; SKIP_BITS(re, &s->gb, 2); - UPDATE_CACHE(re, &s->gb); + ms->esc3_level_length = ll; + ms->esc3_run_length = SHOW_UBITS(re, &h->gb, 2) + 3; SKIP_BITS(re, &h->gb, 2); + UPDATE_CACHE(re, &h->gb); } - run= SHOW_UBITS(re, &s->gb, s->esc3_run_length); - SKIP_BITS(re, &s->gb, s->esc3_run_length); + run = SHOW_UBITS(re, &h->gb, ms->esc3_run_length); + SKIP_BITS(re, &h->gb, ms->esc3_run_length); - sign= SHOW_UBITS(re, &s->gb, 1); - SKIP_BITS(re, &s->gb, 1); + sign= SHOW_UBITS(re, &h->gb, 1); + SKIP_BITS(re, &h->gb, 1); - level= SHOW_UBITS(re, &s->gb, s->esc3_level_length); - SKIP_BITS(re, &s->gb, s->esc3_level_length); + level = SHOW_UBITS(re, &h->gb, ms->esc3_level_length); + SKIP_BITS(re, &h->gb, ms->esc3_level_length); if(sign) level= -level; } @@ -755,38 +744,40 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, if(last) i+=192; } else { /* second escape */ - SKIP_BITS(re, &s->gb, 2); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 2); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i+= run + rl->max_run[run>>7][level/qmul] + run_diff; //FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { /* first escape */ - SKIP_BITS(re, &s->gb, 1); - GET_RL_VLC(level, run, re, &s->gb, rl_vlc, TEX_VLC_BITS, 2, 1); + SKIP_BITS(re, &h->gb, 1); + GET_RL_VLC(level, run, re, &h->gb, rl_vlc, TEX_VLC_BITS, 2, 1); i+= run; level = level + rl->max_level[run>>7][(run-1)&63] * qmul;//FIXME opt indexing - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } } else { i+= run; - level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1); - LAST_SKIP_BITS(re, &s->gb, 1); + level = (level ^ SHOW_SBITS(re, &h->gb, 1)) - SHOW_SBITS(re, &h->gb, 1); + LAST_SKIP_BITS(re, &h->gb, 1); } if (i > 62){ i-= 192; if(i&(~63)){ - const int left= get_bits_left(&s->gb); + const int left = get_bits_left(&h->gb); if (((i + 192 == 64 && level / qmul == -1) || - !(s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) && + !(h->c.avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) && left >= 0) { - av_log(s->avctx, AV_LOG_ERROR, "ignoring overflow at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "ignoring overflow at %d %d\n", + h->c.mb_x, h->c.mb_y); i = 63; break; }else{ - av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); + av_log(h->c.avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", + h->c.mb_x, h->c.mb_y); return -1; } } @@ -797,35 +788,31 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, block[scan_table[i]] = level; } - CLOSE_READER(re, &s->gb); + CLOSE_READER(re, &h->gb); } + if (h->c.mb_intra) { not_coded: - if (s->mb_intra) { - ff_mpeg4_pred_ac(s, block, n, dc_pred_dir); - if (s->ac_pred) { - i = 63; /* XXX: not optimal */ - } + ff_mpeg4_pred_ac(h, block, n, dc_pred_dir); } - if (s->msmpeg4_version >= MSMP4_WMV1 && i > 0) i=63; //FIXME/XXX optimize - s->block_last_index[n] = i; + h->c.block_last_index[n] = i; return 0; } -void ff_msmpeg4_decode_motion(MpegEncContext *s, int *mx_ptr, int *my_ptr) +void ff_msmpeg4_decode_motion(MSMP4DecContext *const ms, int *mx_ptr, int *my_ptr) { - const MVTable *mv; - int code, mx, my; + const VLCElem *const mv_vlc = mv_tables[ms->mv_table_index]; + H263DecContext *const h = &ms->h; + int sym, mx, my; - mv = &ff_mv_tables[s->mv_table_index]; - - code = get_vlc2(&s->gb, mv->vlc, MV_VLC_BITS, 2); - if (code == MSMPEG4_MV_TABLES_NB_ELEMS) { - mx = get_bits(&s->gb, 6); - my = get_bits(&s->gb, 6); + sym = get_vlc2(&h->gb, mv_vlc, MV_VLC_BITS, 2); + if (sym) { + mx = sym >> 8; + my = sym & 0xFF; } else { - mx = mv->table_mvx[code]; - my = mv->table_mvy[code]; + /* Escape */ + mx = get_bits(&h->gb, 6); + my = get_bits(&h->gb, 6); } mx += *mx_ptr - 32; @@ -844,12 +831,54 @@ void ff_msmpeg4_decode_motion(MpegEncContext *s, int *mx_ptr, int *my_ptr) *my_ptr = my; } +av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + H263DecContext *const h = avctx->priv_data; + int ret; + + ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); + if (ret < 0) + return ret; + + if (ff_h263_decode_init(avctx) < 0) + return -1; + + // We unquantize inter blocks as we parse them. + h->c.dct_unquantize_inter = NULL; + + h->decode_header = msmpeg4_decode_picture_header; + + ff_msmpeg4_common_init(&h->c); + + switch (h->c.msmpeg4_version) { + case MSMP4_V1: + case MSMP4_V2: + h->decode_mb = msmpeg4v12_decode_mb; + break; + case MSMP4_V3: + case MSMP4_WMV1: + h->decode_mb = msmpeg4v34_decode_mb; + break; + case MSMP4_WMV2: + break; + default: + av_unreachable("List contains all cases using ff_msmpeg4_decode_init()"); + } + + h->slice_height = h->c.mb_height; //to avoid 1/0 if the first frame is not a keyframe + + ff_thread_once(&init_static_once, msmpeg4_decode_init_static); + + return 0; +} + const FFCodec ff_msmpeg4v1_decoder = { .p.name = "msmpeg4v1", CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 1"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -864,7 +893,7 @@ const FFCodec ff_msmpeg4v2_decoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V2, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -879,7 +908,7 @@ const FFCodec ff_msmpeg4v3_decoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 3"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V3, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, @@ -894,7 +923,7 @@ const FFCodec ff_wmv1_decoder = { CODEC_LONG_NAME("Windows Media Video 7"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(MSMP4DecContext), .init = ff_msmpeg4_decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), .close = ff_mpv_decode_close, diff --git a/libavcodec/msmpeg4dec.h b/libavcodec/msmpeg4dec.h index 5daa7c6bc3..e0fb3cf483 100644 --- a/libavcodec/msmpeg4dec.h +++ b/libavcodec/msmpeg4dec.h @@ -23,19 +23,39 @@ #define AVCODEC_MSMPEG4DEC_H #include "avcodec.h" +#include "h263dec.h" #include "mpegvideo.h" #define INTER_INTRA_VLC_BITS 3 #define MB_NON_INTRA_VLC_BITS 9 +typedef struct MSMP4DecContext { + H263DecContext h; + int bit_rate; + int flipflop_rounding; + int mv_table_index; + int rl_table_index; + int rl_chroma_table_index; + int dc_table_index; + int use_skip_mb_code; + int per_mb_rl_table; + int esc3_level_length; + int esc3_run_length; +} MSMP4DecContext; + +static inline MSMP4DecContext *mpv_to_msmpeg4(H263DecContext *const h) +{ + // Only legal because no MSMPEG-4 decoder uses slice-threading. + return (MSMP4DecContext*)h; +} + extern const VLCElem *ff_mb_non_intra_vlc[4]; extern VLCElem ff_inter_intra_vlc[8]; int ff_msmpeg4_decode_init(AVCodecContext *avctx); -int ff_msmpeg4_decode_picture_header(MpegEncContext *s); -int ff_msmpeg4_decode_ext_header(MpegEncContext *s, int buf_size); -void ff_msmpeg4_decode_motion(MpegEncContext * s, int *mx_ptr, int *my_ptr); -int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, +int ff_msmpeg4_decode_ext_header(H263DecContext *const h, int buf_size); +void ff_msmpeg4_decode_motion(MSMP4DecContext *ms, int *mx_ptr, int *my_ptr); +int ff_msmpeg4_decode_block(MSMP4DecContext *ms, int16_t * block, int n, int coded, const uint8_t *scan_table); #endif diff --git a/libavcodec/msmpeg4enc.c b/libavcodec/msmpeg4enc.c index 5ce4e6e30c..874e0c1f2b 100644 --- a/libavcodec/msmpeg4enc.c +++ b/libavcodec/msmpeg4enc.c @@ -30,6 +30,8 @@ #include #include +#define NO_SLICE_THREADING_HERE + #include "libavutil/attributes.h" #include "libavutil/avutil.h" #include "libavutil/thread.h" @@ -48,22 +50,32 @@ static uint8_t rl_length[NB_RL_TABLES][MAX_LEVEL+1][MAX_RUN+1][2]; +// The lowest 8 bits of each entry are length, the other bits are the code. +// The index of the (mx, my) entry is (mx * 64) + my. +static uint32_t mv_vector_tables[2][4096]; + /* build the table which associate a (x,y) motion vector to a vlc */ -static av_cold void init_mv_table(MVTable *tab, uint16_t table_mv_index[4096]) +static av_cold void init_mv_table(const uint16_t mv_table[], const uint8_t mv_table_lens[], + uint32_t mv_vector_table[4096], + unsigned escape_code, int escape_length) { - int i, x, y; - - tab->table_mv_index = table_mv_index; - - /* mark all entries as not used */ - for(i=0;i<4096;i++) - tab->table_mv_index[i] = MSMPEG4_MV_TABLES_NB_ELEMS; - - for (i = 0; i < MSMPEG4_MV_TABLES_NB_ELEMS; i++) { - x = tab->table_mvx[i]; - y = tab->table_mvy[i]; - tab->table_mv_index[(x << 6) | y] = i; + for (int i = 0; i < 4096; i++) { + // Initialize to the table to "escaped". This code is equivalent to + // the following double loop (with x and y ranging over 0..63): + // tab[x * 64 + y] = (esc_code << 20) | (x << 14) | (y << 8) | esc_length + mv_vector_table[i] = (escape_code << 20) | (i << 8) | escape_length; } + + for (uint32_t i = 0, code = 0; i < MSMPEG4_MV_TABLES_NB_ELEMS; i++) { + int sym = mv_table[i]; + int len = mv_table_lens[i]; + int x = sym >> 8; + int y = sym & 0xFF; + // We ignore the escape value here and restore it after the loop. + mv_vector_table[(x << 6) | y] = (code >> (24 - len)) | len; + code += 1U << (32 - len); + } + mv_vector_table[0] = (escape_code << 20) | escape_length; } void ff_msmpeg4_code012(PutBitContext *pb, int n) @@ -120,9 +132,10 @@ static int get_size_of_code(const RLTable *rl, int last, int run, static av_cold void msmpeg4_encode_init_static(void) { - static uint16_t mv_index_tables[2][4096]; - init_mv_table(&ff_mv_tables[0], mv_index_tables[0]); - init_mv_table(&ff_mv_tables[1], mv_index_tables[1]); + init_mv_table(ff_msmp4_mv_table0, ff_msmp4_mv_table0_lens, + mv_vector_tables[0], 0x0000, 8 + 12); + init_mv_table(ff_msmp4_mv_table1, ff_msmp4_mv_table1_lens, + mv_vector_tables[1], 0x000b, 4 + 12); for (int i = 0; i < NB_RL_TABLES; i++) { for (int level = 1; level <= MAX_LEVEL; level++) { @@ -135,23 +148,9 @@ static av_cold void msmpeg4_encode_init_static(void) } } -av_cold void ff_msmpeg4_encode_init(MpegEncContext *s) -{ - static AVOnce init_static_once = AV_ONCE_INIT; - - ff_msmpeg4_common_init(s); - if (s->msmpeg4_version >= MSMP4_WMV1) { - s->min_qcoeff = -255; - s->max_qcoeff = 255; - } - - /* init various encoding tables */ - ff_thread_once(&init_static_once, msmpeg4_encode_init_static); -} - static void find_best_tables(MSMPEG4EncContext *ms) { - MpegEncContext *const s = &ms->s; + MPVEncContext *const s = &ms->m.s; int i; int best = 0, best_size = INT_MAX; int chroma_best = 0, best_chroma_size = INT_MAX; @@ -175,7 +174,7 @@ static void find_best_tables(MSMPEG4EncContext *ms) int intra_luma_count = ms->ac_stats[1][0][level][run][last]; int intra_chroma_count= ms->ac_stats[1][1][level][run][last]; - if(s->pict_type==AV_PICTURE_TYPE_I){ + if (s->c.pict_type == AV_PICTURE_TYPE_I) { size += intra_luma_count *rl_length[i ][level][run][last]; chroma_size+= intra_chroma_count*rl_length[i+3][level][run][last]; }else{ @@ -197,117 +196,119 @@ static void find_best_tables(MSMPEG4EncContext *ms) } } - if(s->pict_type==AV_PICTURE_TYPE_P) chroma_best= best; + if (s->c.pict_type == AV_PICTURE_TYPE_P) chroma_best = best; memset(ms->ac_stats, 0, sizeof(ms->ac_stats)); - s->rl_table_index = best; - s->rl_chroma_table_index= chroma_best; + ms->rl_table_index = best; + ms->rl_chroma_table_index = chroma_best; - if(s->pict_type != s->last_non_b_pict_type){ - s->rl_table_index= 2; - if(s->pict_type==AV_PICTURE_TYPE_I) - s->rl_chroma_table_index= 1; + if (s->c.pict_type != ms->m.last_non_b_pict_type) { + ms->rl_table_index= 2; + if (s->c.pict_type == AV_PICTURE_TYPE_I) + ms->rl_chroma_table_index = 1; else - s->rl_chroma_table_index= 2; + ms->rl_chroma_table_index = 2; } } /* write MSMPEG4 compatible frame header */ -void ff_msmpeg4_encode_picture_header(MpegEncContext * s) +static int msmpeg4_encode_picture_header(MPVMainEncContext *const m) { - MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)s; + MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)m; + MPVEncContext *const s = &m->s; find_best_tables(ms); - align_put_bits(&s->pb); - put_bits(&s->pb, 2, s->pict_type - 1); + put_bits_assume_flushed(&s->pb); - put_bits(&s->pb, 5, s->qscale); - if (s->msmpeg4_version <= MSMP4_V2) { - s->rl_table_index = 2; - s->rl_chroma_table_index = 2; + put_bits(&s->pb, 2, s->c.pict_type - 1); + + put_bits(&s->pb, 5, s->c.qscale); + if (s->c.msmpeg4_version <= MSMP4_V2) { + ms->rl_table_index = 2; + ms->rl_chroma_table_index = 2; } - s->dc_table_index = 1; - s->mv_table_index = 1; /* only if P-frame */ - s->use_skip_mb_code = 1; /* only if P-frame */ - s->per_mb_rl_table = 0; - if (s->msmpeg4_version == MSMP4_WMV1) - s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE && s->pict_type==AV_PICTURE_TYPE_P); - ff_dlog(s, "%d %"PRId64" %d %d %d\n", s->pict_type, s->bit_rate, - s->inter_intra_pred, s->width, s->height); + ms->dc_table_index = 1; + ms->mv_table_index = 1; /* only if P-frame */ + ms->use_skip_mb_code = 1; /* only if P-frame */ + ms->per_mb_rl_table = 0; + if (s->c.msmpeg4_version == MSMP4_WMV1) + s->c.inter_intra_pred = s->c.width * s->c.height < 320*240 && + m->bit_rate <= II_BITRATE && + s->c.pict_type == AV_PICTURE_TYPE_P; + ff_dlog(s->c.avctx, "%d %"PRId64" %d %d %d\n", s->c.pict_type, m->bit_rate, + s->c.inter_intra_pred, s->c.width, s->c.height); - if (s->pict_type == AV_PICTURE_TYPE_I) { - s->slice_height= s->mb_height/1; - put_bits(&s->pb, 5, 0x16 + s->mb_height/s->slice_height); + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + s->slice_height = s->c.mb_height/1; + put_bits(&s->pb, 5, 0x16 + s->c.mb_height / s->slice_height); - if (s->msmpeg4_version == MSMP4_WMV1) { + if (s->c.msmpeg4_version == MSMP4_WMV1) { ff_msmpeg4_encode_ext_header(s); - if(s->bit_rate>MBAC_BITRATE) - put_bits(&s->pb, 1, s->per_mb_rl_table); + if (m->bit_rate > MBAC_BITRATE) + put_bits(&s->pb, 1, ms->per_mb_rl_table); } - if (s->msmpeg4_version > MSMP4_V2) { - if(!s->per_mb_rl_table){ - ff_msmpeg4_code012(&s->pb, s->rl_chroma_table_index); - ff_msmpeg4_code012(&s->pb, s->rl_table_index); + if (s->c.msmpeg4_version > MSMP4_V2) { + if (!ms->per_mb_rl_table){ + ff_msmpeg4_code012(&s->pb, ms->rl_chroma_table_index); + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); } - put_bits(&s->pb, 1, s->dc_table_index); + put_bits(&s->pb, 1, ms->dc_table_index); } } else { - put_bits(&s->pb, 1, s->use_skip_mb_code); + put_bits(&s->pb, 1, ms->use_skip_mb_code); - if (s->msmpeg4_version == MSMP4_WMV1 && s->bit_rate > MBAC_BITRATE) - put_bits(&s->pb, 1, s->per_mb_rl_table); + if (s->c.msmpeg4_version == MSMP4_WMV1 && m->bit_rate > MBAC_BITRATE) + put_bits(&s->pb, 1, ms->per_mb_rl_table); - if (s->msmpeg4_version > MSMP4_V2) { - if(!s->per_mb_rl_table) - ff_msmpeg4_code012(&s->pb, s->rl_table_index); + if (s->c.msmpeg4_version > MSMP4_V2) { + if (!ms->per_mb_rl_table) + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); - put_bits(&s->pb, 1, s->dc_table_index); + put_bits(&s->pb, 1, ms->dc_table_index); - put_bits(&s->pb, 1, s->mv_table_index); + put_bits(&s->pb, 1, ms->mv_table_index); } } - s->esc3_level_length= 0; - s->esc3_run_length= 0; + s->esc3_level_length = 0; + ms->esc3_run_length = 0; + + return 0; } -void ff_msmpeg4_encode_ext_header(MpegEncContext * s) +void ff_msmpeg4_encode_ext_header(MPVEncContext *const s) { + const MPVMainEncContext *const m = slice_to_mainenc(s); unsigned fps; - if (s->avctx->framerate.num > 0 && s->avctx->framerate.den > 0) - fps = s->avctx->framerate.num / s->avctx->framerate.den; + if (s->c.avctx->framerate.num > 0 && s->c.avctx->framerate.den > 0) + fps = s->c.avctx->framerate.num / s->c.avctx->framerate.den; else { -FF_DISABLE_DEPRECATION_WARNINGS - fps = s->avctx->time_base.den / s->avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - / FFMAX(s->avctx->ticks_per_frame, 1) -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + fps = s->c.avctx->time_base.den / s->c.avctx->time_base.num; } put_bits(&s->pb, 5, FFMIN(fps, 31)); //yes 29.97 -> 29 - put_bits(&s->pb, 11, FFMIN(s->bit_rate / 1024, 2047)); + put_bits(&s->pb, 11, FFMIN(m->bit_rate / 1024, 2047)); - if (s->msmpeg4_version >= MSMP4_V3) + if (s->c.msmpeg4_version >= MSMP4_V3) put_bits(&s->pb, 1, s->flipflop_rounding); else av_assert0(!s->flipflop_rounding); } -void ff_msmpeg4_encode_motion(MpegEncContext * s, +void ff_msmpeg4_encode_motion(MSMPEG4EncContext *const ms, int mx, int my) { - int code; - MVTable *mv; + MPVEncContext *const s = &ms->m.s; + const uint32_t *const mv_vector_table = mv_vector_tables[ms->mv_table_index]; + uint32_t code; /* modulo encoding */ /* WARNING : you cannot reach all the MVs even with the modulo @@ -323,40 +324,31 @@ void ff_msmpeg4_encode_motion(MpegEncContext * s, mx += 32; my += 32; - mv = &ff_mv_tables[s->mv_table_index]; - code = mv->table_mv_index[(mx << 6) | my]; - put_bits(&s->pb, - mv->table_mv_bits[code], - mv->table_mv_code[code]); - if (code == MSMPEG4_MV_TABLES_NB_ELEMS) { - /* escape : code literally */ - put_bits(&s->pb, 6, mx); - put_bits(&s->pb, 6, my); - } + code = mv_vector_table[(mx << 6) | my]; + put_bits(&s->pb, code & 0xff, code >> 8); } -void ff_msmpeg4_handle_slices(MpegEncContext *s){ - if (s->mb_x == 0) { - if (s->slice_height && (s->mb_y % s->slice_height) == 0) { - if (s->msmpeg4_version < MSMP4_WMV1) { - ff_mpeg4_clean_buffers(s); - } - s->first_slice_line = 1; +void ff_msmpeg4_handle_slices(MPVEncContext *const s) +{ + if (s->c.mb_x == 0) { + if (s->slice_height && (s->c.mb_y % s->slice_height) == 0) { + if (s->c.msmpeg4_version < MSMP4_WMV1) + ff_mpeg4_clean_buffers(&s->c); + s->c.first_slice_line = 1; } else { - s->first_slice_line = 0; + s->c.first_slice_line = 0; } } } -static void msmpeg4v2_encode_motion(MpegEncContext * s, int val) +static void msmpeg4v2_encode_motion(MPVEncContext *const s, int val) { int range, bit_size, sign, code, bits; if (val == 0) { - /* zero vector */ - code = 0; - put_bits(&s->pb, ff_mvtab[code][1], ff_mvtab[code][0]); + /* zero vector; corresponds to ff_mvtab[0] */ + put_bits(&s->pb, 1, 0x1); } else { bit_size = s->f_code - 1; range = 1 << bit_size; @@ -382,23 +374,24 @@ static void msmpeg4v2_encode_motion(MpegEncContext * s, int val) } } -void ff_msmpeg4_encode_mb(MpegEncContext * s, - int16_t block[6][64], - int motion_x, int motion_y) +static void msmpeg4_encode_mb(MPVEncContext *const s, + int16_t block[][64], + int motion_x, int motion_y) { + MSMPEG4EncContext *const ms = mpv_to_msmpeg4(s); int cbp, coded_cbp, i; int pred_x, pred_y; ff_msmpeg4_handle_slices(s); - if (!s->mb_intra) { + if (!s->c.mb_intra) { /* compute cbp */ cbp = 0; for (i = 0; i < 6; i++) { - if (s->block_last_index[i] >= 0) + if (s->c.block_last_index[i] >= 0) cbp |= 1 << (5 - i); } - if (s->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) { + if (ms->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) { /* skip macroblock */ put_bits(&s->pb, 1, 1); s->last_bits++; @@ -406,10 +399,10 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, return; } - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ - if (s->msmpeg4_version <= MSMP4_V2) { + if (s->c.msmpeg4_version <= MSMP4_V2) { put_bits(&s->pb, ff_v2_mb_type[cbp&3][1], ff_v2_mb_type[cbp&3][0]); @@ -422,7 +415,7 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, s->misc_bits += get_bits_diff(s); - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); msmpeg4v2_encode_motion(s, motion_x - pred_x); msmpeg4v2_encode_motion(s, motion_y - pred_y); }else{ @@ -433,9 +426,9 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, s->misc_bits += get_bits_diff(s); /* motion vector */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - ff_msmpeg4_encode_motion(s, motion_x - pred_x, - motion_y - pred_y); + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); + ff_msmpeg4_encode_motion(ms, motion_x - pred_x, + motion_y - pred_y); } s->mv_bits += get_bits_diff(s); @@ -448,15 +441,15 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, /* compute cbp */ cbp = 0; for (int i = 0; i < 6; i++) { - int val = (s->block_last_index[i] >= 1); + int val = (s->c.block_last_index[i] >= 1); cbp |= val << (5 - i); } - if (s->msmpeg4_version <= MSMP4_V2) { - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.msmpeg4_version <= MSMP4_V2) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { put_bits(&s->pb, ff_v2_intra_cbpc[cbp&3][1], ff_v2_intra_cbpc[cbp&3][0]); } else { - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ put_bits(&s->pb, ff_v2_mb_type[(cbp&3) + 4][1], @@ -467,14 +460,14 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, ff_h263_cbpy_tab[cbp>>2][1], ff_h263_cbpy_tab[cbp>>2][0]); }else{ - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { /* compute coded_cbp; the 0x3 corresponds to chroma cbp; * luma coded_cbp are set in the loop below */ coded_cbp = cbp & 0x3; for (int i = 0; i < 4; i++) { uint8_t *coded_block; - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_block); - int val = (s->block_last_index[i] >= 1); + int pred = ff_msmpeg4_coded_block_pred(&s->c, i, &coded_block); + int val = (s->c.block_last_index[i] >= 1); *coded_block = val; val ^= pred; coded_cbp |= val << (5 - i); @@ -483,16 +476,17 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, put_bits(&s->pb, ff_msmp4_mb_i_table[coded_cbp][1], ff_msmp4_mb_i_table[coded_cbp][0]); } else { - if (s->use_skip_mb_code) + if (ms->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ put_bits(&s->pb, ff_table_mb_non_intra[cbp][1], ff_table_mb_non_intra[cbp][0]); } put_bits(&s->pb, 1, 0); /* no AC prediction yet */ - if(s->inter_intra_pred){ - s->h263_aic_dir=0; - put_bits(&s->pb, ff_table_inter_intra[s->h263_aic_dir][1], ff_table_inter_intra[s->h263_aic_dir][0]); + if (s->c.inter_intra_pred) { + s->c.h263_aic_dir = 0; + put_bits(&s->pb, ff_table_inter_intra[s->c.h263_aic_dir][1], + ff_table_inter_intra[s->c.h263_aic_dir][0]); } } s->misc_bits += get_bits_diff(s); @@ -505,25 +499,26 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, } } -static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr) +static void msmpeg4_encode_dc(MSMPEG4EncContext *const ms, int level, int n, int *dir_ptr) { + MPVEncContext *const s = &ms->m.s; int sign, code; int pred; int16_t *dc_val; - pred = ff_msmpeg4_pred_dc(s, n, &dc_val, dir_ptr); + pred = ff_msmpeg4_pred_dc(&s->c, n, &dc_val, dir_ptr); /* update predictor */ if (n < 4) { - *dc_val = level * s->y_dc_scale; + *dc_val = level * s->c.y_dc_scale; } else { - *dc_val = level * s->c_dc_scale; + *dc_val = level * s->c.c_dc_scale; } /* do the prediction */ level -= pred; - if (s->msmpeg4_version <= MSMP4_V2) { + if (s->c.msmpeg4_version <= MSMP4_V2) { if (n < 4) { put_bits(&s->pb, ff_v2_dc_lum_table[level + 256][1], @@ -543,8 +538,8 @@ static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr if (code > DC_MAX) code = DC_MAX; - put_bits(&s->pb, ff_msmp4_dc_tables[s->dc_table_index][n >= 4][code][1], - ff_msmp4_dc_tables[s->dc_table_index][n >= 4][code][0]); + put_bits(&s->pb, ff_msmp4_dc_tables[ms->dc_table_index][n >= 4][code][1], + ff_msmp4_dc_tables[ms->dc_table_index][n >= 4][code][0]); if (code == DC_MAX) put_bits(&s->pb, 8, level); @@ -557,7 +552,7 @@ static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr /* Encoding of a block; very similar to MPEG-4 except for a different * escape coding (same as H.263) and more VLC tables. */ -void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) +void ff_msmpeg4_encode_block(MPVEncContext *const s, int16_t * block, int n) { MSMPEG4EncContext *const ms = (MSMPEG4EncContext*)s; int level, run, last, i, j, last_index; @@ -566,31 +561,31 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) const RLTable *rl; const uint8_t *scantable; - if (s->mb_intra) { - msmpeg4_encode_dc(s, block[0], n, &dc_pred_dir); + if (s->c.mb_intra) { + msmpeg4_encode_dc(ms, block[0], n, &dc_pred_dir); i = 1; if (n < 4) { - rl = &ff_rl_table[s->rl_table_index]; + rl = &ff_rl_table[ms->rl_table_index]; } else { - rl = &ff_rl_table[3 + s->rl_chroma_table_index]; + rl = &ff_rl_table[3 + ms->rl_chroma_table_index]; } - run_diff = s->msmpeg4_version >= MSMP4_WMV1; - scantable= s->intra_scantable.permutated; + run_diff = s->c.msmpeg4_version >= MSMP4_WMV1; + scantable = s->c.intra_scantable.permutated; } else { i = 0; - rl = &ff_rl_table[3 + s->rl_table_index]; - run_diff = s->msmpeg4_version > MSMP4_V2; - scantable= s->inter_scantable.permutated; + rl = &ff_rl_table[3 + ms->rl_table_index]; + run_diff = s->c.msmpeg4_version > MSMP4_V2; + scantable = s->c.inter_scantable.permutated; } /* recalculate block_last_index for M$ wmv1 */ - if (s->msmpeg4_version >= MSMP4_WMV1 && s->block_last_index[n] > 0) { + if (s->c.msmpeg4_version >= MSMP4_WMV1 && s->c.block_last_index[n] > 0) { for(last_index=63; last_index>=0; last_index--){ if(block[scantable[last_index]]) break; } - s->block_last_index[n]= last_index; + s->c.block_last_index[n] = last_index; }else - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; /* AC coefs */ last_non_zero = i - 1; for (; i <= last_index; i++) { @@ -607,10 +602,10 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) } if(level<=MAX_LEVEL && run<=MAX_RUN){ - ms->ac_stats[s->mb_intra][n>3][level][run][last]++; + ms->ac_stats[s->c.mb_intra][n>3][level][run][last]++; } - ms->ac_stats[s->mb_intra][n > 3][40][63][0]++; //esc3 like + ms->ac_stats[s->c.mb_intra][n > 3][40][63][0]++; //esc3 like code = get_rl_index(rl, last, run, level); put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); @@ -630,7 +625,7 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) if (run1 < 0) goto esc3; code = get_rl_index(rl, last, run1+1, level); - if (s->msmpeg4_version == MSMP4_WMV1 && code == rl->n) + if (s->c.msmpeg4_version == MSMP4_WMV1 && code == rl->n) goto esc3; code = get_rl_index(rl, last, run1, level); if (code == rl->n) { @@ -638,17 +633,17 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) /* third escape */ put_bits(&s->pb, 1, 0); put_bits(&s->pb, 1, last); - if (s->msmpeg4_version >= MSMP4_WMV1) { - if(s->esc3_level_length==0){ - s->esc3_level_length=8; - s->esc3_run_length= 6; + if (s->c.msmpeg4_version >= MSMP4_WMV1) { + if (s->esc3_level_length == 0) { + s->esc3_level_length = 8; + ms->esc3_run_length = 6; //ESCLVLSZ + ESCRUNSZ - if(s->qscale<8) + if (s->c.qscale < 8) put_bits(&s->pb, 6, 3); else put_bits(&s->pb, 8, 3); } - put_bits(&s->pb, s->esc3_run_length, run); + put_bits(&s->pb, ms->esc3_run_length, run); put_bits(&s->pb, 1, sign); put_bits(&s->pb, s->esc3_level_length, level); }else{ @@ -675,15 +670,36 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) } } +av_cold void ff_msmpeg4_encode_init(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + static AVOnce init_static_once = AV_ONCE_INIT; + + ff_msmpeg4_common_init(&s->c); + + if (s->c.msmpeg4_version <= MSMP4_WMV1) { + m->encode_picture_header = msmpeg4_encode_picture_header; + s->encode_mb = msmpeg4_encode_mb; + } + + if (s->c.msmpeg4_version >= MSMP4_WMV1) { + s->min_qcoeff = -255; + s->max_qcoeff = 255; + } + + /* init various encoding tables */ + ff_thread_once(&init_static_once, msmpeg4_encode_init_static); +} + const FFCodec ff_msmpeg4v2_encoder = { .p.name = "msmpeg4v2", CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 2"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V2, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, @@ -696,10 +712,10 @@ const FFCodec ff_msmpeg4v3_encoder = { CODEC_LONG_NAME("MPEG-4 part 2 Microsoft variant version 3"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_MSMPEG4V3, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, @@ -712,10 +728,10 @@ const FFCodec ff_wmv1_encoder = { CODEC_LONG_NAME("Windows Media Video 7"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV1, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(MSMPEG4EncContext), .init = ff_mpv_encode_init, diff --git a/libavcodec/msmpeg4enc.h b/libavcodec/msmpeg4enc.h index da9a45b589..167600f01f 100644 --- a/libavcodec/msmpeg4enc.h +++ b/libavcodec/msmpeg4enc.h @@ -22,25 +22,36 @@ #ifndef AVCODEC_MSMPEG4ENC_H #define AVCODEC_MSMPEG4ENC_H -#include "mpegvideo.h" +#include "mpegvideoenc.h" #include "put_bits.h" #include "rl.h" typedef struct MSMPEG4EncContext { - MpegEncContext s; + MPVMainEncContext m; + + int mv_table_index; + int rl_table_index; + int rl_chroma_table_index; + int dc_table_index; + int use_skip_mb_code; + int per_mb_rl_table; + int esc3_run_length; /** [mb_intra][isChroma][level][run][last] */ unsigned ac_stats[2][2][MAX_LEVEL + 1][MAX_RUN + 1][2]; } MSMPEG4EncContext; -void ff_msmpeg4_encode_init(MpegEncContext *s); -void ff_msmpeg4_encode_picture_header(MpegEncContext *s); -void ff_msmpeg4_encode_ext_header(MpegEncContext *s); -void ff_msmpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y); -void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n); -void ff_msmpeg4_handle_slices(MpegEncContext *s); -void ff_msmpeg4_encode_motion(MpegEncContext * s, int mx, int my); +static inline MSMPEG4EncContext *mpv_to_msmpeg4(MPVEncContext *s) +{ + // Only legal because no MSMPEG-4 decoder uses slice-threading. + return (MSMPEG4EncContext*)s; +} + +void ff_msmpeg4_encode_init(MPVMainEncContext *m); +void ff_msmpeg4_encode_ext_header(MPVEncContext *s); +void ff_msmpeg4_encode_block(MPVEncContext * s, int16_t * block, int n); +void ff_msmpeg4_handle_slices(MPVEncContext *s); +void ff_msmpeg4_encode_motion(MSMPEG4EncContext *ms, int mx, int my); void ff_msmpeg4_code012(PutBitContext *pb, int n); diff --git a/libavcodec/msrle.c b/libavcodec/msrle.c index 51e843e4a6..288f0d768a 100644 --- a/libavcodec/msrle.c +++ b/libavcodec/msrle.c @@ -95,15 +95,7 @@ static int msrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* make the palette available */ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/msrleenc.c b/libavcodec/msrleenc.c index cc39aa308f..654da42c0a 100644 --- a/libavcodec/msrleenc.c +++ b/libavcodec/msrleenc.c @@ -293,8 +293,6 @@ const FFCodec ff_msrle_encoder = { .init = msrle_encode_init, FF_CODEC_ENCODE_CB(msrle_encode_frame), .close = msrle_encode_close, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_PAL8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mss1.c b/libavcodec/mss1.c index 5460673133..cfda18c6d5 100644 --- a/libavcodec/mss1.c +++ b/libavcodec/mss1.c @@ -121,13 +121,13 @@ static void arith_init(ArithCoder *c, GetBitContext *gb) c->get_number = arith_get_number; } -static int decode_pal(MSS12Context *ctx, ArithCoder *acoder) +static void decode_pal(MSS12Context *ctx, ArithCoder *acoder) { int i, ncol, r, g, b; uint32_t *pal = ctx->pal + 256 - ctx->free_colours; if (!ctx->free_colours) - return 0; + return; ncol = arith_get_number(acoder, ctx->free_colours + 1); for (i = 0; i < ncol; i++) { @@ -136,8 +136,6 @@ static int decode_pal(MSS12Context *ctx, ArithCoder *acoder) b = arith_get_bits(acoder, 8); *pal++ = (0xFFU << 24) | (r << 16) | (g << 8) | b; } - - return !!ncol; } static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, @@ -147,7 +145,6 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, MSS12Context *c = &ctx->ctx; GetBitContext gb; ArithCoder acoder; - int pal_changed = 0; int ret; if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) @@ -164,7 +161,7 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (c->keyframe) { c->corrupted = 0; ff_mss12_slicecontext_reset(&ctx->sc); - pal_changed = decode_pal(c, &acoder); + decode_pal(c, &acoder); ctx->pic->flags |= AV_FRAME_FLAG_KEY; ctx->pic->pict_type = AV_PICTURE_TYPE_I; } else { @@ -178,11 +175,6 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (c->corrupted) return AVERROR_INVALIDDATA; memcpy(ctx->pic->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - ctx->pic->palette_has_changed = pal_changed; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if ((ret = av_frame_ref(rframe, ctx->pic)) < 0) return ret; diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index 1888053eb2..aaeceb055d 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -387,12 +387,12 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, ff_mpeg_flush(avctx); - if ((ret = init_get_bits8(&s->gb, buf, buf_size)) < 0) + if ((ret = init_get_bits8(&v->gb, buf, buf_size)) < 0) return ret; - s->loop_filter = avctx->skip_loop_filter < AVDISCARD_ALL; + v->loop_filter = avctx->skip_loop_filter < AVDISCARD_ALL; - if (ff_vc1_parse_frame_header(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "header error\n"); return AVERROR_INVALIDDATA; } @@ -844,7 +844,7 @@ static av_cold int wmv9_init(AVCodecContext *avctx) v->resync_marker = 0; v->rangered = 0; - v->s.max_b_frames = avctx->max_b_frames = 0; + v->max_b_frames = avctx->max_b_frames = 0; v->quantizer_mode = 0; v->finterpflag = 0; diff --git a/libavcodec/mss2dsp.c b/libavcodec/mss2dsp.c index cc39dd637f..ace92ef9c7 100644 --- a/libavcodec/mss2dsp.c +++ b/libavcodec/mss2dsp.c @@ -56,7 +56,7 @@ static av_always_inline void mss2_blit_wmv9_template(uint8_t *dst, } } } - mask += mask_stride; + mask = FF_PTR_ADD(mask, mask_stride); dst += dst_stride; srcy += srcy_stride; srcu += srcuv_stride * (r & 1); diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c index ca4583d841..27ec26f3a2 100644 --- a/libavcodec/msvideo1.c +++ b/libavcodec/msvideo1.c @@ -312,14 +312,7 @@ static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return ret; if (s->mode_8bit) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (s->mode_8bit) diff --git a/libavcodec/msvideo1enc.c b/libavcodec/msvideo1enc.c index b8704367c7..b1cae72081 100644 --- a/libavcodec/msvideo1enc.c +++ b/libavcodec/msvideo1enc.c @@ -315,5 +315,5 @@ const FFCodec ff_msvideo1_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_RGB555), }; diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c index c5c14cbe79..8661bba566 100644 --- a/libavcodec/mxpegdec.c +++ b/libavcodec/mxpegdec.c @@ -47,10 +47,8 @@ typedef struct MXpegDecodeContext { static av_cold int mxpeg_decode_end(AVCodecContext *avctx) { MXpegDecodeContext *s = avctx->priv_data; - MJpegDecodeContext *jpg = &s->jpg; int i; - jpg->picture_ptr = NULL; ff_mjpeg_decode_end(avctx); for (i = 0; i < 2; ++i) diff --git a/libavcodec/nellymoser.c b/libavcodec/nellymoser.c index 66c5f83a56..890e573abf 100644 --- a/libavcodec/nellymoser.c +++ b/libavcodec/nellymoser.c @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #include diff --git a/libavcodec/nellymoser.h b/libavcodec/nellymoser.h index 6d032c97be..3470bfa6b5 100644 --- a/libavcodec/nellymoser.h +++ b/libavcodec/nellymoser.h @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #ifndef AVCODEC_NELLYMOSER_H diff --git a/libavcodec/nellymoserdec.c b/libavcodec/nellymoserdec.c index e9b124399a..bfde5bba26 100644 --- a/libavcodec/nellymoserdec.c +++ b/libavcodec/nellymoserdec.c @@ -28,7 +28,7 @@ /** * @file * The 3 alphanumeric copyright notices are md5summed they are from the original - * implementors. The original code is available from http://code.google.com/p/nelly2pcm/ + * implementers. The original code is available from http://code.google.com/p/nelly2pcm/ */ #include "libavutil/channel_layout.h" @@ -202,6 +202,5 @@ const FFCodec ff_nellymoser_decoder = { .close = decode_end, FF_CODEC_DECODE_CB(decode_tag), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT), }; diff --git a/libavcodec/nellymoserenc.c b/libavcodec/nellymoserenc.c index 32ae5f7828..6f002eb891 100644 --- a/libavcodec/nellymoserenc.c +++ b/libavcodec/nellymoserenc.c @@ -427,8 +427,7 @@ const FFCodec ff_nellymoser_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_NONE }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/neon/mpegvideo.c b/libavcodec/neon/mpegvideo.c index 8f05d77a65..a0276ad808 100644 --- a/libavcodec/neon/mpegvideo.c +++ b/libavcodec/neon/mpegvideo.c @@ -32,6 +32,7 @@ #endif #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" static void inline ff_dct_unquantize_h263_neon(int qscale, int qadd, int nCoeffs, int16_t *block) @@ -124,7 +125,7 @@ static void dct_unquantize_h263_intra_neon(MpegEncContext *s, int16_t *block, } -av_cold void ff_mpv_common_init_neon(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_neon(MPVUnquantDSPContext *s, int bitexact) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/null.c b/libavcodec/null.c index d8e334437c..e443ddf4f9 100644 --- a/libavcodec/null.c +++ b/libavcodec/null.c @@ -81,15 +81,12 @@ const FFCodec ff_anull_encoder = { .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_ANULL, .p.capabilities = AV_CODEC_CAP_VARIABLE_FRAME_SIZE, - .p.sample_fmts = (const enum AVSampleFormat[]){ - AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, - AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, - AV_SAMPLE_FMT_NONE, - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P, + AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), FF_CODEC_ENCODE_CB(null_encode), }; #endif diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c index 932544564a..7c29f25718 100644 --- a/libavcodec/nvdec.c +++ b/libavcodec/nvdec.c @@ -36,7 +36,7 @@ #include "decode.h" #include "nvdec.h" #include "internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #if !NVDECAPI_CHECK_VERSION(9, 0) #define cudaVideoSurfaceFormat_YUV444 2 @@ -163,7 +163,7 @@ static int nvdec_test_capabilities(NVDECDecoder *decoder, return 0; } -static void nvdec_decoder_free(FFRefStructOpaque unused, void *obj) +static void nvdec_decoder_free(AVRefStructOpaque unused, void *obj) { NVDECDecoder *decoder = obj; @@ -192,7 +192,7 @@ static int nvdec_decoder_create(NVDECDecoder **out, AVBufferRef *hw_device_ref, CUcontext dummy; int ret; - decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0, + decoder = av_refstruct_alloc_ext(sizeof(*decoder), 0, NULL, nvdec_decoder_free); if (!decoder) return AVERROR(ENOMEM); @@ -234,11 +234,11 @@ static int nvdec_decoder_create(NVDECDecoder **out, AVBufferRef *hw_device_ref, return 0; fail: - ff_refstruct_unref(&decoder); + av_refstruct_unref(&decoder); return ret; } -static int nvdec_decoder_frame_init(FFRefStructOpaque opaque, void *obj) +static int nvdec_decoder_frame_init(AVRefStructOpaque opaque, void *obj) { NVDECFramePool *pool = opaque.nc; unsigned int *intp = obj; @@ -251,7 +251,7 @@ static int nvdec_decoder_frame_init(FFRefStructOpaque opaque, void *obj) return 0; } -static void nvdec_decoder_frame_pool_free(FFRefStructOpaque opaque) +static void nvdec_decoder_frame_pool_free(AVRefStructOpaque opaque) { av_free(opaque.nc); } @@ -269,8 +269,8 @@ int ff_nvdec_decode_uninit(AVCodecContext *avctx) ctx->nb_slices = 0; ctx->slice_offsets_allocated = 0; - ff_refstruct_unref(&ctx->decoder); - ff_refstruct_pool_uninit(&ctx->decoder_pool); + av_refstruct_unref(&ctx->decoder); + av_refstruct_pool_uninit(&ctx->decoder_pool); return 0; } @@ -375,13 +375,27 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) switch (sw_desc->comp[0].depth) { case 8: - output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444 : - cudaVideoSurfaceFormat_NV12; + if (chroma_444) { + output_format = cudaVideoSurfaceFormat_YUV444; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + output_format = cudaVideoSurfaceFormat_NV16; +#endif + } else { + output_format = cudaVideoSurfaceFormat_NV12; + } break; case 10: case 12: - output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444_16Bit : - cudaVideoSurfaceFormat_P016; + if (chroma_444) { + output_format = cudaVideoSurfaceFormat_YUV444_16Bit; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + output_format = cudaVideoSurfaceFormat_P216; +#endif + } else { + output_format = cudaVideoSurfaceFormat_P016; + } break; default: av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth\n"); @@ -426,7 +440,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) } pool->dpb_size = frames_ctx->initial_pool_size; - ctx->decoder_pool = ff_refstruct_pool_alloc_ext(sizeof(unsigned int), 0, pool, + ctx->decoder_pool = av_refstruct_pool_alloc_ext(sizeof(unsigned int), 0, pool, nvdec_decoder_frame_init, NULL, NULL, nvdec_decoder_frame_pool_free); if (!ctx->decoder_pool) { @@ -447,9 +461,9 @@ static void nvdec_fdd_priv_free(void *priv) if (!cf) return; - ff_refstruct_unref(&cf->idx_ref); - ff_refstruct_unref(&cf->ref_idx_ref); - ff_refstruct_unref(&cf->decoder); + av_refstruct_unref(&cf->idx_ref); + av_refstruct_unref(&cf->ref_idx_ref); + av_refstruct_unref(&cf->decoder); av_freep(&priv); } @@ -472,15 +486,15 @@ static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data) CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); finish: - ff_refstruct_unref(&unmap_data->idx_ref); - ff_refstruct_unref(&unmap_data->ref_idx_ref); - ff_refstruct_unref(&unmap_data->decoder); + av_refstruct_unref(&unmap_data->idx_ref); + av_refstruct_unref(&unmap_data->ref_idx_ref); + av_refstruct_unref(&unmap_data->decoder); av_free(unmap_data); } static int nvdec_retrieve_data(void *logctx, AVFrame *frame) { - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv; NVDECDecoder *decoder = cf->decoder; @@ -529,8 +543,8 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame) goto copy_fail; unmap_data->idx = cf->idx; - unmap_data->idx_ref = ff_refstruct_ref(cf->idx_ref); - unmap_data->decoder = ff_refstruct_ref(cf->decoder); + unmap_data->idx_ref = av_refstruct_ref(cf->idx_ref); + unmap_data->decoder = av_refstruct_ref(cf->decoder); av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, &shift_h, &shift_v); for (i = 0; frame->linesize[i]; i++) { @@ -561,7 +575,7 @@ finish: int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf = NULL; int ret; @@ -575,9 +589,9 @@ int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) if (!cf) return AVERROR(ENOMEM); - cf->decoder = ff_refstruct_ref(ctx->decoder); + cf->decoder = av_refstruct_ref(ctx->decoder); - cf->idx_ref = ff_refstruct_pool_get(ctx->decoder_pool); + cf->idx_ref = av_refstruct_pool_get(ctx->decoder_pool); if (!cf->idx_ref) { av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); ret = AVERROR(ENOMEM); @@ -599,7 +613,7 @@ fail: int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_sep_ref) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; - FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FrameDecodeData *fdd = frame->private_ref; NVDECFrame *cf; int ret; @@ -611,7 +625,7 @@ int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_ if (has_sep_ref) { if (!cf->ref_idx_ref) { - cf->ref_idx_ref = ff_refstruct_pool_get(ctx->decoder_pool); + cf->ref_idx_ref = av_refstruct_pool_get(ctx->decoder_pool); if (!cf->ref_idx_ref) { av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); ret = AVERROR(ENOMEM); @@ -620,7 +634,7 @@ int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, AVFrame *frame, int has_ } cf->ref_idx = *cf->ref_idx_ref; } else { - ff_refstruct_unref(&cf->ref_idx_ref); + av_refstruct_unref(&cf->ref_idx_ref); cf->ref_idx = cf->idx; } @@ -729,13 +743,53 @@ int ff_nvdec_frame_params(AVCodecContext *avctx, switch (sw_desc->comp[0].depth) { case 8: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + if (chroma_444) { + frames_ctx->sw_format = AV_PIX_FMT_YUV444P; +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + frames_ctx->sw_format = AV_PIX_FMT_NV16; +#endif + } else { + frames_ctx->sw_format = AV_PIX_FMT_NV12; + } break; case 10: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_YUV444P16; +#else + frames_ctx->sw_format = AV_PIX_FMT_YUV444P10MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { + frames_ctx->sw_format = AV_PIX_FMT_P210; +#endif + } else { + frames_ctx->sw_format = AV_PIX_FMT_P010; + } break; case 12: - frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; + if (chroma_444) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_YUV444P16; +#else + frames_ctx->sw_format = AV_PIX_FMT_YUV444P12MSB; +#endif +#ifdef NVDEC_HAVE_422_SUPPORT + } else if (cuvid_chroma_format == cudaVideoChromaFormat_422) { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_P216; +#else + frames_ctx->sw_format = AV_PIX_FMT_P212; +#endif +#endif + } else { +#if FF_API_NVDEC_OLD_PIX_FMTS + frames_ctx->sw_format = AV_PIX_FMT_P016; +#else + frames_ctx->sw_format = AV_PIX_FMT_P012; +#endif + } break; default: return AVERROR(EINVAL); @@ -752,7 +806,7 @@ int ff_nvdec_get_ref_idx(AVFrame *frame) if (!frame || !frame->private_ref) return -1; - fdd = (FrameDecodeData*)frame->private_ref->data; + fdd = frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; if (!cf) return -1; diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h index 555300d27d..2e80c0dc1e 100644 --- a/libavcodec/nvdec.h +++ b/libavcodec/nvdec.h @@ -41,6 +41,11 @@ ((major) < 8 || ((major) == 8 && (minor) <= 0)) #endif +// SDK 13.0 compile time feature checks +#if NVDECAPI_CHECK_VERSION(13, 0) +#define NVDEC_HAVE_422_SUPPORT +#endif + typedef struct NVDECFrame { unsigned int idx; unsigned int ref_idx; @@ -52,7 +57,7 @@ typedef struct NVDECFrame { typedef struct NVDECContext { CUVIDPICPARAMS pic_params; - struct FFRefStructPool *decoder_pool; + struct AVRefStructPool *decoder_pool; struct NVDECDecoder *decoder; ///< RefStruct reference diff --git a/libavcodec/nvdec_av1.c b/libavcodec/nvdec_av1.c index 6b408edb87..d07fe6324c 100644 --- a/libavcodec/nvdec_av1.c +++ b/libavcodec/nvdec_av1.c @@ -39,7 +39,9 @@ static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq) return 8; } -static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_av1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { const AV1DecContext *s = avctx->priv_data; const AV1RawSequenceHeader *seq = s->raw_seq; @@ -62,7 +64,7 @@ static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c index 9adbc521ec..54c98e611d 100644 --- a/libavcodec/nvdec_h264.c +++ b/libavcodec/nvdec_h264.c @@ -34,7 +34,7 @@ static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Picture *src, int frame_idx) { - FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + FrameDecodeData *fdd = src->f->private_ref; const NVDECFrame *cf = fdd->hwaccel_priv; dst->PicIdx = cf ? cf->idx : -1; @@ -47,6 +47,7 @@ static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Pict } static int nvdec_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { const H264Context *h = avctx->priv_data; @@ -65,7 +66,7 @@ static int nvdec_h264_start_frame(AVCodecContext *avctx, if (ret < 0) return ret; - fdd = (FrameDecodeData*)h->cur_pic_ptr->f->private_ref->data; + fdd = h->cur_pic_ptr->f->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -97,7 +98,7 @@ static int nvdec_h264_start_frame(AVCodecContext *avctx, .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, + .pic_init_qp_minus26 = pps->init_qp - 26 - 6 * (sps->bit_depth_luma - 8), .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, diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c index e01ce4c782..2b9df3e702 100644 --- a/libavcodec/nvdec_hevc.c +++ b/libavcodec/nvdec_hevc.c @@ -34,7 +34,7 @@ static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) { - FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + FrameDecodeData *fdd = src->f->private_ref; const NVDECFrame *cf = fdd->hwaccel_priv; pp->RefPicIdx[idx] = cf ? cf->idx : -1; @@ -70,6 +70,7 @@ static void fill_scaling_lists(CUVIDHEVCPICPARAMS *ppc, const HEVCContext *s) } static int nvdec_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { const HEVCContext *s = avctx->priv_data; @@ -89,7 +90,7 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, if (ret < 0) return ret; - fdd = (FrameDecodeData*)s->cur_frame->f->private_ref->data; + fdd = s->cur_frame->f->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mjpeg.c b/libavcodec/nvdec_mjpeg.c index 850634bf1a..f0c9416397 100644 --- a/libavcodec/nvdec_mjpeg.c +++ b/libavcodec/nvdec_mjpeg.c @@ -27,7 +27,9 @@ #include "decode.h" #include "hwaccel_internal.h" -static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { MJpegDecodeContext *s = avctx->priv_data; @@ -43,7 +45,7 @@ static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c index 99b2b14f1f..ca0a1001dc 100644 --- a/libavcodec/nvdec_mpeg12.c +++ b/libavcodec/nvdec_mpeg12.c @@ -30,7 +30,9 @@ #include "nvdec.h" #include "decode.h" -static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { MpegEncContext *s = avctx->priv_data; @@ -47,7 +49,7 @@ static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c index 80da11b5b1..369bd5b997 100644 --- a/libavcodec/nvdec_mpeg4.c +++ b/libavcodec/nvdec_mpeg4.c @@ -28,10 +28,12 @@ #include "decode.h" #include "hwaccel_internal.h" -static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { Mpeg4DecContext *m = avctx->priv_data; - MpegEncContext *s = &m->m; + MPVContext *const s = &m->h.c; NVDECContext *ctx = avctx->internal->hwaccel_priv_data; CUVIDPICPARAMS *pp = &ctx->pic_params; @@ -46,7 +48,7 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -68,18 +70,18 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, .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, + .quant_type = m->mpeg_quant, .quarter_sample = s->quarter_sample, .short_video_header = avctx->codec->id == AV_CODEC_ID_H263, - .divx_flags = s->divx_packed ? 5 : 0, + .divx_flags = m->h.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, + .vop_fcode_forward = m->f_code, + .vop_fcode_backward = m->b_code, .trd = { s->pp_time, s->pp_field_time >> 1 }, .trb = { s->pb_time, s->pb_field_time >> 1 }, diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c index 0668863cb4..d00cf5237a 100644 --- a/libavcodec/nvdec_vc1.c +++ b/libavcodec/nvdec_vc1.c @@ -22,6 +22,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "hwaccel_internal.h" #include "internal.h" @@ -29,7 +30,9 @@ #include "decode.h" #include "vc1.h" -static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_vc1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; @@ -46,7 +49,7 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -84,14 +87,14 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u .multires = v->multires, .syncmarker = v->resync_marker, .rangered = v->rangered, - .maxbframes = s->max_b_frames, + .maxbframes = v->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, + .loopfilter = v->loop_filter, .fastuvmc = v->fastuvmc, .overlap = v->overlap, .quantizer = v->quantizer_mode, @@ -107,6 +110,48 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u return 0; } +static int nvdec_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + const VC1Context *v = avctx->priv_data; + uint32_t marker; + int marker_size; + void *tmp; + + if (ctx->bitstream_len) + marker = VC1_CODE_SLICE; + else if (v->profile == PROFILE_ADVANCED && v->fcm == ILACE_FIELD && v->second_field) + marker = VC1_CODE_FIELD; + else + marker = VC1_CODE_FRAME; + + /* Only insert the marker if not already present in the bitstream */ + marker_size = (size >= sizeof(marker) && AV_RB32(buffer) != marker) ? sizeof(marker) : 0; + + tmp = av_fast_realloc(ctx->bitstream_internal, &ctx->bitstream_allocated, + ctx->bitstream_len + size + marker_size); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = ctx->bitstream_internal = 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 (marker_size) + AV_WB32(ctx->bitstream_internal + ctx->bitstream_len, marker); + + memcpy(ctx->bitstream_internal + ctx->bitstream_len + marker_size, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len; + ctx->bitstream_len += size + marker_size; + ctx->nb_slices++; + + return 0; +} + static int nvdec_vc1_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { @@ -121,7 +166,7 @@ const FFHWAccel ff_vc1_nvdec_hwaccel = { .p.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, + .decode_slice = nvdec_vc1_decode_slice, .frame_params = nvdec_vc1_frame_params, .init = ff_nvdec_decode_init, .uninit = ff_nvdec_decode_uninit, diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c index ff3b3f259c..e273a6ec35 100644 --- a/libavcodec/nvdec_vp8.c +++ b/libavcodec/nvdec_vp8.c @@ -32,7 +32,9 @@ 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) +static int nvdec_vp8_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP8Context *h = avctx->priv_data; @@ -48,7 +50,7 @@ static int nvdec_vp8_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c index e196391c6d..f83ff93818 100644 --- a/libavcodec/nvdec_vp9.c +++ b/libavcodec/nvdec_vp9.c @@ -29,7 +29,9 @@ #include "internal.h" #include "vp9shared.h" -static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +static int nvdec_vp9_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP9SharedContext *h = avctx->priv_data; const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); @@ -47,7 +49,7 @@ static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u if (ret < 0) return ret; - fdd = (FrameDecodeData*)cur_frame->private_ref->data; + fdd = cur_frame->private_ref; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 2cce478be0..d81be00314 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -34,7 +34,11 @@ #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" +#include "libavutil/timecode_internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/stereo3d.h" +#include "libavutil/tdrdi.h" #include "atsc_a53.h" #include "codec_desc.h" #include "encode.h" @@ -59,6 +63,12 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_P010, AV_PIX_FMT_YUV444P, AV_PIX_FMT_P016, // Truncated to 10bits +#ifdef NVENC_HAVE_422_SUPPORT + AV_PIX_FMT_NV16, + AV_PIX_FMT_P210, + AV_PIX_FMT_P216, +#endif + AV_PIX_FMT_YUV444P10MSB, AV_PIX_FMT_YUV444P16, // Truncated to 10bits AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, @@ -67,6 +77,7 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_X2RGB10, AV_PIX_FMT_X2BGR10, AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRP10MSB, AV_PIX_FMT_GBRP16, // Truncated to 10bits AV_PIX_FMT_CUDA, #if CONFIG_D3D11VA @@ -85,11 +96,15 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { NULL, }; -#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ - pix_fmt == AV_PIX_FMT_P016 || \ - pix_fmt == AV_PIX_FMT_YUV444P16 || \ - pix_fmt == AV_PIX_FMT_X2RGB10 || \ - pix_fmt == AV_PIX_FMT_X2BGR10 || \ +#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ + pix_fmt == AV_PIX_FMT_P016 || \ + pix_fmt == AV_PIX_FMT_P210 || \ + pix_fmt == AV_PIX_FMT_P216 || \ + pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ + pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_X2RGB10 || \ + pix_fmt == AV_PIX_FMT_X2BGR10 || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16) #define IS_RGB(pix_fmt) (pix_fmt == AV_PIX_FMT_0RGB32 || \ @@ -99,13 +114,20 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { pix_fmt == AV_PIX_FMT_X2RGB10 || \ pix_fmt == AV_PIX_FMT_X2BGR10) -#define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ - pix_fmt == AV_PIX_FMT_YUV444P16 || \ - pix_fmt == AV_PIX_FMT_GBRP || \ - pix_fmt == AV_PIX_FMT_GBRP16 || \ +#define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ + pix_fmt == AV_PIX_FMT_YUV444P10MSB || \ + pix_fmt == AV_PIX_FMT_YUV444P16 || \ + pix_fmt == AV_PIX_FMT_GBRP || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ + pix_fmt == AV_PIX_FMT_GBRP16 || \ (ctx->rgb_mode == NVENC_RGB_MODE_444 && IS_RGB(pix_fmt))) -#define IS_GBRP(pix_fmt) (pix_fmt == AV_PIX_FMT_GBRP || \ +#define IS_YUV422(pix_fmt) (pix_fmt == AV_PIX_FMT_NV16 || \ + pix_fmt == AV_PIX_FMT_P210 || \ + pix_fmt == AV_PIX_FMT_P216) + +#define IS_GBRP(pix_fmt) (pix_fmt == AV_PIX_FMT_GBRP || \ + pix_fmt == AV_PIX_FMT_GBRP10MSB || \ pix_fmt == AV_PIX_FMT_GBRP16) static const struct { @@ -242,8 +264,10 @@ static void nvenc_map_preset(NvencContext *ctx) static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if NVENCAPI_CHECK_VERSION(12, 3) +#if NVENCAPI_CHECK_VERSION(13, 1) const char *minver = "(unknown)"; +#elif NVENCAPI_CHECK_VERSION(13, 0) + const char *minver = "570.0"; #elif NVENCAPI_CHECK_VERSION(12, 2) # if defined(_WIN32) || defined(__CYGWIN__) const char *minver = "551.76"; @@ -477,6 +501,16 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } +#ifdef NVENC_HAVE_422_SUPPORT + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_YUV422_ENCODE); +#else + ret = 0; +#endif + if (IS_YUV422(ctx->data_pix_fmt) && ret <= 0) { + av_log(avctx, AV_LOG_WARNING, "YUV422P not supported\n"); + return AVERROR(ENOSYS); + } + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE); if (ctx->flags & NVENC_LOSSLESS && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n"); @@ -606,7 +640,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } -#ifdef NVENC_HAVE_TEMPORAL_FILTER +#if defined(NVENC_HAVE_TEMPORAL_FILTER) || defined(NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER) ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER); if(ctx->tf_level > 0 && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "Temporal filtering not supported by the device\n"); @@ -635,6 +669,14 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); +#ifdef NVENC_HAVE_MVHEVC + ctx->multiview_supported = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_MVHEVC_ENCODE) > 0; + if(ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN && !ctx->multiview_supported) { + av_log(avctx, AV_LOG_WARNING, "Multiview not supported by the device\n"); + return AVERROR(ENOSYS); + } +#endif + return 0; } @@ -863,8 +905,8 @@ static av_cold void set_constqp(AVCodecContext *avctx) rc->constQP.qpIntra = av_clip(ctx->cqp * fabs(avctx->i_quant_factor) + avctx->i_quant_offset + 0.5, 0, qmax); } - avctx->qmin = -1; - avctx->qmax = -1; + avctx->qmin = ctx->qmin = -1; + avctx->qmax = ctx->qmax = -1; } static av_cold void set_vbr(AVCodecContext *avctx) @@ -878,27 +920,37 @@ static av_cold void set_vbr(AVCodecContext *avctx) int qmax = 51; #endif - if (avctx->qmin >= 0 && avctx->qmax >= 0) { + if (avctx->qmin >= 0 || avctx->qmax >= 0) + av_log(avctx, AV_LOG_WARNING, "Passing qmin/qmax via global AVCodecContext options. Use encoder options instead.\n"); + + if (avctx->qmin >= 0 && ctx->qmin < 0) + ctx->qmin = avctx->qmin; + if (avctx->qmax >= 0 && ctx->qmax < 0) + ctx->qmax = avctx->qmax; + avctx->qmin = ctx->qmin; + avctx->qmax = ctx->qmax; + + if (ctx->qmin >= 0 && ctx->qmax >= 0) { rc->enableMinQP = 1; rc->enableMaxQP = 1; - rc->minQP.qpInterB = avctx->qmin; - rc->minQP.qpInterP = avctx->qmin; - rc->minQP.qpIntra = avctx->qmin; + rc->minQP.qpInterB = ctx->qmin; + rc->minQP.qpInterP = ctx->qmin; + rc->minQP.qpIntra = ctx->qmin; - rc->maxQP.qpInterB = avctx->qmax; - rc->maxQP.qpInterP = avctx->qmax; - rc->maxQP.qpIntra = avctx->qmax; + rc->maxQP.qpInterB = ctx->qmax; + rc->maxQP.qpInterP = ctx->qmax; + rc->maxQP.qpIntra = ctx->qmax; - qp_inter_p = (avctx->qmax + 3 * avctx->qmin) / 4; // biased towards Qmin - } else if (avctx->qmin >= 0) { + qp_inter_p = (ctx->qmax + 3 * ctx->qmin) / 4; // biased towards Qmin + } else if (ctx->qmin >= 0) { rc->enableMinQP = 1; - rc->minQP.qpInterB = avctx->qmin; - rc->minQP.qpInterP = avctx->qmin; - rc->minQP.qpIntra = avctx->qmin; + rc->minQP.qpInterB = ctx->qmin; + rc->minQP.qpInterP = ctx->qmin; + rc->minQP.qpIntra = ctx->qmin; - qp_inter_p = avctx->qmin; + qp_inter_p = ctx->qmin; } else { qp_inter_p = 26; // default to 26 } @@ -944,8 +996,8 @@ static av_cold void set_lossless(AVCodecContext *avctx) rc->constQP.qpInterP = 0; rc->constQP.qpIntra = 0; - avctx->qmin = -1; - avctx->qmax = -1; + avctx->qmin = ctx->qmin = -1; + avctx->qmax = ctx->qmax = -1; } static void nvenc_override_rate_control(AVCodecContext *avctx) @@ -959,7 +1011,7 @@ static void nvenc_override_rate_control(AVCodecContext *avctx) return; #ifndef NVENC_NO_DEPRECATED_RC case NV_ENC_PARAMS_RC_VBR_MINQP: - if (avctx->qmin < 0) { + if (avctx->qmin < 0 && ctx->qmin < 0) { av_log(avctx, AV_LOG_WARNING, "The variable bitrate rate-control requires " "the 'qmin' option set.\n"); @@ -1082,7 +1134,8 @@ static av_cold int nvenc_setup_rate_control(AVCodecContext *avctx) ctx->rc = NV_ENC_PARAMS_RC_CONSTQP; } else if (ctx->twopass) { ctx->rc = NV_ENC_PARAMS_RC_VBR_HQ; - } else if (avctx->qmin >= 0 && avctx->qmax >= 0) { + } else if ((avctx->qmin >= 0 && avctx->qmax >= 0) || + (ctx->qmin >= 0 && ctx->qmax >= 0)) { ctx->rc = NV_ENC_PARAMS_RC_VBR_MINQP; } } @@ -1247,6 +1300,7 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->intraRefreshPeriod = cc->gopLength; h264->intraRefreshCnt = cc->gopLength - 1; cc->gopLength = NVENC_INFINITE_GOPLENGTH; + h264->outputRecoveryPointSEI = 1; #ifdef NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH h264->singleSliceIntraRefresh = ctx->single_slice_intra_refresh; #endif @@ -1267,7 +1321,12 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - h264->outputBufferingPeriodSEI = 1; + /* Older SDKs use outputBufferingPeriodSEI to control filler data */ + h264->outputBufferingPeriodSEI = ctx->cbr_padding; + +#ifdef NVENC_HAVE_FILLER_DATA + h264->enableFillerDataInsertion = ctx->cbr_padding; +#endif } h264->outputPictureTimingSEI = 1; @@ -1297,6 +1356,18 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID; avctx->profile = AV_PROFILE_H264_HIGH; break; +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + case NV_ENC_H264_PROFILE_HIGH_10: + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_10; + break; +#endif +#ifdef NVENC_HAVE_422_SUPPORT + case NV_ENC_H264_PROFILE_HIGH_422: + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_422_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_422; + break; +#endif case NV_ENC_H264_PROFILE_HIGH_444P: cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID; avctx->profile = AV_PROFILE_H264_HIGH_444_PREDICTIVE; @@ -1304,19 +1375,37 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) } } +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + // force setting profile as high10 if input is 10 bit or if it should be encoded as 10 bit + if (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) { + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_10; + } +#endif + // force setting profile as high444p if input is AV_PIX_FMT_YUV444P if (IS_YUV444(ctx->data_pix_fmt)) { cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID; avctx->profile = AV_PROFILE_H264_HIGH_444_PREDICTIVE; } - h264->chromaFormatIDC = avctx->profile == AV_PROFILE_H264_HIGH_444_PREDICTIVE ? 3 : 1; +#ifdef NVENC_HAVE_422_SUPPORT + // force setting profile as high422p if input is AV_PIX_FMT_YUV422P + if (IS_YUV422(ctx->data_pix_fmt)) { + cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_422_GUID; + avctx->profile = AV_PROFILE_H264_HIGH_422; + } +#endif + + vui->bitstreamRestrictionFlag = cc->gopLength != 1 || avctx->profile < AV_PROFILE_H264_HIGH; + + h264->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : IS_YUV422(ctx->data_pix_fmt) ? 2 : 1; h264->level = ctx->level; #ifdef NVENC_HAVE_NEW_BIT_DEPTH_API - h264->inputBitDepth = h264->outputBitDepth = - IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + h264->inputBitDepth = IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + h264->outputBitDepth = (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; #endif if (ctx->coder >= 0) @@ -1332,6 +1421,30 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->numRefL1 = avctx->refs; #endif +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + if (ctx->tf_level >= 0) { + h264->tfLevel = ctx->tf_level; + + switch (ctx->tf_level) + { + case NV_ENC_TEMPORAL_FILTER_LEVEL_0: + case NV_ENC_TEMPORAL_FILTER_LEVEL_4: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid temporal filtering level.\n"); + return AVERROR(EINVAL); + } + + if (ctx->encode_config.frameIntervalP < 5) + av_log(avctx, AV_LOG_WARNING, "Temporal filtering needs at least 4 B-Frames (-bf 4).\n"); + } +#endif + +#ifdef NVENC_HAVE_TIME_CODE + if (ctx->s12m_tc) + h264->enableTimeCode = 1; +#endif + return 0; } @@ -1378,11 +1491,23 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->intraRefreshPeriod = cc->gopLength; hevc->intraRefreshCnt = cc->gopLength - 1; cc->gopLength = NVENC_INFINITE_GOPLENGTH; +#ifdef NVENC_HAVE_HEVC_OUTPUT_RECOVERY_POINT_SEI + hevc->outputRecoveryPointSEI = 1; +#endif #ifdef NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH hevc->singleSliceIntraRefresh = ctx->single_slice_intra_refresh; #endif } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + ctx->mdm = hevc->outputMasteringDisplay = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + ctx->cll = hevc->outputMaxCll = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); +#endif + #ifdef NVENC_HAVE_HEVC_CONSTRAINED_ENCODING if (ctx->constrained_encoding) hevc->enableConstrainedEncoding = 1; @@ -1400,11 +1525,36 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - hevc->outputBufferingPeriodSEI = 1; + /* Older SDKs use outputBufferingPeriodSEI to control filler data */ + hevc->outputBufferingPeriodSEI = ctx->cbr_padding; + +#ifdef NVENC_HAVE_FILLER_DATA + hevc->enableFillerDataInsertion = ctx->cbr_padding; +#endif } hevc->outputPictureTimingSEI = 1; +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview_supported && (ctx->profile == NV_ENC_HEVC_PROFILE_MAIN || ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN)) { + const AVFrameSideData *sd_stereo3d = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_STEREO3D); + const AVFrameSideData *sd_tdrdi = av_frame_side_data_get(avctx->decoded_side_data, avctx->nb_decoded_side_data, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS); + const AVStereo3D *stereo3d = sd_stereo3d ? (const AVStereo3D*)sd_stereo3d->data : NULL; + + if (sd_tdrdi && stereo3d && stereo3d->type == AV_STEREO3D_FRAMESEQUENCE) + ctx->profile = NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN; + + if (ctx->profile == NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN && stereo3d && + stereo3d->type != AV_STEREO3D_2D && + stereo3d->type != AV_STEREO3D_UNSPEC && + stereo3d->type != AV_STEREO3D_FRAMESEQUENCE) + { + av_log(avctx, AV_LOG_WARNING, "Unsupported multiview input, disabling multiview encoding.\n"); + ctx->profile = NV_ENC_HEVC_PROFILE_MAIN; + } + } +#endif + switch (ctx->profile) { case NV_ENC_HEVC_PROFILE_MAIN: cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID; @@ -1418,6 +1568,18 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) cc->profileGUID = NV_ENC_HEVC_PROFILE_FREXT_GUID; avctx->profile = AV_PROFILE_HEVC_REXT; break; +#ifdef NVENC_HAVE_MVHEVC + case NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN: + cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID; + avctx->profile = AV_PROFILE_HEVC_MULTIVIEW_MAIN; + ctx->multiview = 1; + + hevc->enableMVHEVC = 1; + hevc->outputHevc3DReferenceDisplayInfo = 1; + + av_log(avctx, AV_LOG_VERBOSE, "Enabling MV HEVC encoding.\n"); + break; +#endif } // force setting profile as main10 if input is 10 bit or if it should be encoded as 10 bit @@ -1426,13 +1588,20 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) avctx->profile = AV_PROFILE_HEVC_MAIN_10; } - // force setting profile as rext if input is yuv444 - if (IS_YUV444(ctx->data_pix_fmt)) { + // force setting profile as rext if input is yuv444 or yuv422 + if (IS_YUV444(ctx->data_pix_fmt) || IS_YUV422(ctx->data_pix_fmt)) { cc->profileGUID = NV_ENC_HEVC_PROFILE_FREXT_GUID; avctx->profile = AV_PROFILE_HEVC_REXT; } - hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : 1; +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview && avctx->profile != AV_PROFILE_HEVC_MULTIVIEW_MAIN) { + av_log(avctx, AV_LOG_ERROR, "Multiview encoding only works for Main profile content.\n"); + return AVERROR(EINVAL); + } +#endif + + hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : IS_YUV422(ctx->data_pix_fmt) ? 2 : 1; #ifdef NVENC_HAVE_NEW_BIT_DEPTH_API hevc->inputBitDepth = IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; @@ -1522,7 +1691,7 @@ static av_cold int nvenc_setup_av1_config(AVCodecContext *avctx) av1->idrPeriod = cc->gopLength; if (IS_CBR(cc->rcParams.rateControlMode)) { - av1->enableBitstreamPadding = 1; + av1->enableBitstreamPadding = ctx->cbr_padding; } if (ctx->tile_cols >= 0) @@ -1551,12 +1720,40 @@ static av_cold int nvenc_setup_av1_config(AVCodecContext *avctx) av1->pixelBitDepthMinus8 = (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) ? 2 : 0; #endif +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + ctx->mdm = av1->outputMasteringDisplay = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + ctx->cll = av1->outputMaxCll = !!av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); +#endif + if (ctx->b_ref_mode >= 0) av1->useBFramesAsRef = ctx->b_ref_mode; av1->numFwdRefs = avctx->refs; av1->numBwdRefs = avctx->refs; +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + if (ctx->tf_level >= 0) { + av1->tfLevel = ctx->tf_level; + + switch (ctx->tf_level) + { + case NV_ENC_TEMPORAL_FILTER_LEVEL_0: + case NV_ENC_TEMPORAL_FILTER_LEVEL_4: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid temporal filtering level.\n"); + return AVERROR(EINVAL); + } + + if (ctx->encode_config.frameIntervalP < 5) + av_log(avctx, AV_LOG_WARNING, "Temporal filtering needs at least 4 B-Frames (-bf 4).\n"); + } +#endif + return 0; } #endif @@ -1669,13 +1866,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) ctx->init_encode_params.frameRateDen = avctx->framerate.den; } else { ctx->init_encode_params.frameRateNum = avctx->time_base.den; -FF_DISABLE_DEPRECATION_WARNINGS - ctx->init_encode_params.frameRateDen = avctx->time_base.num -#if FF_API_TICKS_PER_FRAME - * avctx->ticks_per_frame -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + ctx->init_encode_params.frameRateDen = avctx->time_base.num; } #ifdef NVENC_HAVE_UNIDIR_B @@ -1807,7 +1998,9 @@ static NV_ENC_BUFFER_FORMAT nvenc_map_buffer_format(enum AVPixelFormat pix_fmt) case AV_PIX_FMT_YUV444P: return NV_ENC_BUFFER_FORMAT_YUV444; case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRP10MSB: case AV_PIX_FMT_YUV444P16: + case AV_PIX_FMT_YUV444P10MSB: return NV_ENC_BUFFER_FORMAT_YUV444_10BIT; case AV_PIX_FMT_0RGB32: case AV_PIX_FMT_RGB32: @@ -1819,6 +2012,13 @@ static NV_ENC_BUFFER_FORMAT nvenc_map_buffer_format(enum AVPixelFormat pix_fmt) return NV_ENC_BUFFER_FORMAT_ARGB10; case AV_PIX_FMT_X2BGR10: return NV_ENC_BUFFER_FORMAT_ABGR10; +#ifdef NVENC_HAVE_422_SUPPORT + case AV_PIX_FMT_NV16: + return NV_ENC_BUFFER_FORMAT_NV16; + case AV_PIX_FMT_P210: + case AV_PIX_FMT_P216: + return NV_ENC_BUFFER_FORMAT_P210; +#endif default: return NV_ENC_BUFFER_FORMAT_UNDEFINED; } @@ -2288,7 +2488,52 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, } } -static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, +#ifdef NVENC_HAVE_TIME_CODE +static void nvenc_fill_time_code(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_TIME_CODE *time_code) +{ + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE); + + if (sd) { + uint32_t *tc = (uint32_t*)sd->data; + int cnt = FFMIN(tc[0], FF_ARRAY_ELEMS(time_code->clockTimestamp)); + + switch (cnt) { + case 0: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + time_code->skipClockTimestampInsertion = 1; + break; + case 2: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME_DOUBLING; + break; + case 3: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME_TRIPLING; + break; + default: + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + break; + } + + for (int i = 0; i < cnt; i++) { + unsigned hh, mm, ss, ff, drop; + ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, avctx->framerate, tc[i + 1], 0, 0); + + time_code->clockTimestamp[i].countingType = 0; + time_code->clockTimestamp[i].discontinuityFlag = 0; + time_code->clockTimestamp[i].cntDroppedFrames = drop; + time_code->clockTimestamp[i].nFrames = ff; + time_code->clockTimestamp[i].secondsValue = ss; + time_code->clockTimestamp[i].minutesValue = mm; + time_code->clockTimestamp[i].hoursValue = hh; + time_code->clockTimestamp[i].timeOffset = 0; + } + } else { + time_code->displayPicStruct = NV_ENC_PIC_STRUCT_DISPLAY_FRAME; + time_code->skipClockTimestampInsertion = 1; + } +} +#endif + +static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_PIC_PARAMS *params, NV_ENC_SEI_PAYLOAD *sei_data, int sei_count) @@ -2306,6 +2551,11 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, params->codecPicParams.h264PicParams.seiPayloadArrayCnt = sei_count; } +#ifdef NVENC_HAVE_TIME_CODE + if (ctx->s12m_tc) + nvenc_fill_time_code(avctx, frame, ¶ms->codecPicParams.h264PicParams.timeCode); +#endif + break; case AV_CODEC_ID_HEVC: params->codecPicParams.hevcPicParams.sliceMode = @@ -2373,6 +2623,9 @@ static int nvenc_set_timestamp(AVCodecContext *avctx, // This can be more than necessary, but we don't know the real reorder delay. delay = FFMAX(ctx->encode_config.frameIntervalP - 1, 0); +#ifdef NVENC_HAVE_MVHEVC + delay *= ctx->multiview ? 2 : 1; +#endif if (ctx->output_frame_num >= delay) { pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list); ctx->output_frame_num++; @@ -2607,7 +2860,7 @@ static int prepare_sei_data_array(AVCodecContext *avctx, const AVFrame *frame) } } - if (ctx->s12m_tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) { + if (ctx->s12m_tc && avctx->codec->id != AV_CODEC_ID_H264 && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) { void *tc_data = NULL; size_t tc_size = 0; @@ -2772,6 +3025,78 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) } } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA +static int nvenc_set_mastering_display_data(AVCodecContext *avctx, const AVFrame *frame, NV_ENC_PIC_PARAMS *pic_params, + MASTERING_DISPLAY_INFO *mastering_disp_info, CONTENT_LIGHT_LEVEL *content_light_level) +{ + NvencContext *ctx = avctx->priv_data; + + if (ctx->mdm || ctx->cll) { + const AVFrameSideData *sd_mdm = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + const AVFrameSideData *sd_cll = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + const int chroma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 16 : 50000; + const int max_luma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 8 : 10000; + const int min_luma_den = (avctx->codec->id == AV_CODEC_ID_AV1) ? 1 << 14 : 10000; + + if (!sd_mdm) + sd_mdm = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (!sd_cll) + sd_cll = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + + if (sd_mdm) { + const AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd_mdm->data; + + mastering_disp_info->r.x = av_rescale(mdm->display_primaries[0][0].num, chroma_den, + mdm->display_primaries[0][0].den); + mastering_disp_info->r.y = av_rescale(mdm->display_primaries[0][1].num, chroma_den, + mdm->display_primaries[0][1].den); + mastering_disp_info->g.x = av_rescale(mdm->display_primaries[1][0].num, chroma_den, + mdm->display_primaries[1][0].den); + mastering_disp_info->g.y = av_rescale(mdm->display_primaries[1][1].num, chroma_den, + mdm->display_primaries[1][1].den); + mastering_disp_info->b.x = av_rescale(mdm->display_primaries[2][0].num, chroma_den, + mdm->display_primaries[2][0].den); + mastering_disp_info->b.y = av_rescale(mdm->display_primaries[2][1].num, chroma_den, + mdm->display_primaries[2][1].den); + mastering_disp_info->whitePoint.x = av_rescale(mdm->white_point[0].num, chroma_den, + mdm->white_point[0].den); + mastering_disp_info->whitePoint.y = av_rescale(mdm->white_point[1].num, chroma_den, + mdm->white_point[1].den); + mastering_disp_info->maxLuma = av_rescale(mdm->max_luminance.num, max_luma_den, + mdm->max_luminance.den); + mastering_disp_info->minLuma = av_rescale(mdm->min_luminance.num, min_luma_den, + mdm->min_luminance.den); + + if (avctx->codec->id == AV_CODEC_ID_HEVC) + pic_params->codecPicParams.hevcPicParams.pMasteringDisplay = mastering_disp_info; + else if (avctx->codec->id == AV_CODEC_ID_AV1) + pic_params->codecPicParams.av1PicParams.pMasteringDisplay = mastering_disp_info; + else + return AVERROR_BUG; + } + if (sd_cll) { + const AVContentLightMetadata *cll = (AVContentLightMetadata *)sd_cll->data; + + content_light_level->maxContentLightLevel = cll->MaxCLL; + content_light_level->maxPicAverageLightLevel = cll->MaxFALL; + + if (avctx->codec->id == AV_CODEC_ID_HEVC) + pic_params->codecPicParams.hevcPicParams.pMaxCll = content_light_level; + else if (avctx->codec->id == AV_CODEC_ID_AV1) + pic_params->codecPicParams.av1PicParams.pMaxCll = content_light_level; + else + return AVERROR_BUG; + } + } + + return 0; +} +#endif + static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { NVENCSTATUS nv_status; @@ -2779,6 +3104,13 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) int res, res2; int sei_count = 0; int i; +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + MASTERING_DISPLAY_INFO mastering_disp_info = { 0 }; + CONTENT_LIGHT_LEVEL content_light_level = { 0 }; +#endif +#ifdef NVENC_HAVE_MVHEVC + HEVC_3D_REFERENCE_DISPLAY_INFO ref_disp_info = { 0 }; +#endif NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -2843,11 +3175,64 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) sei_count = res; } +#ifdef NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA + res = nvenc_set_mastering_display_data(avctx, frame, &pic_params, &mastering_disp_info, &content_light_level); + if (res < 0) + return res; +#endif + +#ifdef NVENC_HAVE_MVHEVC + if (ctx->multiview) { + const AVFrameSideData *sd_tdrdi = av_frame_get_side_data(frame, AV_FRAME_DATA_3D_REFERENCE_DISPLAYS); + const AVFrameSideData *sd_view_id = av_frame_get_side_data(frame, AV_FRAME_DATA_VIEW_ID); + + if (sd_view_id) + ctx->next_view_id = *(int*)sd_view_id->data; + + pic_params.codecPicParams.hevcPicParams.viewId = ctx->next_view_id; + + if (sd_tdrdi) { + AV3DReferenceDisplaysInfo *tdrdi = (AV3DReferenceDisplaysInfo*)sd_tdrdi->data; + + ref_disp_info.refViewingDistanceFlag = tdrdi->ref_viewing_distance_flag; + ref_disp_info.precRefViewingDist = tdrdi->prec_ref_viewing_dist; + ref_disp_info.precRefDisplayWidth = tdrdi->prec_ref_display_width; + + ref_disp_info.numRefDisplaysMinus1 = tdrdi->num_ref_displays - 1; + + for (i = 0; i < tdrdi->num_ref_displays && + i < FF_ARRAY_ELEMS(ref_disp_info.leftViewId); i++) { + const AV3DReferenceDisplay *display = av_tdrdi_get_display(tdrdi, i); + ref_disp_info.leftViewId[i] = display->left_view_id; + ref_disp_info.rightViewId[i] = display->right_view_id; + ref_disp_info.exponentRefDisplayWidth[i] = display->exponent_ref_display_width; + ref_disp_info.mantissaRefDisplayWidth[i] = display->mantissa_ref_display_width; + ref_disp_info.exponentRefViewingDistance[i] = display->exponent_ref_viewing_distance; + ref_disp_info.mantissaRefViewingDistance[i] = display->mantissa_ref_viewing_distance; + ref_disp_info.additionalShiftPresentFlag[i] = display->additional_shift_present_flag; + ref_disp_info.numSampleShiftPlus512[i] = display->num_sample_shift + 512; + } + + pic_params.codecPicParams.hevcPicParams.p3DReferenceDisplayInfo = &ref_disp_info; + ctx->display_sei_sent = 1; + } else if (!ctx->display_sei_sent) { + ref_disp_info.precRefDisplayWidth = 31; + ref_disp_info.leftViewId[0] = 0; + ref_disp_info.rightViewId[0] = 1; + + pic_params.codecPicParams.hevcPicParams.p3DReferenceDisplayInfo = &ref_disp_info; + ctx->display_sei_sent = 1; + } + + ctx->next_view_id = !ctx->next_view_id; + } +#endif + res = nvenc_store_frame_data(avctx, &pic_params, frame); if (res < 0) return res; - nvenc_codec_specific_pic_params(avctx, &pic_params, ctx->sei_data, sei_count); + nvenc_codec_specific_pic_params(avctx, frame, &pic_params, ctx->sei_data, sei_count); } else { pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS; } diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index 0130b99369..4a4d6730b1 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -61,6 +61,7 @@ typedef void ID3D11Device; #define NVENC_HAVE_MULTIPLE_REF_FRAMES #define NVENC_HAVE_CUSTREAM_PTR #define NVENC_HAVE_GETLASTERRORSTRING +#define NVENC_HAVE_FILLER_DATA #endif // SDK 10.0 compile time feature checks @@ -78,6 +79,11 @@ typedef void ID3D11Device; #define NVENC_HAVE_SINGLE_SLICE_INTRA_REFRESH #endif +// SDK 12.0 compile time feature checks +#if NVENCAPI_CHECK_VERSION(12, 0) +#define NVENC_HAVE_HEVC_OUTPUT_RECOVERY_POINT_SEI +#endif + // SDK 12.1 compile time feature checks #if NVENCAPI_CHECK_VERSION(12, 1) #define NVENC_NO_DEPRECATED_RC @@ -91,6 +97,17 @@ typedef void ID3D11Device; #define NVENC_HAVE_LOOKAHEAD_LEVEL #define NVENC_HAVE_UHQ_TUNING #define NVENC_HAVE_UNIDIR_B +#define NVENC_HAVE_TIME_CODE // added in 12.0, but incomplete until 12.2 +#endif + +// SDK 13.0 compile time feature checks +#if NVENCAPI_CHECK_VERSION(13, 0) +#define NVENC_HAVE_H264_10BIT_SUPPORT +#define NVENC_HAVE_422_SUPPORT +#define NVENC_HAVE_AV1_UHQ_TUNING +#define NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER +#define NVENC_HAVE_HEVC_AND_AV1_MASTERING_METADATA +#define NVENC_HAVE_MVHEVC #endif typedef struct NvencSurface @@ -151,6 +168,12 @@ enum { NV_ENC_H264_PROFILE_BASELINE, NV_ENC_H264_PROFILE_MAIN, NV_ENC_H264_PROFILE_HIGH, +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + NV_ENC_H264_PROFILE_HIGH_10, +#endif +#ifdef NVENC_HAVE_422_SUPPORT + NV_ENC_H264_PROFILE_HIGH_422, +#endif NV_ENC_H264_PROFILE_HIGH_444P, }; @@ -158,6 +181,11 @@ enum { NV_ENC_HEVC_PROFILE_MAIN, NV_ENC_HEVC_PROFILE_MAIN_10, NV_ENC_HEVC_PROFILE_REXT, +#ifdef NVENC_HAVE_MVHEVC + NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN, +#endif + + NV_ENC_HEVC_PROFILE_COUNT }; enum { @@ -231,6 +259,7 @@ typedef struct NvencContext void *nvencoder; uint32_t frame_idx_counter; + uint32_t next_view_id; int preset; int profile; @@ -257,6 +286,8 @@ typedef struct NvencContext float quality; int aud; int bluray_compat; + int qmin; + int qmax; int init_qp_p; int init_qp_b; int init_qp_i; @@ -285,6 +316,10 @@ typedef struct NvencContext int lookahead_level; int unidir_b; int split_encode_mode; + int mdm, cll; + int cbr_padding; + int multiview, multiview_supported; + int display_sei_sent; } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_av1.c b/libavcodec/nvenc_av1.c index 79253cff66..df6a93edcb 100644 --- a/libavcodec/nvenc_av1.c +++ b/libavcodec/nvenc_av1.c @@ -38,8 +38,11 @@ static const AVOption options[] = { { "p5", "slow (good quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P5 }, 0, 0, VE, .unit = "preset" }, { "p6", "slower (better quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P6 }, 0, 0, VE, .unit = "preset" }, { "p7", "slowest (best quality)", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_P7 }, 0, 0, VE, .unit = "preset" }, - { "tune", "Set the encoding tuning info", OFFSET(tuning_info), AV_OPT_TYPE_INT, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, NV_ENC_TUNING_INFO_HIGH_QUALITY, NV_ENC_TUNING_INFO_LOSSLESS, VE, .unit = "tune" }, + { "tune", "Set the encoding tuning info", OFFSET(tuning_info), AV_OPT_TYPE_INT, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, NV_ENC_TUNING_INFO_HIGH_QUALITY, NV_ENC_TUNING_INFO_COUNT - 1, VE, .unit = "tune" }, { "hq", "High quality", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_HIGH_QUALITY }, 0, 0, VE, .unit = "tune" }, +#ifdef NVENC_HAVE_AV1_UHQ_TUNING + { "uhq", "Ultra high quality", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_HIGH_QUALITY }, 0, 0, VE, .unit = "tune" }, +#endif { "ll", "Low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "ull", "Ultra low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "lossless", "Lossless", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOSSLESS }, 0, 0, VE, .unit = "tune" }, @@ -116,6 +119,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, { "no-scenecut", "When lookahead is enabled, set this to 1 to disable adaptive I-frame insertion at scene cuts", OFFSET(no_scenecut), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "forced-idr", "If forcing keyframes, force them as IDR frames.", @@ -149,6 +156,14 @@ static const AVOption options[] = { OFFSET(extra_sei), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + { "tf_level", "Specifies the strength of the temporal filtering", + OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_0 }, 0, 0, VE, .unit = "tf_level" }, + { "4", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_4 }, 0, 0, VE, .unit = "tf_level" }, +#endif #ifdef NVENC_HAVE_LOOKAHEAD_LEVEL { "lookahead_level", "Specifies the lookahead level. Higher level may improve quality at the expense of performance.", OFFSET(lookahead_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT, VE, .unit = "lookahead_level" }, @@ -201,7 +216,7 @@ const FFCodec ff_av1_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .p.priv_class = &av1_nvenc_class, .defaults = defaults, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 | diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index 8cbe4dca39..842e4eef60 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -61,6 +61,12 @@ static const AVOption options[] = { { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_BASELINE }, 0, 0, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH }, 0, 0, VE, .unit = "profile" }, +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + { "high10", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_10 }, 0, 0, VE, .unit = "profile" }, +#endif +#ifdef NVENC_HAVE_422_SUPPORT + { "high422", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_422 }, 0, 0, VE, .unit = "profile" }, +#endif { "high444p", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_PROFILE_HIGH_444P }, 0, 0, VE, .unit = "profile" }, #ifdef NVENC_HAVE_H264_LVL6 { "level", "Set the encoding level restriction", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_H264_62, VE, .unit = "level" }, @@ -168,6 +174,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "weighted_pred","Set 1 to enable weighted prediction", OFFSET(weighted_pred),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "coder", "Coder type", OFFSET(coder), AV_OPT_TYPE_INT, { .i64 = -1 },-1, 2, VE, .unit = "coder" }, @@ -189,6 +199,9 @@ static const AVOption options[] = { { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, .unit = "b_ref_mode" }, #endif { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, +#ifdef NVENC_HAVE_TIME_CODE + { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, +#endif { "dpb_size", "Specifies the DPB size used for encoding (0 means automatic)", OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, #ifdef NVENC_HAVE_MULTIPASS @@ -199,6 +212,9 @@ static const AVOption options[] = { { "fullres", "Two Pass encoding is enabled where first Pass is full resolution", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TWO_PASS_FULL_RESOLUTION }, 0, 0, VE, .unit = "multipass" }, #endif +#ifdef NVENC_HAVE_H264_10BIT_SUPPORT + { "highbitdepth", "Enable 10 bit encode for 8 bit input",OFFSET(highbitdepth),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif #ifdef NVENC_HAVE_LDKFS { "ldkfs", "Low delay key frame scale; Specifies the Scene Change frame size increase allowed in case of single frame VBV and CBR", OFFSET(ldkfs), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UCHAR_MAX, VE }, @@ -215,6 +231,16 @@ static const AVOption options[] = { OFFSET(max_slice_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "constrained-encoding", "Enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices", OFFSET(constrained_encoding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_FILLER_DATA + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif +#ifdef NVENC_HAVE_H264_AND_AV1_TEMPORAL_FILTER + { "tf_level", "Specifies the strength of the temporal filtering", + OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_0 }, 0, 0, VE, .unit = "tf_level" }, + { "4", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TEMPORAL_FILTER_LEVEL_4 }, 0, 0, VE, .unit = "tf_level" }, +#endif #ifdef NVENC_HAVE_LOOKAHEAD_LEVEL { "lookahead_level", "Specifies the lookahead level. Higher level may improve quality at the expense of performance.", OFFSET(lookahead_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT, VE, .unit = "lookahead_level" }, @@ -264,7 +290,7 @@ const FFCodec ff_h264_nvenc_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.wrapper_name = "nvenc", .hw_configs = ff_nvenc_hw_configs, diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 5696e14dd4..54e2fe323e 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -60,10 +60,13 @@ static const AVOption options[] = { { "ull", "Ultra low latency", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "tune" }, { "lossless", "Lossless", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_TUNING_INFO_LOSSLESS }, 0, 0, VE, .unit = "tune" }, #endif - { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, NV_ENC_HEVC_PROFILE_MAIN, AV_PROFILE_HEVC_REXT, VE, .unit = "profile" }, + { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, NV_ENC_HEVC_PROFILE_MAIN, NV_ENC_HEVC_PROFILE_COUNT - 1, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "main10", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, .unit = "profile" }, { "rext", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_REXT }, 0, 0, VE, .unit = "profile" }, +#ifdef NVENC_HAVE_MVHEVC + { "mv", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MULTIVIEW_MAIN }, 0, 0, VE, .unit = "profile" }, +#endif { "level", "Set the encoding level restriction", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_HEVC_62, VE, .unit = "level" }, { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, 0, 0, VE, .unit = "level" }, { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_HEVC_1 }, 0, 0, VE, .unit = "level" }, @@ -158,6 +161,10 @@ static const AVOption options[] = { OFFSET(qp_cb_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, { "qp_cr_offset", "Quantization parameter offset for cr channel", OFFSET(qp_cr_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, -12, 12, VE }, + { "qmin", "Specifies the minimum QP used for rate control", + OFFSET(qmin), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qmax", "Specifies the maximum QP used for rate control", + OFFSET(qmax), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "weighted_pred","Set 1 to enable weighted prediction", OFFSET(weighted_pred),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, #ifdef NVENC_HAVE_HEVC_BFRAME_REF_MODE @@ -202,6 +209,10 @@ static const AVOption options[] = { OFFSET(max_slice_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "constrained-encoding", "Enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices", OFFSET(constrained_encoding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_FILLER_DATA + { "cbr_padding", "Pad the bitstream to ensure bitrate does not drop below the target in CBR mode", + OFFSET(cbr_padding), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif #ifdef NVENC_HAVE_TEMPORAL_FILTER { "tf_level", "Specifies the strength of the temporal filtering", OFFSET(tf_level), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, .unit = "tf_level" }, @@ -263,7 +274,7 @@ const FFCodec ff_hevc_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .p.priv_class = &hevc_nvenc_class, .defaults = defaults, - .p.pix_fmts = ff_nvenc_pix_fmts, + CODEC_PIXFMTS_ARRAY(ff_nvenc_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 | diff --git a/libavcodec/ohcodec.c b/libavcodec/ohcodec.c new file mode 100644 index 0000000000..f8a6faaba5 --- /dev/null +++ b/libavcodec/ohcodec.c @@ -0,0 +1,79 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ohcodec.h" + +#include "libavutil/error.h" + +int ff_oh_err_to_ff_err(OH_AVErrCode err) +{ + switch (err) { + case AV_ERR_OK: + return 0; + case AV_ERR_NO_MEMORY: + return AVERROR(ENOMEM); + case AV_ERR_OPERATE_NOT_PERMIT: + return AVERROR(EPERM); + case AV_ERR_INVALID_VAL: + return AVERROR(EINVAL); + case AV_ERR_IO: + return AVERROR(EIO); + case AV_ERR_TIMEOUT: + return AVERROR(ETIMEDOUT); + case AV_ERR_UNKNOWN: + return AVERROR_UNKNOWN; + case AV_ERR_SERVICE_DIED: + return AVERROR_EXTERNAL; + case AV_ERR_INVALID_STATE: + return AVERROR(EINVAL); + case AV_ERR_UNSUPPORT: + return AVERROR(ENOTSUP); + default: + return AVERROR_EXTERNAL; + } +} + +static const struct { + OH_AVPixelFormat oh_pix; + enum AVPixelFormat pix; +} oh_pix_map[] = { + {AV_PIXEL_FORMAT_NV12, AV_PIX_FMT_NV12}, + {AV_PIXEL_FORMAT_NV21, AV_PIX_FMT_NV21}, + {AV_PIXEL_FORMAT_YUVI420, AV_PIX_FMT_YUV420P}, + {AV_PIXEL_FORMAT_SURFACE_FORMAT, AV_PIX_FMT_OHCODEC}, +}; + +enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++) + if (oh_pix_map[i].oh_pix == oh_pix) + return oh_pix_map[i].pix; + + return AV_PIX_FMT_NONE; +} + +int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++) + if (oh_pix_map[i].pix == pix) + return oh_pix_map[i].oh_pix; + + return 0; +} diff --git a/libavcodec/ohcodec.h b/libavcodec/ohcodec.h new file mode 100644 index 0000000000..074747247b --- /dev/null +++ b/libavcodec/ohcodec.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_OHCODEC_H +#define AVCODEC_OHCODEC_H + +#include +#include +#include +#include + +#include "libavutil/pixfmt.h" + +#include "codec_id.h" + +typedef struct OHBufferQueueItem { + uint32_t index; + OH_AVBuffer *buffer; +} OHBufferQueueItem; + +int ff_oh_err_to_ff_err(OH_AVErrCode err); + +static inline const char *ff_oh_mime(enum AVCodecID codec_id, void *log) +{ + switch (codec_id) { + case AV_CODEC_ID_H264: + return OH_AVCODEC_MIMETYPE_VIDEO_AVC; + case AV_CODEC_ID_HEVC: + return OH_AVCODEC_MIMETYPE_VIDEO_HEVC; + default: + av_log(log, AV_LOG_ERROR, "Unsupported codec %s\n", + avcodec_get_name(codec_id)); + return NULL; + } +} + +enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix); +int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix); + +#endif diff --git a/libavcodec/ohdec.c b/libavcodec/ohdec.c new file mode 100644 index 0000000000..cf1177afcd --- /dev/null +++ b/libavcodec/ohdec.c @@ -0,0 +1,771 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_components.h" + +#include +#include +#include + +#include "libavutil/fifo.h" +#include "libavutil/hwcontext_oh.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "hwconfig.h" +#include "ohcodec.h" + +typedef struct OHCodecDecContext { + AVClass *avclass; + OH_AVCodec *dec; + /* A reference count to dec. Each hardware frame has a reference count to + * dec. dec will be destroyed only after oh_decode_close and all hardware + * frames have been released. + */ + AVBufferRef *dec_ref; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_queue; + + AVMutex output_mutex; + AVCond output_cond; + AVFifo *output_queue; + + AVPacket pkt; + + int decode_status; + bool eof_sent; + + bool output_to_window; + bool got_stream_info; + int width; + int height; + int stride; + int slice_height; + OH_AVPixelFormat pix_fmt; + + char *name; + int allow_sw; +} OHCodecDecContext; + +typedef struct OHCodecBuffer { + uint32_t index; + OH_AVBuffer *buffer; + AVBufferRef *dec_ref; +} OHCodecBuffer; + +static void oh_decode_release(void *opaque, uint8_t *data) +{ + OH_AVCodec *dec = (OH_AVCodec *)data; + OH_AVErrCode err = OH_VideoDecoder_Destroy(dec); + if (err == AV_ERR_OK) + av_log(NULL, AV_LOG_DEBUG, "Destroy decoder success\n"); + else + av_log(NULL, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); +} + +static int oh_decode_create(OHCodecDecContext *s, AVCodecContext *avctx) +{ + const char *name = s->name; + + if (!name) { + const char *mime = ff_oh_mime(avctx->codec_id, avctx); + if (!mime) + return AVERROR_BUG; + OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, false, HARDWARE); + if (!cap) { + if (!s->allow_sw) { + av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_WARNING, + "Failed to get hardware codec %s, try software backend\n", mime); + cap = OH_AVCodec_GetCapabilityByCategory(mime, false, SOFTWARE); + if (!cap) { + av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime); + return AVERROR_EXTERNAL; + } + } + name = OH_AVCapability_GetName(cap); + if (!name) + return AVERROR_EXTERNAL; + } + + s->dec = OH_VideoDecoder_CreateByName(name); + if (!s->dec) { + av_log(avctx, AV_LOG_ERROR, "Create decoder with name %s failed\n", name); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_DEBUG, "Create decoder %s success\n", name); + + s->dec_ref = av_buffer_create((uint8_t *)s->dec, 0, oh_decode_release, + NULL, 0); + if (!s->dec_ref) + return AVERROR(ENOMEM); + + return 0; +} + +static int oh_decode_set_format(OHCodecDecContext *s, AVCodecContext *avctx) +{ + int ret; + OHNativeWindow *window = NULL; + + if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); + if (device_ctx->type == AV_HWDEVICE_TYPE_OHCODEC) { + AVOHCodecDeviceContext *dev = device_ctx->hwctx; + window = dev->native_window; + s->output_to_window = true; + } else { + av_log(avctx, AV_LOG_WARNING, "Ignore invalid hw device type %s\n", + av_hwdevice_get_type_name(device_ctx->type)); + } + } + + if (avctx->width <= 0 || avctx->height <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Invalid width/height (%dx%d), width and height are mandatory for ohcodec\n", + avctx->width, avctx->height); + return AVERROR(EINVAL); + } + + OH_AVFormat *format = OH_AVFormat_Create(); + if (!format) + return AVERROR(ENOMEM); + + OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height); + if (!s->output_to_window) + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, + AV_PIXEL_FORMAT_NV12); + else + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, + AV_PIXEL_FORMAT_SURFACE_FORMAT); + OH_AVErrCode err = OH_VideoDecoder_Configure(s->dec, format); + OH_AVFormat_Destroy(format); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + if (s->output_to_window) { + err = OH_VideoDecoder_SetSurface(s->dec, window); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Set surface failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + } + + return 0; +} + +static void oh_decode_on_err(OH_AVCodec *codec, int32_t err, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + + // Careful on the lock order. + // Always lock input first. + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->decode_status = ff_oh_err_to_ff_err(err); + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void oh_decode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format, + void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + int32_t n; + double d; + + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &s->width) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &s->height) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride) || + !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, + &s->slice_height)) { + av_log(avctx, AV_LOG_ERROR, "Get dimension info from format failed\n"); + goto out; + } + + if (ff_set_dimensions(avctx, s->width, s->height) < 0) + goto out; + + if (s->stride <= 0 || s->slice_height <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Buffer stride (%d) or slice height (%d) is invalid\n", + s->stride, s->slice_height); + goto out; + } + + if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, &n)) { + s->pix_fmt = n; + /* When use output_to_window, the returned format is the memory + * layout of hardware frame, not AV_PIXEL_FORMAT_SURFACE_FORMAT as + * expected. + */ + if (s->output_to_window) + avctx->pix_fmt = AV_PIX_FMT_OHCODEC; + else + avctx->pix_fmt = ff_oh_pix_to_ff_pix(s->pix_fmt); + // Check whether this pixel format is supported + if (avctx->pix_fmt == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Unsupported OH_AVPixelFormat %d\n", + n); + goto out; + } + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to get pixel format\n"); + goto out; + } + + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_MATRIX_COEFFICIENTS, + &n)) + avctx->colorspace = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_COLOR_PRIMARIES, + &n)) + avctx->color_primaries = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_TRANSFER_CHARACTERISTICS, + &n)) + avctx->color_trc = n; + if (OH_AVFormat_GetIntValue(format, + OH_MD_KEY_RANGE_FLAG, + &n)) + avctx->color_range = n ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (OH_AVFormat_GetDoubleValue(format, OH_MD_KEY_VIDEO_SAR, &d)) { + AVRational sar = av_d2q(d, 4096 * 4); + ff_set_sar(avctx, sar); + } + + s->got_stream_info = true; + + return; +out: + av_log(avctx, AV_LOG_ERROR, "Invalid format from decoder: %s\n", + OH_AVFormat_DumpInfo(format)); + oh_decode_on_err(codec, AV_ERR_UNKNOWN, userdata); +} + +static void oh_decode_on_need_input(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->input_mutex); + int ret = av_fifo_write(s->input_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static void oh_decode_on_output(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecDecContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->output_mutex); + int ret = av_fifo_write(s->output_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static int oh_decode_start(OHCodecDecContext *s, AVCodecContext *avctx) +{ + int ret; + OH_AVErrCode err; + OH_AVCodecCallback cb = { + .onError = oh_decode_on_err, + .onStreamChanged = oh_decode_on_stream_changed, + .onNeedInputBuffer = oh_decode_on_need_input, + .onNewOutputBuffer = oh_decode_on_output, + }; + + err = OH_VideoDecoder_RegisterCallback(s->dec, cb, avctx); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoDecoder_Prepare(s->dec); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoDecoder_Start(s->dec); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + return 0; +} + +static av_cold int oh_decode_init(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + // Initialize these fields first, so oh_decode_close can destroy them safely + ff_mutex_init(&s->input_mutex, NULL); + ff_cond_init(&s->input_cond, NULL); + ff_mutex_init(&s->output_mutex, NULL); + ff_cond_init(&s->output_cond, NULL); + + int ret = oh_decode_create(s, avctx); + if (ret < 0) + return ret; + ret = oh_decode_set_format(s, avctx); + if (ret < 0) + return ret; + + size_t fifo_size = 16; + s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + if (!s->input_queue || !s->output_queue) + return AVERROR(ENOMEM); + + ret = oh_decode_start(s, avctx); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold int oh_decode_close(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + if (s->dec) { + /* Stop but don't destroy dec directly, to keep hardware frames on + * the fly valid. + */ + OH_AVErrCode err = OH_VideoDecoder_Stop(s->dec); + if (err == AV_ERR_OK) + av_log(avctx, AV_LOG_DEBUG, "Stop decoder success\n"); + else + av_log(avctx, AV_LOG_ERROR, "Stop decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); + s->dec = NULL; + av_buffer_unref(&s->dec_ref); + } + + av_packet_unref(&s->pkt); + + ff_mutex_destroy(&s->input_mutex); + ff_cond_destroy(&s->input_cond); + av_fifo_freep2(&s->input_queue); + + ff_mutex_destroy(&s->output_mutex); + ff_cond_destroy(&s->output_cond); + av_fifo_freep2(&s->output_queue); + + return 0; +} + +static void oh_buffer_release(void *opaque, uint8_t *data) +{ + if (!opaque) + return; + + OHCodecBuffer *buffer = opaque; + + if (!buffer->dec_ref) { + av_free(buffer); + return; + } + + if (buffer->buffer) { + OH_AVCodec *dec = (OH_AVCodec *)buffer->dec_ref->data; + OH_AVCodecBufferAttr attr; + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(buffer->buffer, &attr); + if (err == AV_ERR_OK && !(attr.flags & AVCODEC_BUFFER_FLAGS_DISCARD)) + OH_VideoDecoder_RenderOutputBuffer(dec, buffer->index); + else + OH_VideoDecoder_FreeOutputBuffer(dec, buffer->index); + } + + av_buffer_unref(&buffer->dec_ref); + av_free(buffer); +} + +static int oh_decode_wrap_hw_buffer(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output, + const OH_AVCodecBufferAttr *attr) +{ + OHCodecDecContext *s = avctx->priv_data; + + frame->width = s->width; + frame->height = s->height; + int ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) + return ret; + + frame->format = AV_PIX_FMT_OHCODEC; + OHCodecBuffer *buffer = av_mallocz(sizeof(*buffer)); + if (!buffer) + return AVERROR(ENOMEM); + + buffer->dec_ref = av_buffer_ref(s->dec_ref); + if (!buffer->dec_ref) { + oh_buffer_release(buffer, NULL); + return AVERROR(ENOMEM); + } + + buffer->index = output->index; + buffer->buffer = output->buffer; + frame->buf[0] = av_buffer_create((uint8_t *)buffer->buffer, 1, + oh_buffer_release, + buffer, AV_BUFFER_FLAG_READONLY); + if (!frame->buf[0]) { + oh_buffer_release(buffer, NULL); + return AVERROR(ENOMEM); + } + // Point to OH_AVBuffer + frame->data[3] = frame->buf[0]->data; + frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase); + frame->pkt_dts = AV_NOPTS_VALUE; + + return 0; +} + +static int oh_decode_wrap_sw_buffer(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output, + const OH_AVCodecBufferAttr *attr) +{ + OHCodecDecContext *s = avctx->priv_data; + + frame->format = avctx->pix_fmt; + frame->width = s->width; + frame->height = s->height; + int ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase); + frame->pkt_dts = AV_NOPTS_VALUE; + + uint8_t *p = OH_AVBuffer_GetAddr(output->buffer); + if (!p) { + av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n"); + return AVERROR_EXTERNAL; + } + + uint8_t *src[4] = {0}; + int src_linesizes[4] = {0}; + + ret = av_image_fill_linesizes(src_linesizes, frame->format, s->stride); + if (ret < 0) + return ret; + ret = av_image_fill_pointers(src, frame->format, s->slice_height, p, + src_linesizes); + if (ret < 0) + return ret; + av_image_copy2(frame->data, frame->linesize, src, src_linesizes, + frame->format, frame->width, frame->height); + + OH_AVErrCode err = OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "FreeOutputBuffer failed, %d, %s\n", err, + av_err2str(ret)); + return ret; + } + + return 0; +} + +static int oh_decode_output_frame(AVCodecContext *avctx, AVFrame *frame, + OHBufferQueueItem *output) +{ + OHCodecDecContext *s = avctx->priv_data; + OH_AVCodecBufferAttr attr; + + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + + if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) { + av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n"); + OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index); + return AVERROR_EOF; + } + + if (!s->got_stream_info) { + // This shouldn't happen, add a warning message. + av_log(avctx, AV_LOG_WARNING, + "decoder didn't notify stream info, try get format explicitly\n"); + + OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(s->dec); + if (!format) { + av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n"); + return AVERROR_EXTERNAL; + } + + oh_decode_on_stream_changed(s->dec, format, avctx); + OH_AVFormat_Destroy(format); + if (!s->got_stream_info) + return AVERROR_EXTERNAL; + } + + if (s->output_to_window) + return oh_decode_wrap_hw_buffer(avctx, frame, output, &attr); + return oh_decode_wrap_sw_buffer(avctx, frame, output, &attr); +} + +static int oh_decode_send_pkt(AVCodecContext *avctx, OHBufferQueueItem *input) +{ + OHCodecDecContext *s = avctx->priv_data; + OH_AVErrCode err; + int ret; + + if (!s->pkt.size && !s->eof_sent) { + OH_AVCodecBufferAttr attr = { + .flags = AVCODEC_BUFFER_FLAGS_EOS, + }; + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + s->eof_sent = true; + return 0; + } + + uint8_t *p = OH_AVBuffer_GetAddr(input->buffer); + int32_t n = OH_AVBuffer_GetCapacity(input->buffer); + if (!p || n <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to get buffer addr (%p) or capacity (%d)\n", + p, n); + return AVERROR_EXTERNAL; + } + n = FFMIN(s->pkt.size, n); + memcpy(p, s->pkt.data, n); + + OH_AVCodecBufferAttr attr = { + .size = n, + .offset = 0, + .pts = av_rescale_q(s->pkt.pts, avctx->pkt_timebase, + AV_TIME_BASE_Q), + .flags = (s->pkt.flags & AV_PKT_FLAG_KEY) + ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0, + }; + + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + return ret; + } + err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + if (n < s->pkt.size) { + s->pkt.size -= n; + s->pkt.data += n; + } else { + av_packet_unref(&s->pkt); + } + + return 0; +} + +static int oh_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + OHCodecDecContext *s = avctx->priv_data; + + while (1) { + OHBufferQueueItem buffer = {0}; + int ret; + + // Try get output + ff_mutex_lock(&s->output_mutex); + while (!s->decode_status) { + if (av_fifo_read(s->output_queue, &buffer, 1) >= 0) + break; + // Only wait after send EOF + if (s->eof_sent && !s->decode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->decode_status; + ff_mutex_unlock(&s->output_mutex); + + // Got a frame + if (buffer.buffer) + return oh_decode_output_frame(avctx, frame, &buffer); + if (ret < 0) + return ret; + + if (!s->pkt.size) { + /* fetch new packet or eof */ + ret = ff_decode_get_packet(avctx, &s->pkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + // Wait input buffer + ff_mutex_lock(&s->input_mutex); + while (!s->decode_status) { + if (av_fifo_read(s->input_queue, &buffer, 1) >= 0) + break; + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->decode_status; + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + return ret; + + ret = oh_decode_send_pkt(avctx, &buffer); + if (ret < 0) + return ret; + } + + return AVERROR(EAGAIN); +} + +static void oh_decode_flush(AVCodecContext *avctx) +{ + OHCodecDecContext *s = avctx->priv_data; + + OH_VideoDecoder_Flush(s->dec); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + av_fifo_reset2(s->input_queue); + av_fifo_reset2(s->output_queue); + s->decode_status = 0; + s->eof_sent = false; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + OH_VideoDecoder_Start(s->dec); +} + +static const AVCodecHWConfigInternal *const oh_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_OHCODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_OHCODEC, + }, + .hwaccel = NULL, + }, + NULL +}; + +#define OFFSET(x) offsetof(OHCodecDecContext, x) +#define VD (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM) +static const AVOption ohcodec_vdec_options[] = { + {"codec_name", "Select codec by name", + OFFSET(name), AV_OPT_TYPE_STRING, .flags = VD}, + {"allow_sw", "Allow software decoding", + OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD}, + {NULL} +}; + +#define DECLARE_OHCODEC_VCLASS(short_name) \ + static const AVClass short_name##_oh_dec_class = { \ + .class_name = #short_name "_ohcodec", \ + .item_name = av_default_item_name, \ + .option = ohcodec_vdec_options, \ + .version = LIBAVUTIL_VERSION_INT, \ + }; + +#define DECLARE_OHCODEC_VDEC(short_name, full_name, codec_id, bsf) \ + DECLARE_OHCODEC_VCLASS(short_name) \ + const FFCodec ff_##short_name##_oh_decoder = { \ + .p.name = #short_name "_ohcodec", \ + CODEC_LONG_NAME(full_name " OpenHarmony Codec"), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = codec_id, \ + .p.priv_class = &short_name##_oh_dec_class, \ + .priv_data_size = sizeof(OHCodecDecContext), \ + .init = oh_decode_init, \ + FF_CODEC_RECEIVE_FRAME_CB(oh_decode_receive_frame), \ + .flush = oh_decode_flush, \ + .close = oh_decode_close, \ + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | \ + AV_CODEC_CAP_HARDWARE, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .bsfs = bsf, \ + .hw_configs = oh_hw_configs, \ + .p.wrapper_name = "ohcodec", \ + }; + +#if CONFIG_H264_OH_DECODER +DECLARE_OHCODEC_VDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb") +#endif + +#if CONFIG_HEVC_OH_DECODER +DECLARE_OHCODEC_VDEC(hevc, "H.265", AV_CODEC_ID_HEVC, "hevc_mp4toannexb") +#endif diff --git a/libavcodec/ohenc.c b/libavcodec/ohenc.c new file mode 100644 index 0000000000..76bddd45b6 --- /dev/null +++ b/libavcodec/ohenc.c @@ -0,0 +1,711 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_components.h" + +#include +#include +#include +#include + +#include "libavutil/fifo.h" +#include "libavutil/hwcontext_oh.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "hwconfig.h" +#include "ohcodec.h" + +typedef struct OHCodecEncContext { + AVClass *avclass; + OH_AVCodec *enc; + + AVMutex input_mutex; + AVCond input_cond; + AVFifo *input_queue; + + AVMutex output_mutex; + AVCond output_cond; + AVFifo *output_queue; + + AVFrame *frame; + uint8_t *extradata; + int extradata_size; + + int encode_status; + bool eof_sent; + + bool got_stream_info; + int stride; + int slice_height; + + OHNativeWindow *native_window; + char *name; + int allow_sw; + int bitrate_mode; +} OHCodecEncContext; + +static const enum AVPixelFormat ohcodec_pix_fmts[] = { + AV_PIX_FMT_OHCODEC, + AV_PIX_FMT_NV12, + AV_PIX_FMT_NONE +}; + +static int oh_encode_create(OHCodecEncContext *s, AVCodecContext *avctx) +{ + const char *name = s->name; + + if (!name) { + const char *mime = ff_oh_mime(avctx->codec_id, avctx); + if (!mime) + return AVERROR_BUG; + OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, true, HARDWARE); + if (!cap) { + if (!s->allow_sw) { + av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_WARNING, + "Failed to get hardware codec %s, try software backend\n", mime); + cap = OH_AVCodec_GetCapabilityByCategory(mime, true, SOFTWARE); + if (!cap) { + av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime); + return AVERROR_EXTERNAL; + } + } + name = OH_AVCapability_GetName(cap); + if (!name) + return AVERROR_EXTERNAL; + } + + s->enc = OH_VideoEncoder_CreateByName(name); + if (!s->enc) { + av_log(avctx, AV_LOG_ERROR, "Create encoder with name %s failed\n", name); + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_DEBUG, "Create encoder %s success\n", name); + + return 0; +} + +static int oh_encode_set_format(OHCodecEncContext *s, AVCodecContext *avctx) +{ + int ret; + + OH_AVFormat *format = OH_AVFormat_Create(); + if (!format) + return AVERROR(ENOMEM); + + bool b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width); + b = b && OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set width/height (%dx%d) failed\n", + avctx->width, avctx->height); + ret = AVERROR_EXTERNAL; + goto out; + } + if (avctx->framerate.num && avctx->framerate.den) + OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, + av_q2d(avctx->framerate)); + int pix = ff_oh_pix_from_ff_pix(avctx->pix_fmt); + if (!pix) { + ret = AVERROR_BUG; + goto out; + } + b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, pix); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set pixel format to %d failed\n", pix); + ret = AVERROR_EXTERNAL; + goto out; + } + + if (s->bitrate_mode != -1) { + b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, s->bitrate_mode); + if (!b) { + av_log(avctx, AV_LOG_ERROR, "Set bitrate mode to %d failed\n", + s->bitrate_mode); + ret = AVERROR_EXTERNAL; + goto out; + } + } + OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, avctx->bit_rate); + + if (avctx->gop_size > 0) { + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + // In milliseconds + int gop = av_rescale_q(avctx->gop_size, + av_make_q(avctx->framerate.den, + avctx->framerate.num), + av_make_q(1, 1000)); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, gop); + } else { + av_log(avctx, AV_LOG_WARNING, "Skip setting gop without framerate\n"); + } + } else if (!avctx->gop_size) { + // All frames are key frame + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, 0); + } else if (avctx->gop_size == -1) { + // Infinite gop + OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, -1); + } + + OH_AVErrCode err = OH_VideoEncoder_Configure(s->enc, format); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n", + err, av_err2str(ret)); + goto out; + } + + if (avctx->pix_fmt == AV_PIX_FMT_OHCODEC) { + if (avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, + "ohcodec can only export native window via hw device, " + "doesn't support import hw device\n"); + ret = AVERROR(EINVAL); + goto out; + } + + err = OH_VideoEncoder_GetSurface(s->enc, &s->native_window); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Get surface failed, %d, %s\n", + err, av_err2str(ret)); + goto out; + } + av_log(avctx, AV_LOG_INFO, "Native window %p\n", s->native_window); + + ret = av_hwdevice_ctx_create(&avctx->hw_device_ctx, + AV_HWDEVICE_TYPE_OHCODEC, NULL, NULL, 0); + if (ret < 0) + goto out; + + AVOHCodecDeviceContext *dev = ((AVHWDeviceContext *)avctx->hw_device_ctx->data)->hwctx; + dev->native_window = s->native_window; + } + + return 0; +out: + OH_AVFormat_Destroy(format); + return ret; +} + +static void oh_encode_on_err(OH_AVCodec *codec, int32_t err, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + + // Careful on the lock order. + // Always lock input first. + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + s->encode_status = ff_oh_err_to_ff_err(err); + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + ff_cond_signal(&s->output_cond); + ff_cond_signal(&s->input_cond); +} + +static void oh_encode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format, + void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride)) + s->stride = avctx->width; + if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &s->slice_height)) + s->slice_height = avctx->height; + + s->got_stream_info = true; +} + +static void oh_encode_on_need_input(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->input_mutex); + int ret = av_fifo_write(s->input_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->input_cond); + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static void oh_encode_on_output(OH_AVCodec *codec, uint32_t index, + OH_AVBuffer *buffer, void *userdata) +{ + AVCodecContext *avctx = userdata; + OHCodecEncContext *s = avctx->priv_data; + OHBufferQueueItem item = { + index, buffer, + }; + + ff_mutex_lock(&s->output_mutex); + int ret = av_fifo_write(s->output_queue, &item, 1); + if (ret >= 0) + ff_cond_signal(&s->output_cond); + ff_mutex_unlock(&s->output_mutex); + + if (ret < 0) + oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata); +} + +static int oh_encode_start(OHCodecEncContext *s, AVCodecContext *avctx) +{ + int ret; + OH_AVErrCode err; + OH_AVCodecCallback cb = { + .onError = oh_encode_on_err, + .onStreamChanged = oh_encode_on_stream_changed, + .onNeedInputBuffer = oh_encode_on_need_input, + .onNewOutputBuffer = oh_encode_on_output, + }; + + err = OH_VideoEncoder_RegisterCallback(s->enc, cb, avctx); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoEncoder_Prepare(s->enc); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + err = OH_VideoEncoder_Start(s->enc); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + + return 0; +} + +static av_cold int oh_encode_init(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + // Initialize these fields first, so oh_decode_close can destroy them safely + ff_mutex_init(&s->input_mutex, NULL); + ff_cond_init(&s->input_cond, NULL); + ff_mutex_init(&s->output_mutex, NULL); + ff_cond_init(&s->output_cond, NULL); + + int ret = oh_encode_create(s, avctx); + if (ret < 0) + return ret; + ret = oh_encode_set_format(s, avctx); + if (ret < 0) + return ret; + + size_t fifo_size = 16; + s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem), + AV_FIFO_FLAG_AUTO_GROW); + s->frame = av_frame_alloc(); + if (!s->input_queue || !s->output_queue || !s->frame) + return AVERROR(ENOMEM); + + ret = oh_encode_start(s, avctx); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold int oh_encode_close(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + if (s->enc) { + if (s->native_window) { + OH_NativeWindow_DestroyNativeWindow(s->native_window); + s->native_window = NULL; + } + OH_VideoEncoder_Stop(s->enc); + OH_AVErrCode err = OH_VideoEncoder_Destroy(s->enc); + if (err == AV_ERR_OK) + av_log(avctx, AV_LOG_DEBUG, "Destroy encoder success\n"); + else + av_log(avctx, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n", + err, av_err2str(ff_oh_err_to_ff_err(err))); + s->enc = NULL; + } + + av_freep(&s->extradata); + av_frame_free(&s->frame); + + ff_mutex_destroy(&s->input_mutex); + ff_cond_destroy(&s->input_cond); + av_fifo_freep2(&s->input_queue); + + ff_mutex_destroy(&s->output_mutex); + ff_cond_destroy(&s->output_cond); + av_fifo_freep2(&s->output_queue); + + return 0; +} + +static int oh_encode_output_packet(AVCodecContext *avctx, AVPacket *pkt, + OHBufferQueueItem *output) +{ + OHCodecEncContext *s = avctx->priv_data; + uint8_t *p; + OH_AVCodecBufferAttr attr; + int ret; + + OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + goto out; + } + if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) { + av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n"); + ret = AVERROR_EOF; + goto out; + } + + p = OH_AVBuffer_GetAddr(output->buffer); + if (!p) { + av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n"); + ret = AVERROR_EXTERNAL; + goto out; + } + if (attr.flags & AVCODEC_BUFFER_FLAGS_CODEC_DATA) { + av_freep(&s->extradata); + s->extradata = av_malloc(attr.size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!s->extradata) { + ret = AVERROR(ENOMEM); + goto out; + } + memset(s->extradata + attr.size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + memcpy(s->extradata, p + attr.offset, attr.size); + s->extradata_size = attr.size; + ret = 0; + goto out; + } + + int64_t extradata_size = s->extradata_size; + s->extradata_size = 0; + + if (extradata_size && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + s->extradata, extradata_size); + if (ret < 0) + goto out; + s->extradata = NULL; + extradata_size = 0; + } + + ret = ff_get_encode_buffer(avctx, pkt, attr.size + extradata_size, 0); + if (ret < 0) + goto out; + + if (extradata_size) + memcpy(pkt->data, s->extradata, extradata_size); + + memcpy(pkt->data + extradata_size, p + attr.offset, attr.size); + pkt->pts = av_rescale_q(attr.pts, AV_TIME_BASE_Q, avctx->time_base); + if (attr.flags & AVCODEC_BUFFER_FLAGS_SYNC_FRAME) + pkt->flags |= AV_PKT_FLAG_KEY; + ret = 0; +out: + OH_VideoEncoder_FreeOutputBuffer(s->enc, output->index); + return ret; +} + +static int oh_encode_send_hw_frame(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + if (s->eof_sent) + return 0; + + if (s->frame->buf[0]) { + av_frame_unref(s->frame); + return 0; + } + + OH_AVErrCode err = OH_VideoEncoder_NotifyEndOfStream(s->enc); + s->eof_sent = true; + return ff_oh_err_to_ff_err(err); +} + +static int oh_encode_send_sw_frame(AVCodecContext *avctx, OHBufferQueueItem *input) +{ + OHCodecEncContext *s = avctx->priv_data; + AVFrame *frame = s->frame; + OH_AVErrCode err; + int ret; + + if (!s->got_stream_info) { + // This shouldn't happen, add a warning message. + av_log(avctx, AV_LOG_WARNING, + "decoder didn't notify stream info, try get format explicitly\n"); + + OH_AVFormat *format = OH_VideoEncoder_GetOutputDescription(s->enc); + if (!format) { + av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n"); + return AVERROR_EXTERNAL; + } + + oh_encode_on_stream_changed(s->enc, format, avctx); + OH_AVFormat_Destroy(format); + if (!s->got_stream_info) + return AVERROR_EXTERNAL; + } + + if (!frame->buf[0] && !s->eof_sent) { + OH_AVCodecBufferAttr attr = { + .flags = AVCODEC_BUFFER_FLAGS_EOS, + }; + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index); + if (err != AV_ERR_OK) + return ff_oh_err_to_ff_err(err); + s->eof_sent = true; + return 0; + } + + uint8_t *p = OH_AVBuffer_GetAddr(input->buffer); + int32_t n = OH_AVBuffer_GetCapacity(input->buffer); + if (!p || n <= 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to get buffer addr (%p) or capacity (%d)\n", + p, n); + return AVERROR_EXTERNAL; + } + + uint8_t *dst[4] = {0}; + int dst_linesizes[4] = {0}; + ret = av_image_fill_linesizes(dst_linesizes, frame->format, s->stride); + if (ret < 0) + return ret; + ret = av_image_fill_pointers(dst, frame->format, s->slice_height, p, + dst_linesizes); + if (ret < 0) + return ret; + + av_image_copy2(dst, dst_linesizes, frame->data, frame->linesize, + frame->format, frame->width, frame->height); + OH_AVCodecBufferAttr attr = { + .size = n, + .offset = 0, + .pts = av_rescale_q(s->frame->pts, avctx->pkt_timebase, + AV_TIME_BASE_Q), + .flags = (s->frame->flags & AV_FRAME_FLAG_KEY) + ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0, + }; + + err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + return ret; + } + err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index); + if (err != AV_ERR_OK) { + ret = ff_oh_err_to_ff_err(err); + av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n", + err, av_err2str(ret)); + return ret; + } + av_frame_unref(s->frame); + + return 0; +} + +static int oh_encode_receive(AVCodecContext *avctx, AVPacket *pkt) +{ + OHCodecEncContext *s = avctx->priv_data; + + while (1) { + OHBufferQueueItem buffer = {0}; + int ret; + + // Try get output + ff_mutex_lock(&s->output_mutex); + while (!s->encode_status) { + if (av_fifo_read(s->output_queue, &buffer, 1) >= 0) + break; + // Only wait after send EOF + if (s->eof_sent && !s->encode_status) + ff_cond_wait(&s->output_cond, &s->output_mutex); + else + break; + } + + ret = s->encode_status; + ff_mutex_unlock(&s->output_mutex); + + // Got a packet + if (buffer.buffer) + return oh_encode_output_packet(avctx, pkt, &buffer); + if (ret < 0) + return ret; + + if (!s->frame->buf[0]) { + /* fetch new frame or eof */ + ret = ff_encode_get_frame(avctx, s->frame); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + if (s->native_window) { + ret = oh_encode_send_hw_frame(avctx); + if (ret < 0) + return ret; + continue; + } + + // Wait input buffer + ff_mutex_lock(&s->input_mutex); + while (!s->encode_status) { + if (av_fifo_read(s->input_queue, &buffer, 1) >= 0) + break; + ff_cond_wait(&s->input_cond, &s->input_mutex); + } + + ret = s->encode_status; + ff_mutex_unlock(&s->input_mutex); + + if (ret < 0) + return ret; + + ret = oh_encode_send_sw_frame(avctx, &buffer); + if (ret < 0) + return ret; + } + + return AVERROR(EAGAIN); +} + +static void oh_encode_flush(AVCodecContext *avctx) +{ + OHCodecEncContext *s = avctx->priv_data; + + OH_VideoEncoder_Flush(s->enc); + + ff_mutex_lock(&s->input_mutex); + ff_mutex_lock(&s->output_mutex); + av_fifo_reset2(s->input_queue); + av_fifo_reset2(s->output_queue); + s->encode_status = 0; + s->eof_sent = false; + ff_mutex_unlock(&s->output_mutex); + ff_mutex_unlock(&s->input_mutex); + + OH_VideoEncoder_Start(s->enc); +} + +static const AVCodecHWConfigInternal *const oh_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_OHCODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC, + }, + .hwaccel = NULL, + }, + NULL +}; + +static const FFCodecDefault ohcodec_defaults[] = { + {"g", "-2"}, + {NULL}, +}; + +#define OFFSET(x) offsetof(OHCodecEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption ohcodec_venc_options[] = { + {"codec_name", "Select codec by name", + OFFSET(name), AV_OPT_TYPE_STRING, .flags = VE}, + {"allow_sw", "Allow software encoding", + OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE}, + {"bitrate_mode", "Bitrate control method", + OFFSET(bitrate_mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, .unit = "bitrate_mode"}, + {"cbr", "Constant bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = CBR}, 0, 0, VE, .unit = "bitrate_mode"}, + {"vbr", "Variable bitrate mode", + 0, AV_OPT_TYPE_CONST, {.i64 = VBR}, 0, 0, VE, .unit = "bitrate_mode"}, + {"cq", "Constant quality mode", + 0, AV_OPT_TYPE_CONST, {.i64 = CQ}, 0, 0, VE, .unit = "bitrate_mode"}, + {NULL}, +}; + +#define DECLARE_OHCODEC_CLASS(name) \ +static const AVClass name ## _oh_enc_class = { \ + .class_name = #name "_ohcodec", \ + .item_name = av_default_item_name, \ + .option = ohcodec_venc_options, \ + .version = LIBAVUTIL_VERSION_INT, \ +}; \ + +#define DECLARE_OHCODEC_ENCODER(short_name, long_name, codec_id) \ +DECLARE_OHCODEC_CLASS(short_name) \ +const FFCodec ff_ ## short_name ## _oh_encoder = { \ + .p.name = #short_name "_ohcodec", \ + CODEC_LONG_NAME(long_name " OpenHarmony Codec"), \ + .p.type = AVMEDIA_TYPE_VIDEO, \ + .p.id = codec_id, \ + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | \ + AV_CODEC_CAP_HARDWARE | \ + AV_CODEC_CAP_ENCODER_FLUSH, \ + .priv_data_size = sizeof(OHCodecEncContext), \ + CODEC_PIXFMTS_ARRAY(ohcodec_pix_fmts), \ + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ + .defaults = ohcodec_defaults, \ + .init = oh_encode_init, \ + FF_CODEC_RECEIVE_PACKET_CB(oh_encode_receive), \ + .close = oh_encode_close, \ + .flush = oh_encode_flush, \ + .p.priv_class = &short_name ## _oh_enc_class, \ + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .p.wrapper_name = "ohcodec", \ + .hw_configs = oh_hw_configs, \ +}; \ + +#if CONFIG_H264_OH_ENCODER +DECLARE_OHCODEC_ENCODER(h264, "H.264", AV_CODEC_ID_H264) +#endif // CONFIG_H264_OH_ENCODER + +#if CONFIG_HEVC_OH_ENCODER +DECLARE_OHCODEC_ENCODER(hevc, "H.265", AV_CODEC_ID_HEVC) +#endif // CONFIG_HEVC_OH_ENCODER diff --git a/libavcodec/omx.c b/libavcodec/omx.c index 2c3865506f..6b900d741d 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -648,6 +648,10 @@ static av_cold int omx_encode_init(AVCodecContext *avctx) OMX_BUFFERHEADERTYPE *buffer; OMX_ERRORTYPE err; + av_log(avctx, AV_LOG_WARNING, + "The %s encoder is deprecated and will be removed in future versions\n", + avctx->codec->name); + /* cleanup relies on the mutexes/conditions being initialized first. */ ret = ff_pthread_init(s, omx_codec_context_offsets); if (ret < 0) @@ -947,7 +951,7 @@ const FFCodec ff_mpeg4_omx_encoder = { .init = omx_encode_init, FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, - .p.pix_fmts = omx_encoder_pix_fmts, + CODEC_PIXFMTS_ARRAY(omx_encoder_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -969,7 +973,7 @@ const FFCodec ff_h264_omx_encoder = { .init = omx_encode_init, FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, - .p.pix_fmts = omx_encoder_pix_fmts, + CODEC_PIXFMTS_ARRAY(omx_encoder_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .p.capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c index 3badfae891..57bd5fd6d6 100644 --- a/libavcodec/on2avc.c +++ b/libavcodec/on2avc.c @@ -1023,6 +1023,5 @@ const FFCodec ff_on2avc_decoder = { .close = on2avc_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/options.c b/libavcodec/options.c index f60c41bdc3..834beb5757 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -69,7 +69,7 @@ static const AVClass *codec_child_class_iterate(void **iter) static AVClassCategory get_category(void *ptr) { AVCodecContext* avctx = ptr; - if (avctx->codec && av_codec_is_decoder(avctx->codec)) + if (avctx->codec && ff_codec_is_decoder(avctx->codec)) return AV_CLASS_CATEGORY_DECODER; else return AV_CLASS_CATEGORY_ENCODER; diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 47da41b0ad..25da169343 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -47,7 +47,7 @@ #define AV_CODEC_DEFAULT_BITRATE 200*1000 static const AVOption avcodec_options[] = { -{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT64_MAX, A|V|E}, +{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, (double)INT64_MAX, A|V|E}, {"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = 128*1000 }, 0, INT_MAX, A|E}, {"bt", "Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate tolerance specifies how far " "ratecontrol is willing to deviate from the target average bitrate value. This is not related " @@ -74,9 +74,6 @@ static const AVOption avcodec_options[] = { {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, .unit = "flags"}, {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, .unit = "flags"}, {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, .unit = "flags"}, -#if FF_API_DROPCHANGED -{"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D | AV_OPT_FLAG_DEPRECATED, .unit = "flags"}, -#endif {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D|S, .unit = "flags2"}, {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, .unit = "flags2"}, {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, .unit = "flags2"}, @@ -224,8 +221,8 @@ static const AVOption avcodec_options[] = { {"profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, {.i64 = AV_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.profile"}, {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.profile"}, {"main10", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, V|E, .unit = "avctx.profile"}, -{"level", "encoding level, usually corresponding to the profile level, codec-specific", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.level"}, -{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.level"}, +{"level", "encoding level, usually corresponding to the profile level, codec-specific", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = AV_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E|CC, .unit = "avctx.level"}, +{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, .unit = "avctx.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}, {"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, .unit = "cmp_func"}, {"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, .unit = "cmp_func"}, @@ -272,9 +269,6 @@ static const AVOption avcodec_options[] = { {"ch_layout", NULL, OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL }, 0, 0, A|E|D, .unit = "ch_layout"}, {"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0.0, FLT_MAX, V|E}, {"rc_min_vbv_use", NULL, OFFSET(rc_min_vbv_overflow_use), AV_OPT_TYPE_FLOAT, {.dbl = 3 }, 0.0, FLT_MAX, V|E}, -#if FF_API_TICKS_PER_FRAME -{"ticks_per_frame", NULL, OFFSET(ticks_per_frame), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, INT_MAX, A|V|E|D}, -#endif {"color_primaries", "color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_UNSPECIFIED }, 1, INT_MAX, V|E|D, .unit = "color_primaries_type"}, {"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT709 }, INT_MIN, INT_MAX, V|E|D, .unit = "color_primaries_type"}, {"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, .unit = "color_primaries_type"}, diff --git a/libavcodec/opus/dec.c b/libavcodec/opus/dec.c index 6c59dc1f46..29c490ae37 100644 --- a/libavcodec/opus/dec.c +++ b/libavcodec/opus/dec.c @@ -323,7 +323,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); - av_audio_fifo_drain(s->celt_delay, delay_samples); + av_audio_fifo_reset(s->celt_delay); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } @@ -393,9 +393,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size return samples; } -static int opus_decode_subpacket(OpusStreamContext *s, - const uint8_t *buf, int buf_size, - int nb_samples) +static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf) { int output_samples = 0; int flush_needed = 0; @@ -491,8 +489,9 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, OpusStreamContext *s = &c->streams[i]; s->out[0] = s->out[1] = NULL; + int fifo_samples = av_audio_fifo_size(s->sync_buffer); delayed_samples = FFMAX(delayed_samples, - s->delayed_samples + av_audio_fifo_size(s->sync_buffer)); + s->delayed_samples + fifo_samples); } /* decode the header of the first sub-packet to find out the sample count */ @@ -578,13 +577,15 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, s->silk_samplerate = get_silk_samplerate(s->packet.config); } - ret = opus_decode_subpacket(&c->streams[i], buf, s->packet.data_size, - coded_samples); + ret = opus_decode_subpacket(&c->streams[i], buf); if (ret < 0) return ret; s->decoded_samples = ret; decoded_samples = FFMIN(decoded_samples, ret); + if (!buf) + continue; + buf += s->packet.packet_size; buf_size -= s->packet.packet_size; } @@ -639,10 +640,10 @@ static av_cold void opus_decode_flush(AVCodecContext *ctx) memset(&s->packet, 0, sizeof(s->packet)); s->delayed_samples = 0; - av_audio_fifo_drain(s->celt_delay, av_audio_fifo_size(s->celt_delay)); + av_audio_fifo_reset(s->celt_delay); swr_close(s->swr); - av_audio_fifo_drain(s->sync_buffer, av_audio_fifo_size(s->sync_buffer)); + av_audio_fifo_reset(s->sync_buffer); ff_silk_flush(s->silk); ff_celt_flush(s->celt); diff --git a/libavcodec/opus/enc.c b/libavcodec/opus/enc.c index 5398263119..8d20b6c192 100644 --- a/libavcodec/opus/enc.c +++ b/libavcodec/opus/enc.c @@ -433,7 +433,7 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, if (f->silence) { if (f->framebits >= 16) - ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit singalling) */ + ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit signalling) */ for (int ch = 0; ch < s->channels; ch++) memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); return; @@ -746,9 +746,7 @@ const FFCodec ff_opus_encoder = { FF_CODEC_ENCODE_CB(opus_encode_frame), .close = opus_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.supported_samplerates = (const int []){ 48000, 0 }, - .p.ch_layouts = (const AVChannelLayout []){ AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/opus/parse.c b/libavcodec/opus/parse.c index 78a2a75fc7..687199b1bb 100644 --- a/libavcodec/opus/parse.c +++ b/libavcodec/opus/parse.c @@ -466,4 +466,3 @@ fail: av_channel_layout_uninit(&layout); return ret; } - diff --git a/libavcodec/opus/parser.c b/libavcodec/opus/parser.c index 41665e68f9..9bf0b31fba 100644 --- a/libavcodec/opus/parser.c +++ b/libavcodec/opus/parser.c @@ -78,6 +78,21 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le return buf + bytestream2_tell(&gb); } +static int set_frame_duration(AVCodecParserContext *ctx, AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + OpusParserContext *s = ctx->priv_data; + + if (ff_opus_parse_packet(&s->pkt, buf, buf_size, s->ctx.nb_streams > 1) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n"); + return AVERROR_INVALIDDATA; + } + + ctx->duration = s->pkt.frame_count * s->pkt.frame_duration; + + return 0; +} + /** * Find the end of the current frame in the bitstream. * @return the position of the first byte of the next frame, or -1 @@ -126,25 +141,12 @@ static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx, if (!s->ts_framing) payload_len = buf_size; - if (avctx->extradata && !s->extradata_parsed) { - ret = ff_opus_parse_extradata(avctx, &s->ctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n"); - return AVERROR_INVALIDDATA; - } - av_freep(&s->ctx.channel_maps); - s->extradata_parsed = 1; - } - if (payload_len <= buf_size && (!s->ts_framing || start_found)) { - ret = ff_opus_parse_packet(&s->pkt, payload, payload_len, s->ctx.nb_streams > 1); + ret = set_frame_duration(ctx, avctx, payload, payload_len); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n"); pc->frame_start_found = 0; return AVERROR_INVALIDDATA; } - - ctx->duration = s->pkt.frame_count * s->pkt.frame_duration; } if (s->ts_framing) { @@ -170,26 +172,45 @@ static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx, { OpusParserContext *s = ctx->priv_data; ParseContext *pc = &s->pc; - int next, header_len; + int next, header_len = 0; - next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len); + avctx->sample_rate = 48000; - if (s->ts_framing && next != AVERROR_INVALIDDATA && - ff_combine_frame(pc, next, &buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; + if (avctx->extradata && !s->extradata_parsed) { + if (ff_opus_parse_extradata(avctx, &s->ctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n"); + goto fail; + } + av_freep(&s->ctx.channel_maps); + s->extradata_parsed = 1; } - if (next == AVERROR_INVALIDDATA){ - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; + if (ctx->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + + if (set_frame_duration(ctx, avctx, buf, buf_size) < 0) + goto fail; + } else { + next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len); + + if (s->ts_framing && next != AVERROR_INVALIDDATA && + ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + goto fail; + } + + if (next == AVERROR_INVALIDDATA){ + goto fail; + } } *poutbuf = buf + header_len; *poutbuf_size = buf_size - header_len; return next; + +fail: + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; } const AVCodecParser ff_opus_parser = { diff --git a/libavcodec/opus/silk.c b/libavcodec/opus/silk.c index 97bb95037c..ffa2ec996b 100644 --- a/libavcodec/opus/silk.c +++ b/libavcodec/opus/silk.c @@ -844,8 +844,10 @@ int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc, } for (i = 0; i < nb_frames; i++) { - for (j = 0; j < coded_channels && !s->midonly; j++) - silk_decode_frame(s, rc, i, j, coded_channels, active[j][i], active[1][i], 0); + for (j = 0; j < coded_channels && !s->midonly; j++) { + int active1 = coded_channels > 1 ? active[1][i] : 0; + silk_decode_frame(s, rc, i, j, coded_channels, active[j][i], active1, 0); + } /* reset the side channel if it is not coded */ if (s->midonly && s->frame[1].coded) diff --git a/libavcodec/opus/tab.c b/libavcodec/opus/tab.c index e7d20d1688..5147b66b69 100644 --- a/libavcodec/opus/tab.c +++ b/libavcodec/opus/tab.c @@ -110,12 +110,8 @@ const uint16_t ff_silk_model_pitch_highbits[] = { 216, 224, 231, 237, 241, 243, 245, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 }; -const uint16_t ff_silk_model_pitch_lowbits_nb[] = { 256, 64, 128, 192, 256 }; - const uint16_t ff_silk_model_pitch_lowbits_mb[] = { 256, 43, 85, 128, 171, 213, 256 }; -const uint16_t ff_silk_model_pitch_lowbits_wb[] = { 256, 32, 64, 96, 128, 160, 192, 224, 256 }; - const uint16_t ff_silk_model_pitch_delta[] = { 256, 46, 48, 50, 53, 57, 63, 73, 88, 114, 152, 182, 204, 219, 229, 236, 242, 246, 250, 252, 254, 256 @@ -763,8 +759,6 @@ const uint16_t ff_celt_model_alloc_trim[] = { 128, 2, 4, 9, 19, 41, 87, 109, 119, 124, 126, 128 }; -const uint16_t ff_celt_model_energy_small[] = { 4, 2, 3, 4 }; - const uint8_t ff_celt_freq_bands[] = { /* in steps of 200Hz */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 }; @@ -1161,7 +1155,7 @@ const uint32_t * const ff_celt_pvq_u_row[15] = { }; /* Deemphasis constant (alpha_p), as specified in RFC6716 as 0.8500061035. - * libopus uses a slighly rounded constant, set to 0.85 exactly, + * libopus uses a slightly rounded constant, set to 0.85 exactly, * to simplify its fixed-point version, but it's not significant to impact * compliance. */ #define CELT_EMPH_COEFF 0.8500061035 diff --git a/libavcodec/opus/tab.h b/libavcodec/opus/tab.h index 109a422b9f..ac140d5868 100644 --- a/libavcodec/opus/tab.h +++ b/libavcodec/opus/tab.h @@ -53,9 +53,9 @@ extern const uint16_t ff_silk_model_lsf_s2_ext[]; extern const uint16_t ff_silk_model_lsf_interpolation_offset[]; extern const uint16_t ff_silk_model_pitch_highbits[]; -extern const uint16_t ff_silk_model_pitch_lowbits_nb[]; +#define ff_silk_model_pitch_lowbits_nb ff_silk_model_lcg_seed extern const uint16_t ff_silk_model_pitch_lowbits_mb[]; -extern const uint16_t ff_silk_model_pitch_lowbits_wb[]; +#define ff_silk_model_pitch_lowbits_wb ff_silk_model_gain_lowbits extern const uint16_t ff_silk_model_pitch_delta[]; extern const uint16_t ff_silk_model_pitch_contour_nb10ms[]; extern const uint16_t ff_silk_model_pitch_contour_nb20ms[]; @@ -124,7 +124,7 @@ extern const int ff_silk_stereo_interp_len[3]; extern const uint16_t ff_celt_model_tapset[]; extern const uint16_t ff_celt_model_spread[]; extern const uint16_t ff_celt_model_alloc_trim[]; -extern const uint16_t ff_celt_model_energy_small[]; +#define ff_celt_model_energy_small ff_celt_model_tapset extern const uint8_t ff_celt_freq_bands[]; extern const uint8_t ff_celt_freq_range[]; diff --git a/libavcodec/osq.c b/libavcodec/osq.c index 1bf6264699..76090aa8d0 100644 --- a/libavcodec/osq.c +++ b/libavcodec/osq.c @@ -146,10 +146,12 @@ static void reset_stats(OSQChannel *cb) static void update_stats(OSQChannel *cb, int val) { - cb->sum += FFABS(val) - cb->history[cb->pos]; - cb->history[cb->pos] = FFABS(val); + cb->sum += FFABS((int64_t)val) - cb->history[cb->pos]; + cb->history[cb->pos] = FFABS((int64_t)val); cb->pos++; cb->count++; + //NOTE for this to make sense count would need to be limited to FF_ARRAY_ELEMS(cb->history) + //Otherwise the average computation later makes no sense if (cb->pos >= FF_ARRAY_ELEMS(cb->history)) cb->pos = 0; } @@ -163,7 +165,8 @@ static int update_residue_parameter(OSQChannel *cb) if (!sum) return 0; x = sum / cb->count; - rice_k = ceil(log2(x)); + av_assert2(x <= 0x80000000U); + rice_k = av_ceil_log2(x); if (rice_k >= 30) { double f = floor(sum / 1.4426952 + 0.5); if (f <= 1) { @@ -190,7 +193,7 @@ static uint32_t get_urice(GetBitContext *gb, int k) static int32_t get_srice(GetBitContext *gb, int x) { - int32_t y = get_urice(gb, x); + uint32_t y = get_urice(gb, x); return get_bits1(gb) ? -y : y; } @@ -209,6 +212,8 @@ static int osq_channel_parameters(AVCodecContext *avctx, int ch) cb->residue_parameter = get_urice(gb, 4); if (!cb->residue_parameter || cb->residue_parameter >= 31) return AVERROR_INVALIDDATA; + if (cb->coding_mode == 2) + avpriv_request_sample(avctx, "coding mode 2"); } else if (cb->coding_mode == 3) { cb->residue_bits = get_urice(gb, 4); if (!cb->residue_bits || cb->residue_bits >= 31) @@ -300,7 +305,7 @@ static int do_decode(AVCodecContext *avctx, AVFrame *frame, int decorrelate, int dst[n] += (int)(P2 + P3) / 2 + (unsigned)p; break; case 8: - dst[n] += (int)(P2 + P3) / 2; + dst[n] += (int)(P2 + P3) / 2 + 0U; break; case 9: dst[n] += (int)(P2 * 2 + P3) / 3 + (unsigned)p; @@ -309,13 +314,13 @@ static int do_decode(AVCodecContext *avctx, AVFrame *frame, int decorrelate, int dst[n] += (int)(P2 + P3 * 2) / 3 + (unsigned)p; break; case 11: - dst[n] += (int)((unsigned)dst[A] + dst[B]) / 2; + dst[n] += (int)((unsigned)dst[A] + dst[B]) / 2 + 0U; break; case 12: dst[n] += (unsigned)dst[B]; break; case 13: - dst[n] += (int)(unsigned)(dst[D] + dst[B]) / 2; + dst[n] += (int)((unsigned)dst[D] + dst[B]) / 2 + 0U; break; case 14: dst[n] += (int)((unsigned)P2 + dst[A]) / 2 + (unsigned)p; @@ -489,9 +494,6 @@ const FFCodec ff_osq_decoder = { .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), .flush = osq_flush, }; diff --git a/libavcodec/packet.c b/libavcodec/packet.c index 381001fd65..2d1f282927 100644 --- a/libavcodec/packet.c +++ b/libavcodec/packet.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/avutil.h" +#include "libavutil/container_fifo.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" @@ -307,6 +308,8 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type) case AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM: return "IAMF Recon Gain Info Parameter Data"; case AV_PKT_DATA_FRAME_CROPPING: return "Frame Cropping"; case AV_PKT_DATA_LCEVC: return "LCEVC NAL data"; + case AV_PKT_DATA_3D_REFERENCE_DISPLAYS: return "3D Reference Displays Info"; + case AV_PKT_DATA_RTCP_SR: return "RTCP Sender Report"; } return NULL; } @@ -752,3 +755,35 @@ void av_packet_side_data_free(AVPacketSideData **psd, int *pnb_sd) av_freep(psd); *pnb_sd = 0; } + +static void *container_packet_alloc(void *opaque) +{ + return av_packet_alloc(); +} + +static void container_packet_reset(void *opaque, void *obj) +{ + av_packet_unref(obj); +} + +static void container_packet_free(void *opaque, void *obj) +{ + AVPacket *pkt = obj; + av_packet_free(&pkt); +} + +static int container_packet_transfer(void *opaque, void *dst, void *src, unsigned flags) +{ + if (flags & AV_CONTAINER_FIFO_FLAG_REF) + return av_packet_ref(dst, src); + + av_packet_move_ref(dst, src); + return 0; +} + +AVContainerFifo *av_container_fifo_alloc_avpacket(unsigned flags) +{ + return av_container_fifo_alloc(NULL, container_packet_alloc, + container_packet_reset, container_packet_free, + container_packet_transfer, 0); +} diff --git a/libavcodec/packet.h b/libavcodec/packet.h index 0a28010542..55389a957d 100644 --- a/libavcodec/packet.h +++ b/libavcodec/packet.h @@ -142,7 +142,7 @@ enum AVPacketSideDataType { AV_PKT_DATA_CPB_PROPERTIES, /** - * Recommmends skipping the specified number of samples + * Recommends skipping the specified number of samples * @code * u32le number of samples to skip from start of this packet * u32le number of samples to skip from end of this packet @@ -345,6 +345,23 @@ enum AVPacketSideDataType { */ AV_PKT_DATA_LCEVC, + /** + * This side data contains information about the reference display width(s) + * and reference viewing distance(s) as well as information about the + * corresponding reference stereo pair(s), i.e., the pair(s) of views to be + * displayed for the viewer's left and right eyes on the reference display + * at the reference viewing distance. + * The payload is the AV3DReferenceDisplaysInfo struct defined in + * libavutil/tdrdi.h. + */ + AV_PKT_DATA_3D_REFERENCE_DISPLAYS, + + /** + * Contains the last received RTCP SR (Sender Report) information + * in the form of the AVRTCPSenderReport struct. + */ + AV_PKT_DATA_RTCP_SR, + /** * The number of side data types. * This is not part of the public API/ABI in the sense that it may @@ -356,10 +373,6 @@ enum AVPacketSideDataType { AV_PKT_DATA_NB }; -#if FF_API_QUALITY_FACTOR -#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED -#endif - /** * This structure stores auxiliary information for decoding, presenting, or * otherwise processing the coded stream. It is typically exported by demuxers @@ -368,11 +381,11 @@ enum AVPacketSideDataType { * * Global side data is handled as follows: * - During demuxing, it may be exported through - * @ref AVStream.codecpar.side_data "AVStream's codec parameters", which can + * @ref AVCodecParameters.coded_side_data "AVStream's codec parameters", which can * then be passed as input to decoders through the * @ref AVCodecContext.coded_side_data "decoder context's side data", for * initialization. - * - For muxing, it can be fed through @ref AVStream.codecpar.side_data + * - For muxing, it can be fed through @ref AVCodecParameters.coded_side_data * "AVStream's codec parameters", typically the output of encoders through * the @ref AVCodecContext.coded_side_data "encoder context's side data", for * initialization. @@ -880,6 +893,13 @@ int av_packet_make_writable(AVPacket *pkt); */ void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); +/** + * Allocate an AVContainerFifo instance for AVPacket. + * + * @param flags currently unused + */ +struct AVContainerFifo *av_container_fifo_alloc_avpacket(unsigned flags); + /** * @} */ diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c index c17ae9ae4d..d8d6db5219 100644 --- a/libavcodec/pafvideo.c +++ b/libavcodec/pafvideo.c @@ -328,11 +328,6 @@ static int paf_video_decode(AVCodecContext *avctx, AVFrame *rframe, b = b << 2 | b >> 4; *out++ = (0xFFU << 24) | (r << 16) | (g << 8) | b; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - c->pic->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } c->dirty[c->current_frame] = 1; diff --git a/libavcodec/pamenc.c b/libavcodec/pamenc.c index 45ec29ccb3..e0c6eda235 100644 --- a/libavcodec/pamenc.c +++ b/libavcodec/pamenc.c @@ -135,11 +135,9 @@ const FFCodec ff_pam_encoder = { .p.id = AV_CODEC_ID_PAM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pam_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 5128009cd4..b12c48f79f 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -25,6 +25,7 @@ extern const AVCodecParser ff_aac_latm_parser; extern const AVCodecParser ff_ac3_parser; extern const AVCodecParser ff_adx_parser; extern const AVCodecParser ff_amr_parser; +extern const AVCodecParser ff_apv_parser; extern const AVCodecParser ff_av1_parser; extern const AVCodecParser ff_avs2_parser; extern const AVCodecParser ff_avs3_parser; @@ -35,6 +36,7 @@ extern const AVCodecParser ff_cri_parser; extern const AVCodecParser ff_dca_parser; extern const AVCodecParser ff_dirac_parser; extern const AVCodecParser ff_dnxhd_parser; +extern const AVCodecParser ff_dnxuc_parser; extern const AVCodecParser ff_dolby_e_parser; extern const AVCodecParser ff_dpx_parser; extern const AVCodecParser ff_dvaudio_parser; @@ -44,6 +46,7 @@ extern const AVCodecParser ff_dvd_nav_parser; extern const AVCodecParser ff_evc_parser; extern const AVCodecParser ff_flac_parser; extern const AVCodecParser ff_ftr_parser; +extern const AVCodecParser ff_ffv1_parser; extern const AVCodecParser ff_g723_1_parser; extern const AVCodecParser ff_g729_parser; extern const AVCodecParser ff_gif_parser; @@ -65,6 +68,7 @@ extern const AVCodecParser ff_mpegvideo_parser; extern const AVCodecParser ff_opus_parser; extern const AVCodecParser ff_png_parser; extern const AVCodecParser ff_pnm_parser; +extern const AVCodecParser ff_prores_raw_parser; extern const AVCodecParser ff_qoi_parser; extern const AVCodecParser ff_rv34_parser; extern const AVCodecParser ff_sbc_parser; diff --git a/libavcodec/pcm-bluray.c b/libavcodec/pcm-bluray.c index 235020d78f..e3f83e0b0f 100644 --- a/libavcodec/pcm-bluray.c +++ b/libavcodec/pcm-bluray.c @@ -307,7 +307,5 @@ const FFCodec ff_pcm_bluray_decoder = { .p.id = AV_CODEC_ID_PCM_BLURAY, FF_CODEC_DECODE_CB(pcm_bluray_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]){ - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/pcm-blurayenc.c b/libavcodec/pcm-blurayenc.c index 7147c804ad..006c16d2d1 100644 --- a/libavcodec/pcm-blurayenc.c +++ b/libavcodec/pcm-blurayenc.c @@ -278,20 +278,12 @@ const FFCodec ff_pcm_bluray_encoder = { .priv_data_size = sizeof(BlurayPCMEncContext), .init = pcm_bluray_encode_init, FF_CODEC_ENCODE_CB(pcm_bluray_encode_frame), - .p.supported_samplerates = (const int[]) { 48000, 96000, 192000, 0 }, - .p.ch_layouts = (const AVChannelLayout[]) { - AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_SURROUND, - AV_CHANNEL_LAYOUT_2_1, - AV_CHANNEL_LAYOUT_4POINT0, - AV_CHANNEL_LAYOUT_2_2, - AV_CHANNEL_LAYOUT_5POINT0, - AV_CHANNEL_LAYOUT_5POINT1, - AV_CHANNEL_LAYOUT_7POINT0, - AV_CHANNEL_LAYOUT_7POINT1, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000, 96000, 192000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_SURROUND, AV_CHANNEL_LAYOUT_2_1, + AV_CHANNEL_LAYOUT_4POINT0, AV_CHANNEL_LAYOUT_2_2, + AV_CHANNEL_LAYOUT_5POINT0, AV_CHANNEL_LAYOUT_5POINT1, + AV_CHANNEL_LAYOUT_7POINT0, AV_CHANNEL_LAYOUT_7POINT1), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/pcm-dvd.c b/libavcodec/pcm-dvd.c index 319746c62e..06389a21af 100644 --- a/libavcodec/pcm-dvd.c +++ b/libavcodec/pcm-dvd.c @@ -305,7 +305,5 @@ const FFCodec ff_pcm_dvd_decoder = { FF_CODEC_DECODE_CB(pcm_dvd_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE - }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/pcm-dvdenc.c b/libavcodec/pcm-dvdenc.c index 71e9b6915a..a740f0e381 100644 --- a/libavcodec/pcm-dvdenc.c +++ b/libavcodec/pcm-dvdenc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "avcodec.h" #include "bytestream.h" @@ -45,7 +46,7 @@ static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx) freq = 1; break; default: - av_assert1(0); + av_unreachable("Already checked via CODEC_SAMPLERATES"); } switch (avctx->sample_fmt) { @@ -58,7 +59,7 @@ static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx) quant = 2; break; default: - av_assert1(0); + av_unreachable("Already checked via CODEC_SAMPLEFMTS"); } avctx->bits_per_coded_sample = 16 + quant * 4; @@ -181,13 +182,8 @@ const FFCodec ff_pcm_dvd_encoder = { .priv_data_size = sizeof(PCMDVDContext), .init = pcm_dvd_encode_init, FF_CODEC_ENCODE_CB(pcm_dvd_encode_frame), - .p.supported_samplerates = (const int[]) { 48000, 96000, 0}, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - AV_CHANNEL_LAYOUT_5POINT1, - AV_CHANNEL_LAYOUT_7POINT1, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLERATES(48000, 96000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_5POINT1, AV_CHANNEL_LAYOUT_7POINT1), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c index a51086a92d..68b1945194 100644 --- a/libavcodec/pcm.c +++ b/libavcodec/pcm.c @@ -243,51 +243,108 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } typedef struct PCMDecode { - short table[256]; + int sample_size; +} PCMDecode; + +static av_cold av_unused int pcm_decode_init(AVCodecContext *avctx) +{ + PCMDecode *s = avctx->priv_data; + static const struct { + enum AVCodecID codec_id; + int8_t sample_fmt; + uint8_t sample_size; + uint8_t bits_per_sample; + } codec_id_to_samplefmt[] = { + #define ENTRY(CODEC_ID, SAMPLE_FMT, BITS_PER_SAMPLE) \ + { AV_CODEC_ID_PCM_ ## CODEC_ID, AV_SAMPLE_FMT_ ## SAMPLE_FMT, \ + BITS_PER_SAMPLE / 8, BITS_PER_SAMPLE } + ENTRY(S8, U8, 8), ENTRY(S8_PLANAR, U8P, 8), + ENTRY(S16BE, S16, 16), ENTRY(S16BE_PLANAR, S16P, 16), + ENTRY(S16LE, S16, 16), ENTRY(S16LE_PLANAR, S16P, 16), + ENTRY(S24DAUD, S16, 24), ENTRY(S24BE, S32, 24), + ENTRY(S24LE, S32, 24), ENTRY(S24LE_PLANAR, S32P, 24), + ENTRY(S32BE, S32, 32), ENTRY(S32LE, S32, 32), + ENTRY(S32LE_PLANAR, S32P, 32), + ENTRY(S64BE, S64, 64), ENTRY(S64LE, S64, 64), + ENTRY(SGA, U8, 8), ENTRY(U8, U8, 8), + ENTRY(U16BE, S16, 16), ENTRY(U16LE, S16, 16), + ENTRY(U24BE, S32, 24), ENTRY(U24LE, S32, 24), + ENTRY(U32BE, S32, 32), ENTRY(U32LE, S32, 32), + ENTRY(F32BE, FLT, 32), ENTRY(F32LE, FLT, 32), + ENTRY(F64BE, DBL, 64), ENTRY(F64LE, DBL, 64), + { .codec_id = AV_CODEC_ID_PCM_LXF, .sample_fmt = AV_SAMPLE_FMT_S32P, .sample_size = 5 }, + }; + + for (unsigned i = 0; i < FF_ARRAY_ELEMS(codec_id_to_samplefmt); ++i) { + if (codec_id_to_samplefmt[i].codec_id == avctx->codec_id) { + s->sample_size = codec_id_to_samplefmt[i].sample_size; + avctx->sample_fmt = codec_id_to_samplefmt[i].sample_fmt; + if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) + avctx->bits_per_raw_sample = codec_id_to_samplefmt[i].bits_per_sample; + break; + } + av_assert1(i + 1 < FF_ARRAY_ELEMS(codec_id_to_samplefmt)); + } + + return 0; +} + +typedef struct PCMScaleDecode { + PCMDecode base; void (*vector_fmul_scalar)(float *dst, const float *src, float mul, int len); float scale; -} PCMDecode; +} PCMScaleDecode; -static av_cold int pcm_decode_init(AVCodecContext *avctx) +static av_cold av_unused int pcm_scale_decode_init(AVCodecContext *avctx) { - PCMDecode *s = avctx->priv_data; + PCMScaleDecode *s = avctx->priv_data; AVFloatDSPContext *fdsp; - int i; + + avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + s->base.sample_size = 4; + + if (avctx->bits_per_coded_sample < 1 || avctx->bits_per_coded_sample > 24) + return AVERROR_INVALIDDATA; + + s->scale = 1. / (1 << (avctx->bits_per_coded_sample - 1)); + fdsp = avpriv_float_dsp_alloc(0); + if (!fdsp) + return AVERROR(ENOMEM); + s->vector_fmul_scalar = fdsp->vector_fmul_scalar; + av_free(fdsp); + + return 0; +} + +typedef struct PCMLUTDecode { + PCMDecode base; + int16_t table[256]; +} PCMLUTDecode; + +static av_cold av_unused int pcm_lut_decode_init(AVCodecContext *avctx) +{ + PCMLUTDecode *s = avctx->priv_data; switch (avctx->codec_id) { + default: + av_unreachable("pcm_lut_decode_init() only used with alaw, mulaw and vidc"); case AV_CODEC_ID_PCM_ALAW: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = alaw2linear(i); break; case AV_CODEC_ID_PCM_MULAW: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = ulaw2linear(i); break; case AV_CODEC_ID_PCM_VIDC: - for (i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) s->table[i] = vidc2linear(i); break; - case AV_CODEC_ID_PCM_F16LE: - case AV_CODEC_ID_PCM_F24LE: - if (avctx->bits_per_coded_sample < 1 || avctx->bits_per_coded_sample > 24) - return AVERROR_INVALIDDATA; - - s->scale = 1. / (1 << (avctx->bits_per_coded_sample - 1)); - fdsp = avpriv_float_dsp_alloc(0); - if (!fdsp) - return AVERROR(ENOMEM); - s->vector_fmul_scalar = fdsp->vector_fmul_scalar; - av_free(fdsp); - break; - default: - break; } - avctx->sample_fmt = avctx->codec->sample_fmts[0]; - - if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) - avctx->bits_per_raw_sample = av_get_bits_per_sample(avctx->codec_id); + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + s->base.sample_size = 1; return 0; } @@ -328,23 +385,15 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, int buf_size = avpkt->size; PCMDecode *s = avctx->priv_data; int channels = avctx->ch_layout.nb_channels; - int sample_size, c, n, ret, samples_per_block; + int sample_size = s->sample_size; + int c, n, ret, samples_per_block; uint8_t *samples; int32_t *dst_int32_t; - sample_size = av_get_bits_per_sample(avctx->codec_id) / 8; - - /* av_get_bits_per_sample returns 0 for AV_CODEC_ID_PCM_DVD */ samples_per_block = 1; if (avctx->codec_id == AV_CODEC_ID_PCM_LXF) { /* we process 40-bit blocks per channel for LXF */ samples_per_block = 2; - sample_size = 5; - } - - if (sample_size == 0) { - av_log(avctx, AV_LOG_ERROR, "Invalid sample_size\n"); - return AVERROR(EINVAL); } if (channels == 0) { @@ -500,12 +549,14 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, break; case AV_CODEC_ID_PCM_ALAW: case AV_CODEC_ID_PCM_MULAW: - case AV_CODEC_ID_PCM_VIDC: - for (; n > 0; n--) { - AV_WN16A(samples, s->table[*src++]); - samples += 2; - } + case AV_CODEC_ID_PCM_VIDC: { + const int16_t *const lut = ((PCMLUTDecode*)avctx->priv_data)->table; + int16_t *restrict samples_16 = (int16_t*)samples; + + for (; n > 0; n--) + *samples_16++ = lut[*src++]; break; + } case AV_CODEC_ID_PCM_LXF: { int i; @@ -536,9 +587,10 @@ static int pcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avctx->codec_id == AV_CODEC_ID_PCM_F16LE || avctx->codec_id == AV_CODEC_ID_PCM_F24LE) { - s->vector_fmul_scalar((float *)frame->extended_data[0], - (const float *)frame->extended_data[0], - s->scale, FFALIGN(frame->nb_samples * avctx->ch_layout.nb_channels, 4)); + PCMScaleDecode *s2 = avctx->priv_data; + s2->vector_fmul_scalar((float *)frame->extended_data[0], + (const float *)frame->extended_data[0], + s2->scale, FFALIGN(frame->nb_samples * avctx->ch_layout.nb_channels, 4)); } *got_frame_ptr = 1; @@ -552,13 +604,12 @@ const FFCodec ff_ ## name_ ## _encoder = { \ .p.name = #name_, \ CODEC_LONG_NAME(long_name_), \ .p.type = AVMEDIA_TYPE_AUDIO, \ - .p.id = AV_CODEC_ID_ ## id_, \ + .p.id = id_, \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | \ AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, \ .init = pcm_encode_init, \ FF_CODEC_ENCODE_CB(pcm_encode_frame), \ - .p.sample_fmts = (const enum AVSampleFormat[]){ sample_fmt_, \ - AV_SAMPLE_FMT_NONE }, \ + CODEC_SAMPLEFMTS(sample_fmt_), \ } #define PCM_ENCODER_2(cf, id, sample_fmt, name, long_name) \ @@ -566,65 +617,76 @@ const FFCodec ff_ ## name_ ## _encoder = { \ #define PCM_ENCODER_3(cf, id, sample_fmt, name, long_name) \ PCM_ENCODER_2(cf, id, sample_fmt, name, long_name) #define PCM_ENCODER(id, sample_fmt, name, long_name) \ - PCM_ENCODER_3(CONFIG_ ## id ## _ENCODER, id, sample_fmt, name, long_name) + PCM_ENCODER_3(CONFIG_PCM_ ## id ## _ENCODER, AV_CODEC_ID_PCM_ ## id, \ + AV_SAMPLE_FMT_ ## sample_fmt, pcm_ ## name, long_name) -#define PCM_DECODER_0(id, sample_fmt, name, long_name) -#define PCM_DECODER_1(id_, sample_fmt_, name_, long_name_) \ +#define PCM_DECODER_0(id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DECODER_1(id_, sample_fmt, name_, long_name, Context, init_func)\ const FFCodec ff_ ## name_ ## _decoder = { \ .p.name = #name_, \ - CODEC_LONG_NAME(long_name_), \ + CODEC_LONG_NAME(long_name), \ .p.type = AVMEDIA_TYPE_AUDIO, \ - .p.id = AV_CODEC_ID_ ## id_, \ - .priv_data_size = sizeof(PCMDecode), \ - .init = pcm_decode_init, \ + .p.id = id_, \ + .priv_data_size = sizeof(Context), \ + .init = init_func, \ FF_CODEC_DECODE_CB(pcm_decode_frame), \ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE, \ - .p.sample_fmts = (const enum AVSampleFormat[]){ sample_fmt_, \ - AV_SAMPLE_FMT_NONE }, \ } -#define PCM_DECODER_2(cf, id, sample_fmt, name, long_name) \ - PCM_DECODER_ ## cf(id, sample_fmt, name, long_name) -#define PCM_DECODER_3(cf, id, sample_fmt, name, long_name) \ - PCM_DECODER_2(cf, id, sample_fmt, name, long_name) -#define PCM_DECODER(id, sample_fmt, name, long_name) \ - PCM_DECODER_3(CONFIG_ ## id ## _DECODER, id, sample_fmt, name, long_name) +#define PCM_DECODER_2(cf, id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_ ## cf(id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DECODER_3(cf, id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_2(cf, id, sample_fmt, name, long_name, Context, init_func) +#define PCM_DEC_EXT(id, sample_fmt, name, long_name, Context, init_func) \ + PCM_DECODER_3(CONFIG_PCM_ ## id ## _DECODER, AV_CODEC_ID_PCM_ ## id, \ + AV_SAMPLE_FMT_ ## sample_fmt, pcm_ ## name, long_name, \ + Context, init_func) + +#define PCM_DECODER(id, sample_fmt, name, long_name) \ + PCM_DEC_EXT(id, sample_fmt, name, long_name, PCMDecode, pcm_decode_init) #define PCM_CODEC(id, sample_fmt_, name, long_name_) \ PCM_ENCODER(id, sample_fmt_, name, long_name_); \ PCM_DECODER(id, sample_fmt_, name, long_name_) -/* Note: Do not forget to add new entries to the Makefile as well. */ -PCM_CODEC (PCM_ALAW, AV_SAMPLE_FMT_S16, pcm_alaw, "PCM A-law / G.711 A-law"); -PCM_DECODER(PCM_F16LE, AV_SAMPLE_FMT_FLT, pcm_f16le, "PCM 16.8 floating point little-endian"); -PCM_DECODER(PCM_F24LE, AV_SAMPLE_FMT_FLT, pcm_f24le, "PCM 24.0 floating point little-endian"); -PCM_CODEC (PCM_F32BE, AV_SAMPLE_FMT_FLT, pcm_f32be, "PCM 32-bit floating point big-endian"); -PCM_CODEC (PCM_F32LE, AV_SAMPLE_FMT_FLT, pcm_f32le, "PCM 32-bit floating point little-endian"); -PCM_CODEC (PCM_F64BE, AV_SAMPLE_FMT_DBL, pcm_f64be, "PCM 64-bit floating point big-endian"); -PCM_CODEC (PCM_F64LE, AV_SAMPLE_FMT_DBL, pcm_f64le, "PCM 64-bit floating point little-endian"); -PCM_DECODER(PCM_LXF, AV_SAMPLE_FMT_S32P,pcm_lxf, "PCM signed 20-bit little-endian planar"); -PCM_CODEC (PCM_MULAW, AV_SAMPLE_FMT_S16, pcm_mulaw, "PCM mu-law / G.711 mu-law"); -PCM_CODEC (PCM_S8, AV_SAMPLE_FMT_U8, pcm_s8, "PCM signed 8-bit"); -PCM_CODEC (PCM_S8_PLANAR, AV_SAMPLE_FMT_U8P, pcm_s8_planar, "PCM signed 8-bit planar"); -PCM_CODEC (PCM_S16BE, AV_SAMPLE_FMT_S16, pcm_s16be, "PCM signed 16-bit big-endian"); -PCM_CODEC (PCM_S16BE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16be_planar, "PCM signed 16-bit big-endian planar"); -PCM_CODEC (PCM_S16LE, AV_SAMPLE_FMT_S16, pcm_s16le, "PCM signed 16-bit little-endian"); -PCM_CODEC (PCM_S16LE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16le_planar, "PCM signed 16-bit little-endian planar"); -PCM_CODEC (PCM_S24BE, AV_SAMPLE_FMT_S32, pcm_s24be, "PCM signed 24-bit big-endian"); -PCM_CODEC (PCM_S24DAUD, AV_SAMPLE_FMT_S16, pcm_s24daud, "PCM D-Cinema audio signed 24-bit"); -PCM_CODEC (PCM_S24LE, AV_SAMPLE_FMT_S32, pcm_s24le, "PCM signed 24-bit little-endian"); -PCM_CODEC (PCM_S24LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s24le_planar, "PCM signed 24-bit little-endian planar"); -PCM_CODEC (PCM_S32BE, AV_SAMPLE_FMT_S32, pcm_s32be, "PCM signed 32-bit big-endian"); -PCM_CODEC (PCM_S32LE, AV_SAMPLE_FMT_S32, pcm_s32le, "PCM signed 32-bit little-endian"); -PCM_CODEC (PCM_S32LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s32le_planar, "PCM signed 32-bit little-endian planar"); -PCM_CODEC (PCM_U8, AV_SAMPLE_FMT_U8, pcm_u8, "PCM unsigned 8-bit"); -PCM_CODEC (PCM_U16BE, AV_SAMPLE_FMT_S16, pcm_u16be, "PCM unsigned 16-bit big-endian"); -PCM_CODEC (PCM_U16LE, AV_SAMPLE_FMT_S16, pcm_u16le, "PCM unsigned 16-bit little-endian"); -PCM_CODEC (PCM_U24BE, AV_SAMPLE_FMT_S32, pcm_u24be, "PCM unsigned 24-bit big-endian"); -PCM_CODEC (PCM_U24LE, AV_SAMPLE_FMT_S32, pcm_u24le, "PCM unsigned 24-bit little-endian"); -PCM_CODEC (PCM_U32BE, AV_SAMPLE_FMT_S32, pcm_u32be, "PCM unsigned 32-bit big-endian"); -PCM_CODEC (PCM_U32LE, AV_SAMPLE_FMT_S32, pcm_u32le, "PCM unsigned 32-bit little-endian"); -PCM_CODEC (PCM_S64BE, AV_SAMPLE_FMT_S64, pcm_s64be, "PCM signed 64-bit big-endian"); -PCM_CODEC (PCM_S64LE, AV_SAMPLE_FMT_S64, pcm_s64le, "PCM signed 64-bit little-endian"); -PCM_CODEC (PCM_VIDC, AV_SAMPLE_FMT_S16, pcm_vidc, "PCM Archimedes VIDC"); -PCM_DECODER(PCM_SGA, AV_SAMPLE_FMT_U8, pcm_sga, "PCM SGA"); +#define PCM_CODEC_EXT(id, sample_fmt, name, long_name, DecContext, dec_init_func) \ + PCM_DEC_EXT(id, sample_fmt, name, long_name, DecContext, dec_init_func); \ + PCM_ENCODER(id, sample_fmt, name, long_name) + +/* Note: Do not forget to add new entries to the Makefile and + * to the table in pcm_decode_init() as well. */ +// AV_CODEC_ID_* pcm_* name +// AV_SAMPLE_FMT_* long name DecodeContext decode init func +PCM_CODEC_EXT(ALAW, S16, alaw, "PCM A-law / G.711 A-law", PCMLUTDecode, pcm_lut_decode_init); +PCM_DEC_EXT (F16LE, FLT, f16le, "PCM 16.8 floating point little-endian", PCMScaleDecode, pcm_scale_decode_init); +PCM_DEC_EXT (F24LE, FLT, f24le, "PCM 24.0 floating point little-endian", PCMScaleDecode, pcm_scale_decode_init); +PCM_CODEC (F32BE, FLT, f32be, "PCM 32-bit floating point big-endian"); +PCM_CODEC (F32LE, FLT, f32le, "PCM 32-bit floating point little-endian"); +PCM_CODEC (F64BE, DBL, f64be, "PCM 64-bit floating point big-endian"); +PCM_CODEC (F64LE, DBL, f64le, "PCM 64-bit floating point little-endian"); +PCM_DECODER (LXF, S32P,lxf, "PCM signed 20-bit little-endian planar"); +PCM_CODEC_EXT(MULAW, S16, mulaw, "PCM mu-law / G.711 mu-law", PCMLUTDecode, pcm_lut_decode_init); +PCM_CODEC (S8, U8, s8, "PCM signed 8-bit"); +PCM_CODEC (S8_PLANAR, U8P, s8_planar, "PCM signed 8-bit planar"); +PCM_CODEC (S16BE, S16, s16be, "PCM signed 16-bit big-endian"); +PCM_CODEC (S16BE_PLANAR, S16P,s16be_planar, "PCM signed 16-bit big-endian planar"); +PCM_CODEC (S16LE, S16, s16le, "PCM signed 16-bit little-endian"); +PCM_CODEC (S16LE_PLANAR, S16P,s16le_planar, "PCM signed 16-bit little-endian planar"); +PCM_CODEC (S24BE, S32, s24be, "PCM signed 24-bit big-endian"); +PCM_CODEC (S24DAUD, S16, s24daud, "PCM D-Cinema audio signed 24-bit"); +PCM_CODEC (S24LE, S32, s24le, "PCM signed 24-bit little-endian"); +PCM_CODEC (S24LE_PLANAR, S32P,s24le_planar, "PCM signed 24-bit little-endian planar"); +PCM_CODEC (S32BE, S32, s32be, "PCM signed 32-bit big-endian"); +PCM_CODEC (S32LE, S32, s32le, "PCM signed 32-bit little-endian"); +PCM_CODEC (S32LE_PLANAR, S32P,s32le_planar, "PCM signed 32-bit little-endian planar"); +PCM_CODEC (U8, U8, u8, "PCM unsigned 8-bit"); +PCM_CODEC (U16BE, S16, u16be, "PCM unsigned 16-bit big-endian"); +PCM_CODEC (U16LE, S16, u16le, "PCM unsigned 16-bit little-endian"); +PCM_CODEC (U24BE, S32, u24be, "PCM unsigned 24-bit big-endian"); +PCM_CODEC (U24LE, S32, u24le, "PCM unsigned 24-bit little-endian"); +PCM_CODEC (U32BE, S32, u32be, "PCM unsigned 32-bit big-endian"); +PCM_CODEC (U32LE, S32, u32le, "PCM unsigned 32-bit little-endian"); +PCM_CODEC (S64BE, S64, s64be, "PCM signed 64-bit big-endian"); +PCM_CODEC (S64LE, S64, s64le, "PCM signed 64-bit little-endian"); +PCM_CODEC_EXT(VIDC, S16, vidc, "PCM Archimedes VIDC", PCMLUTDecode, pcm_lut_decode_init); +PCM_DECODER (SGA, U8, sga, "PCM SGA"); diff --git a/libavcodec/pcxenc.c b/libavcodec/pcxenc.c index b763c7df47..f450d7bca1 100644 --- a/libavcodec/pcxenc.c +++ b/libavcodec/pcxenc.c @@ -199,11 +199,9 @@ const FFCodec ff_pcx_encoder = { .p.id = AV_CODEC_ID_PCX, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pcx_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, + AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, + AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c index d93bcf1b6a..20583c9afa 100644 --- a/libavcodec/pgssubdec.c +++ b/libavcodec/pgssubdec.c @@ -447,7 +447,7 @@ static int parse_presentation_segment(AVCodecContext *avctx, PGSSubObjectRef *const object = &ctx->presentation.objects[i]; if (buf_end - buf < 8) { - av_log(avctx, AV_LOG_ERROR, "Insufficent space for object\n"); + av_log(avctx, AV_LOG_ERROR, "Insufficient space for object\n"); ctx->presentation.object_count = i; return AVERROR_INVALIDDATA; } diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c index 845a882454..428bc150a9 100644 --- a/libavcodec/pictordec.c +++ b/libavcodec/pictordec.c @@ -172,7 +172,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, 1 byte run (=0) 2 bytes run 1 byte val - thats 5 bytes and the maximum run we can code is 65535 + that's 5 bytes and the maximum run we can code is 65535 The RLE decoder can exit prematurly but it does not on any image available Based on this the formula is assumed correct for undamaged images. @@ -192,11 +192,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; memset(frame->data[0], 0, s->height * frame->linesize[0]); frame->pict_type = AV_PICTURE_TYPE_I; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pos_after_pal = bytestream2_tell(&s->g) + esize; palette = (uint32_t*)frame->data[1]; diff --git a/libavcodec/pixblockdsp.c b/libavcodec/pixblockdsp.c index 1fff244511..110a374260 100644 --- a/libavcodec/pixblockdsp.c +++ b/libavcodec/pixblockdsp.c @@ -21,7 +21,6 @@ #include "config.h" #include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" -#include "avcodec.h" #include "pixblockdsp.h" static void get_pixels_16_c(int16_t *restrict block, const uint8_t *pixels, @@ -85,40 +84,33 @@ static void diff_pixels_c(int16_t *restrict block, const uint8_t *s1, } } -av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx) +av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, int bits_per_raw_sample) { - av_unused const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8; + const unsigned high_bit_depth = bits_per_raw_sample > 8 && + bits_per_raw_sample <= 16; c->diff_pixels_unaligned = c->diff_pixels = diff_pixels_c; - switch (avctx->bits_per_raw_sample) { - case 9: - case 10: - case 12: - case 14: + if (high_bit_depth) { c->get_pixels_unaligned = get_pixels_unaligned_16_c; - c->get_pixels = get_pixels_16_c; - break; - default: - if (avctx->bits_per_raw_sample<=8 || avctx->codec_type != AVMEDIA_TYPE_VIDEO) { - c->get_pixels_unaligned = - c->get_pixels = get_pixels_8_c; - } - break; + c->get_pixels = get_pixels_16_c; + } else { + c->get_pixels_unaligned = + c->get_pixels = get_pixels_8_c; } #if ARCH_AARCH64 - ff_pixblockdsp_init_aarch64(c, avctx, high_bit_depth); + ff_pixblockdsp_init_aarch64(c, high_bit_depth); #elif ARCH_ARM - ff_pixblockdsp_init_arm(c, avctx, high_bit_depth); + ff_pixblockdsp_init_arm(c, high_bit_depth); #elif ARCH_PPC - ff_pixblockdsp_init_ppc(c, avctx, high_bit_depth); + ff_pixblockdsp_init_ppc(c, high_bit_depth); #elif ARCH_RISCV - ff_pixblockdsp_init_riscv(c, avctx, high_bit_depth); + ff_pixblockdsp_init_riscv(c, high_bit_depth); #elif ARCH_X86 - ff_pixblockdsp_init_x86(c, avctx, high_bit_depth); + ff_pixblockdsp_init_x86(c, high_bit_depth); #elif ARCH_MIPS - ff_pixblockdsp_init_mips(c, avctx, high_bit_depth); + ff_pixblockdsp_init_mips(c, high_bit_depth); #endif } diff --git a/libavcodec/pixblockdsp.h b/libavcodec/pixblockdsp.h index cac5f3d4a2..d493d0e22b 100644 --- a/libavcodec/pixblockdsp.h +++ b/libavcodec/pixblockdsp.h @@ -19,13 +19,17 @@ #ifndef AVCODEC_PIXBLOCKDSP_H #define AVCODEC_PIXBLOCKDSP_H +#include #include -#include "avcodec.h" +#define PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED \ + !(ARCH_ARM || ARCH_MIPS || ARCH_PPC || ARCH_RISCV) typedef struct PixblockDSPContext { void (*get_pixels)(int16_t *restrict block /* align 16 */, - const uint8_t *pixels /* align 8 */, + /* align 16 for > 8 bits; align 8 for <= 8 bits + * (or 1 if PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED is set) */ + const uint8_t *pixels, ptrdiff_t stride); void (*get_pixels_unaligned)(int16_t *restrict block /* align 16 */, const uint8_t *pixels, @@ -41,20 +45,18 @@ typedef struct PixblockDSPContext { } PixblockDSPContext; -void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx); -void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init(PixblockDSPContext *c, int bits_per_raw_sample); +void ff_pixblockdsp_init_aarch64(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_alpha(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_arm(PixblockDSPContext *c, + unsigned high_bit_depth); +void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, + unsigned high_bit_depth); +void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_arm(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_x86(PixblockDSPContext *c, unsigned high_bit_depth); -void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_x86(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, +void ff_pixblockdsp_init_mips(PixblockDSPContext *c, unsigned high_bit_depth); #endif /* AVCODEC_PIXBLOCKDSP_H */ diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index c5b32c166d..b9c997ab0e 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -757,7 +757,7 @@ static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame) if (clli) { /* * 0.0001 divisor value - * see: https://www.w3.org/TR/png-3/#cLLi-chunk + * see: https://www.w3.org/TR/png-3/#cLLI-chunk */ clli->MaxCLL = s->clli_max / 10000; clli->MaxFALL = s->clli_avg / 10000; @@ -1073,6 +1073,7 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, { int bits = 0; int channels; + int remainder = bytestream2_get_bytes_left(gb); if (!(s->hdr_state & PNG_IHDR)) { av_log(avctx, AV_LOG_ERROR, "sBIT before IHDR\n"); @@ -1080,16 +1081,17 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, } if (s->pic_state & PNG_IDAT) { - av_log(avctx, AV_LOG_ERROR, "sBIT after IDAT\n"); - return AVERROR_INVALIDDATA; + av_log(avctx, AV_LOG_WARNING, "Ignoring illegal sBIT chunk after IDAT\n"); + return 0; } channels = s->color_type & PNG_COLOR_MASK_PALETTE ? 3 : ff_png_get_nb_channels(s->color_type); - if (bytestream2_get_bytes_left(gb) != channels) { - av_log(avctx, AV_LOG_ERROR, "Invalid sBIT size: %d, expected: %d\n", - bytestream2_get_bytes_left(gb), channels); - return AVERROR_INVALIDDATA; + if (remainder != channels) { + av_log(avctx, AV_LOG_WARNING, "Invalid sBIT size: %d, expected: %d\n", remainder, channels); + /* not enough space left in chunk to read info */ + if (remainder < channels) + return 0; } for (int i = 0; i < channels; i++) { @@ -1098,8 +1100,8 @@ static int decode_sbit_chunk(AVCodecContext *avctx, PNGDecContext *s, } if (bits <= 0 || bits > (s->color_type & PNG_COLOR_MASK_PALETTE ? 8 : s->bit_depth)) { - av_log(avctx, AV_LOG_ERROR, "Invalid significant bits: %d\n", bits); - return AVERROR_INVALIDDATA; + av_log(avctx, AV_LOG_WARNING, "Invalid significant bits: %d\n", bits); + return 0; } s->significant_bits = bits; @@ -1566,18 +1568,20 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, break; } - case MKTAG('c', 'L', 'L', 'i'): + case MKTAG('c', 'L', 'L', 'i'): /* legacy spelling, for backwards compat */ + case MKTAG('c', 'L', 'L', 'I'): if (bytestream2_get_bytes_left(&gb_chunk) != 8) { - av_log(avctx, AV_LOG_WARNING, "Invalid cLLi chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); + av_log(avctx, AV_LOG_WARNING, "Invalid cLLI chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); break; } s->have_clli = 1; s->clli_max = bytestream2_get_be32u(&gb_chunk); s->clli_avg = bytestream2_get_be32u(&gb_chunk); break; - case MKTAG('m', 'D', 'C', 'v'): + case MKTAG('m', 'D', 'C', 'v'): /* legacy spelling, for backward compat */ + case MKTAG('m', 'D', 'C', 'V'): if (bytestream2_get_bytes_left(&gb_chunk) != 24) { - av_log(avctx, AV_LOG_WARNING, "Invalid mDCv chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); + av_log(avctx, AV_LOG_WARNING, "Invalid mDCV chunk size: %d\n", bytestream2_get_bytes_left(&gb_chunk)); break; } s->have_mdcv = 1; diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index cb79c04e11..9bbb8267cf 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -445,7 +445,7 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) AVContentLightMetadata *clli = (AVContentLightMetadata *) side_data->data; AV_WB32(s->buf, clli->MaxCLL * 10000); AV_WB32(s->buf + 4, clli->MaxFALL * 10000); - png_write_chunk(&s->bytestream, MKTAG('c', 'L', 'L', 'i'), s->buf, 8); + png_write_chunk(&s->bytestream, MKTAG('c', 'L', 'L', 'I'), s->buf, 8); } side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); @@ -460,7 +460,7 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) AV_WB16(s->buf + 14, PNG_Q2D(mdcv->white_point[1], 50000)); AV_WB32(s->buf + 16, PNG_Q2D(mdcv->max_luminance, 10000)); AV_WB32(s->buf + 20, PNG_Q2D(mdcv->min_luminance, 10000)); - png_write_chunk(&s->bytestream, MKTAG('m', 'D', 'C', 'v'), s->buf, 24); + png_write_chunk(&s->bytestream, MKTAG('m', 'D', 'C', 'V'), s->buf, 24); } } @@ -1205,7 +1205,7 @@ static av_cold int png_enc_close(AVCodecContext *avctx) static const AVOption options[] = { {"dpi", "Set image resolution (in dots per inch)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE}, {"dpm", "Set image resolution (in dots per meter)", OFFSET(dpm), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE}, - { "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_NONE }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, .unit = "pred" }, + { "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_PAETH }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, .unit = "pred" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_NONE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "sub", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_SUB }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "up", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_UP }, INT_MIN, INT_MAX, VE, .unit = "pred" }, @@ -1233,14 +1233,12 @@ const FFCodec ff_png_encoder = { .init = png_enc_init, .close = png_enc_close, FF_CODEC_ENCODE_CB(encode_png), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, + AV_PIX_FMT_MONOBLACK), .p.priv_class = &pngenc_class, .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; @@ -1256,14 +1254,11 @@ const FFCodec ff_apng_encoder = { .init = png_enc_init, .close = png_enc_close, FF_CODEC_ENCODE_CB(encode_apng), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, + AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE), .p.priv_class = &pngenc_class, .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; diff --git a/libavcodec/pnmdec.c b/libavcodec/pnmdec.c index 59013ada49..68bb7a41ec 100644 --- a/libavcodec/pnmdec.c +++ b/libavcodec/pnmdec.c @@ -22,6 +22,7 @@ #include "config_components.h" #include "libavutil/half2float.h" +#include "libavutil/intfloat.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/pnmenc.c b/libavcodec/pnmenc.c index 9e1b11382b..8f67fe0a3b 100644 --- a/libavcodec/pnmenc.c +++ b/libavcodec/pnmenc.c @@ -25,6 +25,7 @@ #include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "libavutil/float2half.h" +#include "libavutil/intfloat.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -231,9 +232,7 @@ const FFCodec ff_pgm_encoder = { .p.id = AV_CODEC_ID_PGM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE), }; #endif @@ -245,9 +244,7 @@ const FFCodec ff_pgmyuv_encoder = { .p.id = AV_CODEC_ID_PGMYUV, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE), }; #endif @@ -259,9 +256,7 @@ const FFCodec ff_ppm_encoder = { .p.id = AV_CODEC_ID_PPM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE), }; #endif @@ -273,8 +268,7 @@ const FFCodec ff_pbm_encoder = { .p.id = AV_CODEC_ID_PBM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), }; #endif @@ -286,11 +280,8 @@ const FFCodec ff_pfm_encoder = { .p.id = AV_CODEC_ID_PFM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32LE, - AV_PIX_FMT_GRAYF32LE, - AV_PIX_FMT_GBRPF32BE, - AV_PIX_FMT_GRAYF32BE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32LE, AV_PIX_FMT_GRAYF32LE, + AV_PIX_FMT_GBRPF32BE, AV_PIX_FMT_GRAYF32BE), }; #endif @@ -313,8 +304,6 @@ const FFCodec ff_phm_encoder = { .priv_data_size = sizeof(PHMEncContext), .init = phm_enc_init, FF_CODEC_ENCODE_CB(pnm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32, - AV_PIX_FMT_GRAYF32, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GRAYF32), }; #endif diff --git a/libavcodec/ppc/Makefile b/libavcodec/ppc/Makefile index 10b9ca60da..cbd9621e05 100644 --- a/libavcodec/ppc/Makefile +++ b/libavcodec/ppc/Makefile @@ -12,7 +12,7 @@ OBJS-$(CONFIG_LLVIDDSP) += ppc/lossless_videodsp_altivec.o OBJS-$(CONFIG_ME_CMP) += ppc/me_cmp.o OBJS-$(CONFIG_MPEGAUDIODSP) += ppc/mpegaudiodsp_altivec.o OBJS-$(CONFIG_MPEGVIDEO) += ppc/mpegvideo_altivec.o -OBJS-$(CONFIG_MPEGVIDEOENC) += ppc/mpegvideoencdsp.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += ppc/mpegvideoencdsp.o OBJS-$(CONFIG_PIXBLOCKDSP) += ppc/pixblockdsp.o OBJS-$(CONFIG_VC1DSP) += ppc/vc1dsp_altivec.o OBJS-$(CONFIG_VIDEODSP) += ppc/videodsp.o diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c index 4bf6b28ed6..d8cf7518d5 100644 --- a/libavcodec/ppc/hpeldsp_altivec.c +++ b/libavcodec/ppc/hpeldsp_altivec.c @@ -46,7 +46,7 @@ void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li register ptrdiff_t line_size_4 = line_size * (1 << 2); // hand-unrolling the loop by 4 gains about 15% -// mininum execution time goes from 74 to 60 cycles +// minimum execution time goes from 74 to 60 cycles // it's faster than -funroll-loops, but using // -funroll-loops w/ this is bad - 74 cycles again. // all this is on a 7450, tuning for the 7450 diff --git a/libavcodec/ppc/me_cmp.c b/libavcodec/ppc/me_cmp.c index 90f21525d7..764e30da2a 100644 --- a/libavcodec/ppc/me_cmp.c +++ b/libavcodec/ppc/me_cmp.c @@ -51,7 +51,7 @@ iv = vec_vsx_ld(1, pix);\ } #endif -static int sad16_x2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_x2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -91,7 +91,7 @@ static int sad16_x2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_ return s; } -static int sad16_y2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_y2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -141,7 +141,7 @@ static int sad16_y2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_ return s; } -static int sad16_xy2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_xy2_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -230,7 +230,7 @@ static int sad16_xy2_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8 return s; } -static int sad16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad16_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -265,7 +265,7 @@ static int sad16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int sad8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sad8_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -309,7 +309,7 @@ static int sad8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *p /* Sum of Squared Errors for an 8x8 block, AltiVec-enhanced. * It's the sad8_altivec code above w/ squaring added. */ -static int sse8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse8_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -354,7 +354,7 @@ static int sse8_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *p /* Sum of Squared Errors for a 16x16 block, AltiVec-enhanced. * It's the sad16_altivec code above w/ squaring added. */ -static int sse16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +static int sse16_altivec(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int i; @@ -392,7 +392,7 @@ static int sse16_altivec(MpegEncContext *v, const uint8_t *pix1, const uint8_t * return s; } -static int hadamard8_diff8x8_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff8x8_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int __attribute__((aligned(16))) sum; @@ -518,7 +518,7 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, const uint8_t *dst, * On the 970, the hand-made RA is still a win (around 690 vs. around 780), * but xlc goes to around 660 on the regular C code... */ -static int hadamard8_diff16x8_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff16x8_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int __attribute__((aligned(16))) sum; @@ -709,7 +709,7 @@ static int hadamard8_diff16x8_altivec(MpegEncContext *s, const uint8_t *dst, return sum; } -static int hadamard8_diff16_altivec(MpegEncContext *s, const uint8_t *dst, +static int hadamard8_diff16_altivec(MPVEncContext *s, const uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h) { int score = hadamard8_diff16x8_altivec(s, dst, src, stride, 8); diff --git a/libavcodec/ppc/mpegvideo_altivec.c b/libavcodec/ppc/mpegvideo_altivec.c index bcb59ba845..26e98acfb8 100644 --- a/libavcodec/ppc/mpegvideo_altivec.c +++ b/libavcodec/ppc/mpegvideo_altivec.c @@ -27,12 +27,14 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/mem_internal.h" #include "libavutil/ppc/cpu.h" #include "libavutil/ppc/util_altivec.h" #include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideo_unquantize.h" #if HAVE_ALTIVEC @@ -41,7 +43,7 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, int16_t *block, int n, int qscale) { - int i, level, qmul, qadd; + int i, qmul, qadd; int nCoeffs; qadd = (qscale - 1) | 1; @@ -56,11 +58,14 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, }else qadd = 0; i = 1; - nCoeffs= 63; //does not always use zigzag table + if (s->ac_pred) + nCoeffs = 63; + else + nCoeffs = s->intra_scantable.raster_end[s->block_last_index[n]]; } else { i = 0; av_assert2(s->block_last_index[n]>=0); - nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + nCoeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; } { @@ -70,7 +75,6 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, register vector signed short blockv, qmulv, qaddv, nqaddv, temp1; register vector bool short blockv_null, blockv_neg; register short backup_0 = block[0]; - register int j = 0; qmulv = vec_splat((vec_s16)vec_lde(0, &qmul8), 0); qaddv = vec_splat((vec_s16)vec_lde(0, &qadd8), 0); @@ -78,7 +82,7 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, // vectorize all the 16 bytes-aligned blocks // of 8 elements - for(; (j + 7) <= nCoeffs ; j+=8) { + for (register int j = 0; j <= nCoeffs ; j += 8) { blockv = vec_ld(j << 1, block); blockv_neg = vec_cmplt(blockv, vczero); blockv_null = vec_cmpeq(blockv, vczero); @@ -91,22 +95,6 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, vec_st(blockv, j << 1, block); } - // if nCoeffs isn't a multiple of 8, finish the job - // using good old scalar units. - // (we could do it using a truncated vector, - // but I'm not sure it's worth the hassle) - for(; j <= nCoeffs ; j++) { - level = block[j]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[j] = level; - } - } - if (i == 1) { // cheat. this avoid special-casing the first iteration block[0] = backup_0; @@ -116,16 +104,13 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s, #endif /* HAVE_ALTIVEC */ -av_cold void ff_mpv_common_init_ppc(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_ppc(MPVUnquantDSPContext *s, int bitexact) { #if HAVE_ALTIVEC if (!PPC_ALTIVEC(av_get_cpu_flags())) return; - if ((s->avctx->dct_algo == FF_DCT_AUTO) || - (s->avctx->dct_algo == FF_DCT_ALTIVEC)) { - s->dct_unquantize_h263_intra = dct_unquantize_h263_altivec; - s->dct_unquantize_h263_inter = dct_unquantize_h263_altivec; - } + s->dct_unquantize_h263_intra = dct_unquantize_h263_altivec; + s->dct_unquantize_h263_inter = dct_unquantize_h263_altivec; #endif /* HAVE_ALTIVEC */ } diff --git a/libavcodec/ppc/pixblockdsp.c b/libavcodec/ppc/pixblockdsp.c index 01d14b4124..75287b1e85 100644 --- a/libavcodec/ppc/pixblockdsp.c +++ b/libavcodec/ppc/pixblockdsp.c @@ -27,7 +27,6 @@ #include "libavutil/ppc/cpu.h" #include "libavutil/ppc/util_altivec.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" #if HAVE_ALTIVEC @@ -263,7 +262,6 @@ static void diff_pixels_vsx(int16_t *restrict block, const uint8_t *s1, #endif /* HAVE_VSX */ av_cold void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { #if HAVE_ALTIVEC diff --git a/libavcodec/ppc/svq1enc_altivec.c b/libavcodec/ppc/svq1enc_altivec.c index 5721bede34..78c79a68dc 100644 --- a/libavcodec/ppc/svq1enc_altivec.c +++ b/libavcodec/ppc/svq1enc_altivec.c @@ -29,7 +29,7 @@ #include "libavcodec/svq1encdsp.h" -#if HAVE_ALTIVEC +#if HAVE_ALTIVEC && HAVE_BIGENDIAN static int ssd_int8_vs_int16_altivec(const int8_t *pix1, const int16_t *pix2, intptr_t size) { @@ -69,14 +69,14 @@ static int ssd_int8_vs_int16_altivec(const int8_t *pix1, const int16_t *pix2, return u.score[3]; } -#endif /* HAVE_ALTIVEC */ +#endif /* HAVE_ALTIVEC && HAVE_BIGENDIAN */ av_cold void ff_svq1enc_init_ppc(SVQ1EncDSPContext *c) { -#if HAVE_ALTIVEC +#if HAVE_ALTIVEC && HAVE_BIGENDIAN if (!PPC_ALTIVEC(av_get_cpu_flags())) return; c->ssd_int8_vs_int16 = ssd_int8_vs_int16_altivec; -#endif /* HAVE_ALTIVEC */ +#endif /* HAVE_ALTIVEC && HAVE_BIGENDIAN */ } diff --git a/libavcodec/ppc/vp8dsp_altivec.c b/libavcodec/ppc/vp8dsp_altivec.c index 061914fc38..9d637af00b 100644 --- a/libavcodec/ppc/vp8dsp_altivec.c +++ b/libavcodec/ppc/vp8dsp_altivec.c @@ -312,7 +312,7 @@ static void put_vp8_pixels16_altivec(uint8_t *dst, ptrdiff_t dstride, const uint perm = vec_lvsl(0, src); #endif // hand-unrolling the loop by 4 gains about 15% -// mininum execution time goes from 74 to 60 cycles +// minimum execution time goes from 74 to 60 cycles // it's faster than -funroll-loops, but using // -funroll-loops w/ this is bad - 74 cycles again. // all this is on a 7450, tuning for the 7450 diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c index 3cef82be3b..1b67870c43 100644 --- a/libavcodec/profiles.c +++ b/libavcodec/profiles.c @@ -182,6 +182,12 @@ const AVProfile ff_prores_profiles[] = { { AV_PROFILE_UNKNOWN } }; +const AVProfile ff_prores_raw_profiles[] = { + { AV_PROFILE_PRORES_RAW, "RAW" }, + { AV_PROFILE_PRORES_RAW_HQ, "RAW HQ" }, + { AV_PROFILE_UNKNOWN } +}; + const AVProfile ff_mjpeg_profiles[] = { { AV_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, "Baseline" }, { AV_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT, "Sequential" }, @@ -203,4 +209,15 @@ const AVProfile ff_evc_profiles[] = { { AV_PROFILE_UNKNOWN }, }; +const AVProfile ff_apv_profiles[] = { + { AV_PROFILE_APV_422_10, "422-10" }, + { AV_PROFILE_APV_422_12, "422-12" }, + { AV_PROFILE_APV_444_10, "444-10" }, + { AV_PROFILE_APV_444_12, "444-12" }, + { AV_PROFILE_APV_4444_10, "4444-10" }, + { AV_PROFILE_APV_4444_12, "4444-12" }, + { AV_PROFILE_APV_400_10, "400-10" }, + { AV_PROFILE_UNKNOWN }, +}; + #endif /* !CONFIG_SMALL */ diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h index 33b7ffc17a..6f4011ff0c 100644 --- a/libavcodec/profiles.h +++ b/libavcodec/profiles.h @@ -74,8 +74,10 @@ extern const AVProfile ff_vp9_profiles[]; extern const AVProfile ff_av1_profiles[]; extern const AVProfile ff_sbc_profiles[]; extern const AVProfile ff_prores_profiles[]; +extern const AVProfile ff_prores_raw_profiles[]; extern const AVProfile ff_mjpeg_profiles[]; extern const AVProfile ff_arib_caption_profiles[]; extern const AVProfile ff_evc_profiles[]; +extern const AVProfile ff_apv_profiles[]; #endif /* AVCODEC_PROFILES_H */ diff --git a/libavcodec/progressframe.h b/libavcodec/progressframe.h index 32a345beec..e3cb83c5b4 100644 --- a/libavcodec/progressframe.h +++ b/libavcodec/progressframe.h @@ -102,10 +102,9 @@ void ff_progress_frame_report(ProgressFrame *f, int progress); void ff_progress_frame_await(const ProgressFrame *f, int progress); /** - * This function allocates ProgressFrame.f - * May be called before ff_progress_frame_get_buffer() in the cases where the - * AVFrame needs to be accessed before the ff_thread_get_buffer() call in - * ff_progress_frame_alloc(). + * This function sets up the ProgressFrame, i.e. ProgressFrame.f + * and ProgressFrame.progress. ProgressFrame.f will be blank + * (as if from av_frame_alloc() or av_frame_unref()) on success. * * @note: This must only be called by codecs with the * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. @@ -113,8 +112,7 @@ void ff_progress_frame_await(const ProgressFrame *f, int progress); int ff_progress_frame_alloc(struct AVCodecContext *avctx, ProgressFrame *f); /** - * This function sets up the ProgressFrame, i.e. allocates ProgressFrame.f - * if needed, and also calls ff_thread_get_buffer() on the frame. + * Wrapper around ff_progress_frame_alloc() and ff_thread_get_buffer(). * * @note: This must only be called by codecs with the * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c new file mode 100644 index 0000000000..b2aa97ddda --- /dev/null +++ b/libavcodec/prores_raw.c @@ -0,0 +1,537 @@ +/* + * ProRes RAW decoder + * Copyright (c) 2023-2025 Paul B Mahol + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/mem_internal.h" +#include "libavutil/mem.h" + +#define CACHED_BITSTREAM_READER !ARCH_X86_32 + +#include "config_components.h" +#include "avcodec.h" +#include "bytestream.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "idctdsp.h" +#include "proresdata.h" +#include "thread.h" +#include "hwconfig.h" +#include "hwaccel_internal.h" + +#include "prores_raw.h" + +static av_cold int decode_init(AVCodecContext *avctx) +{ + ProResRAWContext *s = avctx->priv_data; + uint8_t idct_permutation[64]; + + avctx->bits_per_raw_sample = 12; + avctx->color_primaries = AVCOL_PRI_UNSPECIFIED; + avctx->color_trc = AVCOL_TRC_UNSPECIFIED; + avctx->colorspace = AVCOL_SPC_UNSPECIFIED; + + s->pix_fmt = AV_PIX_FMT_NONE; + + ff_blockdsp_init(&s->bdsp); + ff_proresdsp_init(&s->prodsp, avctx->bits_per_raw_sample); + + ff_init_scantable_permutation(idct_permutation, + s->prodsp.idct_permutation_type); + + ff_permute_scantable(s->scan, ff_prores_interlaced_scan, idct_permutation); + + return 0; +} + +static int16_t get_value(GetBitContext *gb, int16_t codebook) +{ + const int16_t switch_bits = codebook >> 8; + const int16_t rice_order = codebook & 0xf; + const int16_t exp_order = (codebook >> 4) & 0xf; + int16_t q, bits; + + uint32_t b = show_bits_long(gb, 32); + if (!b) + return 0; + q = ff_clz(b); + + if (b & 0x80000000) { + skip_bits_long(gb, 1 + rice_order); + return (b & 0x7FFFFFFF) >> (31 - rice_order); + } + + if (q <= switch_bits) { + skip_bits_long(gb, 1 + rice_order + q); + return (q << rice_order) + + (((b << (q + 1)) >> 1) >> (31 - rice_order)); + } + + bits = exp_order + (q << 1) - switch_bits; + skip_bits_long(gb, bits); + return (b >> (32 - bits)) + + ((switch_bits + 1) << rice_order) - + (1 << exp_order); +} + +#define TODCCODEBOOK(x) ((x + 1) >> 1) + +static const uint8_t align_tile_w[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, +}; + +#define DC_CB_MAX 12 +const uint8_t ff_prores_raw_dc_cb[DC_CB_MAX + 1] = { + 16, 33, 50, 51, 51, 51, 68, 68, 68, 68, 68, 68, 118, +}; + +#define AC_CB_MAX 94 +const int16_t ff_prores_raw_ac_cb[AC_CB_MAX + 1] = { + 0, 529, 273, 273, 546, 546, 546, 290, 290, 290, 563, 563, + 563, 563, 563, 563, 563, 563, 307, 307, 580, 580, 580, 580, + 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, + 580, 580, 580, 580, 580, 580, 853, 853, 853, 853, 853, 853, + 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, + 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, + 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, + 853, 853, 853, 853, 853, 853, 853, 853, 853, 853, 358 +}; + +#define RN_CB_MAX 27 +const int16_t ff_prores_raw_rn_cb[RN_CB_MAX + 1] = { + 512, 256, 0, 0, 529, 529, 273, 273, 17, 17, 33, 33, 546, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 50, 50, 68, +}; + +#define LN_CB_MAX 14 +const int16_t ff_prores_raw_ln_cb[LN_CB_MAX + 1] = { + 256, 273, 546, 546, 290, 290, 1075, 1075, 563, 563, 563, 563, 563, 563, 51 +}; + +static int decode_comp(AVCodecContext *avctx, TileContext *tile, + AVFrame *frame, const uint8_t *data, int size, + int component, int16_t *qmat) +{ + int ret; + ProResRAWContext *s = avctx->priv_data; + const ptrdiff_t linesize = frame->linesize[0] >> 1; + uint16_t *dst = (uint16_t *)(frame->data[0] + tile->y*frame->linesize[0] + 2*tile->x); + + int idx; + const int w = FFMIN(s->tw, avctx->width - tile->x) / 2; + const int nb_blocks = w / 8; + const int log2_nb_blocks = 31 - ff_clz(nb_blocks); + const int block_mask = (1 << log2_nb_blocks) - 1; + const int nb_codes = 64 * nb_blocks; + + LOCAL_ALIGNED_32(int16_t, block, [64*16]); + + int16_t sign = 0; + int16_t dc_add = 0; + int16_t dc_codebook; + + int16_t ac, rn, ln; + int16_t ac_codebook = 49; + int16_t rn_codebook = 0; + int16_t ln_codebook = 66; + + const uint8_t *scan = s->scan; + GetBitContext gb; + + if (component > 1) + dst += linesize; + dst += component & 1; + + if ((ret = init_get_bits8(&gb, data, size)) < 0) + return ret; + + for (int n = 0; n < nb_blocks; n++) + s->bdsp.clear_block(block + n*64); + + /* Special handling for first block */ + int dc = get_value(&gb, 700); + int prev_dc = (dc >> 1) ^ -(dc & 1); + block[0] = (((dc&1) + (dc>>1) ^ -(int)(dc & 1)) + (dc & 1)) + 1; + + for (int n = 1; n < nb_blocks; n++) { + if (get_bits_left(&gb) <= 0) + break; + + if ((n & 15) == 1) + dc_codebook = 100; + else + dc_codebook = ff_prores_raw_dc_cb[FFMIN(TODCCODEBOOK(dc), DC_CB_MAX)]; + + dc = get_value(&gb, dc_codebook); + + sign = sign ^ dc & 1; + dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign; + sign = dc_add < 0; + prev_dc += dc_add; + + block[n*64] = prev_dc + 1; + } + + for (int n = nb_blocks; n <= nb_codes;) { + if (get_bits_left(&gb) <= 0) + break; + + ln = get_value(&gb, ln_codebook); + + for (int i = 0; i < ln; i++) { + if (get_bits_left(&gb) <= 0) + break; + + if ((n + i) >= nb_codes) + break; + + ac = get_value(&gb, ac_codebook); + ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)]; + sign = -get_bits1(&gb); + + idx = scan[(n + i) >> log2_nb_blocks] + (((n + i) & block_mask) << 6); + block[idx] = ((ac + 1) ^ sign) - sign; + } + + n += ln; + if (n >= nb_codes) + break; + + rn = get_value(&gb, rn_codebook); + rn_codebook = ff_prores_raw_rn_cb[FFMIN(rn, RN_CB_MAX)]; + + n += rn + 1; + if (n >= nb_codes) + break; + + if (get_bits_left(&gb) <= 0) + break; + + ac = get_value(&gb, ac_codebook); + sign = -get_bits1(&gb); + + idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6); + block[idx] = ((ac + 1) ^ sign) - sign; + + ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)]; + ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)]; + + n++; + } + + for (int n = 0; n < nb_blocks; n++) { + uint16_t *ptr = dst + n*16; + s->prodsp.idct_put_bayer(ptr, linesize, block + n*64, qmat); + } + + return 0; +} + +static int decode_tile(AVCodecContext *avctx, TileContext *tile, + AVFrame *frame) +{ + int ret; + ProResRAWContext *s = avctx->priv_data; + + GetByteContext *gb = &tile->gb; + LOCAL_ALIGNED_32(int16_t, qmat, [64]); + + if (tile->x >= avctx->width) + return 0; + + /* Tile header */ + int header_len = bytestream2_get_byteu(gb) >> 3; + int16_t scale = bytestream2_get_byteu(gb); + + int size[4]; + size[0] = bytestream2_get_be16(gb); + size[1] = bytestream2_get_be16(gb); + size[2] = bytestream2_get_be16(gb); + size[3] = bytestream2_size(gb) - size[0] - size[1] - size[2] - header_len; + if (size[3] < 0) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < 64; i++) + qmat[i] = s->qmat[i] * scale >> 1; + + const uint8_t *comp_start = gb->buffer_start + header_len; + + ret = decode_comp(avctx, tile, frame, comp_start, + size[0], 2, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0], + size[1], 1, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1], + size[2], 3, qmat); + if (ret < 0) + goto fail; + + ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1] + size[2], + size[3], 0, qmat); + if (ret < 0) + goto fail; + + return 0; +fail: + av_log(avctx, AV_LOG_ERROR, "tile %d/%d decoding error\n", tile->x, tile->y); + return ret; +} + +static int decode_tiles(AVCodecContext *avctx, void *arg, + int n, int thread_nb) +{ + ProResRAWContext *s = avctx->priv_data; + TileContext *tile = &s->tiles[n]; + AVFrame *frame = arg; + + return decode_tile(avctx, tile, frame); +} + +static enum AVPixelFormat get_pixel_format(AVCodecContext *avctx, + enum AVPixelFormat pix_fmt) +{ + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + AV_PIX_FMT_VULKAN, +#endif + pix_fmt, + AV_PIX_FMT_NONE, + }; + + return ff_get_format(avctx, pix_fmts); +} + +static int decode_frame(AVCodecContext *avctx, + AVFrame *frame, int *got_frame_ptr, + AVPacket *avpkt) +{ + int ret; + ProResRAWContext *s = avctx->priv_data; + DECLARE_ALIGNED(32, uint8_t, qmat)[64]; + memset(qmat, 1, 64); + + GetByteContext gb; + bytestream2_init(&gb, avpkt->data, avpkt->size); + if (bytestream2_get_be32(&gb) != avpkt->size) + return AVERROR_INVALIDDATA; + + /* ProRes RAW frame */ + if (bytestream2_get_le32(&gb) != MKTAG('p','r','r','f')) + return AVERROR_INVALIDDATA; + + int header_len = bytestream2_get_be16(&gb); + if (header_len < 62) + return AVERROR_INVALIDDATA; + + GetByteContext gb_hdr; + bytestream2_init(&gb_hdr, gb.buffer, header_len - 2); + bytestream2_skip(&gb, header_len - 2); + + bytestream2_skip(&gb_hdr, 1); + s->version = bytestream2_get_byte(&gb_hdr); + if (s->version > 1) { + avpriv_request_sample(avctx, "Version %d", s->version); + return AVERROR_PATCHWELCOME; + } + + /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */ + bytestream2_skip(&gb_hdr, 4); + + /* Width and height must always be even */ + int w = bytestream2_get_be16(&gb_hdr); + int h = bytestream2_get_be16(&gb_hdr); + if ((w & 1) || (h & 1)) + return AVERROR_INVALIDDATA; + + if (w != avctx->width || h != avctx->height) { + av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n", + avctx->width, avctx->height, w, h); + if ((ret = ff_set_dimensions(avctx, w, h)) < 0) + return ret; + } + + avctx->coded_width = FFALIGN(w, 16); + avctx->coded_height = FFALIGN(h, 16); + + enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16; + if (pix_fmt != s->pix_fmt) { + s->pix_fmt = pix_fmt; + + ret = get_pixel_format(avctx, pix_fmt); + if (ret < 0) + return ret; + + avctx->pix_fmt = ret; + } + + bytestream2_skip(&gb_hdr, 1 * 4); + bytestream2_skip(&gb_hdr, 2); /* & 0x3 */ + bytestream2_skip(&gb_hdr, 2); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 4 * 3 * 3); + bytestream2_skip(&gb_hdr, 4); + bytestream2_skip(&gb_hdr, 2); + + /* Flags */ + int flags = bytestream2_get_be16(&gb_hdr); + int align = (flags >> 1) & 0x7; + + /* Quantization matrix */ + if (flags & 1) + bytestream2_get_buffer(&gb_hdr, qmat, 64); + + if ((flags >> 4) & 1) { + bytestream2_skip(&gb_hdr, 2); + bytestream2_skip(&gb_hdr, 2 * 7); + } + + ff_permute_scantable(s->qmat, s->prodsp.idct_permutation, qmat); + + s->nb_tw = (w + 15) >> 4; + s->nb_th = (h + 15) >> 4; + s->nb_tw = (s->nb_tw >> align) + align_tile_w[~(-1 * (1 << align)) & s->nb_tw]; + s->nb_tiles = s->nb_tw * s->nb_th; + av_log(avctx, AV_LOG_DEBUG, "%dx%d | nb_tiles: %d\n", s->nb_tw, s->nb_th, s->nb_tiles); + + s->tw = s->version == 0 ? 128 : 256; + s->th = 16; + av_log(avctx, AV_LOG_DEBUG, "tile_size: %dx%d\n", s->tw, s->th); + + av_fast_mallocz(&s->tiles, &s->tiles_size, s->nb_tiles * sizeof(*s->tiles)); + if (!s->tiles) + return AVERROR(ENOMEM); + + if (bytestream2_get_bytes_left(&gb) < s->nb_tiles * 2) + return AVERROR_INVALIDDATA; + + /* Read tile data offsets */ + int offset = bytestream2_tell(&gb) + s->nb_tiles * 2; + for (int n = 0; n < s->nb_tiles; n++) { + TileContext *tile = &s->tiles[n]; + + int size = bytestream2_get_be16(&gb); + if (offset >= avpkt->size) + return AVERROR_INVALIDDATA; + if (size >= avpkt->size) + return AVERROR_INVALIDDATA; + if (offset > avpkt->size - size) + return AVERROR_INVALIDDATA; + + bytestream2_init(&tile->gb, avpkt->data + offset, size); + + tile->y = (n / s->nb_tw) * s->th; + tile->x = (n % s->nb_tw) * s->tw; + + offset += size; + } + + ret = ff_thread_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + s->frame = frame; + + /* Start */ + if (avctx->hwaccel) { + const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); + + ret = ff_hwaccel_frame_priv_alloc(avctx, &s->hwaccel_picture_private); + if (ret < 0) + return ret; + + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); + if (ret < 0) + return ret; + + for (int n = 0; n < s->nb_tiles; n++) { + TileContext *tile = &s->tiles[n]; + ret = hwaccel->decode_slice(avctx, tile->gb.buffer, + tile->gb.buffer_end - tile->gb.buffer); + if (ret < 0) + return ret; + } + + ret = hwaccel->end_frame(avctx); + if (ret < 0) + return ret; + + av_refstruct_unref(&s->hwaccel_picture_private); + } else { + avctx->execute2(avctx, decode_tiles, frame, NULL, s->nb_tiles); + } + + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int decode_end(AVCodecContext *avctx) +{ + ProResRAWContext *s = avctx->priv_data; + av_refstruct_unref(&s->hwaccel_picture_private); + av_freep(&s->tiles); + return 0; +} + +#if HAVE_THREADS +static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) +{ + ProResRAWContext *rsrc = src->priv_data; + ProResRAWContext *rdst = dst->priv_data; + + rdst->pix_fmt = rsrc->pix_fmt; + + return 0; +} +#endif + +const FFCodec ff_prores_raw_decoder = { + .p.name = "prores_raw", + CODEC_LONG_NAME("Apple ProRes RAW"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES_RAW, + .priv_data_size = sizeof(ProResRAWContext), + .init = decode_init, + .close = decode_end, + FF_CODEC_DECODE_CB(decode_frame), + UPDATE_THREAD_CONTEXT(update_thread_context), + .p.capabilities = AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_FRAME_THREADS | + AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + HWACCEL_VULKAN(prores_raw), +#endif + NULL + }, +}; diff --git a/libavcodec/prores_raw.h b/libavcodec/prores_raw.h new file mode 100644 index 0000000000..3ac8068dd5 --- /dev/null +++ b/libavcodec/prores_raw.h @@ -0,0 +1,63 @@ +/* + * ProRes RAW decoder + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_PRORES_RAW_H +#define AVCODEC_PRORES_RAW_H + +#include "libavutil/frame.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixfmt.h" + +#include "bytestream.h" +#include "blockdsp.h" +#include "proresdsp.h" + +typedef struct TileContext { + GetByteContext gb; + unsigned x, y; +} TileContext; + +typedef struct ProResRAWContext { + ProresDSPContext prodsp; + BlockDSPContext bdsp; + + TileContext *tiles; + unsigned int tiles_size; + int nb_tiles; + int tw, th; + int nb_tw, nb_th; + + enum AVPixelFormat pix_fmt; + AVFrame *frame; + void *hwaccel_picture_private; + + int version; + + DECLARE_ALIGNED(32, uint8_t, scan)[64]; + DECLARE_ALIGNED(32, uint8_t, qmat)[64]; +} ProResRAWContext; + +extern const uint8_t ff_prores_raw_dc_cb[13]; +extern const int16_t ff_prores_raw_ac_cb[95]; +extern const int16_t ff_prores_raw_rn_cb[28]; +extern const int16_t ff_prores_raw_ln_cb[15]; + +#endif /* AVCODEC_PRORES_RAW_H */ diff --git a/libavcodec/prores_raw_parser.c b/libavcodec/prores_raw_parser.c new file mode 100644 index 0000000000..fca3ec37fb --- /dev/null +++ b/libavcodec/prores_raw_parser.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" +#include "bytestream.h" + +static int prores_raw_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + GetByteContext gb; + + switch (avctx->codec_tag) { + case 0: + break; + case MKTAG('a','p','r','n'): + avctx->profile = AV_PROFILE_PRORES_RAW; + break; + case MKTAG('a','p','r','h'): + avctx->profile = AV_PROFILE_PRORES_RAW_HQ; + break; + default: + avpriv_request_sample(avctx, "Profile %d", avctx->codec_tag); + return buf_size; + break; + } + + bytestream2_init(&gb, buf, buf_size); + if (bytestream2_get_be32(&gb) != buf_size) /* Packet size */ + return buf_size; + + if (bytestream2_get_le32(&gb) != MKTAG('p','r','r','f')) /* Frame header */ + return buf_size; + + int header_size = bytestream2_get_be16(&gb); + if (header_size < 62) + return buf_size; + + bytestream2_skip(&gb, 1); + int version = bytestream2_get_byte(&gb); + if (version > 1) { + avpriv_request_sample(avctx, "Version %d", version); + return buf_size; + } + + /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */ + bytestream2_skip(&gb, 4); + + s->width = bytestream2_get_be16(&gb); + s->height = bytestream2_get_be16(&gb); + s->coded_width = FFALIGN(s->width, 16); + s->coded_height = FFALIGN(s->height, 16); + s->format = AV_PIX_FMT_BAYER_RGGB16; + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + s->field_order = AV_FIELD_PROGRESSIVE; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + /* This parser only performs analysis */ + *poutbuf = buf; + *poutbuf_size = buf_size; + + return buf_size; +} + +const AVCodecParser ff_prores_raw_parser = { + .codec_ids = { AV_CODEC_ID_PRORES_RAW }, + .parser_parse = prores_raw_parse, +}; diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index 6a256107b4..deaf84bda0 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -26,8 +26,6 @@ //#define DEBUG -#define LONG_BITSTREAM_READER - #include "config_components.h" #include "libavutil/internal.h" @@ -134,9 +132,7 @@ static void unpack_alpha_12(GetBitContext *gb, uint16_t *dst, int num_coeffs, static av_cold int decode_init(AVCodecContext *avctx) { - int ret = 0; ProresContext *ctx = avctx->priv_data; - uint8_t idct_permutation[64]; avctx->bits_per_raw_sample = 10; @@ -166,36 +162,24 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag); } - if (avctx->bits_per_raw_sample == 10) { - av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 10b decoding based on codec tag.\n"); - } else { /* 12b */ - av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 12b decoding based on codec tag.\n"); - } + ctx->unpack_alpha = avctx->bits_per_raw_sample == 10 ? + unpack_alpha_10 : unpack_alpha_12; + + av_log(avctx, AV_LOG_DEBUG, + "Auto bitdepth precision. Use %db decoding based on codec tag.\n", + avctx->bits_per_raw_sample); ff_blockdsp_init(&ctx->bdsp); - ret = ff_proresdsp_init(&ctx->prodsp, avctx->bits_per_raw_sample); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Fail to init proresdsp for bits per raw sample %d\n", avctx->bits_per_raw_sample); - return ret; - } + ff_proresdsp_init(&ctx->prodsp, avctx->bits_per_raw_sample); - ff_init_scantable_permutation(idct_permutation, - ctx->prodsp.idct_permutation_type); - - ff_permute_scantable(ctx->progressive_scan, ff_prores_progressive_scan, idct_permutation); - ff_permute_scantable(ctx->interlaced_scan, ff_prores_interlaced_scan, idct_permutation); + ff_permute_scantable(ctx->progressive_scan, ff_prores_progressive_scan, + ctx->prodsp.idct_permutation); + ff_permute_scantable(ctx->interlaced_scan, ff_prores_interlaced_scan, + ctx->prodsp.idct_permutation); ctx->pix_fmt = AV_PIX_FMT_NONE; - if (avctx->bits_per_raw_sample == 10){ - ctx->unpack_alpha = unpack_alpha_10; - } else if (avctx->bits_per_raw_sample == 12){ - ctx->unpack_alpha = unpack_alpha_12; - } else { - av_log(avctx, AV_LOG_ERROR, "Fail to set unpack_alpha for bits per raw sample %d\n", avctx->bits_per_raw_sample); - return AVERROR_BUG; - } - return ret; + return 0; } static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, @@ -268,6 +252,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, if (pix_fmt != ctx->pix_fmt) { #define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL) +#if HWACCEL_MAX enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; int ret; @@ -283,6 +268,9 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, return ret; avctx->pix_fmt = ret; +#else + avctx->pix_fmt = ctx->pix_fmt = pix_fmt; +#endif } ctx->frame->color_primaries = buf[14]; @@ -428,7 +416,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons unsigned int rice_order, exp_order, switch_bits; \ unsigned int q, buf, bits; \ \ - UPDATE_CACHE(re, gb); \ + UPDATE_CACHE_32(re, gb); /* We really need 32 bits */ \ buf = GET_CACHE(re, gb); \ \ /* number of bits to switch between rice and exp golomb */ \ @@ -440,7 +428,7 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons \ if (q > switch_bits) { /* exp golomb */ \ bits = exp_order - switch_bits + (q<<1); \ - if (bits > FFMIN(MIN_CACHE_BITS, 31)) \ + if (bits > 31) \ return AVERROR_INVALIDDATA; \ val = SHOW_UBITS(re, gb, bits) - (1 << exp_order) + \ ((switch_bits + 1) << rice_order); \ @@ -502,7 +490,7 @@ static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContex int log2_block_count = av_log2(blocks_per_slice); OPEN_READER(re, gb); - UPDATE_CACHE(re, gb); \ + UPDATE_CACHE_32(re, gb); run = 4; level = 2; @@ -584,12 +572,15 @@ static int decode_slice_chroma(AVCodecContext *avctx, SliceContext *slice, for (i = 0; i < blocks_per_slice; i++) ctx->bdsp.clear_block(blocks+(i<<6)); - init_get_bits(&gb, buf, buf_size << 3); + /* Some encodes have empty chroma scans to simulate grayscale */ + if (buf_size) { + init_get_bits(&gb, buf, buf_size << 3); - if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0) - return ret; - if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0) - return ret; + if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0) + return ret; + if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0) + return ret; + } block = blocks; for (i = 0; i < slice->mb_count; i++) { @@ -650,7 +641,6 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]); int mb_x_shift; int ret; - uint16_t val_no_chroma; slice->ret = -1; //av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n", @@ -714,7 +704,7 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int if (ret < 0) return ret; - if (!(avctx->flags & AV_CODEC_FLAG_GRAY) && (u_data_size + v_data_size) > 0) { + if (!(avctx->flags & AV_CODEC_FLAG_GRAY)) { ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_u, chroma_stride, buf + y_data_size, u_data_size, qmat_chroma_scaled, log2_chroma_blocks_per_mb); @@ -727,20 +717,6 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int if (ret < 0) return ret; } - else { - size_t mb_max_x = slice->mb_count << (mb_x_shift - 1); - size_t i, j; - if (avctx->bits_per_raw_sample == 10) { - val_no_chroma = 511; - } else { /* 12b */ - val_no_chroma = 511 * 4; - } - for (i = 0; i < 16; ++i) - for (j = 0; j < mb_max_x; ++j) { - *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = val_no_chroma; - *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = val_no_chroma; - } - } /* decode alpha plane if available */ if (ctx->alpha_info && pic->data[3] && a_data_size) { @@ -803,9 +779,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; ff_thread_finish_setup(avctx); - if (avctx->hwaccel) { + if (HWACCEL_MAX && avctx->hwaccel) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, NULL, 0); + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); if (ret < 0) return ret; ret = hwaccel->decode_slice(avctx, avpkt->data, avpkt->size); @@ -876,10 +852,12 @@ const FFCodec ff_prores_decoder = { UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), +#if HWACCEL_MAX .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL HWACCEL_VIDEOTOOLBOX(prores), #endif NULL }, +#endif }; diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c index bc253e55f7..a4921128f7 100644 --- a/libavcodec/proresdsp.c +++ b/libavcodec/proresdsp.c @@ -22,10 +22,57 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/intreadwrite.h" #include "idctdsp.h" #include "proresdsp.h" -#include "simple_idct.h" + +#define IN_IDCT_DEPTH 16 +#define PRORES_ONLY + +#define BIT_DEPTH 10 +#define EXTRA_SHIFT +#include "simple_idct_template.c" +#undef BIT_DEPTH +#undef EXTRA_SHIFT + +#define BIT_DEPTH 12 +#include "simple_idct_template.c" +#undef BIT_DEPTH + +/** + * 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. + */ +static void prores_idct_10(int16_t *restrict block, const int16_t *restrict qmat) +{ + for (int i = 0; i < 64; i++) + block[i] *= qmat[i]; + + for (int i = 0; i < 8; i++) + idctRowCondDC_extrashift_10(block + i*8, 2); + + for (int i = 0; i < 8; i++) { + block[i] += 8192; + idctSparseCol_extrashift_10(block + i); + } +} + +static void prores_idct_12(int16_t *restrict block, const int16_t *restrict qmat) +{ + for (int i = 0; i < 64; i++) + block[i] *= qmat[i]; + + for (int i = 0; i < 8; i++) + idctRowCondDC_int16_12bit(block + i*8, 0); + + for (int i = 0; i < 8; i++) { + block[i] += 8192; + idctSparseCol_int16_12bit(block + i); + } +} #define CLIP_MIN (1 << 2) ///< minimum value for clipping resulting pixels #define CLIP_MAX_10 (1 << 10) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels @@ -39,21 +86,28 @@ */ static inline void put_pixel(uint16_t *dst, ptrdiff_t linesize, const int16_t *in, int bits_per_raw_sample) { - int x, y, src_offset, dst_offset; - - for (y = 0, dst_offset = 0; y < 8; y++, dst_offset += linesize) { - for (x = 0; x < 8; x++) { - src_offset = (y << 3) + x; + for (int y = 0; y < 8; y++, dst += linesize) { + for (int x = 0; x < 8; x++) { + int src_offset = (y << 3) + x; if (bits_per_raw_sample == 10) { - dst[dst_offset + x] = CLIP_10(in[src_offset]); + dst[x] = CLIP_10(in[src_offset]); } else {//12b - dst[dst_offset + x] = CLIP_12(in[src_offset]); + dst[x] = CLIP_12(in[src_offset]); } } } } +static inline void put_pixel_bayer_12(uint16_t *dst, ptrdiff_t linesize, + const int16_t *in) +{ + for (int y = 0; y < 8; y++, dst += linesize) { + for (int x = 0; x < 8; x++) + dst[x*2] = CLIP_12(in[(y << 3) + x]) << 4; + } +} + static void put_pixels_10(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) { put_pixel(dst, linesize, in, 10); @@ -66,26 +120,33 @@ static void put_pixels_12(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) static void prores_idct_put_10_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) { - ff_prores_idct_10(block, qmat); + prores_idct_10(block, qmat); put_pixels_10(out, linesize >> 1, block); } static void prores_idct_put_12_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) { - ff_prores_idct_12(block, qmat); + prores_idct_12(block, qmat); put_pixels_12(out, linesize >> 1, block); } -av_cold int ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample) +static void prores_idct_put_bayer_12_c(uint16_t *out, ptrdiff_t linesize, + int16_t *block, const int16_t *qmat) +{ + prores_idct_12(block, qmat); + put_pixel_bayer_12(out, linesize << 1, block); +} + +av_cold void ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample) { if (bits_per_raw_sample == 10) { dsp->idct_put = prores_idct_put_10_c; dsp->idct_permutation_type = FF_IDCT_PERM_NONE; - } else if (bits_per_raw_sample == 12) { - dsp->idct_put = prores_idct_put_12_c; - dsp->idct_permutation_type = FF_IDCT_PERM_NONE; } else { - return AVERROR_BUG; + av_assert1(bits_per_raw_sample == 12); + dsp->idct_put = prores_idct_put_12_c; + dsp->idct_put_bayer = prores_idct_put_bayer_12_c; + dsp->idct_permutation_type = FF_IDCT_PERM_NONE; } #if ARCH_X86 @@ -94,5 +155,4 @@ av_cold int ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample) ff_init_scantable_permutation(dsp->idct_permutation, dsp->idct_permutation_type); - return 0; } diff --git a/libavcodec/proresdsp.h b/libavcodec/proresdsp.h index 966ba3d797..f8b57d7e87 100644 --- a/libavcodec/proresdsp.h +++ b/libavcodec/proresdsp.h @@ -30,9 +30,10 @@ typedef struct ProresDSPContext { int idct_permutation_type; uint8_t idct_permutation[64]; void (*idct_put)(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat); + void (*idct_put_bayer)(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat); } ProresDSPContext; -int ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample); +void ff_proresdsp_init(ProresDSPContext *dsp, int bits_per_raw_sample); void ff_proresdsp_init_x86(ProresDSPContext *dsp, int bits_per_raw_sample); diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c index 4493ed03ba..1d40410199 100644 --- a/libavcodec/proresenc_anatoliy.c +++ b/libavcodec/proresenc_anatoliy.c @@ -27,6 +27,7 @@ * Known FOURCCs: 'ap4h' (444), 'apch' (HQ), 'apcn' (422), 'apcs' (LT), 'acpo' (Proxy) */ +#include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" @@ -382,7 +383,7 @@ static int encode_slice_plane(int16_t *blocks, int mb_count, uint8_t *buf, unsig encode_acs(&pb, blocks, blocks_per_slice, qmat, scan); flush_put_bits(&pb); - return put_bits_ptr(&pb) - pb.buf; + return put_bytes_output(&pb); } static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx, @@ -396,14 +397,12 @@ static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx, *y_data_size = encode_slice_plane(blocks_y, mb_count, buf, data_size, ctx->qmat_luma[qp - 1], 0, ctx->scantable); - if (!(avctx->flags & AV_CODEC_FLAG_GRAY)) { - *u_data_size = encode_slice_plane(blocks_u, mb_count, buf + *y_data_size, data_size - *y_data_size, - ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); + *u_data_size = encode_slice_plane(blocks_u, mb_count, buf + *y_data_size, data_size - *y_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); - *v_data_size = encode_slice_plane(blocks_v, mb_count, buf + *y_data_size + *u_data_size, - data_size - *y_data_size - *u_data_size, - ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); - } + *v_data_size = encode_slice_plane(blocks_v, mb_count, buf + *y_data_size + *u_data_size, + data_size - *y_data_size - *u_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); return *y_data_size + *u_data_size + *v_data_size; } @@ -845,20 +844,25 @@ static av_cold int prores_encode_init(AVCodecContext *avctx) } if (avctx->profile == AV_PROFILE_UNKNOWN) { - if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV422P10: avctx->profile = AV_PROFILE_PRORES_STANDARD; av_log(avctx, AV_LOG_INFO, "encoding with ProRes standard (apcn) profile\n"); - } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10) { + break; + case AV_PIX_FMT_YUV444P10: avctx->profile = AV_PROFILE_PRORES_4444; av_log(avctx, AV_LOG_INFO, "encoding with ProRes 4444 (ap4h) profile\n"); - } else if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) { + break; + case AV_PIX_FMT_YUVA444P10: avctx->profile = AV_PROFILE_PRORES_4444; av_log(avctx, AV_LOG_INFO, "encoding with ProRes 4444+ (ap4h) profile\n"); - } else - av_assert0(0); + break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); + } } else if (avctx->profile < AV_PROFILE_PRORES_PROXY || avctx->profile > AV_PROFILE_PRORES_XQ) { av_log( @@ -955,7 +959,7 @@ const FFCodec ff_prores_aw_encoder = { .p.id = AV_CODEC_ID_PRORES, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, @@ -973,7 +977,7 @@ const FFCodec ff_prores_encoder = { .p.id = AV_CODEC_ID_PRORES, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = pix_fmts, + CODEC_PIXFMTS_ARRAY(pix_fmts), .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 226f95f8c6..b98bc5c195 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -1033,7 +1033,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, // slices if (!ctx->force_quant) { - ret = avctx->execute2(avctx, find_quant_thread, (void*)pic, NULL, + ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL, ctx->mb_height); if (ret) return ret; @@ -1381,10 +1381,7 @@ const FFCodec ff_prores_ks_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, - AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &proresenc_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), diff --git a/libavcodec/psd.c b/libavcodec/psd.c index 3e5bfcd360..ea88f254bf 100644 --- a/libavcodec/psd.c +++ b/libavcodec/psd.c @@ -173,10 +173,10 @@ static int decode_header(PSDContext * s) } bytestream2_skip(&s->gb, len_section); - /* image ressources */ + /* image resources */ len_section = bytestream2_get_be32(&s->gb); if (len_section < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Negative size for image ressources section.\n"); + av_log(s->avctx, AV_LOG_ERROR, "Negative size for image resources section.\n"); return AVERROR_INVALIDDATA; } @@ -418,9 +418,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, s->uncompressed_size = s->line_size * s->height * s->channel_count; - if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) - return ret; - /* decode picture if need */ if (s->compression == PSD_RLE) { s->tmp = av_malloc(s->uncompressed_size); @@ -443,6 +440,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, ptr_data = s->gb.buffer; } + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + /* Store data */ if ((avctx->pix_fmt == AV_PIX_FMT_YA8)||(avctx->pix_fmt == AV_PIX_FMT_YA16BE)){/* Interleaved */ ptr = picture->data[0]; @@ -533,11 +533,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, } if (s->color_mode == PSD_INDEXED) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - picture->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(picture->data[1], s->palette, AVPALETTE_SIZE); } diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c index 890b13e1c8..87f7b216cd 100644 --- a/libavcodec/psymodel.c +++ b/libavcodec/psymodel.c @@ -19,11 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include "avcodec.h" #include "psymodel.h" -#include "iirfilter.h" #include "libavutil/mem.h" extern const FFPsyModel ff_aac_psy_model; @@ -37,8 +34,8 @@ av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, ctx->avctx = avctx; ctx->ch = av_calloc(avctx->ch_layout.nb_channels, 2 * sizeof(ctx->ch[0])); ctx->group = av_calloc(num_groups, sizeof(ctx->group[0])); - ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens); - ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens); + ctx->bands = av_memdup(bands, num_lens * sizeof(ctx->bands[0])); + ctx->num_bands = av_memdup(num_bands, num_lens * sizeof(ctx->num_bands[0])); ctx->cutoff = avctx->cutoff; if (!ctx->ch || !ctx->group || !ctx->bands || !ctx->num_bands) { @@ -46,9 +43,6 @@ av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, return AVERROR(ENOMEM); } - memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens); - memcpy(ctx->num_bands, num_bands, sizeof(ctx->num_bands[0]) * num_lens); - /* assign channels to groups (with virtual channels for coupling) */ for (i = 0; i < num_groups; i++) { /* NOTE: Add 1 to handle the AAC chan_config without modification. @@ -89,73 +83,3 @@ av_cold void ff_psy_end(FFPsyContext *ctx) av_freep(&ctx->group); av_freep(&ctx->ch); } - -typedef struct FFPsyPreprocessContext{ - AVCodecContext *avctx; - float stereo_att; - struct FFIIRFilterCoeffs *fcoeffs; - struct FFIIRFilterState **fstate; - struct FFIIRFilterContext fiir; -}FFPsyPreprocessContext; - -#define FILT_ORDER 4 - -av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *avctx) -{ - FFPsyPreprocessContext *ctx; - int i; - float cutoff_coeff = 0; - ctx = av_mallocz(sizeof(FFPsyPreprocessContext)); - if (!ctx) - return NULL; - ctx->avctx = avctx; - - /* AAC has its own LP method */ - if (avctx->codec_id != AV_CODEC_ID_AAC) { - if (avctx->cutoff > 0) - cutoff_coeff = 2.0 * avctx->cutoff / avctx->sample_rate; - - if (cutoff_coeff && cutoff_coeff < 0.98) - ctx->fcoeffs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_MODE_LOWPASS, FILT_ORDER, - cutoff_coeff, 0.0, 0.0); - if (ctx->fcoeffs) { - ctx->fstate = av_calloc(avctx->ch_layout.nb_channels, sizeof(ctx->fstate[0])); - if (!ctx->fstate) { - av_free(ctx->fcoeffs); - av_free(ctx); - return NULL; - } - for (i = 0; i < avctx->ch_layout.nb_channels; i++) - ctx->fstate[i] = ff_iir_filter_init_state(FILT_ORDER); - } - } - - ff_iir_filter_init(&ctx->fiir); - - return ctx; -} - -void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels) -{ - int ch; - int frame_size = ctx->avctx->frame_size; - FFIIRFilterContext *iir = &ctx->fiir; - - if (ctx->fstate) { - for (ch = 0; ch < channels; ch++) - iir->filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size, - &audio[ch][frame_size], 1, &audio[ch][frame_size], 1); - } -} - -av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx) -{ - int i; - ff_iir_filter_free_coeffsp(&ctx->fcoeffs); - if (ctx->fstate) - for (i = 0; i < ctx->avctx->ch_layout.nb_channels; i++) - ff_iir_filter_free_statep(&ctx->fstate[i]); - av_freep(&ctx->fstate); - av_free(ctx); -} diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index d32e56de0d..6d604566e3 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -29,13 +29,13 @@ * @see doc/multithreading.txt */ +#include "libavutil/attributes.h" #include "libavutil/thread.h" #include "avcodec.h" #include "avcodec_internal.h" #include "codec_internal.h" #include "pthread_internal.h" -#include "thread.h" /** * Set the threading algorithms used. @@ -46,7 +46,7 @@ * * @param avctx The context. */ -static void validate_thread_parameters(AVCodecContext *avctx) +static av_cold void validate_thread_parameters(AVCodecContext *avctx) { int frame_threading_supported = (avctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) && !(avctx->flags & AV_CODEC_FLAG_LOW_DELAY) @@ -69,7 +69,7 @@ static void validate_thread_parameters(AVCodecContext *avctx) avctx->thread_count, MAX_AUTO_THREADS); } -int ff_thread_init(AVCodecContext *avctx) +av_cold int ff_thread_init(AVCodecContext *avctx) { validate_thread_parameters(avctx); @@ -81,7 +81,7 @@ int ff_thread_init(AVCodecContext *avctx) return 0; } -void ff_thread_free(AVCodecContext *avctx) +av_cold void ff_thread_free(AVCodecContext *avctx) { if (avctx->active_thread_type&FF_THREAD_FRAME) ff_frame_thread_free(avctx, avctx->thread_count); diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 1b1b96623f..4ea5dd3698 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -34,7 +34,7 @@ #include "internal.h" #include "packet_internal.h" #include "pthread_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" #include "version_major.h" @@ -365,7 +365,11 @@ static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext dst->has_b_frames = src->has_b_frames; dst->idct_algo = src->idct_algo; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS dst->properties = src->properties; +FF_ENABLE_DEPRECATION_WARNINGS +#endif dst->bits_per_coded_sample = src->bits_per_coded_sample; dst->sample_aspect_ratio = src->sample_aspect_ratio; @@ -374,11 +378,6 @@ static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext dst->level = src->level; dst->bits_per_raw_sample = src->bits_per_raw_sample; -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - dst->ticks_per_frame = src->ticks_per_frame; -FF_ENABLE_DEPRECATION_WARNINGS -#endif dst->color_primaries = src->color_primaries; dst->color_trc = src->color_trc; @@ -405,7 +404,7 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->hwaccel_flags = src->hwaccel_flags; - ff_refstruct_replace(&dst->internal->pool, src->internal->pool); + av_refstruct_replace(&dst->internal->pool, src->internal->pool); ff_decode_internal_sync(dst, src); } @@ -714,7 +713,7 @@ void ff_thread_finish_setup(AVCodecContext *avctx) { } /// Waits for all threads to finish. -static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) +static av_cold void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) { int i; @@ -746,7 +745,7 @@ DEFINE_OFFSET_ARRAY(PerThreadContext, per_thread, pthread_init_cnt, (OFF(input_cond), OFF(progress_cond), OFF(output_cond))); #undef OFF -void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) +av_cold void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) { FrameThreadContext *fctx = avctx->internal->thread_ctx; const FFCodec *codec = ffcodec(avctx->codec); @@ -780,7 +779,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_freep(&ctx->priv_data); } - ff_refstruct_unref(&ctx->internal->pool); + av_refstruct_unref(&ctx->internal->pool); av_packet_free(&ctx->internal->in_pkt); av_packet_free(&ctx->internal->last_pkt_props); ff_decode_internal_uninit(ctx); @@ -918,7 +917,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, return 0; } -int ff_frame_thread_init(AVCodecContext *avctx) +av_cold int ff_frame_thread_init(AVCodecContext *avctx) { int thread_count = avctx->thread_count; const FFCodec *codec = ffcodec(avctx->codec); @@ -981,7 +980,7 @@ error: return err; } -void ff_thread_flush(AVCodecContext *avctx) +av_cold void ff_thread_flush(AVCodecContext *avctx) { int i; FrameThreadContext *fctx = avctx->internal->thread_ctx; @@ -1062,7 +1061,7 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); - f->progress = ff_refstruct_allocz(sizeof(*f->progress)); + f->progress = av_refstruct_allocz(sizeof(*f->progress)); if (!f->progress) return AVERROR(ENOMEM); @@ -1071,19 +1070,19 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) ret = ff_thread_get_buffer(avctx, f->f, flags); if (ret) - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); return ret; } void ff_thread_release_ext_buffer(ThreadFrame *f) { - ff_refstruct_unref(&f->progress); + av_refstruct_unref(&f->progress); f->owner[0] = f->owner[1] = NULL; if (f->f) av_frame_unref(f->f); } -enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) +av_cold enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) { PerThreadContext *p; const void *ref; @@ -1098,7 +1097,7 @@ enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) memcpy(&ref, (const char*)p->parent->threads[0].avctx->priv_data + offset, sizeof(ref)); av_assert1(ref); - ff_refstruct_replace((char*)avctx->priv_data + offset, ref); + av_refstruct_replace((char*)avctx->priv_data + offset, ref); return FF_THREAD_IS_COPY; } diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c index a4d31c6f4d..f9da670735 100644 --- a/libavcodec/pthread_slice.c +++ b/libavcodec/pthread_slice.c @@ -22,30 +22,22 @@ * @see doc/multithreading.txt */ -#include "config.h" - #include "avcodec.h" #include "codec_internal.h" #include "internal.h" #include "pthread_internal.h" #include "thread.h" -#include "libavutil/avassert.h" -#include "libavutil/common.h" +#include "libavutil/attributes.h" #include "libavutil/cpu.h" +#include "libavutil/macros.h" #include "libavutil/mem.h" -#include "libavutil/thread.h" #include "libavutil/slicethread.h" typedef int (action_func)(AVCodecContext *c, void *arg); typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); typedef int (main_func)(AVCodecContext *c); -typedef struct Progress { - pthread_cond_t cond; - pthread_mutex_t mutex; -} Progress; - typedef struct SliceThreadContext { AVSliceThread *thread; action_func *func; @@ -54,11 +46,6 @@ typedef struct SliceThreadContext { void *args; int *rets; int job_size; - - int *entries; - int entries_count; - int thread_count; - Progress *progress; } SliceThreadContext; static void main_function(void *priv) { @@ -79,21 +66,12 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb c->rets[jobnr] = ret; } -void ff_slice_thread_free(AVCodecContext *avctx) +av_cold void ff_slice_thread_free(AVCodecContext *avctx) { SliceThreadContext *c = avctx->internal->thread_ctx; - int i; avpriv_slicethread_free(&c->thread); - for (i = 0; i < c->thread_count; i++) { - Progress *const progress = &c->progress[i]; - pthread_mutex_destroy(&progress->mutex); - pthread_cond_destroy(&progress->cond); - } - - av_freep(&c->entries); - av_freep(&c->progress); av_freep(&avctx->internal->thread_ctx); } @@ -131,18 +109,12 @@ int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* f return thread_execute(avctx, NULL, arg, ret, job_count, 0); } -int ff_slice_thread_init(AVCodecContext *avctx) +av_cold int ff_slice_thread_init(AVCodecContext *avctx) { SliceThreadContext *c; int thread_count = avctx->thread_count; void (*mainfunc)(void *); - // We cannot do this in the encoder init as the threads are created before - if (av_codec_is_encoder(avctx->codec) && - avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && - avctx->height > 2800) - thread_count = avctx->thread_count = 1; - if (!thread_count) { int nb_cpus = av_cpu_count(); if (avctx->height) @@ -160,14 +132,16 @@ int ff_slice_thread_init(AVCodecContext *avctx) } avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c)); + if (!c) + return AVERROR(ENOMEM); mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL; - if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) { - if (c) - avpriv_slicethread_free(&c->thread); - av_freep(&avctx->internal->thread_ctx); + thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, + mainfunc, thread_count); + if (thread_count <= 1) { + ff_slice_thread_free(avctx); avctx->thread_count = 1; avctx->active_thread_type = 0; - return 0; + return thread_count < 0 ? thread_count : 0; } avctx->thread_count = thread_count; @@ -175,86 +149,3 @@ int ff_slice_thread_init(AVCodecContext *avctx) avctx->execute2 = thread_execute2; return 0; } - -int av_cold ff_slice_thread_init_progress(AVCodecContext *avctx) -{ - SliceThreadContext *const p = avctx->internal->thread_ctx; - int err, i = 0, thread_count = avctx->thread_count; - - p->progress = av_calloc(thread_count, sizeof(*p->progress)); - if (!p->progress) { - err = AVERROR(ENOMEM); - goto fail; - } - - for (; i < thread_count; i++) { - Progress *const progress = &p->progress[i]; - err = pthread_mutex_init(&progress->mutex, NULL); - if (err) { - err = AVERROR(err); - goto fail; - } - err = pthread_cond_init (&progress->cond, NULL); - if (err) { - err = AVERROR(err); - pthread_mutex_destroy(&progress->mutex); - goto fail; - } - } - err = 0; -fail: - p->thread_count = i; - return err; -} - -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) -{ - SliceThreadContext *p = avctx->internal->thread_ctx; - Progress *const progress = &p->progress[thread]; - int *entries = p->entries; - - pthread_mutex_lock(&progress->mutex); - entries[field] +=n; - pthread_cond_signal(&progress->cond); - pthread_mutex_unlock(&progress->mutex); -} - -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) -{ - SliceThreadContext *p = avctx->internal->thread_ctx; - Progress *progress; - int *entries = p->entries; - - if (!entries || !field) return; - - thread = thread ? thread - 1 : p->thread_count - 1; - progress = &p->progress[thread]; - - pthread_mutex_lock(&progress->mutex); - while ((entries[field - 1] - entries[field]) < shift){ - pthread_cond_wait(&progress->cond, &progress->mutex); - } - pthread_mutex_unlock(&progress->mutex); -} - -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count) -{ - if (avctx->active_thread_type & FF_THREAD_SLICE) { - SliceThreadContext *p = avctx->internal->thread_ctx; - - if (p->entries_count == count) { - memset(p->entries, 0, p->entries_count * sizeof(*p->entries)); - return 0; - } - av_freep(&p->entries); - - p->entries = av_calloc(count, sizeof(*p->entries)); - if (!p->entries) { - p->entries_count = 0; - return AVERROR(ENOMEM); - } - p->entries_count = count; - } - - return 0; -} diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h index 0caaa6b338..c3eee622d4 100644 --- a/libavcodec/put_bits.h +++ b/libavcodec/put_bits.h @@ -39,14 +39,14 @@ typedef uint64_t BitBuf; #define AV_WBBUF AV_WB64 #define AV_WLBUF AV_WL64 +#define BUF_BITS 64 #else typedef uint32_t BitBuf; #define AV_WBBUF AV_WB32 #define AV_WLBUF AV_WL32 +#define BUF_BITS 32 #endif -static const int BUF_BITS = 8 * sizeof(BitBuf); - typedef struct PutBitContext { BitBuf bit_buf; int bit_left; @@ -74,6 +74,16 @@ static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, s->bit_buf = 0; } +/** + * Inform the compiler that a PutBitContext is flushed (i.e. if it has just + * been initialized or flushed). Undefined behaviour occurs if this is used + * with a PutBitContext for which this is not true. + */ +static inline void put_bits_assume_flushed(const PutBitContext *s) +{ + av_assume(s->bit_left == BUF_BITS); +} + /** * @return the total number of bits written to the bitstream. */ @@ -329,12 +339,15 @@ static void av_unused put_bits32(PutBitContext *s, uint32_t value) } /** - * Write up to 64 bits into a bitstream. + * Write up to 63 bits into a bitstream. */ -static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +static inline void put_bits63(PutBitContext *s, int n, uint64_t value) { - av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + av_assert2(n < 64U && value < (UINT64_C(1) << n)); +#if BUF_BITS >= 64 + put_bits_no_assert(s, n, value); +#else if (n < 32) put_bits(s, n, value); else if (n == 32) @@ -349,6 +362,19 @@ static inline void put_bits64(PutBitContext *s, int n, uint64_t value) put_bits(s, n - 32, hi); put_bits32(s, lo); #endif + } +#endif +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +{ + av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + + if (n < 64) { + put_bits63(s, n, value); } else { uint32_t lo = value & 0xffffffff; uint32_t hi = value >> 32; @@ -359,7 +385,6 @@ static inline void put_bits64(PutBitContext *s, int n, uint64_t value) put_bits32(s, hi); put_bits32(s, lo); #endif - } } @@ -367,7 +392,7 @@ static inline void put_sbits63(PutBitContext *pb, int n, int64_t value) { av_assert2(n >= 0 && n < 64); - put_bits64(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); + put_bits63(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); } /** diff --git a/libavcodec/put_golomb.h b/libavcodec/put_golomb.h index 43c1233fdb..91e7852a17 100644 --- a/libavcodec/put_golomb.h +++ b/libavcodec/put_golomb.h @@ -62,7 +62,7 @@ static inline void set_ue_golomb_long(PutBitContext *pb, uint32_t i) put_bits(pb, ff_ue_golomb_len[i], i + 1); else { int e = av_log2(i + 1); - put_bits64(pb, 2 * e + 1, i + 1); + put_bits63(pb, 2 * e + 1, i + 1); } } diff --git a/libavcodec/qcelpdec.c b/libavcodec/qcelpdec.c index 1435fecc2e..4ec25a8f0f 100644 --- a/libavcodec/qcelpdec.c +++ b/libavcodec/qcelpdec.c @@ -89,6 +89,8 @@ static av_cold int qcelp_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; avctx->sample_fmt = AV_SAMPLE_FMT_FLT; + if (!avctx->sample_rate) + avctx->sample_rate = 8000; for (i = 0; i < 10; i++) q->prev_lspf[i] = (i + 1) / 11.0; @@ -397,7 +399,7 @@ static void apply_gain_ctrl(float *v_out, const float *v_ref, const float *v_in) int i; for (i = 0; i < 160; i += 40) { - float res = avpriv_scalarproduct_float_c(v_ref + i, v_ref + i, 40); + float res = ff_scalarproduct_float_c(v_ref + i, v_ref + i, 40); ff_scale_vector_to_given_sum_of_squares(v_out + i, v_in + i, res, 40); } } @@ -676,9 +678,9 @@ static void postfilter(QCELPContext *q, float *samples, float *lpc) ff_tilt_compensation(&q->postfilter_tilt_mem, 0.3, pole_out + 10, 160); ff_adaptive_gain_control(samples, pole_out + 10, - avpriv_scalarproduct_float_c(q->formant_mem + 10, - q->formant_mem + 10, - 160), + ff_scalarproduct_float_c(q->formant_mem + 10, + q->formant_mem + 10, + 160), 160, 0.9375, &q->postfilter_agc_mem); } diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c index e629e3b42a..b2136c6824 100644 --- a/libavcodec/qdm2.c +++ b/libavcodec/qdm2.c @@ -34,6 +34,7 @@ #include #include +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -199,9 +200,8 @@ static const int switchtable[23] = { static int qdm2_get_vlc(GetBitContext *gb, const VLC *vlc, int flag, int depth) { - int value; - - value = get_vlc2(gb, vlc->table, vlc->bits, depth); + int value = get_vlc2(gb, vlc->table, vlc->bits, + av_builtin_constant_p(depth) ? depth : 2); /* stage-2, 3 bits exponent escape sequence */ if (value < 0) @@ -1661,20 +1661,20 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); while (bytestream2_get_bytes_left(&gb) > 8) { - if (bytestream2_peek_be64(&gb) == (((uint64_t)MKBETAG('f','r','m','a') << 32) | + if (bytestream2_peek_be64u(&gb) == (((uint64_t)MKBETAG('f','r','m','a') << 32) | (uint64_t)MKBETAG('Q','D','M','2'))) break; - bytestream2_skip(&gb, 1); + bytestream2_skipu(&gb, 1); } - if (bytestream2_get_bytes_left(&gb) < 12) { + if (bytestream2_get_bytes_left(&gb) < 44) { av_log(avctx, AV_LOG_ERROR, "not enough extradata (%i)\n", bytestream2_get_bytes_left(&gb)); return AVERROR_INVALIDDATA; } - bytestream2_skip(&gb, 8); - size = bytestream2_get_be32(&gb); + bytestream2_skipu(&gb, 8); + size = bytestream2_get_be32u(&gb); if (size > bytestream2_get_bytes_left(&gb)) { av_log(avctx, AV_LOG_ERROR, "extradata size too small, %i < %i\n", @@ -1683,14 +1683,14 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) } av_log(avctx, AV_LOG_DEBUG, "size: %d\n", size); - if (bytestream2_get_be32(&gb) != MKBETAG('Q','D','C','A')) { + if (bytestream2_get_be32u(&gb) != MKBETAG('Q','D','C','A')) { av_log(avctx, AV_LOG_ERROR, "invalid extradata, expecting QDCA\n"); return AVERROR_INVALIDDATA; } - bytestream2_skip(&gb, 4); + bytestream2_skipu(&gb, 4); - s->nb_channels = s->channels = bytestream2_get_be32(&gb); + s->nb_channels = s->channels = bytestream2_get_be32u(&gb); if (s->channels <= 0 || s->channels > MPA_MAX_CHANNELS) { av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n"); return AVERROR_INVALIDDATA; @@ -1698,11 +1698,11 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); av_channel_layout_default(&avctx->ch_layout, s->channels); - avctx->sample_rate = bytestream2_get_be32(&gb); - avctx->bit_rate = bytestream2_get_be32(&gb); - s->group_size = bytestream2_get_be32(&gb); - s->fft_size = bytestream2_get_be32(&gb); - s->checksum_size = bytestream2_get_be32(&gb); + avctx->sample_rate = bytestream2_get_be32u(&gb); + avctx->bit_rate = bytestream2_get_be32u(&gb); + s->group_size = bytestream2_get_be32u(&gb); + s->fft_size = bytestream2_get_be32u(&gb); + s->checksum_size = bytestream2_get_be32u(&gb); if (s->checksum_size >= 1U << 28 || s->checksum_size <= 1) { av_log(avctx, AV_LOG_ERROR, "data block size invalid (%u)\n", s->checksum_size); return AVERROR_INVALIDDATA; diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index ca38f48bd9..fd2d894477 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -384,11 +384,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000); if (ret < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* jump to image data */ bytestream2_skip(&gbc, 18); diff --git a/libavcodec/qoadec.c b/libavcodec/qoadec.c index c5cf351f9c..770bbe4706 100644 --- a/libavcodec/qoadec.c +++ b/libavcodec/qoadec.c @@ -165,6 +165,5 @@ const FFCodec ff_qoa_decoder = { FF_CODEC_DECODE_CB(qoa_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/qoienc.c b/libavcodec/qoienc.c index b9efdc2fa5..3149f162d6 100644 --- a/libavcodec/qoienc.c +++ b/libavcodec/qoienc.c @@ -134,8 +134,5 @@ const FFCodec ff_qoi_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(qoi_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24), }; diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c index 9b4ad8e25d..08bff5c81b 100644 --- a/libavcodec/qpeg.c +++ b/libavcodec/qpeg.c @@ -297,14 +297,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, } /* make the palette available on the way out */ -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = -#endif ff_copy_palette(a->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(p->data[1], a->pal, AVPALETTE_SIZE); if ((ret = av_frame_replace(ref, p)) < 0) diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 8a3dc95706..cd5195a54b 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -35,7 +35,7 @@ #include "avcodec.h" #include "qsv_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl)) #define QSV_HAVE_USER_PLUGIN !QSV_ONEVPL @@ -745,7 +745,7 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, return 0; } -static void mids_buf_free(FFRefStructOpaque opaque, void *obj) +static void mids_buf_free(AVRefStructOpaque opaque, void *obj) { AVBufferRef *hw_frames_ref = opaque.nc; av_buffer_unref(&hw_frames_ref); @@ -765,7 +765,7 @@ static QSVMid *qsv_create_mids(AVBufferRef *hw_frames_ref) if (!hw_frames_ref1) return NULL; - mids = ff_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0, + mids = av_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0, hw_frames_ref1, mids_buf_free); if (!mids) { av_buffer_unref(&hw_frames_ref1); @@ -806,7 +806,7 @@ static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_re return AVERROR(ENOMEM); } - resp->mids[resp->NumFrameActual + 1] = ff_refstruct_ref(mids); + resp->mids[resp->NumFrameActual + 1] = av_refstruct_ref(mids); return 0; } @@ -899,7 +899,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, } ret = qsv_setup_mids(resp, frames_ref, mids); - ff_refstruct_unref(&mids); + av_refstruct_unref(&mids); av_buffer_unref(&frames_ref); if (ret < 0) { av_log(ctx->logctx, AV_LOG_ERROR, @@ -919,7 +919,7 @@ static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) return MFX_ERR_NONE; av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - ff_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]); + av_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]); av_freep(&resp->mids); return MFX_ERR_NONE; } @@ -1139,7 +1139,7 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession, /* allocate the memory ids for the external frames */ if (frames_hwctx->nb_surfaces) { - ff_refstruct_unref(&qsv_frames_ctx->mids); + av_refstruct_unref(&qsv_frames_ctx->mids); qsv_frames_ctx->mids = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx); if (!qsv_frames_ctx->mids) return AVERROR(ENOMEM); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 039ba62484..144cf5b9e9 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -51,7 +51,7 @@ #include "hwconfig.h" #include "qsv.h" #include "qsv_internal.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #if QSV_ONEVPL #include @@ -696,7 +696,7 @@ static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDispla { int ret; - // The SDK re-uses this flag for HDR SEI parsing + // The SDK reuses this flag for HDR SEI parsing if (mdcv->InsertPayloadToggle) { AVMasteringDisplayMetadata *mastering; const int mapping[3] = {2, 0, 1}; @@ -726,7 +726,7 @@ static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDispla } } - // The SDK re-uses this flag for HDR SEI parsing + // The SDK reuses this flag for HDR SEI parsing if (clli->InsertPayloadToggle) { AVContentLightMetadata *light; @@ -984,7 +984,7 @@ static void qsv_decode_close_qsvcontext(QSVContext *q) ff_qsv_close_internal_session(&q->internal_qs); av_buffer_unref(&q->frames_ctx.hw_frames_ctx); - ff_refstruct_unref(&q->frames_ctx.mids); + av_refstruct_unref(&q->frames_ctx.mids); av_buffer_pool_uninit(&q->pool); } @@ -1002,7 +1002,7 @@ static int qsv_process_data(AVCodecContext *avctx, QSVContext *q, // sw_pix_fmt, coded_width/height should be set for ff_get_format(), // assume sw_pix_fmt is NV12 and coded_width/height to be 1280x720, - // the assumption may be not corret but will be updated after header decoded if not true. + // the assumption may be not correct but will be updated after header decoded if not true. if (q->orig_pix_fmt != AV_PIX_FMT_NONE) pix_fmt = q->orig_pix_fmt; if (!avctx->coded_width) diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 8200a14012..318a99e2a1 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -42,7 +42,7 @@ #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" struct profile_names { mfxU16 profile; @@ -2057,7 +2057,7 @@ static int submit_frame(QSVEncContext *q, const AVFrame *frame, } } else { /* make a copy if the input is not padded as libmfx requires */ - /* and to make allocation continious for data[0]/data[1] */ + /* and to make allocation continuous for data[0]/data[1] */ if ((frame->height & (q->height_align - 1) || frame->linesize[0] & (q->width_align - 1)) || ((frame->format == AV_PIX_FMT_NV12 || frame->format == AV_PIX_FMT_P010 || frame->format == AV_PIX_FMT_P012) && (frame->data[1] - frame->data[0] != frame->linesize[0] * FFALIGN(qf->frame->height, q->height_align)))) { @@ -2716,7 +2716,7 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q) ff_qsv_close_internal_session(&q->internal_qs); av_buffer_unref(&q->frames_ctx.hw_frames_ctx); - ff_refstruct_unref(&q->frames_ctx.mids); + av_refstruct_unref(&q->frames_ctx.mids); cur = q->work_frames; while (cur) { diff --git a/libavcodec/qsvenc_av1.c b/libavcodec/qsvenc_av1.c index a86b409bed..c7aa6e58d5 100644 --- a/libavcodec/qsvenc_av1.c +++ b/libavcodec/qsvenc_av1.c @@ -217,10 +217,7 @@ FFCodec ff_av1_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 304d1e7dcb..7d39338d6a 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -199,9 +199,7 @@ const FFCodec ff_h264_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index 80fdf782a7..ae3981fb72 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -396,17 +396,10 @@ const FFCodec ff_hevc_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_P012, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_Y210, - AV_PIX_FMT_QSV, - AV_PIX_FMT_BGRA, - AV_PIX_FMT_X2RGB10, - AV_PIX_FMT_VUYX, - AV_PIX_FMT_XV30, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_P012, + AV_PIX_FMT_YUYV422, AV_PIX_FMT_Y210, AV_PIX_FMT_QSV, + AV_PIX_FMT_BGRA, AV_PIX_FMT_X2RGB10, AV_PIX_FMT_VUYX, + AV_PIX_FMT_XV30), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c index b2458eee06..0e04c2025d 100644 --- a/libavcodec/qsvenc_jpeg.c +++ b/libavcodec/qsvenc_jpeg.c @@ -88,11 +88,8 @@ const FFCodec ff_mjpeg_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_BGRA, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGRA, + AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index ad3da6d672..c52a2c1f90 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -102,9 +102,7 @@ const FFCodec ff_mpeg2_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_QSV), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qsvenc_vp9.c b/libavcodec/qsvenc_vp9.c index b247c39c86..db93cca15e 100644 --- a/libavcodec/qsvenc_vp9.c +++ b/libavcodec/qsvenc_vp9.c @@ -111,12 +111,8 @@ const FFCodec ff_vp9_qsv_encoder = { FF_CODEC_ENCODE_CB(qsv_enc_frame), .close = qsv_enc_close, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, - AV_PIX_FMT_P010, - AV_PIX_FMT_VUYX, - AV_PIX_FMT_QSV, - AV_PIX_FMT_XV30, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_VUYX, + AV_PIX_FMT_QSV, AV_PIX_FMT_XV30), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index 9b016d7e83..be105bdfb6 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -537,15 +537,7 @@ static int qtrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } if(has_palette) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* make the palette available on the way out */ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c index 71d57d7eb8..ae341c60b6 100644 --- a/libavcodec/qtrleenc.c +++ b/libavcodec/qtrleenc.c @@ -409,8 +409,7 @@ const FFCodec ff_qtrle_encoder = { .init = qtrle_encode_init, FF_CODEC_ENCODE_CB(qtrle_encode_frame), .close = qtrle_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, + AV_PIX_FMT_GRAY8), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c index ec1ebc8d60..b1ade5cde6 100644 --- a/libavcodec/r210enc.c +++ b/libavcodec/r210enc.c @@ -99,7 +99,7 @@ const FFCodec ff_r210_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif #if CONFIG_R10K_ENCODER @@ -111,7 +111,7 @@ const FFCodec ff_r10k_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif #if CONFIG_AVRP_ENCODER @@ -123,6 +123,6 @@ const FFCodec ff_avrp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; #endif diff --git a/libavcodec/ra144enc.c b/libavcodec/ra144enc.c index 92c35ac12c..d38c39ce14 100644 --- a/libavcodec/ra144enc.c +++ b/libavcodec/ra144enc.c @@ -546,8 +546,7 @@ const FFCodec ff_ra_144_encoder = { .init = ra144_encode_init, FF_CODEC_ENCODE_CB(ra144_encode_frame), .close = ra144_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]){ 8000, 0 }, - .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(8000), + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO), }; diff --git a/libavcodec/ra288.c b/libavcodec/ra288.c index 5b186a7a3d..550af7f29f 100644 --- a/libavcodec/ra288.c +++ b/libavcodec/ra288.c @@ -37,6 +37,8 @@ #define MAX_BACKWARD_FILTER_ORDER 36 #define MAX_BACKWARD_FILTER_LEN 40 #define MAX_BACKWARD_FILTER_NONREC 35 +#define ATTEN 0.5625 +#include "g728_template.c" #define RA288_BLOCK_SIZE 5 #define RA288_BLOCKS_PER_FRAME 32 @@ -87,13 +89,6 @@ static av_cold int ra288_decode_init(AVCodecContext *avctx) return 0; } -static void convolve(float *tgt, const float *src, int len, int n) -{ - for (; n >= 0; n--) - tgt[n] = avpriv_scalarproduct_float_c(src, src - n, len); - -} - static void decode(RA288Context *ractx, float gain, int cb_coef) { int i; @@ -119,7 +114,7 @@ static void decode(RA288Context *ractx, float gain, int cb_coef) for (i=0; i < 5; i++) buffer[i] = codetable[cb_coef][i] * sumsum; - sum = avpriv_scalarproduct_float_c(buffer, buffer, 5); + sum = ff_scalarproduct_float_c(buffer, buffer, 5); sum = FFMAX(sum, 5.0 / (1<<24)); @@ -131,45 +126,6 @@ static void decode(RA288Context *ractx, float gain, int cb_coef) ff_celp_lp_synthesis_filterf(block, ractx->sp_lpc, buffer, 5, 36); } -/** - * Hybrid window filtering, see blocks 36 and 49 of the G.728 specification. - * - * @param order filter order - * @param n input length - * @param non_rec number of non-recursive samples - * @param out filter output - * @param hist pointer to the input history of the filter - * @param out pointer to the non-recursive part of the output - * @param out2 pointer to the recursive part of the output - * @param window pointer to the windowing function table - */ -static void do_hybrid_window(RA288Context *ractx, - int order, int n, int non_rec, float *out, - float *hist, float *out2, const float *window) -{ - int i; - float buffer1[MAX_BACKWARD_FILTER_ORDER + 1]; - float buffer2[MAX_BACKWARD_FILTER_ORDER + 1]; - LOCAL_ALIGNED(32, float, work, [FFALIGN(MAX_BACKWARD_FILTER_ORDER + - MAX_BACKWARD_FILTER_LEN + - MAX_BACKWARD_FILTER_NONREC, 16)]); - - av_assert2(order>=0); - - ractx->vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16)); - - convolve(buffer1, work + order , n , order); - convolve(buffer2, work + order + n, non_rec, order); - - for (i=0; i <= order; i++) { - out2[i] = out2[i] * 0.5625 + buffer1[i]; - out [i] = out2[i] + buffer2[i]; - } - - /* Multiply by the white noise correcting factor (WNCF). */ - *out *= 257.0 / 256.0; -} - /** * Backward synthesis filter, find the LPC coefficients from past speech data. */ @@ -180,9 +136,9 @@ static void backward_filter(RA288Context *ractx, { float temp[MAX_BACKWARD_FILTER_ORDER+1]; - do_hybrid_window(ractx, order, n, non_rec, temp, hist, rec, window); + do_hybrid_window(ractx->vector_fmul, order, n, non_rec, temp, hist, rec, window); - if (!compute_lpc_coefs(temp, order, lpc, 0, 1, 1)) + if (!compute_lpc_coefs(temp, 0, order, lpc, 0, 1, 1, NULL)) ractx->vector_fmul(lpc, lpc, tab, FFALIGN(order, 16)); memmove(hist, hist + n, move_size*sizeof(*hist)); diff --git a/libavcodec/ralf.c b/libavcodec/ralf.c index 8f7fac7935..036c3a931c 100644 --- a/libavcodec/ralf.c +++ b/libavcodec/ralf.c @@ -523,7 +523,6 @@ const FFCodec ff_ralf_decoder = { .flush = decode_flush, .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h index 89d178ac31..15217a99a3 100644 --- a/libavcodec/rangecoder.h +++ b/libavcodec/rangecoder.h @@ -61,27 +61,19 @@ void ff_build_rac_states(RangeCoder *c, int factor, int max_p); static inline void renorm_encoder(RangeCoder *c) { - // FIXME: optimize - while (c->range < 0x100) { - if (c->outstanding_byte < 0) { - c->outstanding_byte = c->low >> 8; - } else if (c->low <= 0xFF00) { - *c->bytestream++ = c->outstanding_byte; + if (c->low - 0xFF01 >= 0x10000 - 0xFF01U) { + int mask = c->low - 0xFF01 >> 31; + *c->bytestream = c->outstanding_byte + 1 + mask; + c->bytestream += c->outstanding_byte >= 0; for (; c->outstanding_count; c->outstanding_count--) - *c->bytestream++ = 0xFF; + *c->bytestream++ = mask; c->outstanding_byte = c->low >> 8; - } else if (c->low >= 0x10000) { - *c->bytestream++ = c->outstanding_byte + 1; - for (; c->outstanding_count; c->outstanding_count--) - *c->bytestream++ = 0x00; - c->outstanding_byte = (c->low >> 8) & 0xFF; } else { c->outstanding_count++; } c->low = (c->low & 0xFF) << 8; c->range <<= 8; - } } static inline int get_rac_count(RangeCoder *c) @@ -108,12 +100,12 @@ static inline void put_rac(RangeCoder *c, uint8_t *const state, int bit) *state = c->one_state[*state]; } - renorm_encoder(c); + if (c->range < 0x100) + renorm_encoder(c); } static inline void refill(RangeCoder *c) { - if (c->range < 0x100) { c->range <<= 8; c->low <<= 8; if (c->bytestream < c->bytestream_end) { @@ -121,7 +113,6 @@ static inline void refill(RangeCoder *c) c->bytestream++; } else c->overread ++; - } } static inline int get_rac(RangeCoder *c, uint8_t *const state) @@ -131,13 +122,15 @@ static inline int get_rac(RangeCoder *c, uint8_t *const state) c->range -= range1; if (c->low < c->range) { *state = c->zero_state[*state]; - refill(c); + if (c->range < 0x100) + refill(c); return 0; } else { c->low -= c->range; *state = c->one_state[*state]; c->range = range1; - refill(c); + if (c->range < 0x100) + refill(c); return 1; } } diff --git a/libavcodec/rasc.c b/libavcodec/rasc.c index 7b0251ca3f..a8e00a41a6 100644 --- a/libavcodec/rasc.c +++ b/libavcodec/rasc.c @@ -779,7 +779,7 @@ static av_cold int decode_close(AVCodecContext *avctx) return 0; } -static void decode_flush(AVCodecContext *avctx) +static av_cold void decode_flush(AVCodecContext *avctx) { RASCContext *s = avctx->priv_data; diff --git a/libavcodec/ratecontrol.c b/libavcodec/ratecontrol.c index 86ec7a3443..7f89b5b218 100644 --- a/libavcodec/ratecontrol.c +++ b/libavcodec/ratecontrol.c @@ -35,25 +35,26 @@ #include "mpegvideoenc.h" #include "libavutil/eval.h" -void ff_write_pass1_stats(MpegEncContext *s) +void ff_write_pass1_stats(MPVMainEncContext *const m) { - snprintf(s->avctx->stats_out, 256, + const MPVEncContext *const s = &m->s; + snprintf(s->c.avctx->stats_out, 256, "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d " "fcode:%d bcode:%d mc-var:%"PRId64" var:%"PRId64" icount:%d hbits:%d;\n", - s->cur_pic.ptr->display_picture_number, - s->cur_pic.ptr->coded_picture_number, - s->pict_type, - s->cur_pic.ptr->f->quality, + s->c.cur_pic.ptr->display_picture_number, + s->c.cur_pic.ptr->coded_picture_number, + s->c.pict_type, + s->c.cur_pic.ptr->f->quality, s->i_tex_bits, s->p_tex_bits, s->mv_bits, s->misc_bits, s->f_code, s->b_code, - s->mc_mb_var_sum, - s->mb_var_sum, + m->mc_mb_var_sum, + m->mb_var_sum, s->i_count, - s->header_bits); + m->header_bits); } static AVRational get_fpsQ(AVCodecContext *avctx) @@ -61,13 +62,7 @@ static AVRational get_fpsQ(AVCodecContext *avctx) if (avctx->framerate.num > 0 && avctx->framerate.den > 0) return avctx->framerate; -FF_DISABLE_DEPRECATION_WARNINGS -#if FF_API_TICKS_PER_FRAME - return av_div_q((AVRational){1, FFMAX(avctx->ticks_per_frame, 1)}, avctx->time_base); -#else return av_inv_q(avctx->time_base); -#endif -FF_ENABLE_DEPRECATION_WARNINGS } static double get_fps(AVCodecContext *avctx) @@ -101,10 +96,11 @@ static double bits2qp_cb(void *rce, double qp) return bits2qp(rce, qp); } -static double get_diff_limited_q(MpegEncContext *s, const RateControlEntry *rce, double q) +static double get_diff_limited_q(MPVMainEncContext *m, const RateControlEntry *rce, double q) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + AVCodecContext *const a = s->c.avctx; const int pict_type = rce->new_pict_type; const double last_p_q = rcc->last_qscale_for[AV_PICTURE_TYPE_P]; const double last_non_b_q = rcc->last_qscale_for[rcc->last_non_b_pict_type]; @@ -140,21 +136,22 @@ static double get_diff_limited_q(MpegEncContext *s, const RateControlEntry *rce, /** * Get the qmin & qmax for pict_type. */ -static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pict_type) +static void get_qminmax(int *qmin_ret, int *qmax_ret, MPVMainEncContext *const m, int pict_type) { - int qmin = s->lmin; - int qmax = s->lmax; + MPVEncContext *const s = &m->s; + int qmin = m->lmin; + int qmax = m->lmax; av_assert0(qmin <= qmax); switch (pict_type) { case AV_PICTURE_TYPE_B: - qmin = (int)(qmin * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); - qmax = (int)(qmax * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); + qmin = (int)(qmin * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->c.avctx->b_quant_factor) + s->c.avctx->b_quant_offset + 0.5); break; case AV_PICTURE_TYPE_I: - qmin = (int)(qmin * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); - qmax = (int)(qmax * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); + qmin = (int)(qmin * FFABS(s->c.avctx->i_quant_factor) + s->c.avctx->i_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->c.avctx->i_quant_factor) + s->c.avctx->i_quant_offset + 0.5); break; } @@ -168,24 +165,25 @@ static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pic *qmax_ret = qmax; } -static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, +static double modify_qscale(MPVMainEncContext *const m, const RateControlEntry *rce, double q, int frame_num) { - RateControlContext *rcc = &s->rc_context; - const double buffer_size = s->avctx->rc_buffer_size; - const double fps = get_fps(s->avctx); - const double min_rate = s->avctx->rc_min_rate / fps; - const double max_rate = s->avctx->rc_max_rate / fps; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + const double buffer_size = s->c.avctx->rc_buffer_size; + const double fps = get_fps(s->c.avctx); + const double min_rate = s->c.avctx->rc_min_rate / fps; + const double max_rate = s->c.avctx->rc_max_rate / fps; const int pict_type = rce->new_pict_type; int qmin, qmax; - get_qminmax(&qmin, &qmax, s, pict_type); + get_qminmax(&qmin, &qmax, m, pict_type); /* modulation */ - if (s->rc_qmod_freq && - frame_num % s->rc_qmod_freq == 0 && + if (rcc->qmod_freq && + frame_num % rcc->qmod_freq == 0 && pict_type == AV_PICTURE_TYPE_P) - q *= s->rc_qmod_amp; + q *= rcc->qmod_amp; /* buffer overflow/underflow protection */ if (buffer_size) { @@ -198,15 +196,15 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, d = 1.0; else if (d < 0.0001) d = 0.0001; - q *= pow(d, 1.0 / s->rc_buffer_aggressivity); + q *= pow(d, 1.0 / rcc->buffer_aggressivity); q_limit = bits2qp(rce, FFMAX((min_rate - buffer_size + rcc->buffer_index) * - s->avctx->rc_min_vbv_overflow_use, 1)); + s->c.avctx->rc_min_vbv_overflow_use, 1)); if (q > q_limit) { - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) + av_log(s->c.avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit); q = q_limit; } @@ -218,24 +216,24 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, d = 1.0; else if (d < 0.0001) d = 0.0001; - q /= pow(d, 1.0 / s->rc_buffer_aggressivity); + q /= pow(d, 1.0 / rcc->buffer_aggressivity); q_limit = bits2qp(rce, FFMAX(rcc->buffer_index * - s->avctx->rc_max_available_vbv_use, + s->c.avctx->rc_max_available_vbv_use, 1)); if (q < q_limit) { - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) + av_log(s->c.avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit); q = q_limit; } } } - ff_dlog(s, "q:%f max:%f min:%f size:%f index:%f agr:%f\n", + ff_dlog(s->c.avctx, "q:%f max:%f min:%f size:%f index:%f agr:%f\n", q, max_rate, min_rate, buffer_size, rcc->buffer_index, - s->rc_buffer_aggressivity); - if (s->rc_qsquish == 0.0 || qmin == qmax) { + rcc->buffer_aggressivity); + if (rcc->qsquish == 0.0 || qmin == qmax) { if (q < qmin) q = qmin; else if (q > qmax) @@ -259,13 +257,14 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, /** * Modify the bitrate curve from pass1 for one frame. */ -static double get_qscale(MpegEncContext *s, RateControlEntry *rce, +static double get_qscale(MPVMainEncContext *const m, RateControlEntry *rce, double rate_factor, int frame_num) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; const int pict_type = rce->new_pict_type; - const double mb_num = s->mb_num; + const double mb_num = s->c.mb_num; double q, bits; int i; @@ -284,7 +283,7 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, rce->pict_type == AV_PICTURE_TYPE_P, rce->pict_type == AV_PICTURE_TYPE_B, rcc->qscale_sum[pict_type] / (double)rcc->frame_count[pict_type], - a->qcompress, + avctx->qcompress, rcc->i_cplx_sum[AV_PICTURE_TYPE_I] / (double)rcc->frame_count[AV_PICTURE_TYPE_I], rcc->i_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], rcc->p_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], @@ -295,7 +294,7 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, bits = av_expr_eval(rcc->rc_eq_eval, const_values, rce); if (isnan(bits)) { - av_log(s->avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", s->rc_eq); + av_log(avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", rcc->rc_eq); return -1; } @@ -306,8 +305,8 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, bits += 1.0; // avoid 1/0 issues /* user override */ - for (i = 0; i < s->avctx->rc_override_count; i++) { - RcOverride *rco = s->avctx->rc_override; + for (i = 0; i < avctx->rc_override_count; i++) { + RcOverride *rco = avctx->rc_override; if (rco[i].start_frame > frame_num) continue; if (rco[i].end_frame < frame_num) @@ -322,31 +321,32 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, q = bits2qp(rce, bits); /* I/B difference */ - if (pict_type == AV_PICTURE_TYPE_I && s->avctx->i_quant_factor < 0.0) - q = -q * s->avctx->i_quant_factor + s->avctx->i_quant_offset; - else if (pict_type == AV_PICTURE_TYPE_B && s->avctx->b_quant_factor < 0.0) - q = -q * s->avctx->b_quant_factor + s->avctx->b_quant_offset; + if (pict_type == AV_PICTURE_TYPE_I && avctx->i_quant_factor < 0.0) + q = -q * avctx->i_quant_factor + avctx->i_quant_offset; + else if (pict_type == AV_PICTURE_TYPE_B && avctx->b_quant_factor < 0.0) + q = -q * avctx->b_quant_factor + avctx->b_quant_offset; if (q < 1) q = 1; return q; } -static int init_pass2(MpegEncContext *s) +static int init_pass2(MPVMainEncContext *const m) { - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; + RateControlContext *const rcc = &m->rc_context; + MPVEncContext *const s = &m->s; + AVCodecContext *const avctx = s->c.avctx; int i, toobig; - AVRational fps = get_fpsQ(s->avctx); + AVRational fps = get_fpsQ(avctx); double complexity[5] = { 0 }; // approximate bits at quant=1 uint64_t const_bits[5] = { 0 }; // quantizer independent bits uint64_t all_const_bits; - uint64_t all_available_bits = av_rescale_q(s->bit_rate, + uint64_t all_available_bits = av_rescale_q(m->bit_rate, (AVRational){rcc->num_entries,1}, fps); double rate_factor = 0; double step; - const int filter_size = (int)(a->qblur * 4) | 1; + const int filter_size = (int)(avctx->qblur * 4) | 1; double expected_bits = 0; // init to silence gcc warning double *qscale, *blurred_qscale, qscale_sum; @@ -370,7 +370,7 @@ static int init_pass2(MpegEncContext *s) const_bits[AV_PICTURE_TYPE_B]; if (all_available_bits < all_const_bits) { - av_log(s->avctx, AV_LOG_ERROR, "requested bitrate is too low\n"); + av_log(avctx, AV_LOG_ERROR, "requested bitrate is too low\n"); return -1; } @@ -387,13 +387,13 @@ static int init_pass2(MpegEncContext *s) expected_bits = 0; rate_factor += step; - rcc->buffer_index = s->avctx->rc_buffer_size / 2; + rcc->buffer_index = avctx->rc_buffer_size / 2; /* find qscale */ for (i = 0; i < rcc->num_entries; i++) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_qscale(s, &rcc->entry[i], rate_factor, i); + qscale[i] = get_qscale(m, &rcc->entry[i], rate_factor, i); rcc->last_qscale_for[rce->pict_type] = qscale[i]; } av_assert0(filter_size % 2 == 1); @@ -402,13 +402,13 @@ static int init_pass2(MpegEncContext *s) for (i = FFMAX(0, rcc->num_entries - 300); i < rcc->num_entries; i++) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + qscale[i] = get_diff_limited_q(m, rce, qscale[i]); } for (i = rcc->num_entries - 1; i >= 0; i--) { const RateControlEntry *rce = &rcc->entry[i]; - qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + qscale[i] = get_diff_limited_q(m, rce, qscale[i]); } /* smooth curve */ @@ -421,7 +421,7 @@ static int init_pass2(MpegEncContext *s) for (j = 0; j < filter_size; j++) { int index = i + j - filter_size / 2; double d = index - i; - double coeff = a->qblur == 0 ? 1.0 : exp(-d * d / (a->qblur * a->qblur)); + double coeff = avctx->qblur == 0 ? 1.0 : exp(-d * d / (avctx->qblur * avctx->qblur)); if (index < 0 || index >= rcc->num_entries) continue; @@ -438,16 +438,16 @@ static int init_pass2(MpegEncContext *s) RateControlEntry *rce = &rcc->entry[i]; double bits; - rce->new_qscale = modify_qscale(s, rce, blurred_qscale[i], i); + rce->new_qscale = modify_qscale(m, rce, blurred_qscale[i], i); bits = qp2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits; - bits += 8 * ff_vbv_update(s, bits); + bits += 8 * ff_vbv_update(m, bits); rce->expected_bits = expected_bits; expected_bits += bits; } - ff_dlog(s->avctx, + ff_dlog(avctx, "expected_bits: %f all_available_bits: %d rate_factor: %f\n", expected_bits, (int)all_available_bits, rate_factor); if (expected_bits > all_available_bits) { @@ -461,32 +461,32 @@ static int init_pass2(MpegEncContext *s) /* check bitrate calculations and print info */ qscale_sum = 0.0; for (i = 0; i < rcc->num_entries; i++) { - ff_dlog(s, "[lavc rc] entry[%d].new_qscale = %.3f qp = %.3f\n", + ff_dlog(avctx, "[lavc rc] entry[%d].new_qscale = %.3f qp = %.3f\n", i, rcc->entry[i].new_qscale, rcc->entry[i].new_qscale / FF_QP2LAMBDA); qscale_sum += av_clip(rcc->entry[i].new_qscale / FF_QP2LAMBDA, - s->avctx->qmin, s->avctx->qmax); + avctx->qmin, avctx->qmax); } av_assert0(toobig <= 40); - av_log(s->avctx, AV_LOG_DEBUG, + av_log(avctx, AV_LOG_DEBUG, "[lavc rc] requested bitrate: %"PRId64" bps expected bitrate: %"PRId64" bps\n", - s->bit_rate, - (int64_t)(expected_bits / ((double)all_available_bits / s->bit_rate))); - av_log(s->avctx, AV_LOG_DEBUG, + m->bit_rate, + (int64_t)(expected_bits / ((double)all_available_bits / m->bit_rate))); + av_log(avctx, AV_LOG_DEBUG, "[lavc rc] estimated target average qp: %.3f\n", (float)qscale_sum / rcc->num_entries); if (toobig == 0) { - av_log(s->avctx, AV_LOG_INFO, + av_log(avctx, AV_LOG_INFO, "[lavc rc] Using all of requested bitrate is not " "necessary for this video with these parameters.\n"); } else if (toobig == 40) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "[lavc rc] Error: bitrate too low for this video " "with these parameters.\n"); return -1; } else if (fabs(expected_bits / all_available_bits - 1.0) > 0.01) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "[lavc rc] Error: 2pass curve failed to converge\n"); return -1; } @@ -494,9 +494,11 @@ static int init_pass2(MpegEncContext *s) return 0; } -av_cold int ff_rate_control_init(MpegEncContext *s) +av_cold int ff_rate_control_init(MPVMainEncContext *const m) { - RateControlContext *rcc = &s->rc_context; + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; int i, res; static const char * const const_names[] = { "PI", @@ -533,19 +535,19 @@ av_cold int ff_rate_control_init(MpegEncContext *s) }; emms_c(); - if (!s->avctx->rc_max_available_vbv_use && s->avctx->rc_buffer_size) { - if (s->avctx->rc_max_rate) { - s->avctx->rc_max_available_vbv_use = av_clipf(s->avctx->rc_max_rate/(s->avctx->rc_buffer_size*get_fps(s->avctx)), 1.0/3, 1.0); + if (!avctx->rc_max_available_vbv_use && avctx->rc_buffer_size) { + if (avctx->rc_max_rate) { + avctx->rc_max_available_vbv_use = av_clipf(avctx->rc_max_rate/(avctx->rc_buffer_size*get_fps(avctx)), 1.0/3, 1.0); } else - s->avctx->rc_max_available_vbv_use = 1.0; + avctx->rc_max_available_vbv_use = 1.0; } res = av_expr_parse(&rcc->rc_eq_eval, - s->rc_eq ? s->rc_eq : "tex^qComp", + rcc->rc_eq ? rcc->rc_eq : "tex^qComp", const_names, func1_names, func1, - NULL, NULL, 0, s->avctx); + NULL, NULL, 0, avctx); if (res < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", s->rc_eq); + av_log(avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", rcc->rc_eq); return res; } @@ -562,19 +564,19 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rcc->last_qscale_for[i] = FF_QP2LAMBDA * 5; } - rcc->buffer_index = s->avctx->rc_initial_buffer_occupancy; + rcc->buffer_index = avctx->rc_initial_buffer_occupancy; if (!rcc->buffer_index) - rcc->buffer_index = s->avctx->rc_buffer_size * 3 / 4; + rcc->buffer_index = avctx->rc_buffer_size * 3 / 4; - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (avctx->flags & AV_CODEC_FLAG_PASS2) { int i; char *p; /* find number of pics */ - p = s->avctx->stats_in; + p = avctx->stats_in; for (i = -1; p; i++) p = strchr(p + 1, ';'); - i += s->max_b_frames; + i += m->max_b_frames; if (i <= 0 || i >= INT_MAX / sizeof(RateControlEntry)) return -1; rcc->entry = av_mallocz(i * sizeof(RateControlEntry)); @@ -589,13 +591,13 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rce->pict_type = rce->new_pict_type = AV_PICTURE_TYPE_P; rce->qscale = rce->new_qscale = FF_QP2LAMBDA * 2; - rce->misc_bits = s->mb_num + 10; - rce->mb_var_sum = s->mb_num * 100; + rce->misc_bits = s->c.mb_num + 10; + rce->mb_var_sum = s->c.mb_num * 100; } /* read stats */ - p = s->avctx->stats_in; - for (i = 0; i < rcc->num_entries - s->max_b_frames; i++) { + p = avctx->stats_in; + for (i = 0; i < rcc->num_entries - m->max_b_frames; i++) { RateControlEntry *rce; int picture_number; int e; @@ -623,7 +625,7 @@ av_cold int ff_rate_control_init(MpegEncContext *s) &rce->mc_mb_var_sum, &rce->mb_var_sum, &rce->i_count, &rce->header_bits); if (e != 13) { - av_log(s->avctx, AV_LOG_ERROR, + av_log(avctx, AV_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); return -1; @@ -632,46 +634,46 @@ av_cold int ff_rate_control_init(MpegEncContext *s) p = next; } - res = init_pass2(s); + res = init_pass2(m); if (res < 0) return res; } - if (!(s->avctx->flags & AV_CODEC_FLAG_PASS2)) { + if (!(avctx->flags & AV_CODEC_FLAG_PASS2)) { rcc->short_term_qsum = 0.001; rcc->short_term_qcount = 0.001; rcc->pass1_rc_eq_output_sum = 0.001; rcc->pass1_wanted_bits = 0.001; - if (s->avctx->qblur > 1.0) { - av_log(s->avctx, AV_LOG_ERROR, "qblur too large\n"); + if (avctx->qblur > 1.0) { + av_log(avctx, AV_LOG_ERROR, "qblur too large\n"); return -1; } /* init stuff with the user specified complexity */ - if (s->rc_initial_cplx) { + if (rcc->initial_cplx) { for (i = 0; i < 60 * 30; i++) { - double bits = s->rc_initial_cplx * (i / 10000.0 + 1.0) * s->mb_num; + double bits = rcc->initial_cplx * (i / 10000.0 + 1.0) * s->c.mb_num; RateControlEntry rce; - if (i % ((s->gop_size + 3) / 4) == 0) + if (i % ((m->gop_size + 3) / 4) == 0) rce.pict_type = AV_PICTURE_TYPE_I; - else if (i % (s->max_b_frames + 1)) + else if (i % (m->max_b_frames + 1)) rce.pict_type = AV_PICTURE_TYPE_B; else rce.pict_type = AV_PICTURE_TYPE_P; rce.new_pict_type = rce.pict_type; - rce.mc_mb_var_sum = bits * s->mb_num / 100000; - rce.mb_var_sum = s->mb_num; + rce.mc_mb_var_sum = bits * s->c.mb_num / 100000; + rce.mb_var_sum = s->c.mb_num; rce.qscale = FF_QP2LAMBDA * 2; rce.f_code = 2; rce.b_code = 1; rce.misc_bits = 1; - if (s->pict_type == AV_PICTURE_TYPE_I) { - rce.i_count = s->mb_num; + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + rce.i_count = s->c.mb_num; rce.i_tex_bits = bits; rce.p_tex_bits = 0; rce.mv_bits = 0; @@ -686,14 +688,23 @@ av_cold int ff_rate_control_init(MpegEncContext *s) rcc->mv_bits_sum[rce.pict_type] += rce.mv_bits; rcc->frame_count[rce.pict_type]++; - get_qscale(s, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i); + get_qscale(m, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i); // FIXME misbehaves a little for variable fps - rcc->pass1_wanted_bits += s->bit_rate / get_fps(s->avctx); + rcc->pass1_wanted_bits += m->bit_rate / get_fps(avctx); } } } + if (s->adaptive_quant) { + unsigned mb_array_size = s->c.mb_stride * s->c.mb_height; + + rcc->cplx_tab = av_malloc_array(mb_array_size, 2 * sizeof(*rcc->cplx_tab)); + if (!rcc->cplx_tab) + return AVERROR(ENOMEM); + rcc->bits_tab = rcc->cplx_tab + mb_array_size; + } + return 0; } @@ -701,20 +712,24 @@ av_cold void ff_rate_control_uninit(RateControlContext *rcc) { emms_c(); + // rc_eq is always managed via an AVOption and therefore not freed here. av_expr_free(rcc->rc_eq_eval); rcc->rc_eq_eval = NULL; av_freep(&rcc->entry); + av_freep(&rcc->cplx_tab); } -int ff_vbv_update(MpegEncContext *s, int frame_size) +int ff_vbv_update(MPVMainEncContext *m, int frame_size) { - RateControlContext *rcc = &s->rc_context; - const double fps = get_fps(s->avctx); - const int buffer_size = s->avctx->rc_buffer_size; - const double min_rate = s->avctx->rc_min_rate / fps; - const double max_rate = s->avctx->rc_max_rate / fps; + MPVEncContext *const s = &m->s; + RateControlContext *const rcc = &m->rc_context; + AVCodecContext *const avctx = s->c.avctx; + const double fps = get_fps(avctx); + const int buffer_size = avctx->rc_buffer_size; + const double min_rate = avctx->rc_min_rate / fps; + const double max_rate = avctx->rc_max_rate / fps; - ff_dlog(s, "%d %f %d %f %f\n", + ff_dlog(avctx, "%d %f %d %f %f\n", buffer_size, rcc->buffer_index, frame_size, min_rate, max_rate); if (buffer_size) { @@ -722,9 +737,9 @@ int ff_vbv_update(MpegEncContext *s, int frame_size) rcc->buffer_index -= frame_size; if (rcc->buffer_index < 0) { - av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n"); - if (frame_size > max_rate && s->qscale == s->avctx->qmax) { - av_log(s->avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n"); + av_log(avctx, AV_LOG_ERROR, "rc buffer underflow\n"); + if (frame_size > max_rate && s->c.qscale == avctx->qmax) { + av_log(avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n"); } rcc->buffer_index = 0; } @@ -735,12 +750,12 @@ int ff_vbv_update(MpegEncContext *s, int frame_size) if (rcc->buffer_index > buffer_size) { int stuffing = ceil((rcc->buffer_index - buffer_size) / 8); - if (stuffing < 4 && s->codec_id == AV_CODEC_ID_MPEG4) + if (stuffing < 4 && s->c.codec_id == AV_CODEC_ID_MPEG4) stuffing = 4; rcc->buffer_index -= 8 * stuffing; - if (s->avctx->debug & FF_DEBUG_RC) - av_log(s->avctx, AV_LOG_DEBUG, "stuffing %d bytes\n", stuffing); + if (avctx->debug & FF_DEBUG_RC) + av_log(avctx, AV_LOG_DEBUG, "stuffing %d bytes\n", stuffing); return stuffing; } @@ -765,32 +780,33 @@ static void update_predictor(Predictor *p, double q, double var, double size) p->coeff += new_coeff; } -static void adaptive_quantization(MpegEncContext *s, double q) +static void adaptive_quantization(RateControlContext *const rcc, + MPVMainEncContext *const m, double q) { - int i; - const float lumi_masking = s->avctx->lumi_masking / (128.0 * 128.0); - const float dark_masking = s->avctx->dark_masking / (128.0 * 128.0); - const float temp_cplx_masking = s->avctx->temporal_cplx_masking; - const float spatial_cplx_masking = s->avctx->spatial_cplx_masking; - const float p_masking = s->avctx->p_masking; - const float border_masking = s->border_masking; + MPVEncContext *const s = &m->s; + const float lumi_masking = s->c.avctx->lumi_masking / (128.0 * 128.0); + const float dark_masking = s->c.avctx->dark_masking / (128.0 * 128.0); + const float temp_cplx_masking = s->c.avctx->temporal_cplx_masking; + const float spatial_cplx_masking = s->c.avctx->spatial_cplx_masking; + const float p_masking = s->c.avctx->p_masking; + const float border_masking = m->border_masking; float bits_sum = 0.0; float cplx_sum = 0.0; - float *cplx_tab = s->cplx_tab; - float *bits_tab = s->bits_tab; - const int qmin = s->avctx->mb_lmin; - const int qmax = s->avctx->mb_lmax; - const int mb_width = s->mb_width; - const int mb_height = s->mb_height; + float *cplx_tab = rcc->cplx_tab; + float *bits_tab = rcc->bits_tab; + const int qmin = s->c.avctx->mb_lmin; + const int qmax = s->c.avctx->mb_lmax; + const int mb_width = s->c.mb_width; + const int mb_height = s->c.mb_height; - for (i = 0; i < s->mb_num; i++) { - const int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + const int mb_xy = s->c.mb_index2xy[i]; float temp_cplx = sqrt(s->mc_mb_var[mb_xy]); // FIXME merge in pow() float spat_cplx = sqrt(s->mb_var[mb_xy]); const int lumi = s->mb_mean[mb_xy]; float bits, cplx, factor; - int mb_x = mb_xy % s->mb_stride; - int mb_y = mb_xy / s->mb_stride; + int mb_x = mb_xy % s->c.mb_stride; + int mb_y = mb_xy / s->c.mb_stride; int mb_distance; float mb_factor = 0.0; if (spat_cplx < 4) @@ -844,7 +860,7 @@ static void adaptive_quantization(MpegEncContext *s, double q) /* handle qmin/qmax clipping */ if (s->mpv_flags & FF_MPV_FLAG_NAQ) { float factor = bits_sum / cplx_sum; - for (i = 0; i < s->mb_num; i++) { + for (int i = 0; i < s->c.mb_num; i++) { float newq = q * cplx_tab[i] / bits_tab[i]; newq *= factor; @@ -862,8 +878,8 @@ static void adaptive_quantization(MpegEncContext *s, double q) cplx_sum = 0.001; } - for (i = 0; i < s->mb_num; i++) { - const int mb_xy = s->mb_index2xy[i]; + for (int i = 0; i < s->c.mb_num; i++) { + const int mb_xy = s->c.mb_index2xy[i]; float newq = q * cplx_tab[i] / bits_tab[i]; int intq; @@ -881,9 +897,10 @@ static void adaptive_quantization(MpegEncContext *s, double q) } } -void ff_get_2pass_fcode(MpegEncContext *s) +void ff_get_2pass_fcode(MPVMainEncContext *const m) { - const RateControlContext *rcc = &s->rc_context; + MPVEncContext *const s = &m->s; + const RateControlContext *rcc = &m->rc_context; const RateControlEntry *rce = &rcc->entry[s->picture_number]; s->f_code = rce->f_code; @@ -892,8 +909,11 @@ void ff_get_2pass_fcode(MpegEncContext *s) // FIXME rd or at least approx for dquant -float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) +float ff_rate_estimate_qscale(MPVMainEncContext *const m, int dry_run) { + MPVEncContext *const s = &m->s; + RateControlContext *rcc = &m->rc_context; + AVCodecContext *const a = s->c.avctx; float q; int qmin, qmax; float br_compensation; @@ -902,34 +922,32 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) double fps; int picture_number = s->picture_number; int64_t wanted_bits; - RateControlContext *rcc = &s->rc_context; - AVCodecContext *a = s->avctx; RateControlEntry local_rce, *rce; double bits; double rate_factor; int64_t var; - const int pict_type = s->pict_type; + const int pict_type = s->c.pict_type; emms_c(); - get_qminmax(&qmin, &qmax, s, pict_type); + get_qminmax(&qmin, &qmax, m, pict_type); - fps = get_fps(s->avctx); + fps = get_fps(s->c.avctx); /* update predictors */ if (picture_number > 2 && !dry_run) { const int64_t last_var = - s->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum + m->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum : rcc->last_mc_mb_var_sum; - av_assert1(s->frame_bits >= s->stuffing_bits); - update_predictor(&rcc->pred[s->last_pict_type], + av_assert1(m->frame_bits >= m->stuffing_bits); + update_predictor(&rcc->pred[m->last_pict_type], rcc->last_qscale, sqrt(last_var), - s->frame_bits - s->stuffing_bits); + m->frame_bits - m->stuffing_bits); } - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { av_assert0(picture_number >= 0); if (picture_number >= rcc->num_entries) { - av_log(s, AV_LOG_ERROR, "Input is longer than 2-pass log file\n"); + av_log(s->c.avctx, AV_LOG_ERROR, "Input is longer than 2-pass log file\n"); return -1; } rce = &rcc->entry[picture_number]; @@ -942,42 +960,42 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) /* FIXME add a dts field to AVFrame and ensure it is set and use it * here instead of reordering but the reordering is simpler for now * until H.264 B-pyramid must be handled. */ - if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) - dts_pic = s->cur_pic.ptr; + if (s->c.pict_type == AV_PICTURE_TYPE_B || s->c.low_delay) + dts_pic = s->c.cur_pic.ptr; else - dts_pic = s->last_pic.ptr; + dts_pic = s->c.last_pic.ptr; if (!dts_pic || dts_pic->f->pts == AV_NOPTS_VALUE) - wanted_bits_double = s->bit_rate * (double)picture_number / fps; + wanted_bits_double = m->bit_rate * (double)picture_number / fps; else - wanted_bits_double = s->bit_rate * (double)dts_pic->f->pts / fps; + wanted_bits_double = m->bit_rate * (double)dts_pic->f->pts / fps; if (wanted_bits_double > INT64_MAX) { - av_log(s, AV_LOG_WARNING, "Bits exceed 64bit range\n"); + av_log(s->c.avctx, AV_LOG_WARNING, "Bits exceed 64bit range\n"); wanted_bits = INT64_MAX; } else wanted_bits = (int64_t)wanted_bits_double; } - diff = s->total_bits - wanted_bits; + diff = m->total_bits - wanted_bits; br_compensation = (a->bit_rate_tolerance - diff) / a->bit_rate_tolerance; if (br_compensation <= 0.0) br_compensation = 0.001; - var = pict_type == AV_PICTURE_TYPE_I ? s->mb_var_sum : s->mc_mb_var_sum; + var = pict_type == AV_PICTURE_TYPE_I ? m->mb_var_sum : m->mc_mb_var_sum; short_term_q = 0; /* avoid warning */ - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (s->c.avctx->flags & AV_CODEC_FLAG_PASS2) { if (pict_type != AV_PICTURE_TYPE_I) av_assert0(pict_type == rce->new_pict_type); q = rce->new_qscale / br_compensation; - ff_dlog(s, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale, - br_compensation, s->frame_bits, var, pict_type); + ff_dlog(s->c.avctx, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale, + br_compensation, m->frame_bits, var, pict_type); } else { rce->pict_type = rce->new_pict_type = pict_type; - rce->mc_mb_var_sum = s->mc_mb_var_sum; - rce->mb_var_sum = s->mb_var_sum; + rce->mc_mb_var_sum = m->mc_mb_var_sum; + rce->mb_var_sum = m->mb_var_sum; rce->qscale = FF_QP2LAMBDA * 2; rce->f_code = s->f_code; rce->b_code = s->b_code; @@ -985,7 +1003,7 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) bits = predict_size(&rcc->pred[pict_type], rce->qscale, sqrt(var)); if (pict_type == AV_PICTURE_TYPE_I) { - rce->i_count = s->mb_num; + rce->i_count = s->c.mb_num; rce->i_tex_bits = bits; rce->p_tex_bits = 0; rce->mv_bits = 0; @@ -1003,16 +1021,16 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) rate_factor = rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum * br_compensation; - q = get_qscale(s, rce, rate_factor, picture_number); + q = get_qscale(m, rce, rate_factor, picture_number); if (q < 0) return -1; av_assert0(q > 0.0); - q = get_diff_limited_q(s, rce, q); + q = get_diff_limited_q(m, rce, q); av_assert0(q > 0.0); // FIXME type dependent blur like in 2-pass - if (pict_type == AV_PICTURE_TYPE_P || s->intra_only) { + if (pict_type == AV_PICTURE_TYPE_P || m->intra_only) { rcc->short_term_qsum *= a->qblur; rcc->short_term_qcount *= a->qblur; @@ -1022,23 +1040,23 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) } av_assert0(q > 0.0); - q = modify_qscale(s, rce, q, picture_number); + q = modify_qscale(m, rce, q, picture_number); - rcc->pass1_wanted_bits += s->bit_rate / fps; + rcc->pass1_wanted_bits += m->bit_rate / fps; av_assert0(q > 0.0); } - if (s->avctx->debug & FF_DEBUG_RC) { - av_log(s->avctx, AV_LOG_DEBUG, + if (s->c.avctx->debug & FF_DEBUG_RC) { + av_log(s->c.avctx, AV_LOG_DEBUG, "%c qp:%d<%2.1f<%d %d want:%"PRId64" total:%"PRId64" comp:%f st_q:%2.2f " "size:%d var:%"PRId64"/%"PRId64" br:%"PRId64" fps:%d\n", av_get_picture_type_char(pict_type), qmin, q, qmax, picture_number, - wanted_bits / 1000, s->total_bits / 1000, - br_compensation, short_term_q, s->frame_bits, - s->mb_var_sum, s->mc_mb_var_sum, - s->bit_rate / 1000, (int)fps); + wanted_bits / 1000, m->total_bits / 1000, + br_compensation, short_term_q, m->frame_bits, + m->mb_var_sum, m->mc_mb_var_sum, + m->bit_rate / 1000, (int)fps); } if (q < qmin) @@ -1047,14 +1065,14 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) q = qmax; if (s->adaptive_quant) - adaptive_quantization(s, q); + adaptive_quantization(rcc, m, q); else q = (int)(q + 0.5); if (!dry_run) { rcc->last_qscale = q; - rcc->last_mc_mb_var_sum = s->mc_mb_var_sum; - rcc->last_mb_var_sum = s->mb_var_sum; + rcc->last_mc_mb_var_sum = m->mc_mb_var_sum; + rcc->last_mb_var_sum = m->mb_var_sum; } return q; } diff --git a/libavcodec/ratecontrol.h b/libavcodec/ratecontrol.h index 4d71a181b5..3bcfa5658a 100644 --- a/libavcodec/ratecontrol.h +++ b/libavcodec/ratecontrol.h @@ -77,17 +77,30 @@ typedef struct RateControlContext{ int frame_count[5]; int last_non_b_pict_type; + /** + * ratecontrol qmin qmax limiting method + * 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. + */ + float qsquish; + float qmod_amp; + int qmod_freq; + float initial_cplx; + float buffer_aggressivity; + + char *rc_eq; struct AVExpr *rc_eq_eval; + + float *cplx_tab, *bits_tab; }RateControlContext; -struct MpegEncContext; +typedef struct MPVMainEncContext MPVMainEncContext; /* rate control */ -int ff_rate_control_init(struct MpegEncContext *s); -float ff_rate_estimate_qscale(struct MpegEncContext *s, int dry_run); -void ff_write_pass1_stats(struct MpegEncContext *s); -int ff_vbv_update(struct MpegEncContext *s, int frame_size); -void ff_get_2pass_fcode(struct MpegEncContext *s); +int ff_rate_control_init(MPVMainEncContext *m); +float ff_rate_estimate_qscale(MPVMainEncContext *m, int dry_run); +void ff_write_pass1_stats(MPVMainEncContext *m); +int ff_vbv_update(MPVMainEncContext *m, int frame_size); +void ff_get_2pass_fcode(MPVMainEncContext *m); void ff_rate_control_uninit(RateControlContext *rcc); #endif /* AVCODEC_RATECONTROL_H */ diff --git a/libavcodec/raw.c b/libavcodec/raw.c index b73b80e5fd..095bd4310b 100644 --- a/libavcodec/raw.c +++ b/libavcodec/raw.c @@ -24,286 +24,9 @@ * Raw Video Codec */ -#include "libavutil/macros.h" #include "avcodec.h" #include "raw.h" - -static const PixelFormatTag raw_pix_fmt_tags[] = { - { AV_PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ - { AV_PIX_FMT_YUV420P, MKTAG('I', 'Y', 'U', 'V') }, - { AV_PIX_FMT_YUV420P, MKTAG('y', 'v', '1', '2') }, - { AV_PIX_FMT_YUV420P, MKTAG('Y', 'V', '1', '2') }, - { AV_PIX_FMT_YUV410P, MKTAG('Y', 'U', 'V', '9') }, - { AV_PIX_FMT_YUV410P, MKTAG('Y', 'V', 'U', '9') }, - { AV_PIX_FMT_YUV411P, MKTAG('Y', '4', '1', 'B') }, - { AV_PIX_FMT_YUV422P, MKTAG('Y', '4', '2', 'B') }, - { AV_PIX_FMT_YUV422P, MKTAG('P', '4', '2', '2') }, - { AV_PIX_FMT_YUV422P, MKTAG('Y', 'V', '1', '6') }, - /* yuvjXXX formats are deprecated hacks specific to libav*, - they are identical to yuvXXX */ - { AV_PIX_FMT_YUVJ420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ - { AV_PIX_FMT_YUVJ420P, MKTAG('I', 'Y', 'U', 'V') }, - { AV_PIX_FMT_YUVJ420P, MKTAG('Y', 'V', '1', '2') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('Y', '4', '2', 'B') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('P', '4', '2', '2') }, - { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', '0', '0') }, - { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', ' ', ' ') }, - - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', '2') }, /* Packed formats */ - { AV_PIX_FMT_YUYV422, MKTAG('Y', '4', '2', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('V', '4', '2', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('V', 'Y', 'U', 'Y') }, - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'N', 'V') }, - { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', 'V') }, - { AV_PIX_FMT_YVYU422, MKTAG('Y', 'V', 'Y', 'U') }, /* Philips */ - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'V', 'Y') }, - { AV_PIX_FMT_UYVY422, MKTAG('H', 'D', 'Y', 'C') }, - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'V') }, - { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'Y') }, - { AV_PIX_FMT_UYVY422, MKTAG('u', 'y', 'v', '1') }, - { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', '1') }, - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'R', 'n') }, /* Avid AVI Codec 1:1 */ - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', '1', 'x') }, /* Avid 1:1x */ - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') }, - { AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ - { AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') }, - { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */ - { AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') }, - { AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') }, - { AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') }, - { AV_PIX_FMT_NV21, MKTAG('N', 'V', '2', '1') }, - { AV_PIX_FMT_VUYA, MKTAG('A', 'Y', 'U', 'V') }, /* MS 4:4:4:4 */ - - /* nut */ - { AV_PIX_FMT_RGB555LE, MKTAG('R', 'G', 'B', 15) }, - { AV_PIX_FMT_BGR555LE, MKTAG('B', 'G', 'R', 15) }, - { AV_PIX_FMT_RGB565LE, MKTAG('R', 'G', 'B', 16) }, - { AV_PIX_FMT_BGR565LE, MKTAG('B', 'G', 'R', 16) }, - { AV_PIX_FMT_RGB555BE, MKTAG(15 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR555BE, MKTAG(15 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB565BE, MKTAG(16 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR565BE, MKTAG(16 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB444LE, MKTAG('R', 'G', 'B', 12) }, - { AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) }, - { AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') }, - { AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) }, - { AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) }, - { AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') }, - { AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') }, - { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, - { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) }, - { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, - { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) }, - { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, - { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') }, - { AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') }, - { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') }, - { AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) }, - { AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) }, - { AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') }, - { AV_PIX_FMT_YUV422P, MKTAG('4', '2', '2', 'P') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('4', '2', '2', 'P') }, - { AV_PIX_FMT_YUV440P, MKTAG('4', '4', '0', 'P') }, - { AV_PIX_FMT_YUVJ440P, MKTAG('4', '4', '0', 'P') }, - { AV_PIX_FMT_YUV444P, MKTAG('4', '4', '4', 'P') }, - { AV_PIX_FMT_YUVJ444P, MKTAG('4', '4', '4', 'P') }, - { AV_PIX_FMT_MONOWHITE,MKTAG('B', '1', 'W', '0') }, - { AV_PIX_FMT_MONOBLACK,MKTAG('B', '0', 'W', '1') }, - { AV_PIX_FMT_BGR8, MKTAG('B', 'G', 'R', 8 ) }, - { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', 8 ) }, - { AV_PIX_FMT_BGR4, MKTAG('B', 'G', 'R', 4 ) }, - { AV_PIX_FMT_RGB4, MKTAG('R', 'G', 'B', 4 ) }, - { AV_PIX_FMT_RGB4_BYTE,MKTAG('B', '4', 'B', 'Y') }, - { AV_PIX_FMT_BGR4_BYTE,MKTAG('R', '4', 'B', 'Y') }, - { AV_PIX_FMT_RGB48LE, MKTAG('R', 'G', 'B', 48 ) }, - { AV_PIX_FMT_RGB48BE, MKTAG( 48, 'R', 'G', 'B') }, - { AV_PIX_FMT_BGR48LE, MKTAG('B', 'G', 'R', 48 ) }, - { AV_PIX_FMT_BGR48BE, MKTAG( 48, 'B', 'G', 'R') }, - { AV_PIX_FMT_GRAY9LE, MKTAG('Y', '1', 0 , 9 ) }, - { AV_PIX_FMT_GRAY9BE, MKTAG( 9 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY10LE, MKTAG('Y', '1', 0 , 10 ) }, - { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, - { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, - { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, - { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, - { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, - { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, - { AV_PIX_FMT_YUV420P9BE, MKTAG( 9 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P9LE, MKTAG('Y', '3', 10 , 9 ) }, - { AV_PIX_FMT_YUV422P9BE, MKTAG( 9 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P9LE, MKTAG('Y', '3', 0 , 9 ) }, - { AV_PIX_FMT_YUV444P9BE, MKTAG( 9 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P10LE, MKTAG('Y', '3', 11 , 10 ) }, - { AV_PIX_FMT_YUV420P10BE, MKTAG(10 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P10LE, MKTAG('Y', '3', 10 , 10 ) }, - { AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) }, - { AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) }, - { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) }, - { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) }, - { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) }, - { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) }, - { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) }, - { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) }, - { AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') }, - { AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) }, - { AV_PIX_FMT_YUV422P16BE, MKTAG(16 , 10 , '3', 'Y') }, - { AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) }, - { AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') }, - { AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) }, - { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) }, - { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) }, - { AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) }, - { AV_PIX_FMT_PAL8, MKTAG('P', 'A', 'L', 8 ) }, - - { AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) }, - { AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P9LE, MKTAG('Y', '4', 10 , 9 ) }, - { AV_PIX_FMT_YUVA422P9BE, MKTAG( 9 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P9LE, MKTAG('Y', '4', 0 , 9 ) }, - { AV_PIX_FMT_YUVA444P9BE, MKTAG( 9 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA420P10LE, MKTAG('Y', '4', 11 , 10 ) }, - { AV_PIX_FMT_YUVA420P10BE, MKTAG(10 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P10LE, MKTAG('Y', '4', 10 , 10 ) }, - { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, - { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, - { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, - { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, - { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, - { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, - { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, - { AV_PIX_FMT_YUVA422P16BE, MKTAG(16 , 10 , '4', 'Y') }, - { AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) }, - { AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') }, - - { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) }, - { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) }, - { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) }, - { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) }, - { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) }, - { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') }, - { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) }, - { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') }, - - { AV_PIX_FMT_GBRAP, MKTAG('G', '4', 00 , 8 ) }, - { AV_PIX_FMT_GBRAP10LE, MKTAG('G', '4', 00 , 10 ) }, - { AV_PIX_FMT_GBRAP10BE, MKTAG(10 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP12LE, MKTAG('G', '4', 00 , 12 ) }, - { AV_PIX_FMT_GBRAP12BE, MKTAG(12 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP14LE, MKTAG('G', '4', 00 , 14 ) }, - { AV_PIX_FMT_GBRAP14BE, MKTAG(14 , 00 , '4', 'G') }, - { AV_PIX_FMT_GBRAP16LE, MKTAG('G', '4', 00 , 16 ) }, - { AV_PIX_FMT_GBRAP16BE, MKTAG(16 , 00 , '4', 'G') }, - - { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) }, - { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') }, - - { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) }, - { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) }, - { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) }, - { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) }, - { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) }, - { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) }, - { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) }, - { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) }, - { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) }, - { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) }, - { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) }, - { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) }, - - /* quicktime */ - { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */ - { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */ - { AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') }, - { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') }, - { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */ - { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') }, - { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') }, - { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') }, - { AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */ - { AV_PIX_FMT_RGB555LE,MKTAG('L', '5', '5', '5') }, - { AV_PIX_FMT_RGB565LE,MKTAG('L', '5', '6', '5') }, - { AV_PIX_FMT_RGB565BE,MKTAG('B', '5', '6', '5') }, - { AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') }, - { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') }, - { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, - { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, - { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') }, - { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, - { AV_PIX_FMT_GRAY16BE,MKTAG('b', '1', '6', 'g') }, - { AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') }, - { AV_PIX_FMT_RGBA64BE,MKTAG('b', '6', '4', 'a') }, - { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG('B', 'G', 'G', 'R') }, - - /* vlc */ - { AV_PIX_FMT_YUV410P, MKTAG('I', '4', '1', '0') }, - { AV_PIX_FMT_YUV411P, MKTAG('I', '4', '1', '1') }, - { AV_PIX_FMT_YUV422P, MKTAG('I', '4', '2', '2') }, - { AV_PIX_FMT_YUV440P, MKTAG('I', '4', '4', '0') }, - { AV_PIX_FMT_YUV444P, MKTAG('I', '4', '4', '4') }, - { AV_PIX_FMT_YUVJ420P, MKTAG('J', '4', '2', '0') }, - { AV_PIX_FMT_YUVJ422P, MKTAG('J', '4', '2', '2') }, - { AV_PIX_FMT_YUVJ440P, MKTAG('J', '4', '4', '0') }, - { AV_PIX_FMT_YUVJ444P, MKTAG('J', '4', '4', '4') }, - { AV_PIX_FMT_YUVA444P, MKTAG('Y', 'U', 'V', 'A') }, - { AV_PIX_FMT_YUVA420P, MKTAG('I', '4', '0', 'A') }, - { AV_PIX_FMT_YUVA422P, MKTAG('I', '4', '2', 'A') }, - { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', '2') }, - { AV_PIX_FMT_RGB555LE, MKTAG('R', 'V', '1', '5') }, - { AV_PIX_FMT_RGB565LE, MKTAG('R', 'V', '1', '6') }, - { AV_PIX_FMT_BGR24, MKTAG('R', 'V', '2', '4') }, - { AV_PIX_FMT_BGR0, MKTAG('R', 'V', '3', '2') }, - { AV_PIX_FMT_RGBA, MKTAG('A', 'V', '3', '2') }, - { AV_PIX_FMT_YUV420P9LE, MKTAG('I', '0', '9', 'L') }, - { AV_PIX_FMT_YUV420P9BE, MKTAG('I', '0', '9', 'B') }, - { AV_PIX_FMT_YUV422P9LE, MKTAG('I', '2', '9', 'L') }, - { AV_PIX_FMT_YUV422P9BE, MKTAG('I', '2', '9', 'B') }, - { AV_PIX_FMT_YUV444P9LE, MKTAG('I', '4', '9', 'L') }, - { AV_PIX_FMT_YUV444P9BE, MKTAG('I', '4', '9', 'B') }, - { AV_PIX_FMT_YUV420P10LE, MKTAG('I', '0', 'A', 'L') }, - { AV_PIX_FMT_YUV420P10BE, MKTAG('I', '0', 'A', 'B') }, - { AV_PIX_FMT_YUV422P10LE, MKTAG('I', '2', 'A', 'L') }, - { AV_PIX_FMT_YUV422P10BE, MKTAG('I', '2', 'A', 'B') }, - { AV_PIX_FMT_YUV444P10LE, MKTAG('I', '4', 'A', 'L') }, - { AV_PIX_FMT_YUV444P10BE, MKTAG('I', '4', 'A', 'B') }, - { AV_PIX_FMT_YUV420P12LE, MKTAG('I', '0', 'C', 'L') }, - { AV_PIX_FMT_YUV420P12BE, MKTAG('I', '0', 'C', 'B') }, - { AV_PIX_FMT_YUV422P12LE, MKTAG('I', '2', 'C', 'L') }, - { AV_PIX_FMT_YUV422P12BE, MKTAG('I', '2', 'C', 'B') }, - { AV_PIX_FMT_YUV444P12LE, MKTAG('I', '4', 'C', 'L') }, - { AV_PIX_FMT_YUV444P12BE, MKTAG('I', '4', 'C', 'B') }, - { AV_PIX_FMT_YUV420P16LE, MKTAG('I', '0', 'F', 'L') }, - { AV_PIX_FMT_YUV420P16BE, MKTAG('I', '0', 'F', 'B') }, - { AV_PIX_FMT_YUV444P16LE, MKTAG('I', '4', 'F', 'L') }, - { AV_PIX_FMT_YUV444P16BE, MKTAG('I', '4', 'F', 'B') }, - - /* special */ - { AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ - { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ - - { AV_PIX_FMT_NONE, 0 }, -}; - -const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void) -{ - return raw_pix_fmt_tags; -} +#include "raw_pix_fmt_tags.h" unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat fmt) { diff --git a/libavcodec/raw.h b/libavcodec/raw.h index 9a4ddef8fc..69f7f530ad 100644 --- a/libavcodec/raw.h +++ b/libavcodec/raw.h @@ -34,8 +34,6 @@ typedef struct PixelFormatTag { unsigned int fourcc; } PixelFormatTag; -const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void); - enum PixelFormatTagLists { PIX_FMT_LIST_RAW, PIX_FMT_LIST_AVI, diff --git a/libavcodec/raw_pix_fmt_tags.h b/libavcodec/raw_pix_fmt_tags.h new file mode 100644 index 0000000000..bdde060cf7 --- /dev/null +++ b/libavcodec/raw_pix_fmt_tags.h @@ -0,0 +1,316 @@ +/* + * Raw Video Codec + * Copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RAW_PIX_FMT_TAGS_H +#define AVCODEC_RAW_PIX_FMT_TAGS_H + +#include "raw.h" +#include "libavutil/macros.h" + +static const PixelFormatTag raw_pix_fmt_tags[] = { + { AV_PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUV420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUV420P, MKTAG('y', 'v', '1', '2') }, + { AV_PIX_FMT_YUV420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'U', 'V', '9') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'V', 'U', '9') }, + { AV_PIX_FMT_YUV411P, MKTAG('Y', '4', '1', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', 'V', '1', '6') }, + /* yuvjXXX formats are deprecated hacks specific to libav*, + they are identical to yuvXXX */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', '0', '0') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', ' ', ' ') }, + + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', '2') }, /* Packed formats */ + { AV_PIX_FMT_YUYV422, MKTAG('Y', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', 'Y', 'U', 'Y') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'N', 'V') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', 'V') }, + { AV_PIX_FMT_YVYU422, MKTAG('Y', 'V', 'Y', 'U') }, /* Philips */ + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'V', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('H', 'D', 'Y', 'C') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'V') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('u', 'y', 'v', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'R', 'n') }, /* Avid AVI Codec 1:1 */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', '1', 'x') }, /* Avid 1:1x */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') }, + { AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ + { AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') }, + { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */ + { AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') }, + { AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') }, + { AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') }, + { AV_PIX_FMT_NV21, MKTAG('N', 'V', '2', '1') }, + { AV_PIX_FMT_VUYA, MKTAG('A', 'Y', 'U', 'V') }, /* MS 4:4:4:4 */ + { AV_PIX_FMT_XV30LE, MKTAG('Y', '4', '1', '0') }, + { AV_PIX_FMT_XV48LE, MKTAG('Y', '4', '1', '6') }, + { AV_PIX_FMT_Y210LE, MKTAG('Y', '2', '1', '0') }, + { AV_PIX_FMT_Y216LE, MKTAG('Y', '2', '1', '6') }, + + /* nut */ + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'G', 'B', 15) }, + { AV_PIX_FMT_BGR555LE, MKTAG('B', 'G', 'R', 15) }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'G', 'B', 16) }, + { AV_PIX_FMT_BGR565LE, MKTAG('B', 'G', 'R', 16) }, + { AV_PIX_FMT_RGB555BE, MKTAG(15 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR555BE, MKTAG(15 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB565BE, MKTAG(16 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR565BE, MKTAG(16 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB444LE, MKTAG('R', 'G', 'B', 12) }, + { AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) }, + { AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) }, + { AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) }, + { AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') }, + { AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') }, + { AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') }, + { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) }, + { AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) }, + { AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') }, + { AV_PIX_FMT_YUV422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUV440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUV444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_MONOWHITE, MKTAG('B', '1', 'W', '0') }, + { AV_PIX_FMT_MONOBLACK, MKTAG('B', '0', 'W', '1') }, + { AV_PIX_FMT_BGR8, MKTAG('B', 'G', 'R', 8 ) }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', 8 ) }, + { AV_PIX_FMT_BGR4, MKTAG('B', 'G', 'R', 4 ) }, + { AV_PIX_FMT_RGB4, MKTAG('R', 'G', 'B', 4 ) }, + { AV_PIX_FMT_RGB4_BYTE, MKTAG('B', '4', 'B', 'Y') }, + { AV_PIX_FMT_BGR4_BYTE, MKTAG('R', '4', 'B', 'Y') }, + { AV_PIX_FMT_RGB48LE, MKTAG('R', 'G', 'B', 48 ) }, + { AV_PIX_FMT_RGB48BE, MKTAG( 48, 'R', 'G', 'B') }, + { AV_PIX_FMT_BGR48LE, MKTAG('B', 'G', 'R', 48 ) }, + { AV_PIX_FMT_BGR48BE, MKTAG( 48, 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY9LE, MKTAG('Y', '1', 0 , 9 ) }, + { AV_PIX_FMT_GRAY9BE, MKTAG( 9 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY10LE, MKTAG('Y', '1', 0 , 10 ) }, + { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, + { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, + { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, + { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, + { AV_PIX_FMT_YUV420P9BE, MKTAG( 9 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('Y', '3', 10 , 9 ) }, + { AV_PIX_FMT_YUV422P9BE, MKTAG( 9 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('Y', '3', 0 , 9 ) }, + { AV_PIX_FMT_YUV444P9BE, MKTAG( 9 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('Y', '3', 11 , 10 ) }, + { AV_PIX_FMT_YUV420P10BE, MKTAG(10 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('Y', '3', 10 , 10 ) }, + { AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) }, + { AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) }, + { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) }, + { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) }, + { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) }, + { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) }, + { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) }, + { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) }, + { AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) }, + { AV_PIX_FMT_YUV422P16BE, MKTAG(16 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) }, + { AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) }, + { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) }, + { AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) }, + { AV_PIX_FMT_PAL8, MKTAG('P', 'A', 'L', 8 ) }, + + { AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) }, + { AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P9LE, MKTAG('Y', '4', 10 , 9 ) }, + { AV_PIX_FMT_YUVA422P9BE, MKTAG( 9 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P9LE, MKTAG('Y', '4', 0 , 9 ) }, + { AV_PIX_FMT_YUVA444P9BE, MKTAG( 9 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P10LE, MKTAG('Y', '4', 11 , 10 ) }, + { AV_PIX_FMT_YUVA420P10BE, MKTAG(10 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P10LE, MKTAG('Y', '4', 10 , 10 ) }, + { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, + { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, + { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, + { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, + { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, + { AV_PIX_FMT_YUVA422P16BE, MKTAG(16 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) }, + { AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') }, + + { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) }, + { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) }, + { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) }, + { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) }, + { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) }, + { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) }, + { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRPF16LE, MKTAG('G', '3', 00 , 17 ) }, + { AV_PIX_FMT_GBRPF16BE, MKTAG(17 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRPF32LE, MKTAG('G', '3', 00 , 33 ) }, + { AV_PIX_FMT_GBRPF32BE, MKTAG(33 , 00 , '3', 'G') }, + + { AV_PIX_FMT_GBRAP, MKTAG('G', '4', 00 , 8 ) }, + { AV_PIX_FMT_GBRAP10LE, MKTAG('G', '4', 00 , 10 ) }, + { AV_PIX_FMT_GBRAP10BE, MKTAG(10 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP12LE, MKTAG('G', '4', 00 , 12 ) }, + { AV_PIX_FMT_GBRAP12BE, MKTAG(12 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP14LE, MKTAG('G', '4', 00 , 14 ) }, + { AV_PIX_FMT_GBRAP14BE, MKTAG(14 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP16LE, MKTAG('G', '4', 00 , 16 ) }, + { AV_PIX_FMT_GBRAP16BE, MKTAG(16 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAPF16LE, MKTAG('G', '4', 00 , 17 ) }, + { AV_PIX_FMT_GBRAPF16BE, MKTAG(17 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAPF32LE, MKTAG('G', '4', 00 , 33 ) }, + { AV_PIX_FMT_GBRAPF32BE, MKTAG(33 , 00 , '4', 'G') }, + + { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) }, + { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') }, + + { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) }, + { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) }, + { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) }, + { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) }, + { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) }, + { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) }, + { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) }, + { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) }, + + /* quicktime */ + { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */ + { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */ + { AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */ + { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') }, + { AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */ + { AV_PIX_FMT_VYU444, MKTAG('v', '3', '0', '8') }, + { AV_PIX_FMT_UYVA, MKTAG('v', '4', '0', '8') }, + { AV_PIX_FMT_V30XLE, MKTAG('v', '4', '1', '0') }, + { AV_PIX_FMT_AYUV, MKTAG('y', '4', '0', '8') }, + { AV_PIX_FMT_RGB555LE, MKTAG('L', '5', '5', '5') }, + { AV_PIX_FMT_RGB565LE, MKTAG('L', '5', '6', '5') }, + { AV_PIX_FMT_RGB565BE, MKTAG('B', '5', '6', '5') }, + { AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') }, + { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY16BE, MKTAG('b', '1', '6', 'g') }, + { AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') }, + { AV_PIX_FMT_RGBA64BE, MKTAG('b', '6', '4', 'a') }, + { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG('B', 'G', 'G', 'R') }, + + /* vlc */ + { AV_PIX_FMT_YUV410P, MKTAG('I', '4', '1', '0') }, + { AV_PIX_FMT_YUV411P, MKTAG('I', '4', '1', '1') }, + { AV_PIX_FMT_YUV422P, MKTAG('I', '4', '2', '2') }, + { AV_PIX_FMT_YUV440P, MKTAG('I', '4', '4', '0') }, + { AV_PIX_FMT_YUV444P, MKTAG('I', '4', '4', '4') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('J', '4', '2', '0') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('J', '4', '2', '2') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('J', '4', '4', '0') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('J', '4', '4', '4') }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', 'U', 'V', 'A') }, + { AV_PIX_FMT_YUVA420P, MKTAG('I', '4', '0', 'A') }, + { AV_PIX_FMT_YUVA422P, MKTAG('I', '4', '2', 'A') }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', '2') }, + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'V', '1', '5') }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'V', '1', '6') }, + { AV_PIX_FMT_BGR24, MKTAG('R', 'V', '2', '4') }, + { AV_PIX_FMT_BGR0, MKTAG('R', 'V', '3', '2') }, + { AV_PIX_FMT_RGBA, MKTAG('A', 'V', '3', '2') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('I', '0', '9', 'L') }, + { AV_PIX_FMT_YUV420P9BE, MKTAG('I', '0', '9', 'B') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('I', '2', '9', 'L') }, + { AV_PIX_FMT_YUV422P9BE, MKTAG('I', '2', '9', 'B') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('I', '4', '9', 'L') }, + { AV_PIX_FMT_YUV444P9BE, MKTAG('I', '4', '9', 'B') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('I', '0', 'A', 'L') }, + { AV_PIX_FMT_YUV420P10BE, MKTAG('I', '0', 'A', 'B') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('I', '2', 'A', 'L') }, + { AV_PIX_FMT_YUV422P10BE, MKTAG('I', '2', 'A', 'B') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('I', '4', 'A', 'L') }, + { AV_PIX_FMT_YUV444P10BE, MKTAG('I', '4', 'A', 'B') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('I', '0', 'C', 'L') }, + { AV_PIX_FMT_YUV420P12BE, MKTAG('I', '0', 'C', 'B') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('I', '2', 'C', 'L') }, + { AV_PIX_FMT_YUV422P12BE, MKTAG('I', '2', 'C', 'B') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('I', '4', 'C', 'L') }, + { AV_PIX_FMT_YUV444P12BE, MKTAG('I', '4', 'C', 'B') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('I', '0', 'F', 'L') }, + { AV_PIX_FMT_YUV420P16BE, MKTAG('I', '0', 'F', 'B') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('I', '4', 'F', 'L') }, + { AV_PIX_FMT_YUV444P16BE, MKTAG('I', '4', 'F', 'B') }, + + /* special */ + { AV_PIX_FMT_RGB565LE, MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ + { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ + + { AV_PIX_FMT_NONE, 0 }, +}; + +#endif /* AVCODEC_RAW_PIX_FMT_TAGS_H */ diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c index b02edac371..53d1fba583 100644 --- a/libavcodec/rawdec.c +++ b/libavcodec/rawdec.c @@ -368,24 +368,13 @@ static int raw_decode(AVCodecContext *avctx, AVFrame *frame, return ret; } - if (ff_copy_palette(context->palette->data, avpkt, avctx)) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } else if (context->is_nut_pal8) { + if (!ff_copy_palette(context->palette->data, avpkt, avctx) && context->is_nut_pal8) { int vid_size = avctx->width * avctx->height; int pal_size = avpkt->size - vid_size; if (avpkt->size > vid_size && pal_size <= AVPALETTE_SIZE) { const uint8_t *pal = avpkt->data + vid_size; memcpy(context->palette->data, pal, pal_size); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } } diff --git a/libavcodec/riscv/Makefile b/libavcodec/riscv/Makefile index 27befce929..736f873fe8 100644 --- a/libavcodec/riscv/Makefile +++ b/libavcodec/riscv/Makefile @@ -33,6 +33,10 @@ RVV-OBJS-$(CONFIG_H264CHROMA) += riscv/h264_mc_chroma.o OBJS-$(CONFIG_H264DSP) += riscv/h264dsp_init.o RVV-OBJS-$(CONFIG_H264DSP) += riscv/h264addpx_rvv.o riscv/h264dsp_rvv.o \ riscv/h264idct_rvv.o +OBJS-$(CONFIG_H264QPEL) += riscv/h264qpel_init.o +RVV-OBJS-$(CONFIG_H264QPEL) += riscv/h264qpel_rvv.o +OBJS-$(CONFIG_HEVC_DECODER) += riscv/hevcdsp_init.o +RVV-OBJS-$(CONFIG_HEVC_DECODER) += riscv/h26x/h2656_inter_rvv.o OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_init.o RVV-OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_rvv.o OBJS-$(CONFIG_IDCTDSP) += riscv/idctdsp_init.o @@ -47,8 +51,8 @@ OBJS-$(CONFIG_LPC) += riscv/lpc_init.o RVV-OBJS-$(CONFIG_LPC) += riscv/lpc_rvv.o OBJS-$(CONFIG_ME_CMP) += riscv/me_cmp_init.o RVV-OBJS-$(CONFIG_ME_CMP) += riscv/me_cmp_rvv.o -OBJS-$(CONFIG_MPEGVIDEOENC) += riscv/mpegvideoencdsp_init.o -RVV-OBJS-$(CONFIG_MPEGVIDEOENC) += riscv/mpegvideoencdsp_rvv.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += riscv/mpegvideoencdsp_init.o +RVV-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += riscv/mpegvideoencdsp_rvv.o OBJS-$(CONFIG_OPUS_DECODER) += riscv/opusdsp_init.o RVV-OBJS-$(CONFIG_OPUS_DECODER) += riscv/opusdsp_rvv.o OBJS-$(CONFIG_PIXBLOCKDSP) += riscv/pixblockdsp_init.o diff --git a/libavcodec/riscv/aacencdsp_init.c b/libavcodec/riscv/aacencdsp_init.c index a2dc0a8d3f..7b4e595af9 100644 --- a/libavcodec/riscv/aacencdsp_init.c +++ b/libavcodec/riscv/aacencdsp_init.c @@ -1,6 +1,6 @@ /* * AAC encoder assembly optimizations - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/aacencdsp_rvv.S b/libavcodec/riscv/aacencdsp_rvv.S index 83d1868079..e19b209a11 100644 --- a/libavcodec/riscv/aacencdsp_rvv.S +++ b/libavcodec/riscv/aacencdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/ac3dsp_init.c b/libavcodec/riscv/ac3dsp_init.c index 24b3881854..f68a592839 100644 --- a/libavcodec/riscv/ac3dsp_init.c +++ b/libavcodec/riscv/ac3dsp_init.c @@ -65,8 +65,8 @@ av_cold void ff_ac3dsp_init_riscv(AC3DSPContext *c) c->sum_square_butterfly_int32 = ff_sum_square_butterfly_int32_rvv; # endif -# endif } } +# endif #endif } diff --git a/libavcodec/riscv/ac3dsp_rvb.S b/libavcodec/riscv/ac3dsp_rvb.S index a3c5187cfe..ecf45a0007 100644 --- a/libavcodec/riscv/ac3dsp_rvb.S +++ b/libavcodec/riscv/ac3dsp_rvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_ac3_exponent_min_rvb, zbb diff --git a/libavcodec/riscv/ac3dsp_rvv.S b/libavcodec/riscv/ac3dsp_rvv.S index 261cb9628b..b1eded0280 100644 --- a/libavcodec/riscv/ac3dsp_rvv.S +++ b/libavcodec/riscv/ac3dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_ac3_exponent_min_rvv, zve32x diff --git a/libavcodec/riscv/ac3dsp_rvvb.S b/libavcodec/riscv/ac3dsp_rvvb.S index 2f4e644553..b8f714d87a 100644 --- a/libavcodec/riscv/ac3dsp_rvvb.S +++ b/libavcodec/riscv/ac3dsp_rvvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_extract_exponents_rvvb, zve32x, zvbb, zba diff --git a/libavcodec/riscv/blockdsp_init.c b/libavcodec/riscv/blockdsp_init.c index adde0b890b..81c0e38b94 100644 --- a/libavcodec/riscv/blockdsp_init.c +++ b/libavcodec/riscv/blockdsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/blockdsp_rvv.S b/libavcodec/riscv/blockdsp_rvv.S index 04da265417..99760e98b9 100644 --- a/libavcodec/riscv/blockdsp_rvv.S +++ b/libavcodec/riscv/blockdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/bswapdsp_rvb.S b/libavcodec/riscv/bswapdsp_rvb.S index 8c7c791fe1..9dff287a3f 100644 --- a/libavcodec/riscv/bswapdsp_rvb.S +++ b/libavcodec/riscv/bswapdsp_rvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" #include "libavutil/riscv/bswap_rvb.S" diff --git a/libavcodec/riscv/bswapdsp_rvv.S b/libavcodec/riscv/bswapdsp_rvv.S index b4911bf0ef..ea0be2de4b 100644 --- a/libavcodec/riscv/bswapdsp_rvv.S +++ b/libavcodec/riscv/bswapdsp_rvv.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_bswap16_buf_rvv, zve32x, zba diff --git a/libavcodec/riscv/bswapdsp_rvvb.S b/libavcodec/riscv/bswapdsp_rvvb.S index 165ac104a9..e420099f72 100644 --- a/libavcodec/riscv/bswapdsp_rvvb.S +++ b/libavcodec/riscv/bswapdsp_rvvb.S @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "libavutil/riscv/asm.S" func ff_bswap32_buf_rvvb, zve32x, zvbb, zba diff --git a/libavcodec/riscv/h263dsp_rvv.S b/libavcodec/riscv/h263dsp_rvv.S index e9cb4ec07b..704344ec0b 100644 --- a/libavcodec/riscv/h263dsp_rvv.S +++ b/libavcodec/riscv/h263dsp_rvv.S @@ -43,7 +43,7 @@ func ff_h263_h_loop_filter_rvv, zve32x vsrl.vi v18, v16, 16 - 3 # v18 = (v16 < 0) ? 7 : 0 slli t2, t1, 1 # 2 * strength vadd.vv v16, v16, v18 - # v16 (d) is signed 7-bit, but later arithmetics require 9 bits. + # v16 (d) is signed 7-bit, but later arithmetic require 9 bits. vsra.vi v16, v16, 3 # d vmv.v.x v20, t2 vmslt.vi v0, v16, 0 diff --git a/libavcodec/riscv/h264dsp_init.c b/libavcodec/riscv/h264dsp_init.c index 9ffc9b0333..f214486bbe 100644 --- a/libavcodec/riscv/h264dsp_init.c +++ b/libavcodec/riscv/h264dsp_init.c @@ -40,6 +40,12 @@ void ff_h264_h_loop_filter_luma_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void ff_h264_h_loop_filter_luma_mbaff_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_v_loop_filter_luma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_luma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv(uint8_t *pix, ptrdiff_t s, + int a, int b); void ff_h264_v_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void ff_h264_h_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, @@ -47,6 +53,13 @@ void ff_h264_h_loop_filter_chroma_8_rvv(uint8_t *pix, ptrdiff_t stride, void ff_h264_h_loop_filter_chroma_mbaff_8_rvv(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_v_loop_filter_chroma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_intra_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv(uint8_t *pix, + ptrdiff_t stride, + int alpha, int beta); #define IDCT_DEPTH(depth) \ void ff_h264_idct_add_##depth##_rvv(uint8_t *d, int16_t *s, int stride); \ @@ -96,25 +109,55 @@ av_cold void ff_h264dsp_init_riscv(H264DSPContext *dsp, const int bit_depth, if (flags & AV_CPU_FLAG_RVV_I32) { const bool zvl128b = ff_rv_vlen_least(128); - if (bit_depth == 8 && zvl128b) { - for (int i = 0; i < 4; i++) { - dsp->weight_h264_pixels_tab[i] = - ff_h264_weight_funcs_8_rvv[i].weight; - dsp->biweight_h264_pixels_tab[i] = - ff_h264_weight_funcs_8_rvv[i].biweight; + if (bit_depth == 8) { + if (zvl128b) { + if (flags & AV_CPU_FLAG_RVB) + dsp->weight_h264_pixels_tab[0] = + ff_h264_weight_funcs_8_rvv[0].weight; + dsp->biweight_h264_pixels_tab[0] = + ff_h264_weight_funcs_8_rvv[0].biweight; } + if (flags & AV_CPU_FLAG_RVV_I64) { + dsp->weight_h264_pixels_tab[1] = + ff_h264_weight_funcs_8_rvv[1].weight; + dsp->biweight_h264_pixels_tab[1] = + ff_h264_weight_funcs_8_rvv[1].biweight; + } + dsp->weight_h264_pixels_tab[2] = + ff_h264_weight_funcs_8_rvv[2].weight; + dsp->biweight_h264_pixels_tab[2] = + ff_h264_weight_funcs_8_rvv[2].biweight; + dsp->weight_h264_pixels_tab[3] = + ff_h264_weight_funcs_8_rvv[3].weight; + dsp->biweight_h264_pixels_tab[3] = + ff_h264_weight_funcs_8_rvv[3].biweight; + } + if (bit_depth == 8 && zvl128b) { dsp->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_8_rvv; dsp->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_8_rvv; dsp->h264_h_loop_filter_luma_mbaff = ff_h264_h_loop_filter_luma_mbaff_8_rvv; + dsp->h264_v_loop_filter_luma_intra = + ff_h264_v_loop_filter_luma_intra_8_rvv; + dsp->h264_h_loop_filter_luma_intra = + ff_h264_h_loop_filter_luma_intra_8_rvv; + dsp->h264_h_loop_filter_luma_mbaff_intra = + ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv; dsp->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_8_rvv; + dsp->h264_v_loop_filter_chroma_intra = + ff_h264_v_loop_filter_chroma_intra_8_rvv; + if (chroma_format_idc <= 1) { dsp->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_8_rvv; dsp->h264_h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_mbaff_8_rvv; + dsp->h264_h_loop_filter_chroma_intra = + ff_h264_h_loop_filter_chroma_intra_8_rvv; + dsp->h264_h_loop_filter_chroma_mbaff_intra = + ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv; } dsp->h264_idct_add = ff_h264_idct_add_8_rvv; diff --git a/libavcodec/riscv/h264dsp_rvv.S b/libavcodec/riscv/h264dsp_rvv.S index 422ac02222..60015a7020 100644 --- a/libavcodec/riscv/h264dsp_rvv.S +++ b/libavcodec/riscv/h264dsp_rvv.S @@ -28,21 +28,30 @@ #include "libavutil/riscv/asm.S" -func ff_h264_weight_pixels_simple_8_rvv, zve32x + .variant_cc ff_h264_weight_pixels_simple_8_rvv +func ff_h264_weight_pixels_simple_8_rvv, zve32x, b csrwi vxrm, 0 sll a5, a5, a3 1: - vsetvli zero, a6, e16, m2, ta, ma - vle8.v v8, (a0) - addi a2, a2, -1 + vsetvli zero, t6, e16, m2, ta, ma + add t0, a0, a1 + vle8.v v8, (a0) + addi a2, a2, -2 + vle8.v v9, (t0) vzext.vf2 v24, v8 + vzext.vf2 v26, v9 vmul.vx v16, v24, a4 + vmul.vx v18, v26, a4 vsadd.vx v16, v16, a5 - vmax.vx v16, v16, zero - vsetvli zero, zero, e8, m1, ta, ma + vsadd.vx v18, v18, a5 + vmax.vx v16, v16, zero + vmax.vx v18, v18, zero + vsetvli zero, zero, e8, m1, ta, ma vnclipu.wx v8, v16, a3 - vse8.v v8, (a0) - add a0, a0, a1 + vnclipu.wx v9, v18, a3 + vse8.v v8, (a0) + vse8.v v9, (t0) + sh1add a0, a1, a0 bnez a2, 1b ret @@ -76,107 +85,81 @@ func ff_h264_biweight_pixels_simple_8_rvv, zve32x ret endfunc -func ff_h264_weight_pixels_8_rvv, zve32x +.macro h264_weight depth, w, b= +func ff_h264_weight_pixels\w\()_\depth\()_rvv, zve64x + lpad 0 + .ifb \b + li t6, \w + j ff_h264_weight_pixels_simple_\depth\()_rvv + .else csrwi vxrm, 0 sll a5, a5, a3 1: - mv t0, a0 - mv t6, a6 -2: - vsetvli t2, a2, e16, m8, ta, ma - vlsseg2e8.v v0, (t0), a1 - addi t6, t6, -2 - vzext.vf2 v16, v0 - vzext.vf2 v24, v4 - vmul.vx v16, v16, a4 - vmul.vx v24, v24, a4 + vsetvli t1, a2, e\b, m2, ta, ma + vlse\b\().v v8, (a0), a1 + vsetvli t0, zero, e16, m4, ta, ma + vzext.vf2 v24, v8 + sub a2, a2, t1 + vmul.vx v16, v24, a4 + mul t2, t1, a1 vsadd.vx v16, v16, a5 - vsadd.vx v24, v24, a5 vmax.vx v16, v16, zero - vmax.vx v24, v24, zero - vsetvli zero, zero, e8, m4, ta, ma - vnclipu.wx v0, v16, a3 - vnclipu.wx v4, v24, a3 - vssseg2e8.v v0, (t0), a1 - addi t0, t0, 2 - bnez t6, 2b - - mul t3, a1, t2 - sub a2, a2, t2 - add a0, a0, t3 + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wx v8, v16, a3 + vsetvli zero, t1, e\b, m2, ta, ma + vsse\b\().v v8, (a0), a1 + add a0, a0, t2 bnez a2, 1b ret + .endif endfunc - .variant_cc ff_h264_biweight_pixels_8_rvv -func ff_h264_biweight_pixels_8_rvv, zve32x +func ff_h264_biweight_pixels\w\()_\depth\()_rvv, zve64x + lpad 0 + li t6, \w + .ifb \b + j ff_h264_biweight_pixels_simple_8_rvv + .else csrwi vxrm, 2 addi a7, a7, 1 ori a7, a7, 1 sll a7, a7, a4 addi a4, a4, 1 1: - mv t0, a0 - mv t1, a1 - mv t5, t6 -2: - vsetvli t2, a3, e16, m8, ta, ma - vlsseg2e8.v v0, (t0), a2 - vlsseg2e8.v v8, (t1), a2 - addi t5, t5, -2 - vmv.v.x v16, a7 - vmv.v.x v24, a7 - vsetvli zero, zero, e8, m4, ta, ma - vwmaccsu.vx v16, a5, v0 - vwmaccsu.vx v24, a5, v4 - vwmaccsu.vx v16, a6, v8 - vwmaccsu.vx v24, a6, v12 - vsetvli zero, zero, e16, m8, ta, ma + vsetvli t1, a3, e\b, m2, ta, ma + vlse\b\().v v8, (a0), a2 + sub a3, a3, t1 + vlse\b\().v v12, (a1), a2 + mul t2, t1, a2 + vsetvli t0, zero, e16, m4, ta, ma + vmv.v.x v16, a7 + vsetvli zero, zero, e8, m2, ta, ma + vwmaccsu.vx v16, a5, v8 + add a1, a1, t2 + vwmaccsu.vx v16, a6, v12 + vsetvli zero, zero, e16, m4, ta, ma vmax.vx v16, v16, zero - vmax.vx v24, v24, zero - vsetvli zero, zero, e8, m4, ta, ma - vnclipu.wx v0, v16, a4 - vnclipu.wx v4, v24, a4 - vssseg2e8.v v0, (t0), a2 - addi t0, t0, 2 - addi t1, t1, 2 - bnez t5, 2b - - mul t3, a2, t2 - sub a3, a3, t2 - add a0, a0, t3 - add a1, a1, t3 + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wx v8, v16, a4 + vsetvli zero, t1, e\b, m2, ta, ma + vsse\b\().v v8, (a0), a2 + add a0, a0, t2 + .endif bnez a3, 1b ret endfunc +.endm -.irp w, 16, 8, 4, 2 -func ff_h264_weight_pixels\w\()_8_rvv, zve32x - lpad 0 - li a6, \w - .if \w == 16 - j ff_h264_weight_pixels_simple_8_rvv - .else - j ff_h264_weight_pixels_8_rvv - .endif -endfunc - -func ff_h264_biweight_pixels\w\()_8_rvv, zve32x - lpad 0 - li t6, \w - .if \w == 16 - j ff_h264_biweight_pixels_simple_8_rvv - .else - j ff_h264_biweight_pixels_8_rvv - .endif -endfunc -.endr +h264_weight 8, 2, 16 +h264_weight 8, 4, 32 +h264_weight 8, 8, 64 +h264_weight 8, 16 .global ff_h264_weight_funcs_8_rvv .hidden ff_h264_weight_funcs_8_rvv -const ff_h264_weight_funcs_8_rvv +const ff_h264_weight_funcs_8_rvv, relocate=1 .irp w, 16, 8, 4, 2 #if __riscv_xlen == 32 .word ff_h264_weight_pixels\w\()_8_rvv @@ -304,7 +287,6 @@ func ff_h264_v_loop_filter_\type\()_8_rvv, zve32x vsetivli zero, 4 * \inners, e8, \e8mul, ta, ma vle8.v v11, (a0) sub t2, t3, a1 - vid.v v0 vle8.v v10, (t3) add t5, a0, a1 vle8.v v9, (t2) @@ -326,6 +308,125 @@ func ff_h264_v_loop_filter_\type\()_8_rvv, zve32x vse8.v v11, (a0) ret endfunc + + .variant_cc ff_h264_loop_filter_\type\()_intra_8_rvv +func ff_h264_loop_filter_\type\()_intra_8_rvv, zve32x + # p3: v8, p2: v9, p1: v10, p0: v11, q0: v12, q1: v13, q2: v14, q3: v15 + # alpha: a2, beta: a3 + csrwi vxrm, 0 + srai a4, a2, 2 + vwsubu.vv v16, v11, v12 + addi a4, a4, 2 + vwsubu.vv v18, v12, v11 + vwsubu.vv v20, v10, v11 + vwsubu.vv v22, v11, v10 + vwsubu.vv v24, v13, v12 + vwsubu.vv v26, v12, v13 + vwsubu.vv v28, v11, v9 + vwsubu.vv v30, v9, v11 + vwsubu.vv v4, v14, v12 + vwsubu.vv v6, v12, v14 + vsetvli zero, zero, e16, \e16mul, ta, ma + vmax.vv v16, v16, v18 # abs(p0 - q0) + vmax.vv v20, v20, v22 # abs(p1 - p0) + vmslt.vx v18, v16, a2 + vmax.vv v24, v24, v26 # abs(q1 - q0) + vmslt.vx v22, v20, a3 +.ifc \type, luma + vmax.vv v28, v28, v30 # abs(p2 - p0) +.endif + vmand.mm v18, v18, v22 + vmslt.vx v23, v24, a3 +.ifc \type, luma + vmax.vv v4, v4, v6 # abs(q2 - q0) + vmand.mm v1, v18, v23 # abs(...) < A && abs(..) < B && abs(..) < B + vmslt.vx v3, v16, a4 # abs(p0 - q0) < (alpha / 4) + 2 + vmslt.vx v6, v28, a3 # abs(p2 - p0) < beta + vmslt.vx v7, v4, a3 # abs(q2 - q0) < beta + vmand.mm v2, v3, v6 + vmand.mm v3, v3, v7 +.else + vmand.mm v0, v18, v23 +.endif + vsetvli zero, zero, e8, \e8mul, ta, mu + vwaddu.vv v22, v11, v13 + vwaddu.vv v30, v10, v12 + vwaddu.wv v22, v22, v10 + vwaddu.wv v30, v30, v13 + vwaddu.wv v22, v22, v10 # 2p1 + p0 + q1 + vwaddu.wv v30, v30, v13 # p1 + q0 + 2q1 +.ifc \type, luma + vwaddu.vv v16, v10, v11 + vwaddu.vv v20, v8, v9 + vwaddu.wv v16, v16, v12 # p1 + p0 + q0 + vwaddu.vv v24, v11, v12 + vwaddu.vv v28, v14, v15 + vwaddu.wv v24, v24, v13 # p0 + q0 + q1 + vwaddu.wv v18, v16, v9 # p2 + p1 + p0 + q0 + vwaddu.wv v16, v16, v13 # p1 + p0 + q0 + q1 + vwaddu.wv v26, v24, v14 # p0 + q0 + q1 + q2 + vwaddu.wv v24, v24, v10 # p1 + p0 + q0 + q1 + vsetvli zero, zero, e16, \e16mul, ta, ma + vsll.vi v20, v20, 1 # 2p3 +2p2 + vadd.vv v16, v16, v18 # p2 +2p1 +2p0 +2q0 + q1 + vadd.vv v20, v18, v20 # 2p3 +3p3 + p1 + p0 + q0 + vsll.vi v28, v28, 1 # 2q2 +2q3 + vadd.vv v24, v24, v26 # p1 +2p0 +2q0 +2q1 + q2 + vadd.vv v28, v26, v28 # p0 + q0 + q1 +3q2 +2q3 + vsetvli zero, zero, e8, \e8mul, ta, mu + vmand.mm v0, v1, v2 + vnclipu.wi v11, v16, 3, v0.t # p0' + vnclipu.wi v10, v18, 2, v0.t # p1' + vnclipu.wi v9, v20, 3, v0.t # p2' + vmandn.mm v0, v1, v2 +.endif + vnclipu.wi v11, v22, 2, v0.t # p0' +.ifc \type, luma + vmand.mm v0, v1, v3 + vnclipu.wi v12, v24, 3, v0.t # q0' + vnclipu.wi v13, v26, 2, v0.t # q1' + vnclipu.wi v14, v28, 3, v0.t # q2' + vmandn.mm v0, v1, v3 +.endif + vnclipu.wi v12, v30, 2, v0.t # q0' + jr t0 +endfunc + +func ff_h264_v_loop_filter_\type\()_intra_8_rvv, zve32x + lpad 0 + sub t3, a0, a1 + vsetivli zero, 4 * \inners, e8, \e8mul, ta, ma + vle8.v v12, (a0) + sub t2, t3, a1 + vle8.v v11, (t3) + add t4, a0, a1 + vle8.v v10, (t2) +.ifc \type, luma + sub t1, t2, a1 +.endif + vle8.v v13, (t4) +.ifc \type, luma + sub t0, t1, a1 + vle8.v v9, (t1) + add t5, t4, a1 + vle8.v v8, (t0) + add t6, t5, a1 + vle8.v v14, (t5) + vle8.v v15, (t6) +.endif + jal t0, ff_h264_loop_filter_\type\()_intra_8_rvv +.ifc \type, luma + vse8.v v9, (t1) + vse8.v v10, (t2) +.endif + vse8.v v11, (t3) + vse8.v v12, (a0) +.ifc \type, luma + vse8.v v13, (t4) + vse8.v v14, (t5) +.endif + ret +endfunc .endm loop_filter luma, 4, m1, m2 @@ -391,3 +492,47 @@ func ff_h264_h_loop_filter_chroma_mbaff_8_rvv, zve32x vssseg2e8.v v10, (a0), a1 ret endfunc + +func ff_h264_h_loop_filter_luma_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -4 + vsetivli zero, 16, e8, m1, ta, ma + vlsseg8e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_intra_8_rvv + vssseg6e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_luma_mbaff_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -4 + vsetivli zero, 8, e8, m1, ta, ma + vlsseg8e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_intra_8_rvv + vssseg6e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -2 + vsetivli zero, 8, e8, mf2, ta, ma + vlsseg4e8.v v10, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_intra_8_rvv + vssseg2e8.v v11, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_mbaff_intra_8_rvv, zve32x + lpad 0 + addi a0, a0, -2 + vsetivli zero, 4, e8, mf2, ta, ma + vlsseg4e8.v v10, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_intra_8_rvv + vssseg2e8.v v11, (a0), a1 + ret +endfunc diff --git a/libavcodec/riscv/h264idct_rvv.S b/libavcodec/riscv/h264idct_rvv.S index d2f77a5b47..2a40e87d62 100644 --- a/libavcodec/riscv/h264idct_rvv.S +++ b/libavcodec/riscv/h264idct_rvv.S @@ -542,7 +542,7 @@ func ff_h264_idct8_dc_add_\depth\()_rvv, zve64x endfunc .endr -const ff_h264_scan8 +const ff_h264_scan8, align=0 .byte 014, 015, 024, 025, 016, 017, 026, 027 .byte 034, 035, 044, 045, 036, 037, 046, 047 .byte 064, 065, 074, 075, 066, 067, 076, 077 @@ -629,6 +629,7 @@ endfunc .endm .macro idct4_add8 type, depth +#if (__riscv_xlen == 64) func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x .if \depth == 8 lpad 0 @@ -644,7 +645,7 @@ func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x sd a4, 24(sp) ld a0, 0(a0) # dest[0] addi a1, a1, 16 * 4 # &block_offset[16] - vsetivli zero, 4, e8, mf4, ta, ma + vsetivli zero, 4, e8, m1, ta, ma jal .Lidct4_add4_\depth\()_rvv ld a4, 24(sp) # nnzc @@ -655,7 +656,7 @@ func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x ld a0, 8(a0) # dest[1] lla t0, ff_h264_scan8 + 32 .ifc \type, 8_422 - vsetivli zero, 4, e8, mf4, ta, ma + vsetivli zero, 4, e8, m1, ta, ma jal .Lidct4_add4_\depth\()_rvv ld a4, 24(sp) # nnzc @@ -665,7 +666,7 @@ func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x addi a1, t5, (-8 - 4) * 4 # &block_offset[24] ld a0, 0(a0) # dest[0] lla t0, ff_h264_scan8 + 24 - vsetivli zero, 4, e8, mf4, ta, ma + vsetivli zero, 4, e8, m1, ta, ma jal .Lidct4_add4_\depth\()_rvv ld a4, 24(sp) # nnzc @@ -679,9 +680,10 @@ func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x ld ra, 8(sp) ld s0, 0(sp) addi sp, sp, 32 - vsetivli zero, 4, e8, mf4, ta, ma + vsetivli zero, 4, e8, m1, ta, ma j .Lidct4_add4_\depth\()_rvv endfunc +#endif .endm .irp depth, 8, 16 diff --git a/libavcodec/riscv/h264qpel_init.c b/libavcodec/riscv/h264qpel_init.c new file mode 100644 index 0000000000..ad407ebff6 --- /dev/null +++ b/libavcodec/riscv/h264qpel_init.c @@ -0,0 +1,113 @@ +/* + * RISC-V optimised DSP functions + * Copyright (c) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/h264qpel.h" + +#define DECL_QPEL_OPS(OP, SIZE, EXT) \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc00_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc10_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc20_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc30_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc01_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc11_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc21_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc31_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc02_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc12_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc22_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc32_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc03_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc13_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc23_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); \ +void ff_ ## OP ## _h264_qpel ## SIZE ## _mc33_ ## EXT(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +DECL_QPEL_OPS(put, 16, rvv256) +DECL_QPEL_OPS(put, 8, rvv256) +// DECL_QPEL_OPS(put, 4, rvv256) + +DECL_QPEL_OPS(avg, 16, rvv256) +DECL_QPEL_OPS(avg, 8, rvv256) +// DECL_QPEL_OPS(avg, 4, rvv256) + +DECL_QPEL_OPS(put, 16, rvv) +DECL_QPEL_OPS(put, 8, rvv) +DECL_QPEL_OPS(put, 4, rvv) + +DECL_QPEL_OPS(avg, 16, rvv) +DECL_QPEL_OPS(avg, 8, rvv) +DECL_QPEL_OPS(avg, 4, rvv) + +#define SET_QPEL_FNS(OP, IDX, SIZE, EXT) \ +do { \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 0] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc00_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 1] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc10_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 2] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc20_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 3] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc30_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 4] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc01_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 5] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc11_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 6] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc21_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 7] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc31_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 8] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc02_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][ 9] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc12_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][10] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc22_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][11] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc32_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][12] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc03_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][13] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc13_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][14] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc23_ ## EXT; \ + c->OP ## _h264_qpel_pixels_tab[IDX][15] = ff_ ## OP ## _h264_qpel ## SIZE ## _mc33_ ## EXT; \ +} while (0) + +av_cold void ff_h264qpel_init_riscv(H264QpelContext *c, int bit_depth) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + if (flags & AV_CPU_FLAG_RVV_I32) { + const int vlen = 8 * ff_get_rv_vlenb(); + + switch (bit_depth) { + case 8: + if (vlen >= 256) { + SET_QPEL_FNS(put, 0, 16, rvv256); + SET_QPEL_FNS(put, 1, 8, rvv256); + SET_QPEL_FNS(put, 2, 4, rvv); + + SET_QPEL_FNS(avg, 0, 16, rvv256); + SET_QPEL_FNS(avg, 1, 8, rvv256); + SET_QPEL_FNS(avg, 2, 4, rvv); + } else if (vlen >= 128) { + SET_QPEL_FNS(put, 0, 16, rvv); + SET_QPEL_FNS(put, 1, 8, rvv); + SET_QPEL_FNS(put, 2, 4, rvv); + + SET_QPEL_FNS(avg, 0, 16, rvv); + SET_QPEL_FNS(avg, 1, 8, rvv); + SET_QPEL_FNS(avg, 2, 4, rvv); + } + break; + } + } +#endif +} diff --git a/libavcodec/riscv/h264qpel_rvv.S b/libavcodec/riscv/h264qpel_rvv.S new file mode 100644 index 0000000000..77a534767c --- /dev/null +++ b/libavcodec/riscv/h264qpel_rvv.S @@ -0,0 +1,464 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Niklas Haas + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "libavutil/riscv/asm.S" + +.macro lx rd, addr +#if (__riscv_xlen == 32) + lw \rd, \addr +#elif (__riscv_xlen == 64) + ld \rd, \addr +#else + lq \rd, \addr +#endif +.endm + +.macro sx rd, addr +#if (__riscv_xlen == 32) + sw \rd, \addr +#elif (__riscv_xlen == 64) + sd \rd, \addr +#else + sq \rd, \addr +#endif +.endm + + /* output is unclipped; clobbers v26-v31 plus t0 and t02 */ +.macro lowpass_h vdst, src + addi t4, \src, 3 + lbu t5, 2(\src) + vle8.v v31, (t4) + lbu t4, 1(\src) + vslide1up.vx v30, v31, t5 + lbu t5, 0(\src) + vslide1up.vx v29, v30, t4 + lbu t4, -1(\src) + vslide1up.vx v28, v29, t5 + lbu t5, -2(\src) + vslide1up.vx v27, v28, t4 + vslide1up.vx v26, v27, t5 + vwaddu.vv \vdst, v26, v31 + vwmaccu.vx \vdst, t6, v28 + vwmaccu.vx \vdst, t6, v29 + vwmaccsu.vx \vdst, a7, v27 + vwmaccsu.vx \vdst, a7, v30 +.endm + + /* output is unclipped */ +.macro lowpass_v vdst, vsrc0, vsrc1, vsrc2, vsrc3, vsrc4, vsrc5, signed=0 + .if \signed + vwadd.vv \vdst, \vsrc0, \vsrc5 + vwmacc.vx \vdst, t6, \vsrc2 + vwmacc.vx \vdst, t6, \vsrc3 + vwmacc.vx \vdst, a7, \vsrc1 + vwmacc.vx \vdst, a7, \vsrc4 + .else + vwaddu.vv \vdst, \vsrc0, \vsrc5 + vwmaccu.vx \vdst, t6, \vsrc2 + vwmaccu.vx \vdst, t6, \vsrc3 + vwmaccsu.vx \vdst, a7, \vsrc1 + vwmaccsu.vx \vdst, a7, \vsrc4 + .endif +.endm + +.macro qpel_mc00 op, dst, src, stride, size +func ff_\op\()_h264_qpel_pixels, zve32x +1: add t1, a2, a1 + add t2, a2, t1 + add t3, a2, t2 + vle8.v v0, (a1) + vle8.v v1, (t1) + vle8.v v2, (t2) + vle8.v v3, (t3) + addi a4, a4, -4 + add a1, a2, t3 + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v4, (a0) + vle8.v v5, (t1) + vle8.v v6, (t2) + vle8.v v7, (t3) + vaaddu.vv v0, v0, v4 + vaaddu.vv v1, v1, v5 + vaaddu.vv v2, v2, v6 + vaaddu.vv v3, v3, v7 + .endif + vse8.v v0, (a0) + vse8.v v1, (t1) + vse8.v v2, (t2) + vse8.v v3, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc +.endm + + qpel_mc00 put, a0, a1, a2, a4 + qpel_mc00 avg, a0, a1, a2, a4 + +.macro qpel_lowpass op, ext, lmul, lmul2 +func ff_\op\()_h264_qpel_h_lowpass_\lmul\ext, zve32x +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + lowpass_h v0, a1 + lowpass_h v2, t1 + lowpass_h v4, t2 + lowpass_h v6, t3 + add a1, a3, t3 + addi a4, a4, -4 + vsetvli zero, zero, e16, \lmul2, ta, ma + vmax.vx v0, v0, zero + vmax.vx v2, v2, zero + vmax.vx v4, v4, zero + vmax.vx v6, v6, zero + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v0, v0, 5 + vnclipu.wi v2, v2, 5 + vnclipu.wi v4, v4, 5 + vnclipu.wi v6, v6, 5 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v8, (a5) + vle8.v v10, (t1) + vle8.v v12, (t2) + vle8.v v14, (t3) + add a5, a2, t3 + vaaddu.vv v0, v0, v8 + vaaddu.vv v2, v2, v10 + vaaddu.vv v4, v4, v12 + vaaddu.vv v6, v6, v14 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v1, (a0) + vle8.v v3, (t1) + vle8.v v5, (t2) + vle8.v v7, (t3) + vaaddu.vv v0, v0, v1 + vaaddu.vv v2, v2, v3 + vaaddu.vv v4, v4, v5 + vaaddu.vv v6, v6, v7 + .endif + vse8.v v0, (a0) + vse8.v v2, (t1) + vse8.v v4, (t2) + vse8.v v6, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc + +func ff_\op\()_h264_qpel_v_lowpass_\lmul\ext, zve32x + sub t1, a1, a3 + sub t2, t1, a3 + vle8.v v2, (a1) + vle8.v v1, (t1) + vle8.v v0, (t2) + add t1, a1, a3 + add t2, t1, a3 + add a1, t2, a3 + vle8.v v3, (t1) + vle8.v v4, (t2) +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + vle8.v v5, (a1) + vle8.v v6, (t1) + vle8.v v7, (t2) + vle8.v v8, (t3) + add a1, a3, t3 + lowpass_v v24, v0, v1, v2, v3, v4, v5 + lowpass_v v26, v1, v2, v3, v4, v5, v6 + lowpass_v v28, v2, v3, v4, v5, v6, v7 + lowpass_v v30, v3, v4, v5, v6, v7, v8 + addi a4, a4, -4 + vsetvli zero, zero, e16, \lmul2, ta, ma + vmax.vx v24, v24, zero + vmax.vx v26, v26, zero + vmax.vx v28, v28, zero + vmax.vx v30, v30, zero + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v24, v24, 5 + vnclipu.wi v26, v26, 5 + vnclipu.wi v28, v28, 5 + vnclipu.wi v30, v30, 5 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v9, (a5) + vle8.v v10, (t1) + vle8.v v11, (t2) + vle8.v v12, (t3) + add a5, a6, t3 + vaaddu.vv v24, v24, v9 + vaaddu.vv v26, v26, v10 + vaaddu.vv v28, v28, v11 + vaaddu.vv v30, v30, v12 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v9, (a0) + vle8.v v10, (t1) + vle8.v v11, (t2) + vle8.v v12, (t3) + vaaddu.vv v24, v24, v9 + vaaddu.vv v26, v26, v10 + vaaddu.vv v28, v28, v11 + vaaddu.vv v30, v30, v12 + .endif + vse8.v v24, (a0) + vse8.v v26, (t1) + vse8.v v28, (t2) + vse8.v v30, (t3) + add a0, a2, t3 + vmv.v.v v0, v4 + vmv.v.v v1, v5 + vmv.v.v v2, v6 + vmv.v.v v3, v7 + vmv.v.v v4, v8 + bnez a4, 1b + jr t0 +endfunc + +func ff_\op\()_h264_qpel_hv_lowpass_\lmul\ext, zve32x + sub t1, a1, a3 + sub t2, t1, a3 + lowpass_h v4, a1 + lowpass_h v2, t1 + lowpass_h v0, t2 + add t1, a1, a3 + add t2, t1, a3 + add a1, t2, a3 + lowpass_h v6, t1 + lowpass_h v8, t2 +1: add t1, a3, a1 + add t2, a3, t1 + add t3, a3, t2 + lowpass_h v10, a1 + lowpass_h v12, t1 + lowpass_h v14, t2 + lowpass_h v16, t3 + vsetvli zero, zero, e16, \lmul2, ta, ma + addi a4, a4, -4 + lowpass_v v20, v0, v2, v4, v6, v8, v10, signed=1 + lowpass_v v24, v2, v4, v6, v8, v10, v12, signed=1 + lowpass_v v28, v4, v6, v8, v10, v12, v14, signed=1 + vnclip.wi v0, v20, 10 + lowpass_v v20, v6, v8, v10, v12, v14, v16, signed=1 + vnclip.wi v2, v24, 10 + vnclip.wi v4, v28, 10 + vnclip.wi v6, v20, 10 + vmax.vx v18, v0, zero + vmax.vx v20, v2, zero + vmax.vx v22, v4, zero + vmax.vx v24, v6, zero + vmv.v.v v0, v8 + vmv.v.v v2, v10 + vmv.v.v v4, v12 + vmv.v.v v6, v14 + vmv.v.v v8, v16 + add a1, a3, t3 + vsetvli zero, zero, e8, \lmul, ta, ma + vnclipu.wi v18, v18, 0 + vnclipu.wi v20, v20, 0 + vnclipu.wi v22, v22, 0 + vnclipu.wi v24, v24, 0 + .ifc \ext, _l2 + add t1, a6, a5 + add t2, a6, t1 + add t3, a6, t2 + vle8.v v26, (a5) + vle8.v v27, (t1) + vle8.v v28, (t2) + vle8.v v29, (t3) + add a5, a6, t3 + vaaddu.vv v18, v18, v26 + vaaddu.vv v20, v20, v27 + vaaddu.vv v22, v22, v28 + vaaddu.vv v24, v24, v29 + .endif + add t1, a2, a0 + add t2, a2, t1 + add t3, a2, t2 + .ifc \op, avg + vle8.v v26, (a0) + vle8.v v27, (t1) + vle8.v v28, (t2) + vle8.v v29, (t3) + vaaddu.vv v18, v18, v26 + vaaddu.vv v20, v20, v27 + vaaddu.vv v22, v22, v28 + vaaddu.vv v24, v24, v29 + .endif + vse8.v v18, (a0) + vse8.v v20, (t1) + vse8.v v22, (t2) + vse8.v v24, (t3) + add a0, a2, t3 + bnez a4, 1b + jr t0 +endfunc +.endm + +/* Note: We could possibly specialize for the width 8 / width 4 cases by + loading 32 bit integers, but this makes the convolutions more complicated + to implement, so it's not necessarily any faster. */ + +.macro h264_qpel lmul, lmul2 + qpel_lowpass put, , \lmul, \lmul2 + qpel_lowpass put, _l2, \lmul, \lmul2 + qpel_lowpass avg, , \lmul, \lmul2 + qpel_lowpass avg, _l2, \lmul, \lmul2 +.endm + + h264_qpel m1, m2 + h264_qpel mf2, m1 + h264_qpel mf4, mf2 + h264_qpel mf8, mf4 + +.macro h264_qpel_1pass op, case, lmul, size, ext=rvv, dir, offset +func ff_\op\()_h264_qpel\size\()_\case\()_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + li a4, \size + li t6, 20 + li a7, -5 + mv a3, a2 + mv t0, ra +.ifnb \offset + .ifc \dir, v + add a5, a1, \offset + .else + addi a5, a1, \offset + .endif + mv a6, a3 + j ff_\op\()_h264_qpel_\dir\()_lowpass_\lmul\()_l2 +.else + j ff_\op\()_h264_qpel_\dir\()_lowpass_\lmul\() +.endif +endfunc +.endm + +.macro h264_qpel_2pass op, case, lmul, size, ext=rvv, dir1, dir2, off1=0, off2 +func ff_\op\()_h264_qpel\size\()_\case\()_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + addi sp, sp, (-(__riscv_xlen >> 2)) + li a4, \size + li t6, 20 + li a7, -5 + sx a0, 0(sp) + sx a1, (__riscv_xlen >> 3)(sp) + .ifc \off1, a2 + add a1, a1, \off1 + .elseif \off1 + addi a1, a1, \off1 + .endif + mv a3, a2 + .ifc \op, avg + // Use temporary array on stack for the first pass + addi a0, sp, -(\size * \size) + li a2, \size + .endif + jal t0, ff_put_h264_qpel_\dir1\()_lowpass_\lmul + lx a0, 0(sp) + lx a1, (__riscv_xlen >> 3)(sp) + .ifc \op, put + // Directly reuse the first pass output buffer + mv a5, a0 + mv a6, a2 + .else + addi a5, sp, -(\size * \size) + li a6, \size + mv a2, a3 + .endif + .ifnb \off2 + addi a1, a1, \off2 + .endif + li a4, \size + mv t0, ra + addi sp, sp, 16 + j ff_\op\()_h264_qpel_\dir2\()_lowpass_\lmul\()_l2 +endfunc +.endm + +.macro ff_h264_qpel_fns op, lmul, size, ext=rvv +func ff_\op\()_h264_qpel\size\()_mc00_\ext, zve32x + lpad 0 + vsetivli zero, \size, e8, \lmul, ta, ma + csrwi vxrm, 0 + li a4, \size + mv t0, ra + j ff_\op\()_h264_qpel_pixels +endfunc + + h264_qpel_1pass \op, mc20, \lmul, \size, \ext, h + h264_qpel_1pass \op, mc02, \lmul, \size, \ext, v + h264_qpel_1pass \op, mc10, \lmul, \size, \ext, h, 0 + h264_qpel_1pass \op, mc30, \lmul, \size, \ext, h, 1 + h264_qpel_1pass \op, mc01, \lmul, \size, \ext, v, zero + h264_qpel_1pass \op, mc03, \lmul, \size, \ext, v, a2 + h264_qpel_1pass \op, mc22, \lmul, \size, \ext, hv + + h264_qpel_2pass \op, mc11, \lmul, \size, \ext, h, v + h264_qpel_2pass \op, mc21, \lmul, \size, \ext, h, hv + h264_qpel_2pass \op, mc12, \lmul, \size, \ext, v, hv + h264_qpel_2pass \op, mc31, \lmul, \size, \ext, h, v, off2=1 + h264_qpel_2pass \op, mc13, \lmul, \size, \ext, h, v, a2 + h264_qpel_2pass \op, mc33, \lmul, \size, \ext, h, v, a2, 1 + h264_qpel_2pass \op, mc23, \lmul, \size, \ext, h, hv, a2 + h264_qpel_2pass \op, mc32, \lmul, \size, \ext, v, hv, 1 +.endm + + ff_h264_qpel_fns put, mf2, 16, rvv256 + ff_h264_qpel_fns put, mf4, 8, rvv256 + /* ff_h264_qpel_fns put, mf8, 4, rvv256 */ + + ff_h264_qpel_fns avg, mf2, 16, rvv256 + ff_h264_qpel_fns avg, mf4, 8, rvv256 + /* ff_h264_qpel_fns avg, mf8, 4, rvv256 */ + + ff_h264_qpel_fns put, m1, 16, rvv + ff_h264_qpel_fns put, mf2, 8, rvv + ff_h264_qpel_fns put, mf4, 4, rvv + + ff_h264_qpel_fns avg, m1, 16, rvv + ff_h264_qpel_fns avg, mf2, 8, rvv + ff_h264_qpel_fns avg, mf4, 4, rvv diff --git a/libavcodec/riscv/h26x/asm.S b/libavcodec/riscv/h26x/asm.S new file mode 100644 index 0000000000..38c68e36ba --- /dev/null +++ b/libavcodec/riscv/h26x/asm.S @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/riscv/asm.S" + +.macro vsetvlstatic w, vlen, en, mn1, mn2, mn3, mn4, mn5, mn6, vta=ta + .if \w == 2 && \vlen == 128 + vsetivli zero, \w, \en, \mn1, \vta, ma + .elseif \w <= 4 && \vlen == 128 + vsetivli zero, \w, \en, \mn2, \vta, ma + .elseif \w <= 8 && \vlen == 128 + vsetivli zero, \w, \en, \mn3, \vta, ma + .elseif \w <= 16 && \vlen == 128 + vsetivli zero, \w, \en, \mn4, \vta, ma + .elseif \w <= 32 && \vlen == 128 + li t0, \w + vsetvli zero, t0, \en, \mn5, \vta, ma + .elseif \w <= 4 && \vlen == 256 + vsetivli zero, \w, \en, \mn1, \vta, ma + .elseif \w <= 8 && \vlen == 256 + vsetivli zero, \w, \en, \mn2, \vta, ma + .elseif \w <= 16 && \vlen == 256 + vsetivli zero, \w, \en, \mn3, \vta, ma + .elseif \w <= 32 && \vlen == 256 + li t0, \w + vsetvli zero, t0, \en, \mn4, \vta, ma + .elseif \w <= 64 && \vlen == 256 + li t0, \w + vsetvli zero, t0, \en, \mn5, \vta, ma + .else + li t0, \w + vsetvli zero, t0, \en, \mn6, \vta, ma + .endif +.endm + +.macro vsetvlstatic8 w, vlen, vta + vsetvlstatic \w, \vlen, e8, mf8, mf4, mf2, m1, m2, m4, \vta +.endm + +.macro vsetvlstatic16 w, vlen, vta + vsetvlstatic \w, \vlen, e16, mf4, mf2, m1, m2, m4, m8, \vta +.endm + +.macro vsetvlstatic32 w, vlen, vta + vsetvlstatic \w, \vlen, e32, mf2, m1, m2, m4, m8, m8, \vta +.endm + +.macro POW2_JMP_TABLE id, vlen +const jmp_table_\id\vlen + .4byte \id\()2\vlen\()f - jmp_table_\id\vlen + .4byte \id\()4\vlen\()f - jmp_table_\id\vlen + .4byte \id\()8\vlen\()f - jmp_table_\id\vlen + .4byte \id\()16\vlen\()f - jmp_table_\id\vlen + .4byte \id\()32\vlen\()f - jmp_table_\id\vlen + .4byte \id\()64\vlen\()f - jmp_table_\id\vlen + .4byte \id\()128\vlen\()f - jmp_table_\id\vlen +endconst +.endm + +.macro POW2_J vlen, id, w + clz t1, \w + neg t1, t1 + lla t5, jmp_table_\id\vlen + sh2add t1, t1, t5 + lw t1, ((__riscv_xlen-2)<<2)(t1) + add t1, t1, t5 + jr t1 +.endm + +.macro put_pixels w, vlen, id, MAX_PB_SIZE +\id\w\vlen: + vsetvlstatic8 \w, \vlen + li t2, 1<<6 +.if \w == 128 && \vlen == 128 +1: + addi t0, a1, 64 + addi t1, a0, 64*2 + vle8.v v0, (a1) + vle8.v v16, (t0) + vwmulu.vx v8, v0, t2 + vwmulu.vx v24, v16, t2 + vse16.v v8, (a0) + vse16.v v24, (t1) + add a1, a1, a2 + addi a3, a3, -1 + addi a0, a0, 128*2 + bnez a3, 1b +.else +1: + vle8.v v0, (a1) + vwmulu.vx v8, v0, t2 + vse16.v v8, (a0) + add a1, a1, a2 + addi a3, a3, -1 + addi a0, a0, \MAX_PB_SIZE<<1 + bnez a3, 1b +.endif + ret +.endm + +.macro func_put_pixels vlen, MAX_PB_SIZE, name +func ff_\name\()_put_pixels_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 3, \vlen + POW2_J \vlen, 3, a6 + .irp w,2,4,8,16,32,64,128 + put_pixels \w, \vlen, 3, \MAX_PB_SIZE + .endr +endfunc +.endm diff --git a/libavcodec/riscv/h26x/h2656_inter_rvv.S b/libavcodec/riscv/h26x/h2656_inter_rvv.S new file mode 100644 index 0000000000..b7ee88fb20 --- /dev/null +++ b/libavcodec/riscv/h26x/h2656_inter_rvv.S @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/riscv/h26x/asm.S" + +func_put_pixels 256, 64, h2656 +func_put_pixels 128, 64, h2656 diff --git a/libavcodec/riscv/h26x/h2656dsp.h b/libavcodec/riscv/h26x/h2656dsp.h new file mode 100644 index 0000000000..6d2ac55556 --- /dev/null +++ b/libavcodec/riscv/h26x/h2656dsp.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_RISCV_H26X_H2656DSP_H +#define AVCODEC_RISCV_H26X_H2656DSP_H + +void ff_h2656_put_pixels_8_rvv_256(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_h2656_put_pixels_8_rvv_128(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); + +#endif diff --git a/libavcodec/riscv/hevcdsp_init.c b/libavcodec/riscv/hevcdsp_init.c new file mode 100644 index 0000000000..70bc8ebea7 --- /dev/null +++ b/libavcodec/riscv/hevcdsp_init.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" + +#include "libavcodec/hevc/dsp.h" +#include "libavcodec/riscv/h26x/h2656dsp.h" + +#define RVV_FNASSIGN(member, v, h, fn, ext) \ + member[1][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[3][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[5][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[7][v][h] = ff_h2656_put_pixels_##8_##ext; \ + member[9][v][h] = ff_h2656_put_pixels_##8_##ext; + +void ff_hevc_dsp_init_riscv(HEVCDSPContext *c, const int bit_depth) +{ +#if HAVE_RVV + const int flags = av_get_cpu_flags(); + int vlenb; + + if (!(flags & AV_CPU_FLAG_RVV_I32) || !(flags & AV_CPU_FLAG_RVB)) + return; + + vlenb = ff_get_rv_vlenb(); + if (vlenb >= 32) { + switch (bit_depth) { + case 8: + RVV_FNASSIGN(c->put_hevc_qpel, 0, 0, pel_pixels, rvv_256); + RVV_FNASSIGN(c->put_hevc_epel, 0, 0, pel_pixels, rvv_256); + break; + default: + break; + } + } else if (vlenb >= 16) { + switch (bit_depth) { + case 8: + RVV_FNASSIGN(c->put_hevc_qpel, 0, 0, pel_pixels, rvv_128); + RVV_FNASSIGN(c->put_hevc_epel, 0, 0, pel_pixels, rvv_128); + break; + default: + break; + } + } +#endif +} diff --git a/libavcodec/riscv/me_cmp_init.c b/libavcodec/riscv/me_cmp_init.c index f246e55cb1..dac1366332 100644 --- a/libavcodec/riscv/me_cmp_init.c +++ b/libavcodec/riscv/me_cmp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -24,55 +24,55 @@ #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" -int ff_pix_abs16_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_x2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_x2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_x2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_x2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs16_y2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs16_y2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_pix_abs8_y2_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_pix_abs8_y2_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse16_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse8_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse8_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse4_rvv(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse4_rvv(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsse16_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsse8_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsse_intra16_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsse_intra8_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsad16_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsad8_rvv(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -int ff_vsad_intra16_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); -int ff_vsad_intra8_rvv(MpegEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsse16_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsse8_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsse_intra16_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsse_intra8_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsad16_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsad8_rvv(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); +int ff_vsad_intra16_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); +int ff_vsad_intra8_rvv(MPVEncContext *c, const uint8_t *s, const uint8_t *dummy, ptrdiff_t stride, int h); int ff_nsse16_rvv(int multiplier, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); int ff_nsse8_rvv(int multiplier, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h); -static int nsse16_rvv_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse16_rvv_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return ff_nsse16_rvv(c->avctx->nsse_weight, s1, s2, stride, h); + return ff_nsse16_rvv(c->c.avctx->nsse_weight, s1, s2, stride, h); else return ff_nsse16_rvv(8, s1, s2, stride, h); } -static int nsse8_rvv_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, +static int nsse8_rvv_wrapper(MPVEncContext *c, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride, int h) { if (c) - return ff_nsse8_rvv(c->avctx->nsse_weight, s1, s2, stride, h); + return ff_nsse8_rvv(c->c.avctx->nsse_weight, s1, s2, stride, h); else return ff_nsse8_rvv(8, s1, s2, stride, h); } diff --git a/libavcodec/riscv/me_cmp_rvv.S b/libavcodec/riscv/me_cmp_rvv.S index 8989c91dde..0b7a49bb0c 100644 --- a/libavcodec/riscv/me_cmp_rvv.S +++ b/libavcodec/riscv/me_cmp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/pixblockdsp_init.c b/libavcodec/riscv/pixblockdsp_init.c index 2735776105..e59fba63cc 100644 --- a/libavcodec/riscv/pixblockdsp_init.c +++ b/libavcodec/riscv/pixblockdsp_init.c @@ -24,7 +24,6 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/pixblockdsp.h" void ff_get_pixels_8_rvi(int16_t *block, const uint8_t *pixels, @@ -42,12 +41,12 @@ void ff_diff_pixels_unaligned_rvv(int16_t *block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { #if HAVE_RV int cpu_flags = av_get_cpu_flags(); +#if __riscv_xlen >= 64 if (cpu_flags & AV_CPU_FLAG_RVI) { if (high_bit_depth) c->get_pixels = ff_get_pixels_16_rvi; @@ -61,7 +60,7 @@ av_cold void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, else c->get_pixels_unaligned = ff_get_pixels_8_rvi; } - +#endif #if HAVE_RVV if ((cpu_flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128)) { c->diff_pixels = ff_diff_pixels_unaligned_rvv; diff --git a/libavcodec/riscv/pixblockdsp_rvi.S b/libavcodec/riscv/pixblockdsp_rvi.S index ed1af70251..c47204856b 100644 --- a/libavcodec/riscv/pixblockdsp_rvi.S +++ b/libavcodec/riscv/pixblockdsp_rvi.S @@ -20,6 +20,7 @@ #include "libavutil/riscv/asm.S" +#if __riscv_xlen >= 64 func ff_get_pixels_8_rvi lpad 0 .irp row, 0, 1, 2, 3, 4, 5, 6, 7 @@ -58,3 +59,4 @@ func ff_get_pixels_16_rvi .endr ret endfunc +#endif diff --git a/libavcodec/riscv/rv34dsp_init.c b/libavcodec/riscv/rv34dsp_init.c index 051dc75653..a8437f0705 100644 --- a/libavcodec/riscv/rv34dsp_init.c +++ b/libavcodec/riscv/rv34dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv34dsp_rvv.S b/libavcodec/riscv/rv34dsp_rvv.S index fc0ffec4fe..69b9306946 100644 --- a/libavcodec/riscv/rv34dsp_rvv.S +++ b/libavcodec/riscv/rv34dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv40dsp_init.c b/libavcodec/riscv/rv40dsp_init.c index 6aba571794..65790fa59c 100644 --- a/libavcodec/riscv/rv40dsp_init.c +++ b/libavcodec/riscv/rv40dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/rv40dsp_rvv.S b/libavcodec/riscv/rv40dsp_rvv.S index ca431eb8ab..7f80f28349 100644 --- a/libavcodec/riscv/rv40dsp_rvv.S +++ b/libavcodec/riscv/rv40dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -20,15 +20,30 @@ #include "libavutil/riscv/asm.S" -.macro manual_avg dst src1 src2 - vadd.vv \dst, \src1, \src2 - vadd.vi \dst, \dst, 1 - vsrl.vi \dst, \dst, 1 -.endm +const rv40_bias + .byte 0, 16, 32, 16 + .byte 32, 28, 32, 28 + .byte 0, 32, 16, 32 + .byte 32, 28, 32, 28 +endconst .macro do_chroma_mc type unroll - csrwi vxrm, 2 + csrwi vxrm, 0 + addi sp, sp, -16 +#if __riscv_xlen == 32 + sw s2, (sp) +#elif __riscv_xlen == 64 + sd s2, (sp) +#else + sq s2, (sp) +#endif + lla t4, rv40_bias + srli t5, a5, 1 + sh2add t4, t5, t4 + srli t5, a4, 1 + add t5, t4, t5 slli t2, a5, 3 + lb s2, (t5) mul t1, a5, a4 sh3add a5, a4, t2 slli a4, a4, 3 @@ -80,17 +95,19 @@ vwmulu.vx v12, v14, a6 vwmaccu.vx v10, t1, v15 vwmaccu.vx v12, a7, v15 - vnclipu.wi v15, v8, 6 + vwaddu.wx v20, v8, s2 + vnsrl.wi v15, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v15, v15, v9 + vaaddu.vv v15, v15, v9 .endif vse8.v v15, (a0) add a0, a0, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif add t4, t4, t3 vse8.v v8, (a0) @@ -115,17 +132,19 @@ vslide1down.vx v14, v14, t5 vsetvli zero, t6, e8, m1, ta, ma vwmaccu.vx v16, t1, v14 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v16, 6 + vwaddu.wx v20, v16, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v9, (a0) - manual_avg v8, v8, v9 + vaaddu.vv v8, v8, v9 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -159,18 +178,20 @@ vwmaccu.vx v10, t0, v8 add a4, a4, a7 vwmaccu.vx v12, t0, v9 - vnclipu.wi v15, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v15, v20, 6 vwmulu.vx v10, v9, a6 - vnclipu.wi v9, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v9, v20, 6 .ifc \type,avg vle8.v v16, (a0) - manual_avg v15, v15, v16 + vaaddu.vv v15, v15, v16 .endif vse8.v v15, (a0) add a0, a0, a2 .ifc \type,avg vle8.v v16, (a0) - manual_avg v9, v9, v16 + vaaddu.vv v9, v9, v16 .endif vse8.v v9, (a0) add a0, a0, a2 @@ -179,18 +200,20 @@ vle8.v v14, (a5) vwmaccu.vx v10, t0, v8 vwmulu.vx v12, v8, a6 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 vwmaccu.vx v12, t0, v14 .ifc \type,avg vle8.v v16, (a0) - manual_avg v8, v8, v16 + vaaddu.vv v8, v8, v16 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v16, (a0) - manual_avg v8, v8, v16 + vaaddu.vv v8, v8, v16 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -226,17 +249,19 @@ vsetvli zero, t6, e8, m1, ta, ma vwmulu.vx v12, v8, a6 vwmaccu.vx v12, a7, v9 - vnclipu.wi v16, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v16, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v16, v16, v18 + vaaddu.vv v16, v16, v18 .endif vse8.v v16, (a0) add a0, a0, a2 - vnclipu.wi v10, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v10, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v10, v10, v18 + vaaddu.vv v10, v10, v18 .endif add a4, a4, t1 vse8.v v10, (a0) @@ -254,18 +279,20 @@ vslide1down.vx v9, v8, t5 vsetvli zero, t6, e8, m1, ta, ma vwmulu.vx v12, v8, a6 - vnclipu.wi v8, v14, 6 + vwaddu.wx v20, v14, s2 + vnsrl.wi v8, v20, 6 vwmaccu.vx v12, a7, v9 .ifc \type,avg vle8.v v18, (a0) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a0) add a0, a0, a2 - vnclipu.wi v8, v12, 6 + vwaddu.wx v20, v12, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a0) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a0) add a0, a0, a2 @@ -293,18 +320,20 @@ vwmulu.vx v10, v8, a6 vle8.v v8, (t0) add t0, t1, a2 - vnclipu.wi v13, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v13, v20, 6 vwmulu.vx v10, v8, a6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v13, v13, v18 + vaaddu.vv v13, v13, v18 .endif vse8.v v13, (a5) add a5, a5, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) add a5, a5, a2 @@ -312,23 +341,34 @@ vle8.v v9, (t1) vle8.v v12, (t0) vwmulu.vx v10, v9, a6 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 vwmulu.vx v10, v12, a6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) add a5, a5, a2 - vnclipu.wi v8, v10, 6 + vwaddu.wx v20, v10, s2 + vnsrl.wi v8, v20, 6 .ifc \type,avg vle8.v v18, (a5) - manual_avg v8, v8, v18 + vaaddu.vv v8, v8, v18 .endif vse8.v v8, (a5) .endif blt t2, a3, 7b 8: +#if __riscv_xlen == 32 + lw s2, (sp) +#elif __riscv_xlen == 64 + ld s2, (sp) +#else + lq s2, (sp) +#endif + addi sp, sp, 16 + ret .endm diff --git a/libavcodec/riscv/svqenc_init.c b/libavcodec/riscv/svqenc_init.c index 5021849e4c..b2eacb6b44 100644 --- a/libavcodec/riscv/svqenc_init.c +++ b/libavcodec/riscv/svqenc_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/svqenc_rvv.S b/libavcodec/riscv/svqenc_rvv.S index d37c319db7..b04998a576 100644 --- a/libavcodec/riscv/svqenc_rvv.S +++ b/libavcodec/riscv/svqenc_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/takdsp_init.c b/libavcodec/riscv/takdsp_init.c index 12d2d8dab9..be3dd97d48 100644 --- a/libavcodec/riscv/takdsp_init.c +++ b/libavcodec/riscv/takdsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/takdsp_rvv.S b/libavcodec/riscv/takdsp_rvv.S index a914ab8189..c0952ab167 100644 --- a/libavcodec/riscv/takdsp_rvv.S +++ b/libavcodec/riscv/takdsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright (c) 2023 Rémi Denis-Courmont * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/vc1dsp_init.c b/libavcodec/riscv/vc1dsp_init.c index de9002f395..d70dd7931f 100644 --- a/libavcodec/riscv/vc1dsp_init.c +++ b/libavcodec/riscv/vc1dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vc1dsp_rvi.S b/libavcodec/riscv/vc1dsp_rvi.S index 7725bfb628..261a2382a7 100644 --- a/libavcodec/riscv/vc1dsp_rvi.S +++ b/libavcodec/riscv/vc1dsp_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vc1dsp_rvv.S b/libavcodec/riscv/vc1dsp_rvv.S index f9b59688ae..e54167c34f 100644 --- a/libavcodec/riscv/vc1dsp_rvv.S +++ b/libavcodec/riscv/vc1dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2023 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright (c) 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. diff --git a/libavcodec/riscv/vp8dsp_init.c b/libavcodec/riscv/vp8dsp_init.c index 250fecb2f0..3e35c72198 100644 --- a/libavcodec/riscv/vp8dsp_init.c +++ b/libavcodec/riscv/vp8dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * @@ -129,8 +129,8 @@ av_cold void ff_vp8dsp_init_riscv(VP8DSPContext *c) #if __riscv_xlen >= 64 if (flags & AV_CPU_FLAG_RVV_I64) c->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_rvv; -#endif c->vp8_idct_add = ff_vp8_idct_add_rvv; +#endif c->vp8_idct_dc_add = ff_vp8_idct_dc_add_rvv; c->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_rvv; if (flags & AV_CPU_FLAG_RVV_I64) diff --git a/libavcodec/riscv/vp8dsp_rvi.S b/libavcodec/riscv/vp8dsp_rvi.S index 07d5c85032..fa98438563 100644 --- a/libavcodec/riscv/vp8dsp_rvi.S +++ b/libavcodec/riscv/vp8dsp_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp8dsp_rvv.S b/libavcodec/riscv/vp8dsp_rvv.S index a8b3e239ba..2ee7029c60 100644 --- a/libavcodec/riscv/vp8dsp_rvv.S +++ b/libavcodec/riscv/vp8dsp_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. @@ -97,7 +97,6 @@ func ff_vp8_luma_dc_wht_rvv, zve64x vsse16.v v3, (t3), t0 ret endfunc -#endif func ff_vp8_idct_add_rvv, zve32x lpad 0 @@ -158,6 +157,7 @@ func ff_vp8_idct_add_rvv, zve32x vsub.vv v3, v4, v7 jr t0 endfunc +#endif func ff_vp8_idct_dc_add_rvv, zve32x lpad 0 @@ -365,7 +365,7 @@ func ff_put_vp8_bilin\len\()_hv_rvv, zve32x endfunc .endr -const subpel_filters +const subpel_filters, align=0 .byte 0, -6, 123, 12, -1, 0 .byte 2, -11, 108, 36, -8, 1 .byte 0, -9, 93, 50, -6, 0 diff --git a/libavcodec/riscv/vp9_intra_rvv.S b/libavcodec/riscv/vp9_intra_rvv.S index 13d695c831..89e984c636 100644 --- a/libavcodec/riscv/vp9_intra_rvv.S +++ b/libavcodec/riscv/vp9_intra_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9_mc_rvi.S b/libavcodec/riscv/vp9_mc_rvi.S index 4a8371b232..764ac1771c 100644 --- a/libavcodec/riscv/vp9_mc_rvi.S +++ b/libavcodec/riscv/vp9_mc_rvi.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9_mc_rvv.S b/libavcodec/riscv/vp9_mc_rvv.S index d1ddbe007b..422ec90332 100644 --- a/libavcodec/riscv/vp9_mc_rvv.S +++ b/libavcodec/riscv/vp9_mc_rvv.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9dsp.h b/libavcodec/riscv/vp9dsp.h index 601939882b..2422cd83e2 100644 --- a/libavcodec/riscv/vp9dsp.h +++ b/libavcodec/riscv/vp9dsp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vp9dsp_init.c b/libavcodec/riscv/vp9dsp_init.c index d53852f673..67c227cf3d 100644 --- a/libavcodec/riscv/vp9dsp_init.c +++ b/libavcodec/riscv/vp9dsp_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). * * This file is part of FFmpeg. * diff --git a/libavcodec/riscv/vvc/Makefile b/libavcodec/riscv/vvc/Makefile new file mode 100644 index 0000000000..e17ab93ab8 --- /dev/null +++ b/libavcodec/riscv/vvc/Makefile @@ -0,0 +1,3 @@ +OBJS-$(CONFIG_VVC_DECODER) += riscv/vvc/dsp_init.o +RVV-OBJS-$(CONFIG_VVC_DECODER) += riscv/vvc/mc_rvv.o \ + riscv/vvc/sad_rvv.o diff --git a/libavcodec/riscv/vvc/dsp_init.c b/libavcodec/riscv/vvc/dsp_init.c new file mode 100644 index 0000000000..d7a89f4779 --- /dev/null +++ b/libavcodec/riscv/vvc/dsp_init.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/vvc/dsp.h" +#include "libavcodec/vvc/dec.h" +#include "libavcodec/riscv/h26x/h2656dsp.h" + +#define bf(fn, bd, opt) fn##_##bd##_##opt + +#define AVG_PROTOTYPES(bd, opt) \ +void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height); \ +void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ + const int16_t *src0, const int16_t *src1, int width, int height, \ + int denom, int w0, int w1, int o0, int o1); + +AVG_PROTOTYPES(8, rvv_128) +AVG_PROTOTYPES(8, rvv_256) + +#define DMVR_PROTOTYPES(bd, opt) \ +void ff_vvc_dmvr_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_h_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_v_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ +void ff_vvc_dmvr_hv_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ + int height, intptr_t mx, intptr_t my, int width); \ + +DMVR_PROTOTYPES(8, rvv_128) +DMVR_PROTOTYPES(8, rvv_256) + +#define DMVR_INIT(bd, opt) do { \ + c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_##opt; \ + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_##opt; \ + c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_##opt; \ + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_##opt; \ +} while (0) + +int ff_vvc_sad_rvv_128(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); +int ff_vvc_sad_rvv_256(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); + +#define PUT_PIXELS_PROTOTYPES2(bd, opt) \ +void bf(ff_vvc_put_pixels, bd, opt)(int16_t *dst, \ + const uint8_t *_src, const ptrdiff_t _src_stride, \ + const int height, const int8_t *hf, const int8_t *vf, const int width); + +PUT_PIXELS_PROTOTYPES2(8, rvv_128) +PUT_PIXELS_PROTOTYPES2(8, rvv_256) + +#define PEL_FUNC(dst, C, idx1, idx2, a) \ + do { \ + for (int w = 1; w < 7; w++) \ + c->inter.dst[C][w][idx1][idx2] = a; \ + } while (0) \ + +#define FUNCS(C, opt) \ + PEL_FUNC(put, C, 0, 0, ff_vvc_put_pixels_8_##opt); \ + +void ff_vvc_dsp_init_riscv(VVCDSPContext *const c, const int bd) +{ +#if HAVE_RVV + const int flags = av_get_cpu_flags(); + int vlenb; + + if (!(flags & AV_CPU_FLAG_RVV_I32) || !(flags & AV_CPU_FLAG_RVB)) + return; + + vlenb = ff_get_rv_vlenb(); + if (vlenb >= 32) { + switch (bd) { + case 8: + c->inter.avg = ff_vvc_avg_8_rvv_256; +# if (__riscv_xlen == 64) + c->inter.w_avg = ff_vvc_w_avg_8_rvv_256; +# endif + DMVR_INIT(8, rvv_256); + FUNCS(LUMA, rvv_256); + FUNCS(CHROMA, rvv_256); + break; + case 10: + c->inter.sad = ff_vvc_sad_rvv_256; + default: + break; + } + } else if (vlenb >= 16) { + switch (bd) { + case 8: + c->inter.avg = ff_vvc_avg_8_rvv_128; +# if (__riscv_xlen == 64) + c->inter.w_avg = ff_vvc_w_avg_8_rvv_128; +# endif + DMVR_INIT(8, rvv_128); + FUNCS(LUMA, rvv_128); + FUNCS(CHROMA, rvv_128); + break; + case 10: + c->inter.sad = ff_vvc_sad_rvv_128; + default: + break; + } + } +#endif +} diff --git a/libavcodec/riscv/vvc/mc_rvv.S b/libavcodec/riscv/vvc/mc_rvv.S new file mode 100644 index 0000000000..e6b2aadafe --- /dev/null +++ b/libavcodec/riscv/vvc/mc_rvv.S @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/riscv/h26x/asm.S" + +.macro avg w, vlen, id +\id\w\vlen: +.if \w < 128 + vsetvlstatic16 \w, \vlen + addi t0, a2, 128*2 + addi t1, a3, 128*2 + add t2, a0, a1 + vle16.v v0, (a2) + vle16.v v8, (a3) + addi a5, a5, -2 + vle16.v v16, (t0) + vle16.v v24, (t1) + vadd.vv v8, v8, v0 + vadd.vv v24, v24, v16 + vmax.vx v8, v8, zero + vmax.vx v24, v24, zero + vsetvlstatic8 \w, \vlen + addi a2, a2, 128*4 + vnclipu.wi v8, v8, 7 + vnclipu.wi v24, v24, 7 + addi a3, a3, 128*4 + vse8.v v8, (a0) + vse8.v v24, (t2) + sh1add a0, a1, a0 +.else + addi a5, a5, -1 + mv t1, a0 + mv t2, a2 + mv t3, a3 + mv t4, a4 +1: + vsetvli t0, a4, e16, m8, ta, ma + sub a4, a4, t0 + vle16.v v0, (a2) + vle16.v v8, (a3) + vadd.vv v8, v8, v0 + vmax.vx v8, v8, zero + vsetvli zero, zero, e8, m4, ta, ma + vnclipu.wi v8, v8, 7 + vse8.v v8, (a0) + sh1add a2, t0, a2 + sh1add a3, t0, a3 + add a0, a0, t0 + bnez a4, 1b + add a0, t1, a1 + addi a2, t2, 128*2 + addi a3, t3, 128*2 + mv a4, t4 +.endif + bnez a5, \id\w\vlen\()b + ret +.endm + +.macro func_avg vlen +func ff_vvc_avg_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 1, \vlen + csrwi vxrm, 0 + POW2_J \vlen, 1, a4 + .irp w,2,4,8,16,32,64,128 + avg \w, \vlen, 1 + .endr +endfunc +.endm + +func_avg 128 +func_avg 256 + +#if (__riscv_xlen == 64) +.macro w_avg w, vlen, id +\id\w\vlen: +.if \w <= 32 || (\w == 64 && \vlen == 256) + vsetvlstatic16 \w, \vlen + addi t0, a2, 128*2 + addi t1, a3, 128*2 + vle16.v v0, (a2) + vle16.v v4, (a3) + addi a5, a5, -2 + vle16.v v8, (t0) + vle16.v v12, (t1) + vwmul.vx v16, v0, a7 + vwmul.vx v24, v8, a7 + vwmacc.vx v16, t3, v4 + vwmacc.vx v24, t3, v12 + vsetvlstatic32 \w, \vlen + add t2, a0, a1 + vadd.vx v16, v16, t4 + vadd.vx v24, v24, t4 + vsetvlstatic16 \w, \vlen + vnsrl.wx v16, v16, t6 + vnsrl.wx v24, v24, t6 + vmax.vx v16, v16, zero + vmax.vx v24, v24, zero + vsetvlstatic8 \w, \vlen + addi a2, a2, 128*4 + vnclipu.wi v16, v16, 0 + vnclipu.wi v24, v24, 0 + vse8.v v16, (a0) + addi a3, a3, 128*4 + vse8.v v24, (t2) + sh1add a0, a1, a0 +.else + addi a5, a5, -1 + mv t1, a0 + mv t2, a2 + mv t5, a3 + mv a6, a4 +1: + vsetvli t0, a4, e16, m4, ta, ma + sub a4, a4, t0 + vle16.v v0, (a2) + vle16.v v4, (a3) + vwmul.vx v16, v0, a7 + vwmacc.vx v16, t3, v4 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v16, v16, t4 + vsetvli zero, zero, e16, m4, ta, ma + vnsrl.wx v16, v16, t6 + vmax.vx v16, v16, zero + vsetvli zero, zero, e8, m2, ta, ma + vnclipu.wi v16, v16, 0 + vse8.v v16, (a0) + sh1add a2, t0, a2 + sh1add a3, t0, a3 + add a0, a0, t0 + bnez a4, 1b + add a0, t1, a1 + addi a2, t2, 128*2 + addi a3, t5, 128*2 + mv a4, a6 +.endif + bnez a5, \id\w\vlen\()b + ret +.endm + +.macro func_w_avg vlen +func ff_vvc_w_avg_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + POW2_JMP_TABLE 2, \vlen + csrwi vxrm, 0 + addi t6, a6, 7 + ld t3, (sp) + ld t4, 8(sp) + ld t5, 16(sp) + addi t4, t4, 1 // o0 + o1 + 1 + add t4, t4, t5 + addi t5, t6, -1 // shift - 1 + sll t4, t4, t5 + POW2_J \vlen, 2, a4 + .irp w,2,4,8,16,32,64,128 + w_avg \w, \vlen, 2 + .endr +endfunc +.endm + +func_w_avg 128 +func_w_avg 256 +#endif + +func dmvr zve32x, zbb, zba + lpad 0 + li t0, 4 +1: + add t1, a1, a2 + addi t4, a0, 128*2 + vle8.v v0, (a1) + vle8.v v4, (t1) + addi a3, a3, -2 + vwmulu.vx v16, v0, t0 + vwmulu.vx v20, v4, t0 + vse16.v v16, (a0) + vse16.v v20, (t4) + sh1add a1, a2, a1 + add a0, a0, 128*2*2 + bnez a3, 1b + ret +endfunc + +.macro dmvr_h_v mn, type, w, vlen +func dmvr_\type\vlen\w, zve32x, zbb, zba + lla t4, ff_vvc_inter_luma_dmvr_filters + sh1add t4, \mn, t4 + lbu t5, (t4) + lbu t6, 1(t4) +1: + vsetvlstatic8 \w, \vlen +.ifc \type,h + addi t0, a1, 1 + addi t1, a1, 2 +.else + add t0, a1, a2 + add t1, t0, a2 +.endif + vle8.v v0, (a1) + vle8.v v4, (t0) + vle8.v v8, (t1) + addi a3, a3, -2 + addi t2, a0, 128*2 + vwmulu.vx v12, v0, t5 + vwmulu.vx v24, v4, t5 + vwmaccu.vx v12, t6, v4 + vwmaccu.vx v24, t6, v8 + vsetvlstatic16 \w, \vlen + vssrl.vi v12, v12, 2 + vssrl.vi v24, v24, 2 + vse16.v v12, (a0) + vse16.v v24, (t2) + add a0, a0, 128*4 + sh1add a1, a2, a1 + bnez a3, 1b + ret +endfunc +.endm + +.macro dmvr_load_h dst, filter0, filter1, w, vlen + vsetvlstatic8 \w, \vlen + addi a6, a1, 1 + vle8.v \dst, (a1) + vle8.v v2, (a6) + vwmulu.vx v4, \dst, \filter0 + vwmaccu.vx v4, \filter1, v2 + vsetvlstatic16 \w, \vlen + vssrl.vi \dst, v4, 2 +.endm + +.macro dmvr_hv w, vlen +func dmvr_hv\vlen\w, zve32x, zbb, zba + lla t0, ff_vvc_inter_luma_dmvr_filters + sh1add t1, a4, t0 + sh1add t2, a5, t0 + lbu t3, (t1) // filter[mx][0] + lbu t4, 1(t1) // filter[mx][1] + lbu t5, (t2) // filter[my][0] + lbu t6, 1(t2) // filter[my][1] + dmvr_load_h v12, t3, t4, \w, \vlen + add a1, a1, a2 +1: + vmul.vx v28, v12, t5 + addi a3, a3, -1 + dmvr_load_h v12, t3, t4, \w, \vlen + vmacc.vx v28, t6, v12 + vssrl.vi v28, v28, 4 + vse16.v v28, (a0) + add a1, a1, a2 + addi a0, a0, 128*2 + bnez a3, 1b + ret +endfunc +.endm + +.macro func_dmvr vlen, name +func ff_vvc_\name\()_8_rvv_\vlen\(), zve32x, zbb, zba + lpad 0 + li t0, 20 + beq a6, t0, DMVR\name\vlen\()20 + .irp w,12,20 +DMVR\name\vlen\w: + .ifc \name, dmvr + vsetvlstatic8 \w, \vlen + j \name + .else + csrwi vxrm, 0 + j \name\()\vlen\w + .endif + .endr +endfunc +.endm + + +.irp vlen,256,128 +.irp w,12,20 +dmvr_h_v a4, h, \w, \vlen +dmvr_h_v a5, v, \w, \vlen +dmvr_hv \w, \vlen +.endr +func_dmvr \vlen, dmvr +func_dmvr \vlen, dmvr_h +func_dmvr \vlen, dmvr_v +func_dmvr \vlen, dmvr_hv +.endr + +func_put_pixels 256, 128, vvc +func_put_pixels 128, 128, vvc diff --git a/libavcodec/riscv/vvc/sad_rvv.S b/libavcodec/riscv/vvc/sad_rvv.S new file mode 100644 index 0000000000..d906de232b --- /dev/null +++ b/libavcodec/riscv/vvc/sad_rvv.S @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS). + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/riscv/h26x/asm.S" + +.macro func_sad vlen +func ff_vvc_sad_rvv_\vlen, zve32x, zbb, zba + lpad 0 + slli t2, a3, 7 // dy * 128 + li t1, 4*128+4 + add t3, t2, a2 // dy * 128 + dx + sub t1, t1, t2 + sub t1, t1, a2 + sh1add a0, t3, a0 + sh1add a1, t1, a1 + li t3, 16 + beq a4, t3, SADVSET\vlen\()16 + .irp w,8,16 +SADVSET\vlen\w: + vsetvlstatic32 \w, \vlen + vmv.v.i v0, 0 + vmv.s.x v24, zero + vsetvlstatic16 \w, \vlen, tu +SAD\vlen\w: + addi a5, a5, -2 + vle16.v v8, (a0) + vle16.v v16, (a1) + vsub.vv v8, v8, v16 + vneg.v v16, v8 + addi a0, a0, 2 * 128 * 2 + vmax.vv v8, v8, v16 + vwaddu.wv v0, v0, v8 + addi a1, a1, 2 * 128 * 2 + bnez a5, SAD\vlen\w + vsetvlstatic32 \w, \vlen + vredsum.vs v24, v0, v24 + vmv.x.s a0, v24 + ret + .endr +endfunc +.endm + +func_sad 256 +func_sad 128 diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index 47b076dbd8..dad0e4c25f 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -29,8 +29,9 @@ #include "avcodec.h" #include "codec_internal.h" #include "decode.h" +#include "decode_bsf.h" #include "hwconfig.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "libavutil/buffer.h" #include "libavutil/common.h" #include "libavutil/frame.h" @@ -123,14 +124,14 @@ static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, in return ret; } -static int rkmpp_close_decoder(AVCodecContext *avctx) +static av_cold int rkmpp_close_decoder(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; - ff_refstruct_unref(&rk_context->decoder); + av_refstruct_unref(&rk_context->decoder); return 0; } -static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj) +static void rkmpp_release_decoder(AVRefStructOpaque unused, void *obj) { RKMPPDecoder *decoder = obj; @@ -149,7 +150,7 @@ static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj) av_buffer_unref(&decoder->device_ref); } -static int rkmpp_init_decoder(AVCodecContext *avctx) +static av_cold int rkmpp_init_decoder(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; RKMPPDecoder *decoder = NULL; @@ -161,7 +162,7 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; // create a decoder and a ref to it - decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0, + decoder = av_refstruct_alloc_ext(sizeof(*decoder), 0, NULL, rkmpp_release_decoder); if (!decoder) { ret = AVERROR(ENOMEM); @@ -279,9 +280,11 @@ static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) // on first packet, send extradata if (decoder->first_packet) { if (avctx->extradata_size) { - ret = rkmpp_write_data(avctx, avctx->extradata, - avctx->extradata_size, - avpkt->pts); + const uint8_t *extradata; + int extradata_size; + ff_decode_get_extradata(avctx, &extradata, &extradata_size); + ret = rkmpp_write_data(avctx, (uint8_t*)extradata, extradata_size, + avpkt->pts); if (ret) { av_log(avctx, AV_LOG_ERROR, "Failed to write extradata to decoder (code = %d)\n", ret); return ret; @@ -304,7 +307,7 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data) RKMPPFrameContext *framecontext = opaque; mpp_frame_deinit(&framecontext->frame); - ff_refstruct_unref(&framecontext->decoder_ref); + av_refstruct_unref(&framecontext->decoder_ref); av_free(desc); } @@ -449,7 +452,7 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) ret = AVERROR(ENOMEM); goto fail; } - framecontext->decoder_ref = ff_refstruct_ref(rk_context->decoder); + framecontext->decoder_ref = av_refstruct_ref(rk_context->decoder); frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref); if (!frame->hw_frames_ctx) { @@ -517,7 +520,7 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) return rkmpp_retrieve_frame(avctx, frame); } -static void rkmpp_flush(AVCodecContext *avctx) +static av_cold void rkmpp_flush(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; RKMPPDecoder *decoder = rk_context->decoder; diff --git a/libavcodec/rl.c b/libavcodec/rl.c index a78242d488..af304c5f87 100644 --- a/libavcodec/rl.c +++ b/libavcodec/rl.c @@ -20,7 +20,6 @@ #include #include "libavutil/attributes.h" -#include "libavutil/avassert.h" #include "rl.h" @@ -78,28 +77,30 @@ av_cold void ff_rl_init(RLTable *rl, av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) { - int i, q; - VLCElem table[1500] = { 0 }; - VLC vlc = { .table = table, .table_allocated = static_size }; - av_assert0(static_size <= FF_ARRAY_ELEMS(table)); - vlc_init(&vlc, 9, rl->n + 1, - &rl->table_vlc[0][1], 4, 2, - &rl->table_vlc[0][0], 4, 2, VLC_INIT_USE_STATIC); + VLCElem *vlc; - for (q = 0; q < 32; q++) { + ff_vlc_init_table_sparse(rl->rl_vlc[0], static_size, 9, rl->n + 1, + &rl->table_vlc[0][1], 4, 2, + &rl->table_vlc[0][0], 4, 2, + NULL, 0, 0, 0); + + vlc = rl->rl_vlc[0]; + + // We count down to avoid trashing the first RL-VLC + for (int q = 32; --q >= 0;) { int qmul = q * 2; int qadd = (q - 1) | 1; if (!rl->rl_vlc[q]) - return; + continue; if (q == 0) { qmul = 1; qadd = 0; } - for (i = 0; i < vlc.table_size; i++) { - int code = vlc.table[i].sym; - int len = vlc.table[i].len; + for (unsigned i = 0; i < static_size; i++) { + int idx = vlc[i].sym; + int len = vlc[i].len; int level, run; if (len == 0) { // illegal code @@ -107,18 +108,18 @@ av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) level = MAX_LEVEL; } else if (len < 0) { // more bits needed run = 0; - level = code; + level = idx; } else { - if (code == rl->n) { // esc + if (idx == rl->n) { // esc run = 66; level = 0; } else { - run = rl->table_run[code] + 1; - level = rl->table_level[code] * qmul + qadd; - if (code >= rl->last) run += 192; + run = rl->table_run[idx] + 1; + level = rl->table_level[idx] * qmul + qadd; + if (idx >= rl->last) run += 192; } } - rl->rl_vlc[q][i].len = len; + rl->rl_vlc[q][i].len8 = len; rl->rl_vlc[q][i].level = level; rl->rl_vlc[q][i].run = run; } diff --git a/libavcodec/rl.h b/libavcodec/rl.h index c45d8659d1..2588de2440 100644 --- a/libavcodec/rl.h +++ b/libavcodec/rl.h @@ -100,13 +100,9 @@ do { \ static inline int get_rl_index(const RLTable *rl, int last, int run, int level) { - int index; - index = rl->index_run[last][run]; - if (index >= rl->n) - return rl->n; if (level > rl->max_level[last][run]) return rl->n; - return index + level - 1; + return rl->index_run[last][run] + level - 1; } #endif /* AVCODEC_RL_H */ diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c index 8d08a13654..8a626c0d29 100644 --- a/libavcodec/roqaudioenc.c +++ b/libavcodec/roqaudioenc.c @@ -198,6 +198,5 @@ const FFCodec ff_roq_dpcm_encoder = { .init = roq_dpcm_encode_init, FF_CODEC_ENCODE_CB(roq_dpcm_encode_frame), .close = roq_dpcm_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), }; diff --git a/libavcodec/roqvideoenc.c b/libavcodec/roqvideoenc.c index 7cbe820f9a..03a1651c7f 100644 --- a/libavcodec/roqvideoenc.c +++ b/libavcodec/roqvideoenc.c @@ -1126,8 +1126,7 @@ const FFCodec ff_roq_encoder = { .init = roq_encode_init, FF_CODEC_ENCODE_CB(roq_encode_frame), .close = roq_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUVJ444P), .color_ranges = AVCOL_RANGE_JPEG, .p.priv_class = &roq_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/rpzaenc.c b/libavcodec/rpzaenc.c index 3a1924d385..32e06c991f 100644 --- a/libavcodec/rpzaenc.c +++ b/libavcodec/rpzaenc.c @@ -619,7 +619,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) if (compare_blocks(&prev_pixels[pblock_offset], &src_pixels[block_offset], &bi, s->skip_frame_thresh) != 0) { - // write out skipable blocks + // write out skippable blocks if (n_blocks) { // write skip opcode @@ -788,7 +788,7 @@ post_skip : } } -static int rpza_encode_init(AVCodecContext *avctx) +static av_cold int rpza_encode_init(AVCodecContext *avctx) { RpzaContext *s = avctx->priv_data; @@ -847,7 +847,7 @@ static int rpza_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } -static int rpza_encode_end(AVCodecContext *avctx) +static av_cold int rpza_encode_end(AVCodecContext *avctx) { RpzaContext *s = (RpzaContext *)avctx->priv_data; @@ -884,6 +884,5 @@ const FFCodec ff_rpza_encoder = { .init = rpza_encode_init, FF_CODEC_ENCODE_CB(rpza_encode_frame), .close = rpza_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB555, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_RGB555), }; diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c index e601ff39ed..3715e1c6d4 100644 --- a/libavcodec/rscc.c +++ b/libavcodec/rscc.c @@ -347,14 +347,7 @@ static int rscc_decode_frame(AVCodecContext *avctx, AVFrame *frame, /* Palette handling */ if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = -#endif ff_copy_palette(ctx->palette, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], ctx->palette, AVPALETTE_SIZE); } // We only return a picture when enough of it is undamaged, this avoids copying nearly broken frames around diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c index 753c6c6cb3..b4545f7624 100644 --- a/libavcodec/rv10.c +++ b/libavcodec/rv10.c @@ -52,7 +52,7 @@ #define DC_VLC_BITS 9 typedef struct RVDecContext { - MpegEncContext m; + H263DecContext h; int sub_id; int orig_width, orig_height; } RVDecContext; @@ -78,18 +78,18 @@ static const uint16_t rv_chrom_len_count[15] = { 1, 2, 4, 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 0, 256, }; -static VLC rv_dc_lum, rv_dc_chrom; +static VLCElem rv_dc_lum[1472], rv_dc_chrom[992]; -int ff_rv_decode_dc(MpegEncContext *s, int n) +int ff_rv_decode_dc(H263DecContext *const h, int n) { int code; if (n < 4) { - code = get_vlc2(&s->gb, rv_dc_lum.table, DC_VLC_BITS, 2); + code = get_vlc2(&h->gb, rv_dc_lum, DC_VLC_BITS, 2); } else { - code = get_vlc2(&s->gb, rv_dc_chrom.table, DC_VLC_BITS, 2); + code = get_vlc2(&h->gb, rv_dc_chrom, DC_VLC_BITS, 2); if (code < 0) { - av_log(s->avctx, AV_LOG_ERROR, "chroma dc error\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "chroma dc error\n"); return -1; } } @@ -97,60 +97,59 @@ int ff_rv_decode_dc(MpegEncContext *s, int n) } /* read RV 1.0 compatible frame header */ -static int rv10_decode_picture_header(MpegEncContext *s) +static int rv10_decode_picture_header(H263DecContext *const h) { int mb_count, pb_frame, marker, mb_xy; - marker = get_bits1(&s->gb); + marker = get_bits1(&h->gb); - if (get_bits1(&s->gb)) - s->pict_type = AV_PICTURE_TYPE_P; + if (get_bits1(&h->gb)) + h->c.pict_type = AV_PICTURE_TYPE_P; else - s->pict_type = AV_PICTURE_TYPE_I; + h->c.pict_type = AV_PICTURE_TYPE_I; if (!marker) - av_log(s->avctx, AV_LOG_ERROR, "marker missing\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "marker missing\n"); - pb_frame = get_bits1(&s->gb); + pb_frame = get_bits1(&h->gb); - ff_dlog(s->avctx, "pict_type=%d pb_frame=%d\n", s->pict_type, pb_frame); + ff_dlog(h->c.avctx, "pict_type=%d pb_frame=%d\n", h->c.pict_type, pb_frame); if (pb_frame) { - avpriv_request_sample(s->avctx, "PB-frame"); + avpriv_request_sample(h->c.avctx, "PB-frame"); return AVERROR_PATCHWELCOME; } - s->qscale = get_bits(&s->gb, 5); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); + h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); return AVERROR_INVALIDDATA; } - if (s->pict_type == AV_PICTURE_TYPE_I) { - if (s->rv10_version == 3) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + if (h->rv10_version == 3) { /* specific MPEG like DC coding not used */ - s->last_dc[0] = get_bits(&s->gb, 8); - s->last_dc[1] = get_bits(&s->gb, 8); - s->last_dc[2] = get_bits(&s->gb, 8); - ff_dlog(s->avctx, "DC:%d %d %d\n", s->last_dc[0], - s->last_dc[1], s->last_dc[2]); + h->c.last_dc[0] = get_bits(&h->gb, 8); + h->c.last_dc[1] = get_bits(&h->gb, 8); + h->c.last_dc[2] = get_bits(&h->gb, 8); + ff_dlog(h->c.avctx, "DC:%d %d %d\n", h->c.last_dc[0], + h->c.last_dc[1], h->c.last_dc[2]); } } /* if multiple packets per frame are sent, the position at which * to display the macroblocks is coded here */ - mb_xy = s->mb_x + s->mb_y * s->mb_width; - if (show_bits(&s->gb, 12) == 0 || (mb_xy && mb_xy < s->mb_num)) { - s->mb_x = get_bits(&s->gb, 6); /* mb_x */ - s->mb_y = get_bits(&s->gb, 6); /* mb_y */ - mb_count = get_bits(&s->gb, 12); + mb_xy = h->c.mb_x + h->c.mb_y * h->c.mb_width; + if (show_bits(&h->gb, 12) == 0 || (mb_xy && mb_xy < h->c.mb_num)) { + h->c.mb_x = get_bits(&h->gb, 6); /* mb_x */ + h->c.mb_y = get_bits(&h->gb, 6); /* mb_y */ + mb_count = get_bits(&h->gb, 12); } else { - s->mb_x = 0; - s->mb_y = 0; - mb_count = s->mb_width * s->mb_height; + h->c.mb_x = 0; + h->c.mb_y = 0; + mb_count = h->c.mb_width * h->c.mb_height; } - skip_bits(&s->gb, 3); /* ignored */ - s->f_code = 1; + skip_bits(&h->gb, 3); /* ignored */ return mb_count; } @@ -160,149 +159,155 @@ static int rv20_decode_picture_header(RVDecContext *rv, int whole_size) static const enum AVPictureType pict_types[] = { AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_I /* hmm ... */, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B }; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int seq, mb_pos, ret; int rpr_max; - s->pict_type = pict_types[get_bits(&s->gb, 2)]; + h->c.pict_type = pict_types[get_bits(&h->gb, 2)]; - if (s->low_delay && s->pict_type == AV_PICTURE_TYPE_B) { - av_log(s->avctx, AV_LOG_ERROR, "low delay B\n"); + if (h->c.low_delay && h->c.pict_type == AV_PICTURE_TYPE_B) { + av_log(h->c.avctx, AV_LOG_ERROR, "low delay B\n"); return -1; } - if (!s->last_pic.ptr && s->pict_type == AV_PICTURE_TYPE_B) { - av_log(s->avctx, AV_LOG_ERROR, "early B-frame\n"); + if (!h->c.last_pic.ptr && h->c.pict_type == AV_PICTURE_TYPE_B) { + av_log(h->c.avctx, AV_LOG_ERROR, "early B-frame\n"); return AVERROR_INVALIDDATA; } - if (get_bits1(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "reserved bit set\n"); + if (get_bits1(&h->gb)) { + av_log(h->c.avctx, AV_LOG_ERROR, "reserved bit set\n"); return AVERROR_INVALIDDATA; } - s->qscale = get_bits(&s->gb, 5); - if (s->qscale == 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); + h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale == 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "Invalid qscale value: 0\n"); return AVERROR_INVALIDDATA; } if (RV_GET_MINOR_VER(rv->sub_id) >= 2) - s->loop_filter = get_bits1(&s->gb) && !s->avctx->lowres; + h->loop_filter = get_bits1(&h->gb) && !h->c.avctx->lowres; if (RV_GET_MINOR_VER(rv->sub_id) <= 1) - seq = get_bits(&s->gb, 8) << 7; + seq = get_bits(&h->gb, 8) << 7; else - seq = get_bits(&s->gb, 13) << 2; + seq = get_bits(&h->gb, 13) << 2; - rpr_max = s->avctx->extradata[1] & 7; + rpr_max = h->c.avctx->extradata[1] & 7; if (rpr_max) { int f, new_w, new_h; int rpr_bits = av_log2(rpr_max) + 1; - f = get_bits(&s->gb, rpr_bits); + f = get_bits(&h->gb, rpr_bits); if (f) { - if (s->avctx->extradata_size < 8 + 2 * f) { - av_log(s->avctx, AV_LOG_ERROR, "Extradata too small.\n"); + if (h->c.avctx->extradata_size < 8 + 2 * f) { + av_log(h->c.avctx, AV_LOG_ERROR, "Extradata too small.\n"); return AVERROR_INVALIDDATA; } - new_w = 4 * ((uint8_t *) s->avctx->extradata)[6 + 2 * f]; - new_h = 4 * ((uint8_t *) s->avctx->extradata)[7 + 2 * f]; + new_w = 4 * h->c.avctx->extradata[6 + 2 * f]; + new_h = 4 * h->c.avctx->extradata[7 + 2 * f]; } else { new_w = rv->orig_width; new_h = rv->orig_height; } - if (new_w != s->width || new_h != s->height || !s->context_initialized) { - AVRational old_aspect = s->avctx->sample_aspect_ratio; - av_log(s->avctx, AV_LOG_DEBUG, + if (new_w != h->c.width || new_h != h->c.height || !h->c.context_initialized) { + AVRational old_aspect = h->c.avctx->sample_aspect_ratio; + av_log(h->c.avctx, AV_LOG_DEBUG, "attempting to change resolution to %dx%d\n", new_w, new_h); - if (av_image_check_size(new_w, new_h, 0, s->avctx) < 0) + if (av_image_check_size(new_w, new_h, 0, h->c.avctx) < 0) return AVERROR_INVALIDDATA; if (whole_size < (new_w + 15)/16 * ((new_h + 15)/16) / 8) return AVERROR_INVALIDDATA; - ff_mpv_common_end(s); + ff_mpv_common_end(&h->c); // attempt to keep aspect during typical resolution switches if (!old_aspect.num) old_aspect = (AVRational){1, 1}; - if (2 * (int64_t)new_w * s->height == (int64_t)new_h * s->width) - s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1}); - if ((int64_t)new_w * s->height == 2 * (int64_t)new_h * s->width) - s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2}); + if (2 * (int64_t)new_w * h->c.height == (int64_t)new_h * h->c.width) + h->c.avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1}); + if ((int64_t)new_w * h->c.height == 2 * (int64_t)new_h * h->c.width) + h->c.avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2}); - ret = ff_set_dimensions(s->avctx, new_w, new_h); + ret = ff_set_dimensions(h->c.avctx, new_w, new_h); if (ret < 0) return ret; - s->width = new_w; - s->height = new_h; - if ((ret = ff_mpv_common_init(s)) < 0) + h->c.width = new_w; + h->c.height = new_h; + if ((ret = ff_mpv_common_init(&h->c)) < 0) return ret; } - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, "F %d/%d/%d\n", f, rpr_bits, rpr_max); + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "F %d/%d/%d\n", f, rpr_bits, rpr_max); } } - if (av_image_check_size(s->width, s->height, 0, s->avctx) < 0) + if (av_image_check_size(h->c.width, h->c.height, 0, h->c.avctx) < 0) return AVERROR_INVALIDDATA; - mb_pos = ff_h263_decode_mba(s); + mb_pos = ff_h263_decode_mba(h); - seq |= s->time & ~0x7FFF; - if (seq - s->time > 0x4000) + seq |= h->c.time & ~0x7FFF; + if (seq - h->c.time > 0x4000) seq -= 0x8000; - if (seq - s->time < -0x4000) + if (seq - h->c.time < -0x4000) seq += 0x8000; - if (seq != s->time) { - if (s->pict_type != AV_PICTURE_TYPE_B) { - s->time = seq; - s->pp_time = s->time - s->last_non_b_time; - s->last_non_b_time = s->time; + if (seq != h->c.time) { + if (h->c.pict_type != AV_PICTURE_TYPE_B) { + h->c.time = seq; + h->c.pp_time = h->c.time - h->c.last_non_b_time; + h->c.last_non_b_time = h->c.time; } else { - s->time = seq; - s->pb_time = s->pp_time - (s->last_non_b_time - s->time); + h->c.time = seq; + h->c.pb_time = h->c.pp_time - (h->c.last_non_b_time - h->c.time); } } - if (s->pict_type == AV_PICTURE_TYPE_B) { - if (s->pp_time <=s->pb_time || s->pp_time <= s->pp_time - s->pb_time || s->pp_time<=0) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.pict_type == AV_PICTURE_TYPE_B) { + if (h->c.pp_time <=h->c.pb_time || h->c.pp_time <= h->c.pp_time - h->c.pb_time || h->c.pp_time<=0) { + av_log(h->c.avctx, AV_LOG_DEBUG, "messed up order, possible from seeking? skipping current B-frame\n"); #define ERROR_SKIP_FRAME -123 return ERROR_SKIP_FRAME; } - ff_mpeg4_init_direct_mv(s); + ff_mpeg4_init_direct_mv(&h->c); } - s->no_rounding = get_bits1(&s->gb); + h->c.no_rounding = get_bits1(&h->gb); - if (RV_GET_MINOR_VER(rv->sub_id) <= 1 && s->pict_type == AV_PICTURE_TYPE_B) + if (RV_GET_MINOR_VER(rv->sub_id) <= 1 && h->c.pict_type == AV_PICTURE_TYPE_B) // binary decoder reads 3+2 bits here but they don't seem to be used - skip_bits(&s->gb, 5); + skip_bits(&h->gb, 5); - s->f_code = 1; - s->h263_aic = s->pict_type == AV_PICTURE_TYPE_I; - s->modified_quant = 1; - if (!s->avctx->lowres) - s->loop_filter = 1; + h->c.h263_aic = h->c.pict_type == AV_PICTURE_TYPE_I; + if (h->c.h263_aic) { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_aic_dc_scale_table; + } else { + h->c.y_dc_scale_table = + h->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; + } + if (!h->c.avctx->lowres) + h->loop_filter = 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_INFO, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_INFO, "num:%5d x:%2d y:%2d type:%d qscale:%2d rnd:%d\n", - seq, s->mb_x, s->mb_y, s->pict_type, s->qscale, - s->no_rounding); + seq, h->c.mb_x, h->c.mb_y, h->c.pict_type, h->c.qscale, + h->c.no_rounding); } - av_assert0(s->pict_type != AV_PICTURE_TYPE_B || !s->low_delay); + av_assert0(h->c.pict_type != AV_PICTURE_TYPE_B || !h->c.low_delay); - return s->mb_width * s->mb_height - mb_pos; + return h->c.mb_width * h->c.mb_height - mb_pos; } -static av_cold void rv10_build_vlc(VLC *vlc, const uint16_t len_count[15], +static av_cold void rv10_build_vlc(VLCElem vlc[], int table_size, + const uint16_t len_count[15], const uint8_t sym_rl[][2], int sym_rl_elems) { uint16_t syms[MAX_VLC_ENTRIES]; @@ -319,32 +324,26 @@ static av_cold void rv10_build_vlc(VLC *vlc, const uint16_t len_count[15], for (unsigned tmp = nb_lens + len_count[i]; nb_lens < tmp; nb_lens++) lens[nb_lens] = i + 2; av_assert1(nb_lens == nb_syms); - ff_vlc_init_from_lengths(vlc, DC_VLC_BITS, nb_lens, lens, 1, - syms, 2, 2, 0, VLC_INIT_STATIC_OVERLONG, NULL); + ff_vlc_init_table_from_lengths(vlc, table_size, DC_VLC_BITS, nb_lens, + lens, 1, syms, 2, 2, 0, 0); } static av_cold void rv10_init_static(void) { - static VLCElem table[1472 + 992]; - - rv_dc_lum.table = table; - rv_dc_lum.table_allocated = 1472; - rv10_build_vlc(&rv_dc_lum, rv_lum_len_count, + rv10_build_vlc(rv_dc_lum, FF_ARRAY_ELEMS(rv_dc_lum), rv_lum_len_count, rv_sym_run_len, FF_ARRAY_ELEMS(rv_sym_run_len)); for (int i = 0; i < 1 << (DC_VLC_BITS - 7 /* Length of skip prefix */); i++) { /* All codes beginning with 0x7F have the same length and value. * Modifying the table directly saves us the useless subtables. */ - rv_dc_lum.table[(0x7F << (DC_VLC_BITS - 7)) + i].sym = 255; - rv_dc_lum.table[(0x7F << (DC_VLC_BITS - 7)) + i].len = 18; + rv_dc_lum[(0x7F << (DC_VLC_BITS - 7)) + i].sym = 255; + rv_dc_lum[(0x7F << (DC_VLC_BITS - 7)) + i].len = 18; } - rv_dc_chrom.table = &table[1472]; - rv_dc_chrom.table_allocated = 992; - rv10_build_vlc(&rv_dc_chrom, rv_chrom_len_count, + rv10_build_vlc(rv_dc_chrom, FF_ARRAY_ELEMS(rv_dc_chrom), rv_chrom_len_count, rv_sym_run_len, FF_ARRAY_ELEMS(rv_sym_run_len) - 2); for (int i = 0; i < 1 << (DC_VLC_BITS - 9 /* Length of skip prefix */); i++) { /* Same as above. */ - rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].sym = 255; - rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].len = 18; + rv_dc_chrom[(0x1FE << (DC_VLC_BITS - 9)) + i].sym = 255; + rv_dc_chrom[(0x1FE << (DC_VLC_BITS - 9)) + i].len = 18; } } @@ -352,7 +351,7 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; RVDecContext *rv = avctx->priv_data; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int major_ver, minor_ver, micro_ver, ret; if (avctx->extradata_size < 8) { @@ -370,8 +369,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) rv->orig_width = avctx->coded_width; rv->orig_height = avctx->coded_height; - s->h263_long_vectors = ((uint8_t *) avctx->extradata)[3] & 1; - rv->sub_id = AV_RB32((uint8_t *) avctx->extradata + 4); + h->h263_long_vectors = avctx->extradata[3] & 1; + rv->sub_id = AV_RB32A(avctx->extradata + 4); + if (avctx->codec_id == AV_CODEC_ID_RV20) { + h->modified_quant = 1; + h->c.chroma_qscale_table = ff_h263_chroma_qscale_table; + } major_ver = RV_GET_MAJOR_VER(rv->sub_id); minor_ver = RV_GET_MINOR_VER(rv->sub_id); @@ -379,12 +382,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) switch (major_ver) { case 1: - s->rv10_version = micro_ver ? 3 : 1; - s->obmc = micro_ver == 2; + h->rv10_version = micro_ver ? 3 : 1; + h->c.obmc = micro_ver == 2; break; case 2: if (minor_ver >= 2) { - s->low_delay = 0; + h->c.low_delay = 0; avctx->has_b_frames = 1; } break; @@ -396,7 +399,7 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) if (avctx->debug & FF_DEBUG_PICT_INFO) { av_log(avctx, AV_LOG_DEBUG, "ver:%X ver0:%"PRIX32"\n", rv->sub_id, - ((uint32_t *) avctx->extradata)[0]); + AV_RL32A(avctx->extradata)); } /* init static VLCs */ @@ -409,136 +412,126 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, int buf_size, int buf_size2, int whole_size) { RVDecContext *rv = avctx->priv_data; - MpegEncContext *s = &rv->m; + H263DecContext *const h = &rv->h; int mb_count, mb_pos, left, start_mb_x, active_bits_size, ret; active_bits_size = buf_size * 8; - init_get_bits(&s->gb, buf, FFMAX(buf_size, buf_size2) * 8); - if (s->codec_id == AV_CODEC_ID_RV10) - mb_count = rv10_decode_picture_header(s); + init_get_bits(&h->gb, buf, FFMAX(buf_size, buf_size2) * 8); + if (h->c.codec_id == AV_CODEC_ID_RV10) + mb_count = rv10_decode_picture_header(h); else mb_count = rv20_decode_picture_header(rv, whole_size); if (mb_count < 0) { if (mb_count != ERROR_SKIP_FRAME) - av_log(s->avctx, AV_LOG_ERROR, "HEADER ERROR\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "HEADER ERROR\n"); return AVERROR_INVALIDDATA; } - if (s->mb_x >= s->mb_width || - s->mb_y >= s->mb_height) { - av_log(s->avctx, AV_LOG_ERROR, "POS ERROR %d %d\n", s->mb_x, s->mb_y); + if (h->c.mb_x >= h->c.mb_width || + h->c.mb_y >= h->c.mb_height) { + av_log(h->c.avctx, AV_LOG_ERROR, "POS ERROR %d %d\n", h->c.mb_x, h->c.mb_y); return AVERROR_INVALIDDATA; } - mb_pos = s->mb_y * s->mb_width + s->mb_x; - left = s->mb_width * s->mb_height - mb_pos; + mb_pos = h->c.mb_y * h->c.mb_width + h->c.mb_x; + left = h->c.mb_width * h->c.mb_height - mb_pos; if (mb_count > left) { - av_log(s->avctx, AV_LOG_ERROR, "COUNT ERROR\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "COUNT ERROR\n"); return AVERROR_INVALIDDATA; } - if (whole_size < s->mb_width * s->mb_height / 8) + if (whole_size < h->c.mb_width * h->c.mb_height / 8) return AVERROR_INVALIDDATA; - if ((s->mb_x == 0 && s->mb_y == 0) || !s->cur_pic.ptr) { + if ((h->c.mb_x == 0 && h->c.mb_y == 0) || !h->c.cur_pic.ptr) { // FIXME write parser so we always have complete frames? - if (s->cur_pic.ptr) { - ff_er_frame_end(&s->er, NULL); - ff_mpv_frame_end(s); - s->mb_x = s->mb_y = s->resync_mb_x = s->resync_mb_y = 0; + if (h->c.cur_pic.ptr) { + ff_er_frame_end(&h->c.er, NULL); + ff_mpv_frame_end(&h->c); + h->c.mb_x = h->c.mb_y = h->c.resync_mb_x = h->c.resync_mb_y = 0; } - if ((ret = ff_mpv_frame_start(s, avctx)) < 0) + if ((ret = ff_mpv_frame_start(&h->c, avctx)) < 0) return ret; - ff_mpeg_er_frame_start(s); + ff_mpv_er_frame_start_ext(&h->c, 0, h->c.pp_time, h->c.pb_time); } else { - if (s->cur_pic.ptr->f->pict_type != s->pict_type) { - av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n"); + if (h->c.cur_pic.ptr->f->pict_type != h->c.pict_type) { + av_log(h->c.avctx, AV_LOG_ERROR, "Slice type mismatch\n"); return AVERROR_INVALIDDATA; } } - ff_dlog(avctx, "qscale=%d\n", s->qscale); + ff_dlog(avctx, "qscale=%d\n", h->c.qscale); /* default quantization values */ - if (s->codec_id == AV_CODEC_ID_RV10) { - if (s->mb_y == 0) - s->first_slice_line = 1; + if (h->c.codec_id == AV_CODEC_ID_RV10) { + if (h->c.mb_y == 0) + h->c.first_slice_line = 1; } else { - s->first_slice_line = 1; - s->resync_mb_x = s->mb_x; - } - start_mb_x = s->mb_x; - s->resync_mb_y = s->mb_y; - if (s->h263_aic) { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_aic_dc_scale_table; - } else { - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; + h->c.first_slice_line = 1; + h->c.resync_mb_x = h->c.mb_x; } + start_mb_x = h->c.mb_x; + h->c.resync_mb_y = h->c.mb_y; - if (s->modified_quant) - s->chroma_qscale_table = ff_h263_chroma_qscale_table; + ff_set_qscale(&h->c, h->c.qscale); - ff_set_qscale(s, s->qscale); - - s->rv10_first_dc_coded[0] = 0; - s->rv10_first_dc_coded[1] = 0; - s->rv10_first_dc_coded[2] = 0; - ff_init_block_index(s); + h->rv10_first_dc_coded[0] = 0; + h->rv10_first_dc_coded[1] = 0; + h->rv10_first_dc_coded[2] = 0; + ff_init_block_index(&h->c); /* decode each macroblock */ - for (s->mb_num_left = mb_count; s->mb_num_left > 0; s->mb_num_left--) { + for (h->mb_num_left = mb_count; h->mb_num_left > 0; h->mb_num_left--) { int ret; - ff_update_block_index(s, 8, s->avctx->lowres, 1); - ff_tlog(avctx, "**mb x=%d y=%d\n", s->mb_x, s->mb_y); + ff_update_block_index(&h->c, 8, h->c.avctx->lowres, 1); + ff_tlog(avctx, "**mb x=%d y=%d\n", h->c.mb_x, h->c.mb_y); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - ret = ff_h263_decode_mb(s, s->block); + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + ret = ff_h263_decode_mb(h); // Repeat the slice end check from ff_h263_decode_mb with our active // bitstream size - if (ret != SLICE_ERROR && active_bits_size >= get_bits_count(&s->gb)) { - int v = show_bits(&s->gb, 16); + if (ret != SLICE_ERROR && active_bits_size >= get_bits_count(&h->gb)) { + int v = show_bits(&h->gb, 16); - if (get_bits_count(&s->gb) + 16 > active_bits_size) - v >>= get_bits_count(&s->gb) + 16 - active_bits_size; + if (get_bits_count(&h->gb) + 16 > active_bits_size) + v >>= get_bits_count(&h->gb) + 16 - active_bits_size; if (!v) ret = SLICE_END; } - if (ret != SLICE_ERROR && active_bits_size < get_bits_count(&s->gb) && - 8 * buf_size2 >= get_bits_count(&s->gb)) { + if (ret != SLICE_ERROR && active_bits_size < get_bits_count(&h->gb) && + 8 * buf_size2 >= get_bits_count(&h->gb)) { active_bits_size = buf_size2 * 8; av_log(avctx, AV_LOG_DEBUG, "update size from %d to %d\n", 8 * buf_size, active_bits_size); ret = SLICE_OK; } - if (ret == SLICE_ERROR || active_bits_size < get_bits_count(&s->gb)) { - av_log(s->avctx, AV_LOG_ERROR, "ERROR at MB %d %d\n", s->mb_x, - s->mb_y); + if (ret == SLICE_ERROR || active_bits_size < get_bits_count(&h->gb)) { + av_log(h->c.avctx, AV_LOG_ERROR, "ERROR at MB %d %d\n", h->c.mb_x, + h->c.mb_y); return AVERROR_INVALIDDATA; } - if (s->pict_type != AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); - ff_mpv_reconstruct_mb(s, s->block); - if (s->loop_filter) - ff_h263_loop_filter(s); + if (h->c.pict_type != AV_PICTURE_TYPE_B) + ff_h263_update_motion_val(&h->c); + ff_mpv_reconstruct_mb(&h->c, h->block); + if (h->loop_filter) + ff_h263_loop_filter(&h->c); - if (++s->mb_x == s->mb_width) { - s->mb_x = 0; - s->mb_y++; - ff_init_block_index(s); + if (++h->c.mb_x == h->c.mb_width) { + h->c.mb_x = 0; + h->c.mb_y++; + ff_init_block_index(&h->c); } - if (s->mb_x == s->resync_mb_x) - s->first_slice_line = 0; + if (h->c.mb_x == h->c.resync_mb_x) + h->c.first_slice_line = 0; if (ret == SLICE_END) break; } - ff_er_add_slice(&s->er, start_mb_x, s->resync_mb_y, s->mb_x - 1, s->mb_y, + ff_er_add_slice(&h->c.er, start_mb_x, h->c.resync_mb_y, h->c.mb_x - 1, h->c.mb_y, ER_MB_END); return active_bits_size; diff --git a/libavcodec/rv10dec.h b/libavcodec/rv10dec.h index daa6b8d653..e878e164b3 100644 --- a/libavcodec/rv10dec.h +++ b/libavcodec/rv10dec.h @@ -21,8 +21,8 @@ #ifndef AVCODEC_RV10DEC_H #define AVCODEC_RV10DEC_H -#include "mpegvideo.h" +struct H263DecContext; -int ff_rv_decode_dc(MpegEncContext *s, int n); +int ff_rv_decode_dc(struct H263DecContext *const h, int n); #endif /* AVCODEC_RV10DEC_H */ diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c index 2104ee0a24..534b93fd81 100644 --- a/libavcodec/rv10enc.c +++ b/libavcodec/rv10enc.c @@ -31,34 +31,35 @@ #include "put_bits.h" #include "rv10enc.h" -int ff_rv10_encode_picture_header(MpegEncContext *s) +int ff_rv10_encode_picture_header(MPVMainEncContext *const m) { + MPVEncContext *const s = &m->s; int full_frame= 0; - align_put_bits(&s->pb); + put_bits_assume_flushed(&s->pb); put_bits(&s->pb, 1, 1); /* marker */ - put_bits(&s->pb, 1, (s->pict_type == AV_PICTURE_TYPE_P)); + put_bits(&s->pb, 1, (s->c.pict_type == AV_PICTURE_TYPE_P)); put_bits(&s->pb, 1, 0); /* not PB-mframe */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (s->c.pict_type == AV_PICTURE_TYPE_I) { /* specific MPEG like DC coding not used */ } /* if multiple packets per frame are sent, the position at which to display the macroblocks is coded here */ if(!full_frame){ - if (s->mb_width * s->mb_height >= (1U << 12)) { - avpriv_report_missing_feature(s->avctx, "Encoding frames with %d (>= 4096) macroblocks", - s->mb_width * s->mb_height); + if (s->c.mb_width * s->c.mb_height >= (1U << 12)) { + avpriv_report_missing_feature(s->c.avctx, "Encoding frames with %d (>= 4096) macroblocks", + s->c.mb_width * s->c.mb_height); return AVERROR(ENOSYS); } put_bits(&s->pb, 6, 0); /* mb_x */ put_bits(&s->pb, 6, 0); /* mb_y */ - put_bits(&s->pb, 12, s->mb_width * s->mb_height); + put_bits(&s->pb, 12, s->c.mb_width * s->c.mb_height); } put_bits(&s->pb, 3, 0); /* ignored */ @@ -71,12 +72,12 @@ const FFCodec ff_rv10_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_RV10, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegEncContext), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv10enc.h b/libavcodec/rv10enc.h index fc3665e839..5aa7250e87 100644 --- a/libavcodec/rv10enc.h +++ b/libavcodec/rv10enc.h @@ -21,9 +21,9 @@ #ifndef AVCODEC_RV10ENC_H #define AVCODEC_RV10ENC_H -#include "mpegvideo.h" +typedef struct MPVMainEncContext MPVMainEncContext; -int ff_rv10_encode_picture_header(MpegEncContext *s); -void ff_rv20_encode_picture_header(MpegEncContext *s); +int ff_rv10_encode_picture_header(MPVMainEncContext *m); +int ff_rv20_encode_picture_header(MPVMainEncContext *m); #endif /* AVCODEC_RV10ENC_H */ diff --git a/libavcodec/rv20enc.c b/libavcodec/rv20enc.c index d0e24f2f26..8bf93e7c09 100644 --- a/libavcodec/rv20enc.c +++ b/libavcodec/rv20enc.c @@ -34,32 +34,38 @@ #include "put_bits.h" #include "rv10enc.h" -void ff_rv20_encode_picture_header(MpegEncContext *s) { - put_bits(&s->pb, 2, s->pict_type); //I 0 vs. 1 ? +int ff_rv20_encode_picture_header(MPVMainEncContext *const m) +{ + MPVEncContext *const s = &m->s; + + put_bits_assume_flushed(&s->pb); + + put_bits(&s->pb, 2, s->c.pict_type); //I 0 vs. 1 ? put_bits(&s->pb, 1, 0); /* unknown bit */ - put_bits(&s->pb, 5, s->qscale); + put_bits(&s->pb, 5, s->c.qscale); put_sbits(&s->pb, 8, s->picture_number); //FIXME wrong, but correct is not known - s->mb_x= s->mb_y= 0; + s->c.mb_x = s->c.mb_y = 0; ff_h263_encode_mba(s); - put_bits(&s->pb, 1, s->no_rounding); + put_bits(&s->pb, 1, s->c.no_rounding); - av_assert0(s->f_code == 1); - av_assert0(s->unrestricted_mv == 0); - av_assert0(s->alt_inter_vlc == 0); - av_assert0(s->umvplus == 0); - av_assert0(s->modified_quant==1); - av_assert0(s->loop_filter==1); + av_assert1(s->f_code == 1); + av_assert1(!s->me.unrestricted_mv); + av_assert1(!s->alt_inter_vlc); + av_assert1(!s->umvplus); + av_assert1(s->modified_quant == 1); + av_assert1(s->loop_filter == 1); - s->h263_aic= s->pict_type == AV_PICTURE_TYPE_I; - if(s->h263_aic){ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_aic_dc_scale_table; + s->c.h263_aic = s->c.pict_type == AV_PICTURE_TYPE_I; + if (s->c.h263_aic) { + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_aic_dc_scale_table; }else{ - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg1_dc_scale_table; } + return 0; } const FFCodec ff_rv20_encoder = { @@ -68,12 +74,12 @@ const FFCodec ff_rv20_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_RV20, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .priv_data_size = sizeof(MpegEncContext), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .priv_data_size = sizeof(MPVMainEncContext), .init = ff_mpv_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv30.c b/libavcodec/rv30.c index 5e1dd01aa1..e0b5395fa6 100644 --- a/libavcodec/rv30.c +++ b/libavcodec/rv30.c @@ -38,7 +38,6 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceInfo *si) { AVCodecContext *avctx = r->s.avctx; - int mb_bits; int w = r->s.width, h = r->s.height; int mb_size; int rpr; @@ -76,8 +75,7 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn si->width = w; si->height = h; mb_size = ((w + 15) >> 4) * ((h + 15) >> 4); - mb_bits = ff_rv34_get_start_offset(gb, mb_size); - si->start = get_bits(gb, mb_bits); + si->start = ff_rv34_get_start_offset(gb, mb_size); skip_bits1(gb); return 0; } @@ -118,7 +116,7 @@ static int rv30_decode_mb_info(RV34DecContext *r) static const int rv30_p_types[6] = { RV34_MB_SKIP, RV34_MB_P_16x16, RV34_MB_P_8x8, -1, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; static const int rv30_b_types[6] = { RV34_MB_SKIP, RV34_MB_B_DIRECT, RV34_MB_B_FORWARD, RV34_MB_B_BACKWARD, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; unsigned code = get_interleaved_ue_golomb(gb); if (code > 11) { diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index d94285431e..f78b91e7df 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -342,7 +342,7 @@ int ff_rv34_get_start_offset(GetBitContext *gb, int mb_size) for(i = 0; i < 5; i++) if(rv34_mb_max_sizes[i] >= mb_size - 1) break; - return rv34_mb_bits_sizes[i]; + return get_bits(gb, rv34_mb_bits_sizes[i]); } /** @@ -363,7 +363,7 @@ static inline RV34VLC* choose_vlc_set(int quant, int mod, int type) static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int t; @@ -398,7 +398,7 @@ static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) static int rv34_decode_inter_mb_header(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int i, t; @@ -871,7 +871,7 @@ static const int num_mvs[RV34_MB_TYPES] = { 0, 0, 1, 4, 1, 1, 0, 0, 2, 2, 2, 1 } static int rv34_decode_mv(RV34DecContext *r, int block_type) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int i, j, k, l; int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride; int next_bt; @@ -1029,9 +1029,8 @@ static inline void rv34_process_block(RV34DecContext *r, uint8_t *pdst, int stride, int fc, int sc, int q_dc, int q_ac) { - MpegEncContext *s = &r->s; - int16_t *ptr = s->block[0]; - int has_ac = rv34_decode_block(ptr, &s->gb, r->cur_vlcs, + int16_t *const ptr = r->block; + int has_ac = rv34_decode_block(ptr, &r->gb, r->cur_vlcs, fc, sc, q_dc, q_ac, q_ac); if(has_ac){ r->rdsp.rv34_idct_add(pdst, stride, ptr); @@ -1045,11 +1044,11 @@ static void rv34_output_i16x16(RV34DecContext *r, int8_t *intra_types, int cbp) { LOCAL_ALIGNED_16(int16_t, block16, [16]); MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int q_dc = rv34_qscale_tab[ r->luma_dc_quant_i[s->qscale] ], q_ac = rv34_qscale_tab[s->qscale]; uint8_t *dst = s->dest[0]; - int16_t *ptr = s->block[0]; + int16_t *const ptr = r->block; int i, j, itype, has_ac; memset(block16, 0, 16 * sizeof(*block16)); @@ -1213,9 +1212,9 @@ static int rv34_set_deblock_coef(RV34DecContext *r) static int rv34_decode_inter_macroblock(RV34DecContext *r, int8_t *intra_types) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; uint8_t *dst = s->dest[0]; - int16_t *ptr = s->block[0]; + int16_t *const ptr = r->block; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp, cbp2; int q_dc, q_ac, has_ac; @@ -1363,12 +1362,12 @@ static int check_slice_end(RV34DecContext *r, MpegEncContext *s) int bits; if(s->mb_y >= s->mb_height) return 1; - if(!s->mb_num_left) + if (!r->mb_num_left) return 1; - if(r->s.mb_skip_run > 1) + if (r->mb_skip_run > 1) return 0; - bits = get_bits_left(&s->gb); - if(bits <= 0 || (bits < 8 && !show_bits(&s->gb, bits))) + bits = get_bits_left(&r->gb); + if (bits <= 0 || (bits < 8 && !show_bits(&r->gb, bits))) return 1; return 0; } @@ -1424,11 +1423,11 @@ static int rv34_decoder_realloc(RV34DecContext *r) static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int buf_size) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int mb_pos, slice_type; int res; - init_get_bits(&r->s.gb, buf, buf_size*8); + init_get_bits(gb, buf, buf_size*8); res = r->parse_slice_header(r, gb, &r->si); if(res < 0){ av_log(s->avctx, AV_LOG_ERROR, "Incorrect or unknown slice header\n"); @@ -1447,8 +1446,8 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int r->si.end = end; s->qscale = r->si.quant; - s->mb_num_left = r->si.end - r->si.start; - r->s.mb_skip_run = 0; + r->mb_num_left = r->si.end - r->si.start; + r->mb_skip_run = 0; mb_pos = s->mb_x + s->mb_y * s->mb_width; if(r->si.start != mb_pos){ @@ -1463,7 +1462,9 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int ff_init_block_index(s); while(!check_slice_end(r, s)) { - ff_update_block_index(s, 8, 0, 1); + s->dest[0] += 16; + s->dest[1] += 8; + s->dest[2] += 8; if(r->si.type) res = rv34_decode_inter_macroblock(r, r->intra_types + s->mb_x * 4 + 4); @@ -1491,7 +1492,7 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int } if(s->mb_x == s->resync_mb_x) s->first_slice_line=0; - s->mb_num_left--; + r->mb_num_left--; } ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, ER_MB_END); @@ -1536,19 +1537,21 @@ av_cold int ff_rv34_decode_init(AVCodecContext *avctx) int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { RV34DecContext *r = dst->priv_data, *r1 = src->priv_data; - MpegEncContext * const s = &r->s, * const s1 = &r1->s; - int err; + MpegEncContext *const s1 = &r1->s; + int ret; if (dst == src || !s1->context_initialized) return 0; - if (s->height != s1->height || s->width != s1->width || s->context_reinit) { - s->height = s1->height; - s->width = s1->width; - if ((err = ff_mpv_common_frame_size_change(s)) < 0) - return err; - if ((err = rv34_decoder_realloc(r)) < 0) - return err; + ret = ff_mpeg_update_thread_context(dst, src); + if (ret < 0) + return ret; + + // Did ff_mpeg_update_thread_context reinit? + if (ret > 0) { + ret = rv34_decoder_realloc(r); + if (ret < 0) + return ret; } r->cur_pts = r1->cur_pts; @@ -1557,12 +1560,7 @@ int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecConte memset(&r->si, 0, sizeof(r->si)); - // Do no call ff_mpeg_update_thread_context on a partially initialized - // decoder context. - if (!s1->context_initialized) - return 0; - - return ff_mpeg_update_thread_context(dst, src); + return 0; } static int get_slice_offset(AVCodecContext *avctx, const uint8_t *buf, int n, int slice_count, int buf_size) @@ -1581,10 +1579,7 @@ static int finish_frame(AVCodecContext *avctx, AVFrame *pict) ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); - s->mb_num_left = 0; - - if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); + r->mb_num_left = 0; if (s->pict_type == AV_PICTURE_TYPE_B) { if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) @@ -1652,8 +1647,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); return AVERROR_INVALIDDATA; } - init_get_bits(&s->gb, buf+offset, (buf_size-offset)*8); - if(r->parse_slice_header(r, &r->s.gb, &si) < 0 || si.start){ + init_get_bits(&r->gb, buf+offset, (buf_size-offset)*8); + if (r->parse_slice_header(r, &r->gb, &si) < 0 || si.start) { av_log(avctx, AV_LOG_ERROR, "First slice header is incorrect\n"); return AVERROR_INVALIDDATA; } @@ -1669,9 +1664,9 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* first slice */ if (si.start == 0) { - if (s->mb_num_left > 0 && s->cur_pic.ptr) { + if (r->mb_num_left > 0 && s->cur_pic.ptr) { av_log(avctx, AV_LOG_ERROR, "New frame but still %d MB left.\n", - s->mb_num_left); + r->mb_num_left); if (!s->context_reinit) ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); @@ -1774,7 +1769,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, size = offset1 - offset; r->si.end = s->mb_width * s->mb_height; - s->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; + r->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; if(i+1 < slice_count){ int offset2 = get_slice_offset(avctx, slices_hdr, i+2, slice_count, buf_size); @@ -1782,8 +1777,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); break; } - init_get_bits(&s->gb, buf+offset1, (buf_size-offset1)*8); - if(r->parse_slice_header(r, &r->s.gb, &si) < 0){ + init_get_bits(&r->gb, buf+offset1, (buf_size-offset1)*8); + if (r->parse_slice_header(r, &r->gb, &si) < 0) { size = offset2 - offset; }else r->si.end = si.start; @@ -1805,13 +1800,12 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, *got_picture_ptr = ret; } else if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) { - av_log(avctx, AV_LOG_INFO, "marking unfished frame as finished\n"); + av_log(avctx, AV_LOG_INFO, "marking unfinished frame as finished\n"); /* always mark the current frame as finished, frame-mt supports * only complete frames */ ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); - s->mb_num_left = 0; - ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); + r->mb_num_left = 0; return AVERROR_INVALIDDATA; } } diff --git a/libavcodec/rv34.h b/libavcodec/rv34.h index 6fe1f8087d..85ab6b4c2c 100644 --- a/libavcodec/rv34.h +++ b/libavcodec/rv34.h @@ -30,6 +30,7 @@ #include "libavutil/mem_internal.h" #include "avcodec.h" +#include "get_bits.h" #include "mpegvideo.h" #include "h264pred.h" @@ -85,6 +86,7 @@ typedef struct SliceInfo{ /** decoder context */ typedef struct RV34DecContext{ MpegEncContext s; + GetBitContext gb; RV34DSPContext rdsp; int8_t *intra_types_hist;///< old block types, used for prediction int8_t *intra_types; ///< block types @@ -96,6 +98,9 @@ typedef struct RV34DecContext{ H264PredContext h; ///< functions for 4x4 and 16x16 intra block prediction SliceInfo si; ///< current slice information + int mb_num_left; ///< number of MBs left in this video packet + int mb_skip_run; + int *mb_type; ///< internal macroblock types int block_type; ///< current block type int luma_vlc; ///< which VLC set will be used for decoding of luma blocks @@ -117,6 +122,7 @@ typedef struct RV34DecContext{ uint8_t *cbp_chroma; ///< CBP values for chroma subblocks uint16_t *deblock_coefs; ///< deblock coefficients for each macroblock + DECLARE_ALIGNED_16(int16_t, block)[16]; /** 8x8 block available flags (for MV prediction) */ DECLARE_ALIGNED(8, uint32_t, avail_cache)[3*4]; diff --git a/libavcodec/rv40.c b/libavcodec/rv40.c index 0a5136d129..2b010295dd 100644 --- a/libavcodec/rv40.c +++ b/libavcodec/rv40.c @@ -131,7 +131,6 @@ static void rv40_parse_picture_size(GetBitContext *gb, int *w, int *h) static int rv40_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceInfo *si) { - int mb_bits; int w = r->s.width, h = r->s.height; int mb_size; int ret; @@ -154,8 +153,7 @@ static int rv40_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn si->width = w; si->height = h; mb_size = ((w + 15) >> 4) * ((h + 15) >> 4); - mb_bits = ff_rv34_get_start_offset(gb, mb_size); - si->start = get_bits(gb, mb_bits); + si->start = ff_rv34_get_start_offset(gb, mb_size); return 0; } @@ -228,18 +226,18 @@ static int rv40_decode_intra_types(RV34DecContext *r, GetBitContext *gb, int8_t static int rv40_decode_mb_info(RV34DecContext *r) { MpegEncContext *s = &r->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &r->gb; int q, i; int prev_type = 0; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; - if(!r->s.mb_skip_run) { - r->s.mb_skip_run = get_interleaved_ue_golomb(gb) + 1; - if(r->s.mb_skip_run > (unsigned)s->mb_num) + if (!r->mb_skip_run) { + r->mb_skip_run = get_interleaved_ue_golomb(gb) + 1; + if (r->mb_skip_run > (unsigned)s->mb_num) return -1; } - if(--r->s.mb_skip_run) + if (--r->mb_skip_run) return RV34_MB_SKIP; if(r->avail_cache[6-4]){ diff --git a/libavcodec/rv60data.h b/libavcodec/rv60data.h new file mode 100644 index 0000000000..d96a7e4e4f --- /dev/null +++ b/libavcodec/rv60data.h @@ -0,0 +1,118 @@ +/* + * RV60 decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RV60DATA_H +#define AVCODEC_RV60DATA_H + +#include + +static const uint8_t rv60_candidate_intra_angles[6] = { + 0, 1, 10, 26, 18, 2 +}; + +static const uint8_t rv60_ipred_angle[9] = { + 0, 2, 5, 9, 13, 17, 21, 26, 32 +}; + +static const uint16_t rv60_ipred_inv_angle[9] = { + 0, 4096, 1638, 910, 630, 482, 390, 315, 256 +}; + +static const uint8_t rv60_avail_mask[64] = { + 0, 1, 0, 3, 0, 1, 0, 7, 0, 1, 0, 3, 0, 1, 0, 0xF, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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 const uint8_t rv60_edge1[4] = { + 0, 2, 2, 2 +}; + +static const uint8_t rv60_edge2[4] = { + 0, 3, 3, 3 +}; + +static const uint8_t rv60_qp_to_idx[64] = { + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, + 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 0 +}; + +static const uint16_t rv60_quants_b[32] = { + 60, 67, 76, 85, 96, 108, 121, 136, + 152, 171, 192, 216, 242, 272, 305, 341, + 383, 432, 481, 544, 606, 683, 767, 854, + 963, 1074, 1212, 1392, 1566, 1708, 1978, 2211 +}; + +static const uint8_t rv60_chroma_quant_dc[32] = { + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23 +}; + +static const uint8_t rv60_chroma_quant_ac[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25 +}; + +static const uint8_t rv60_dsc_to_lx[][4] = { + {0, 0, 0, 1}, {0, 0, 0, 2}, {0, 0, 1, 0}, + {0, 0, 1, 1}, {0, 0, 1, 2}, {0, 0, 2, 0}, {0, 0, 2, 1}, + {0, 0, 2, 2}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 0, 2}, + {0, 1, 1, 0}, {0, 1, 1, 1}, {0, 1, 1, 2}, {0, 1, 2, 0}, + {0, 1, 2, 1}, {0, 1, 2, 2}, {0, 2, 0, 0}, {0, 2, 0, 1}, + {0, 2, 0, 2}, {0, 2, 1, 0}, {0, 2, 1, 1}, {0, 2, 1, 2}, + {0, 2, 2, 0}, {0, 2, 2, 1}, {0, 2, 2, 2}, {1, 0, 0, 0}, + {1, 0, 0, 1}, {1, 0, 0, 2}, {1, 0, 1, 0}, {1, 0, 1, 1}, + {1, 0, 1, 2}, {1, 0, 2, 0}, {1, 0, 2, 1}, {1, 0, 2, 2}, + {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 0, 2}, {1, 1, 1, 0}, + {1, 1, 1, 1}, {1, 1, 1, 2}, {1, 1, 2, 0}, {1, 1, 2, 1}, + {1, 1, 2, 2}, {1, 2, 0, 0}, {1, 2, 0, 1}, {1, 2, 0, 2}, + {1, 2, 1, 0}, {1, 2, 1, 1}, {1, 2, 1, 2}, {1, 2, 2, 0}, + {1, 2, 2, 1}, {1, 2, 2, 2}, {2, 0, 0, 0}, {2, 0, 0, 1}, + {2, 0, 0, 2}, {2, 0, 1, 0}, {2, 0, 1, 1}, {2, 0, 1, 2}, + {2, 0, 2, 0}, {2, 0, 2, 1}, {2, 0, 2, 2}, {2, 1, 0, 0}, + {2, 1, 0, 1}, {2, 1, 0, 2}, {2, 1, 1, 0}, {2, 1, 1, 1}, + {2, 1, 1, 2}, {2, 1, 2, 0}, {2, 1, 2, 1}, {2, 1, 2, 2}, + {2, 2, 0, 0}, {2, 2, 0, 1}, {2, 2, 0, 2}, {2, 2, 1, 0}, + {2, 2, 1, 1}, {2, 2, 1, 2}, {2, 2, 2, 0}, {2, 2, 2, 1}, + {2, 2, 2, 2}, {3, 0, 0, 0}, {3, 0, 0, 1}, {3, 0, 0, 2}, + {3, 0, 1, 0}, {3, 0, 1, 1}, {3, 0, 1, 2}, {3, 0, 2, 0}, + {3, 0, 2, 1}, {3, 0, 2, 2}, {3, 1, 0, 0}, {3, 1, 0, 1}, + {3, 1, 0, 2}, {3, 1, 1, 0}, {3, 1, 1, 1}, {3, 1, 1, 2}, + {3, 1, 2, 0}, {3, 1, 2, 1}, {3, 1, 2, 2}, {3, 2, 0, 0}, + {3, 2, 0, 1}, {3, 2, 0, 2}, {3, 2, 1, 0}, {3, 2, 1, 1}, + {3, 2, 1, 2}, {3, 2, 2, 0}, {3, 2, 2, 1}, {3, 2, 2, 2}, +}; + +static const uint8_t rv60_deblock_limits[32][4] = { + {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, + {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, {0, 0, 128, 0}, + {0, 0, 128, 3}, {0, 1, 128, 3}, {0, 1, 122, 3}, {1, 1, 96, 4}, + {1, 1, 75, 4}, {1, 1, 59, 4}, {1, 1, 47, 6}, {1, 1, 37, 6}, + {1, 1, 29, 6}, {1, 2, 23, 7}, {1, 2, 18, 8}, {1, 2, 15, 8}, + {1, 2, 13, 9}, {2, 3, 11, 9}, {2, 3, 10, 10}, {2, 3, 9, 10}, + {2, 4, 8, 11}, {3, 4, 7, 11}, {3, 5, 6, 12}, {3, 5, 5, 13}, + {3, 5, 4, 14}, {4, 7, 3, 15}, {5, 8, 2, 16}, {5, 9, 1, 17} +}; + +#endif /* AVCODEC_RV60DATA_H */ diff --git a/libavcodec/rv60dec.c b/libavcodec/rv60dec.c new file mode 100644 index 0000000000..208fbc68f7 --- /dev/null +++ b/libavcodec/rv60dec.c @@ -0,0 +1,2439 @@ +/* + * RV60 decoder + * Copyright (c) 2007 Mike Melanson, Konstantin Shishkov + * Copyright (C) 2023 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 + */ + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "golomb.h" +#include "libavutil/mem.h" +#include "rv60data.h" +#include "rv60dsp.h" +#include "rv60vlcs.h" +#include "threadprogress.h" +#include "unary.h" +#include "videodsp.h" + +static const int8_t frame_types[4] = {AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, AV_PICTURE_TYPE_NONE}; + +enum CUType { + CU_INTRA = 0, + CU_INTER_MV, + CU_SKIP, + CU_INTER +}; + +enum PUType { + PU_FULL = 0, + PU_N2HOR, + PU_N2VER, + PU_QUARTERS, + PU_N4HOR, + PU_N34HOR, + PU_N4VER, + PU_N34VER +}; + +enum IntraMode { + INTRAMODE_INDEX = 0, + INTRAMODE_DC64, + INTRAMODE_PLANE64, + INTRAMODE_MODE +}; + +enum MVRefEnum { + MVREF_NONE = 0, + MVREF_REF0, + MVREF_REF1, + MVREF_BREF, + MVREF_REF0ANDBREF, + MVREF_SKIP0, + MVREF_SKIP1, + MVREF_SKIP2, + MVREF_SKIP3 +}; + +static const uint8_t skip_mv_ref[4] = {MVREF_SKIP0, MVREF_SKIP1, MVREF_SKIP2, MVREF_SKIP3}; + +enum { + TRANSFORM_NONE = 0, + TRANSFORM_16X16, + TRANSFORM_8X8, + TRANSFORM_4X4 +}; + +static const VLCElem * cbp8_vlc[7][4]; +static const VLCElem * cbp16_vlc[7][4][4]; + +typedef struct { + const VLCElem * l0[2]; + const VLCElem * l12[2]; + const VLCElem * l3[2]; + const VLCElem * esc; +} CoeffVLCs; + +static CoeffVLCs intra_coeff_vlc[5]; +static CoeffVLCs inter_coeff_vlc[7]; + +#define MAX_VLC_SIZE 864 +static VLCElem table_data[129148]; + +/* 32-bit version of rv34_gen_vlc */ +static const VLCElem * gen_vlc(const uint8_t * bits, int size, VLCInitState * state) +{ + int counts[17] = {0}; + uint32_t codes[18]; + uint32_t cw[MAX_VLC_SIZE]; + + for (int i = 0; i < size; i++) + counts[bits[i]]++; + + codes[0] = counts[0] = 0; + for (int i = 0; i < 17; i++) + codes[i+1] = (codes[i] + counts[i]) << 1; + + for (int i = 0; i < size; i++) + cw[i] = codes[bits[i]]++; + + return ff_vlc_init_tables(state, 9, size, + bits, 1, 1, + cw, 4, 4, 0); +} + +static void build_coeff_vlc(const CoeffLens * lens, CoeffVLCs * vlc, int count, VLCInitState * state) +{ + for (int i = 0; i < count; i++) { + for (int j = 0; j < 2; j++) { + vlc[i].l0[j] = gen_vlc(lens[i].l0[j], 864, state); + vlc[i].l12[j] = gen_vlc(lens[i].l12[j], 108, state); + vlc[i].l3[j] = gen_vlc(lens[i].l3[j], 108, state); + } + vlc[i].esc = gen_vlc(lens[i].esc, 32, state); + } +} + +static av_cold void rv60_init_static_data(void) +{ + VLCInitState state = VLC_INIT_STATE(table_data); + + for (int i = 0; i < 7; i++) + for (int j = 0; j < 4; j++) + cbp16_vlc[i][0][j] = cbp8_vlc[i][j] = gen_vlc(rv60_cbp8_lens[i][j], 64, &state); + + for (int i = 0; i < 7; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 4; k++) + cbp16_vlc[i][j + 1][k] = gen_vlc(rv60_cbp16_lens[i][j][k], 64, &state); + + build_coeff_vlc(rv60_intra_lens, intra_coeff_vlc, 5, &state); + build_coeff_vlc(rv60_inter_lens, inter_coeff_vlc, 7, &state); +} + +typedef struct { + int sign; + int size; + const uint8_t * data; + int data_size; +} Slice; + +typedef struct { + int cu_split_pos; + uint8_t cu_split[1+4+16+64]; + + uint8_t coded_blk[64]; + + uint8_t avg_buffer[64*64 + 32*32*2]; + uint8_t * avg_data[3]; + int avg_linesize[3]; +} ThreadContext; + +typedef struct { + int16_t x; + int16_t y; +} MV; + +typedef struct { + enum MVRefEnum mvref; + MV f_mv; + MV b_mv; +} MVInfo; + +typedef struct { + enum IntraMode imode; + MVInfo mv; +} BlockInfo; + +typedef struct { + enum CUType cu_type; + enum PUType pu_type; +} PUInfo; + +typedef struct RV60Context { + AVCodecContext * avctx; + VideoDSPContext vdsp; + +#define CUR_PIC 0 +#define LAST_PIC 1 +#define NEXT_PIC 2 + AVFrame *last_frame[3]; + + int pict_type; + int qp; + int osvquant; + int ts; + int two_f_refs; + int qp_off_type; + int deblock; + int deblock_chroma; + int awidth; + int aheight; + int cu_width; + int cu_height; + + Slice * slice; + + int pu_stride; + PUInfo * pu_info; + + int blk_stride; + BlockInfo * blk_info; + + int dblk_stride; + uint8_t * left_str; + uint8_t * top_str; + + uint64_t ref_pts[2], ts_scale; + uint32_t ref_ts[2]; + + struct ThreadProgress *progress; + unsigned nb_progress; +} RV60Context; + +static int progress_init(RV60Context *s, unsigned count) +{ + if (s->nb_progress < count) { + void *tmp = av_realloc_array(s->progress, count, sizeof(*s->progress)); + if (!tmp) + return AVERROR(ENOMEM); + s->progress = tmp; + memset(s->progress + s->nb_progress, 0, (count - s->nb_progress) * sizeof(*s->progress)); + for (int i = s->nb_progress; i < count; i++) { + int ret = ff_thread_progress_init(&s->progress[i], 1); + if (ret < 0) + return ret; + s->nb_progress = i + 1; + } + } + + for (int i = 0; i < count; i++) + ff_thread_progress_reset(&s->progress[i]); + + return 0; +} + +static av_cold int rv60_decode_init(AVCodecContext * avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + RV60Context *s = avctx->priv_data; + + s->avctx = avctx; + + ff_videodsp_init(&s->vdsp, 8); + + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + + for (int i = 0; i < 3; i++) { + s->last_frame[i] = av_frame_alloc(); + if (!s->last_frame[i]) + return AVERROR(ENOMEM); + } + + ff_thread_once(&init_static_once, rv60_init_static_data); + + return 0; +} + +static int update_dimensions_clear_info(RV60Context *s, int width, int height) +{ + int ret; + + if (width != s->avctx->width || height != s->avctx->height) { + + av_log(s->avctx, AV_LOG_INFO, "changing dimensions to %dx%d\n", width, height); + + for (int i = 0; i < 3; i++) + av_frame_unref(s->last_frame[i]); + + if ((ret = ff_set_dimensions(s->avctx, width, height)) < 0) + return ret; + + if (s->avctx->width <= 64 || s->avctx->height <= 64) + av_log(s->avctx, AV_LOG_WARNING, "unable to faithfully reproduce emulated edges; expect visual artefacts\n"); + } + + s->awidth = FFALIGN(width, 16); + s->aheight = FFALIGN(height, 16); + + s->cu_width = (width + 63) >> 6; + s->cu_height = (height + 63) >> 6; + + s->pu_stride = s->cu_width << 3; + s->blk_stride = s->cu_width << 4; + + if ((ret = av_reallocp_array(&s->slice, s->cu_height, sizeof(s->slice[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->pu_info, s->pu_stride * (s->cu_height << 3), sizeof(s->pu_info[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->blk_info, s->blk_stride * (s->cu_height << 4), sizeof(s->blk_info[0]))) < 0) + return ret; + + memset(s->pu_info, 0, s->pu_stride * (s->cu_height << 3) * sizeof(s->pu_info[0])); + + for (int j = 0; j < s->cu_height << 4; j++) + for (int i = 0; i < s->cu_width << 4; i++) + s->blk_info[j*s->blk_stride + i].mv.mvref = MVREF_NONE; + + if (s->deblock) { + int size; + + s->dblk_stride = s->awidth >> 2; + + size = s->dblk_stride * (s->aheight >> 2); + + if ((ret = av_reallocp_array(&s->top_str, size, sizeof(s->top_str[0]))) < 0) + return ret; + + if ((ret = av_reallocp_array(&s->left_str, size, sizeof(s->left_str[0]))) < 0) + return ret; + + memset(s->top_str, 0, size); + memset(s->left_str, 0, size); + } + + return 0; +} + +static int read_code012(GetBitContext * gb) +{ + if (!get_bits1(gb)) + return 0; + return get_bits1(gb) + 1; +} + +static int read_frame_header(RV60Context *s, GetBitContext *gb, int * width, int * height) +{ + if (get_bits(gb, 2) != 3) + return AVERROR_INVALIDDATA; + + skip_bits(gb, 2); + skip_bits(gb, 4); + + s->pict_type = frame_types[get_bits(gb, 2)]; + if (s->pict_type == AV_PICTURE_TYPE_NONE) + return AVERROR_INVALIDDATA; + + s->qp = get_bits(gb, 6); + skip_bits1(gb); + skip_bits(gb, 2); + s->osvquant = get_bits(gb, 2); + skip_bits1(gb); + skip_bits(gb, 2); + s->ts = get_bits(gb, 24); + *width = (get_bits(gb, 11) + 1) * 4; + *height = get_bits(gb, 11) * 4; + skip_bits1(gb); + if (s->pict_type == AV_PICTURE_TYPE_I) { + s->two_f_refs = 0; + } else { + if (get_bits1(gb)) + skip_bits(gb, 3); + s->two_f_refs = get_bits1(gb); + } + read_code012(gb); + read_code012(gb); + s->qp_off_type = read_code012(gb); + s->deblock = get_bits1(gb); + s->deblock_chroma = s->deblock && !get_bits1(gb); + + if (get_bits1(gb)) { + int count = get_bits(gb, 2); + if (count) { + skip_bits(gb, 2); + for (int i = 0; i < count; i++) + for (int j = 0; j < 2 << i; j++) + skip_bits(gb, 8); + } + } + + return 0; +} + +static int read_slice_sizes(RV60Context *s, GetBitContext *gb) +{ + int nbits = get_bits(gb, 5) + 1; + int last_size; + + for (int i = 0; i < s->cu_height; i++) + s->slice[i].sign = get_bits1(gb); + + s->slice[0].size = last_size = get_bits_long(gb, nbits); + + if (last_size < 0) + return AVERROR_INVALIDDATA; + + for (int i = 1; i < s->cu_height; i++) { + int diff = get_bits_long(gb, nbits); + if (s->slice[i].sign) + last_size += diff; + else + last_size -= diff; + if (last_size <= 0) + return AVERROR_INVALIDDATA; + s->slice[i].size = last_size; + } + + align_get_bits(gb); + return 0; +} + +static int read_intra_mode(GetBitContext * gb, int * param) +{ + if (get_bits1(gb)) { + *param = read_code012(gb); + return INTRAMODE_INDEX; + } else { + *param = get_bits(gb, 5); + return INTRAMODE_MODE; + } +} + +static int has_top_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + return ypos + dy && xpos + dx + size <= s->awidth; +} + +static int has_left_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + return xpos + dx && ypos + dy + size <= s->aheight; +} + +static int has_top_right_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + if (has_top_block(s, xpos, ypos, dx, dy, size * 2)) { + int cxpos = ((xpos + dx) & 63) >> ff_log2(size); + int cypos = ((ypos + dy) & 63) >> ff_log2(size); + return !(rv60_avail_mask[cxpos] & cypos); + } + return 0; +} + +static int has_left_down_block(const RV60Context * s, int xpos, int ypos, int dx, int dy, int size) +{ + if (has_left_block(s, xpos, ypos, dx, dy, size * 2)) { + int cxpos = (~(xpos + dx) & 63) >> ff_log2(size); + int cypos = (~(ypos + dy) & 63) >> ff_log2(size); + return rv60_avail_mask[cxpos] & cypos; + } + return 0; +} + +typedef struct { + uint8_t t[129]; + uint8_t l[129]; + int has_t; + int has_tr; + int has_l; + int has_ld; +} IntraPredContext; + +typedef struct { + int xpos; + int ypos; + int pu_pos; + int blk_pos; + + enum CUType cu_type; + enum PUType pu_type; + enum IntraMode imode[4]; + int imode_param[4]; + MVInfo mv[4]; + + IntraPredContext ipred; +} CUContext; + +static void ipred_init(IntraPredContext * i) +{ + memset(i->t, 0x80, sizeof(i->t)); + memset(i->l, 0x80, sizeof(i->l)); + i->has_t = i->has_tr = i->has_l = i->has_ld = 0; +} + +static void populate_ipred(const RV60Context * s, CUContext * cu, const uint8_t * src, int stride, int xoff, int yoff, int size, int is_luma) +{ + if (is_luma) + src += (cu->ypos + yoff) * stride + cu->xpos + xoff; + else + src += (cu->ypos >> 1) * stride + (cu->xpos >> 1); + + ipred_init(&cu->ipred); + + if (cu->ypos + yoff > 0) { + cu->ipred.has_t = 1; + + memcpy(cu->ipred.t + 1, src - stride, size); + + if ((is_luma && has_top_right_block(s, cu->xpos, cu->ypos, xoff, yoff, size)) || + (!is_luma && has_top_right_block(s, cu->xpos, cu->ypos, 0, 0, size << 1))) { + cu->ipred.has_tr = 1; + memcpy(cu->ipred.t + size + 1, src - stride + size, size); + } else + memset(cu->ipred.t + size + 1, cu->ipred.t[size], size); + + if (cu->xpos + xoff > 0) + cu->ipred.t[0] = src[-stride - 1]; + } + + if (cu->xpos + xoff > 0) { + cu->ipred.has_l = 1; + + for (int y = 0; y < size; y++) + cu->ipred.l[y + 1] = src[y*stride - 1]; + + if ((is_luma && has_left_down_block(s, cu->xpos, cu->ypos, xoff, yoff, size)) || + (!is_luma && has_left_down_block(s, cu->xpos, cu->ypos, 0, 0, size << 1))) { + cu->ipred.has_ld = 1; + for (int y = size; y < size * 2; y++) + cu->ipred.l[y + 1] = src[y*stride - 1]; + } else + memset(cu->ipred.l + size + 1, cu->ipred.l[size], size); + + if (cu->ypos + yoff > 0) + cu->ipred.l[0] = src[-stride - 1]; + } +} + +static void pred_plane(const IntraPredContext * p, uint8_t * dst, int stride, int size) +{ + int lastl = p->l[size + 1]; + int lastt = p->t[size + 1]; + int tmp1[64], tmp2[64]; + int top_ref[64], left_ref[64]; + int shift; + + for (int i = 0; i < size; i++) { + tmp1[i] = lastl - p->t[i + 1]; + tmp2[i] = lastt - p->l[i + 1]; + } + + shift = ff_log2(size) + 1; + for (int i = 0; i < size; i++) { + top_ref[i] = p->t[i + 1] << (shift - 1); + left_ref[i] = p->l[i + 1] << (shift - 1); + } + + for (int y = 0; y < size; y++) { + int add = tmp2[y]; + int sum = left_ref[y] + size; + for (int x = 0; x < size; x++) { + int v = tmp1[x] + top_ref[x]; + sum += add; + top_ref[x] = v; + dst[y*stride + x] = (sum + v) >> shift; + } + } +} + +static void pred_dc(const IntraPredContext * p, uint8_t * dst, int stride, int size, int filter) +{ + int dc; + + if (!p->has_t && !p->has_l) + dc = 0x80; + else { + int sum = 0; + if (p->has_t) + for (int x = 0; x < size; x++) + sum += p->t[x + 1]; + if (p->has_l) + for (int y = 0; y < size; y++) + sum += p->l[y + 1]; + if (p->has_t && p->has_l) + dc = (sum + size) / (size * 2); + else + dc = (sum + size / 2) / size; + } + + for (int y = 0; y < size; y++) + memset(dst + y*stride, dc, size); + + if (filter && p->has_t && p->has_l) { + dst[0] = (p->t[1] + p->l[1] + 2 * dst[0] + 2) >> 2; + for (int x = 1; x < size; x++) + dst[x] = (p->t[x + 1] + 3 * dst[x] + 2) >> 2; + for (int y = 1; y < size; y++) + dst[y*stride] = (p->l[y + 1] + 3 * dst[y*stride] + 2) >> 2; + } +} + +static void filter_weak(uint8_t * dst, const uint8_t * src, int size) +{ + dst[0] = src[0]; + for (int i = 1; i < size - 1; i++) + dst[i] = (src[i - 1] + 2*src[i] + src[i + 1] + 2) >> 2; + dst[size - 1] = src[size - 1]; +} + +static void filter_bilin32(uint8_t * dst, int v0, int v1, int size) +{ + int diff = v1 - v0; + int sum = (v0 << 5) + (1 << (5 - 1)); + for (int i = 0; i < size; i++) { + dst[i] = sum >> 5; + sum += diff; + } +} + +static void pred_hor_angle(uint8_t * dst, int stride, int size, int weight, const uint8_t * src) +{ + int sum = 0; + for (int x = 0; x < size; x++) { + int off, frac; + sum += weight; + off = (sum >> 5) + 32; + frac = sum & 0x1F; + if (!frac) + for (int y = 0; y < size; y++) + dst[y*stride + x] = src[off + y]; + else { + for (int y = 0; y < size; y++) { + int a = src[off + y]; + int b = src[off + y + 1]; + dst[y*stride + x] = ((32 - frac) * a + frac * b + 16) >> 5; + } + } + } +} + +static void pred_ver_angle(uint8_t * dst, int stride, int size, int weight, const uint8_t * src) +{ + int sum = 0; + for (int y = 0; y < size; y++) { + int off, frac; + sum += weight; + off = (sum >> 5) + 32; + frac = sum & 0x1F; + if (!frac) + memcpy(dst + y*stride, src + off, size); + else { + for (int x = 0; x < size; x++) { + int a = src[off + x]; + int b = src[off + x + 1]; + dst[y*stride + x] = ((32 - frac) * a + frac * b + 16) >> 5; + } + } + } +} + +static int pred_angle(const IntraPredContext * p, uint8_t * dst, int stride, int size, int imode, int filter) +{ + uint8_t filtered1[96], filtered2[96]; + + if (!imode) { + pred_plane(p, dst, stride, size); + } else if (imode == 1) { + pred_dc(p, dst, stride, size, filter); + } else if (imode <= 9) { + int ang_weight = rv60_ipred_angle[10 - imode]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + filter_weak(filtered1 + 32, &p->l[1], size + add_size); + } else { + filter_bilin32(filtered1 + 32, p->l[1], p->l[33], 32); + filter_bilin32(filtered1 + 64, p->l[32], p->l[64], add_size); + } + pred_hor_angle(dst, stride, size, ang_weight, filtered1); + } else if (imode == 10) { + if (size <= 16) + filter_weak(filtered1 + 32, &p->l[1], size); + else + filter_bilin32(filtered1 + 32, p->l[1], p->l[33], 32); + for (int y = 0; y < size; y++) + for (int x = 0; x < size; x++) + dst[y*stride + x] = filtered1[32 + y]; + if (filter) { + int tl = p->t[0]; + for (int x = 0; x < size; x++) + dst[x] = av_clip_uint8(dst[x] + ((p->t[x + 1] - tl) >> 1)); + } + } else if (imode <= 17) { + int ang_weight = rv60_ipred_angle[imode - 10]; + int inv_angle = rv60_ipred_inv_angle[imode - 10]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + memcpy(filtered1 + 32 - 1, p->l, size + 1); + memcpy(filtered2 + 32 - 1, p->t, size + 1); + } else { + filtered1[32 - 1] = p->l[0]; + filter_bilin32(filtered1 + 32, p->l[0], p->l[32], 32); + filtered2[32 - 1] = p->t[0]; + filter_bilin32(filtered2 + 32, p->t[0], p->t[32], 32); + } + if (add_size > 1) { + int sum = 0x80; + for (int i = 1; i < add_size; i++) { + sum += inv_angle; + filtered1[32 - 1 - i] = filtered2[32 - 1 + (sum >> 8)]; + } + } + pred_hor_angle(dst, stride, size, -ang_weight, filtered1); + } else if (imode <= 25) { + int ang_weight = rv60_ipred_angle[26 - imode]; + int inv_angle = rv60_ipred_inv_angle[26 - imode]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) { + memcpy(filtered1 + 32 - 1, p->t, size + 1); + memcpy(filtered2 + 32 - 1, p->l, size + 1); + } else { + filtered1[32 - 1] = p->t[0]; + filter_bilin32(filtered1 + 32, p->t[0], p->t[32], 32); + filtered2[32 - 1] = p->l[0]; + filter_bilin32(filtered2 + 32, p->l[0], p->l[32], 32); + } + if (add_size > 1) { + int sum = 0x80; + for (int i = 1; i < add_size; i++) { + sum += inv_angle; + filtered1[32 - 1 - i] = filtered2[32 - 1 + (sum >> 8)]; + } + } + pred_ver_angle(dst, stride, size, -ang_weight, filtered1); + } else if (imode == 26) { + if (size <= 16) + filter_weak(&filtered1[32], &p->t[1], size); + else + filter_bilin32(filtered1 + 32, p->t[1], p->t[33], 32); + for (int i = 0; i < size; i++) + memcpy(dst + i*stride, filtered1 + 32, size); + if (filter) { + int tl = p->l[0]; + for (int y = 0; y < size; y++) + dst[y*stride] = av_clip_uint8(dst[y*stride] + ((p->l[y+1] - tl) >> 1)); + } + } else if (imode <= 34) { + int ang_weight = rv60_ipred_angle[imode - 26]; + int add_size = (size * ang_weight + 31) >> 5; + if (size <= 16) + filter_weak(&filtered1[32], &p->t[1], size + add_size); + else { + filter_bilin32(filtered1 + 32, p->t[1], p->t[33], 32); + filter_bilin32(filtered1 + 64, p->t[32], p->t[64], add_size); + } + pred_ver_angle(dst, stride, size, ang_weight, filtered1); + } else + return AVERROR_INVALIDDATA; + return 0; +} + +static int pu_is_intra(const PUInfo * pu) +{ + return pu->cu_type == CU_INTRA; +} + +static int ipm_compar(const void * a, const void * b) +{ + return *(const enum IntraMode *)a - *(const enum IntraMode *)b; +} + +#define MK_UNIQUELIST(name, type, max_size) \ +typedef struct { \ + type list[max_size]; \ + int size; \ +} unique_list_##name; \ +\ +static void unique_list_##name##_init(unique_list_##name * s) \ +{ \ + memset(s->list, 0, sizeof(s->list)); \ + s->size = 0; \ +} \ +\ +static void unique_list_##name##_add(unique_list_##name * s, type cand) \ +{ \ + if (s->size == max_size) \ + return; \ + \ + for (int i = 0; i < s->size; i++) { \ + if (!memcmp(&s->list[i], &cand, sizeof(type))) { \ + return; \ + } \ + } \ + s->list[s->size++] = cand; \ +} + +MK_UNIQUELIST(intramode, enum IntraMode, 3) +MK_UNIQUELIST(mvinfo, MVInfo, 4) + +static int reconstruct_intra(const RV60Context * s, const CUContext * cu, int size, int sub) +{ + int blk_pos, tl_x, tl_y; + unique_list_intramode ipm_cand; + + if (cu->imode[0] == INTRAMODE_DC64) + return 1; + + if (cu->imode[0] == INTRAMODE_PLANE64) + return 0; + + unique_list_intramode_init(&ipm_cand); + + if (has_top_block(s, cu->xpos, cu->ypos, (sub & 1) * 4, 0, size)) { + const PUInfo * pu = &s->pu_info[cu->pu_pos - s->pu_stride]; + if (pu_is_intra(pu)) + unique_list_intramode_add(&ipm_cand, s->blk_info[cu->blk_pos - s->blk_stride + (sub & 1)].imode); + } + + blk_pos = cu->blk_pos + (sub >> 1) * s->blk_stride + (sub & 1); + + if (has_left_block(s, cu->xpos, cu->ypos, 0, (sub & 2) * 2, size)) { + const PUInfo * pu = &s->pu_info[cu->pu_pos - 1]; + if (pu_is_intra(pu)) + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - 1 - (sub & 1)].imode); + } + + tl_x = !(sub & 2) ? (cu->xpos + (sub & 1) * 4) : cu->xpos; + tl_y = cu->ypos + (sub & 2) * 4; + if (tl_x > 0 && tl_y > 0) { + const PUInfo * pu; + switch (sub) { + case 0: pu = &s->pu_info[cu->pu_pos - s->pu_stride - 1]; break; + case 1: pu = &s->pu_info[cu->pu_pos - s->pu_stride]; break; + default: pu = &s->pu_info[cu->pu_pos - 1]; + } + if (pu_is_intra(pu)) { + if (sub != 3) + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - s->blk_stride - 1].imode); + else + unique_list_intramode_add(&ipm_cand, s->blk_info[blk_pos - s->blk_stride - 2].imode); + } + } + + for (int i = 0; i < FF_ARRAY_ELEMS(rv60_candidate_intra_angles); i++) + unique_list_intramode_add(&ipm_cand, rv60_candidate_intra_angles[i]); + + if (cu->imode[sub] == INTRAMODE_INDEX) + return ipm_cand.list[cu->imode_param[sub]]; + + if (cu->imode[sub] == INTRAMODE_MODE) { + enum IntraMode imode = cu->imode_param[sub]; + qsort(ipm_cand.list, 3, sizeof(ipm_cand.list[0]), ipm_compar); + for (int i = 0; i < 3; i++) + if (imode >= ipm_cand.list[i]) + imode++; + return imode; + } + + av_assert0(0); // should never reach here + return 0; +} + +static int get_skip_mv_index(enum MVRefEnum mvref) +{ + switch (mvref) { + case MVREF_SKIP1: return 1; + case MVREF_SKIP2: return 2; + case MVREF_SKIP3: return 3; + default: return 0; + } +} + +static void add_if_valid(unique_list_mvinfo * skip_cand, const MVInfo * mvi) +{ + if (mvi->mvref != MVREF_NONE) + unique_list_mvinfo_add(skip_cand, *mvi); +} + +static void fill_mv_skip_cand(RV60Context * s, const CUContext * cu, unique_list_mvinfo * skip_cand, int size) +{ + int mv_size = size >> 2; + + if (cu->xpos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - 1].mv); + if (cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride].mv); + if (cu->ypos && cu->xpos + size < s->awidth) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride + mv_size].mv); + if (cu->xpos && cu->ypos + size < s->aheight) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos + s->blk_stride * mv_size - 1].mv); + if (cu->xpos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos + s->blk_stride * (mv_size - 1) - 1].mv); + if (cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride + mv_size - 1].mv); + if (cu->xpos && cu->ypos) + add_if_valid(skip_cand, &s->blk_info[cu->blk_pos - s->blk_stride - 1].mv); + + for (int i = skip_cand->size; i < 4; i++) + skip_cand->list[i] = (MVInfo){.mvref=MVREF_REF0,.f_mv={0,0},.b_mv={0,0}}; +} + +typedef struct { + int w, h; +} Dimensions; + +static void get_mv_dimensions(Dimensions * dim, enum PUType pu_type, int part_no, int size) +{ + int mv_size = size >> 2; + switch (pu_type) { + case PU_FULL: + dim->w = dim->h = mv_size; + break; + case PU_N2HOR: + dim->w = mv_size; + dim->h = mv_size >> 1; + break; + case PU_N2VER: + dim->w = mv_size >> 1; + dim->h = mv_size; + break; + case PU_QUARTERS: + dim->w = dim->h = mv_size >> 1; + break; + case PU_N4HOR: + dim->w = mv_size; + dim->h = !part_no ? (mv_size >> 2) : ((3 * mv_size) >> 2); + break; + case PU_N34HOR: + dim->w = mv_size; + dim->h = !part_no ? ((3 * mv_size) >> 2) : (mv_size >> 2); + break; + case PU_N4VER: + dim->w = !part_no ? (mv_size >> 2) : ((3 * mv_size) >> 2); + dim->h = mv_size; + break; + case PU_N34VER: + dim->w = !part_no ? ((3 * mv_size) >> 2) : (mv_size >> 2); + dim->h = mv_size; + break; + } +} + +static int has_hor_split(enum PUType pu_type) +{ + return pu_type == PU_N2HOR || pu_type == PU_N4HOR || pu_type == PU_N34HOR || pu_type == PU_QUARTERS; +} + +static int has_ver_split(enum PUType pu_type) +{ + return pu_type == PU_N2VER || pu_type == PU_N4VER || pu_type == PU_N34VER || pu_type == PU_QUARTERS; +} + +static int pu_type_num_parts(enum PUType pu_type) +{ + switch (pu_type) { + case PU_FULL: return 1; + case PU_QUARTERS: return 4; + default: return 2; + } +} + +static void get_next_mv(const RV60Context * s, const Dimensions * dim, enum PUType pu_type, int part_no, int * mv_pos, int * mv_x, int * mv_y) +{ + if (pu_type == PU_QUARTERS) { + if (part_no != 1) { + *mv_pos += dim->w; + *mv_x += dim->w; + } else { + *mv_pos += dim->h*s->blk_stride - dim->w; + *mv_x -= dim->w; + *mv_y += dim->h; + } + } else if (has_hor_split(pu_type)) { + *mv_pos += dim->h * s->blk_stride; + *mv_y += dim->h; + } else if (has_ver_split(pu_type)) { + *mv_pos += dim->w; + *mv_x += dim->w; + } +} + +static int mv_is_ref0(enum MVRefEnum mvref) +{ + return mvref == MVREF_REF0 || mvref == MVREF_REF0ANDBREF; +} + +static int mv_is_forward(enum MVRefEnum mvref) +{ + return mvref == MVREF_REF0 || mvref == MVREF_REF1 || mvref == MVREF_REF0ANDBREF; +} + +static int mv_is_backward(enum MVRefEnum mvref) +{ + return mvref == MVREF_BREF || mvref == MVREF_REF0ANDBREF; +} + +static int mvinfo_matches_forward(const MVInfo * a, const MVInfo * b) +{ + return a->mvref == b->mvref || (mv_is_ref0(a->mvref) && mv_is_ref0(b->mvref)); +} + +static int mvinfo_matches_backward(const MVInfo * a, const MVInfo * b) +{ + return mv_is_backward(a->mvref) && mv_is_backward(b->mvref); +} + +static int mvinfo_is_deblock_cand(const MVInfo * a, const MVInfo * b) +{ + int diff; + + if (a->mvref != b->mvref) + return 1; + + diff = 0; + if (mv_is_forward(a->mvref)) { + int dx = a->f_mv.x - b->f_mv.x; + int dy = a->f_mv.y - b->f_mv.y; + diff += FFABS(dx) + FFABS(dy); + } + if (mv_is_backward(a->mvref)) { + int dx = a->b_mv.x - b->b_mv.x; + int dy = a->b_mv.y - b->b_mv.y; + diff += FFABS(dx) + FFABS(dy); + } + return diff > 4; +} + +static void mv_pred(MV * ret, MV a, MV b, MV c) +{ +#define MEDIAN(x) \ + if (a.x < b.x) \ + if (b.x < c.x) \ + ret->x = b.x; \ + else \ + ret->x = a.x < c.x ? c.x : a.x; \ + else \ + if (b.x < c.x) \ + ret->x = a.x < c.x ? a.x : c.x; \ + else \ + ret->x = b.x; \ + + MEDIAN(x) + MEDIAN(y) +} + +static void predict_mv(const RV60Context * s, MVInfo * dst, int mv_x, int mv_y, int mv_w, const MVInfo * src) +{ + int mv_pos = mv_y * s->blk_stride + mv_x; + MV f_mv, b_mv; + + dst->mvref = src->mvref; + + if (mv_is_forward(src->mvref)) { + MV cand[3] = {0}; + int cand_size = 0; + if (mv_x > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - 1].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + if (mv_y > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + if (has_top_block(s, mv_x << 2, mv_y << 2, mv_w << 2, 0, 4)) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride + mv_w].mv; + if (mvinfo_matches_forward(mv, src)) + cand[cand_size++] = mv->f_mv; + } + + switch (cand_size) { + case 1: + f_mv.x = cand[0].x; + f_mv.y = cand[0].y; + break; + case 2: + f_mv.x = (cand[0].x + cand[1].x) >> 1; + f_mv.y = (cand[0].y + cand[1].y) >> 1; + break; + case 3: + mv_pred(&f_mv, cand[0], cand[1], cand[2]); + break; + default: + f_mv = (MV){0,0}; + break; + } + } else { + f_mv = (MV){0,0}; + } + + dst->f_mv.x = src->f_mv.x + f_mv.x; + dst->f_mv.y = src->f_mv.y + f_mv.y; + + if (mv_is_backward(src->mvref)) { + MV cand[3] = {0}; + int cand_size = 0; + if (mv_x > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - 1].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + if (mv_y > 0) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + if (has_top_block(s, mv_x << 2, mv_y << 2, mv_w << 2, 0, 4)) { + const MVInfo * mv = &s->blk_info[mv_pos - s->blk_stride + mv_w].mv; + if (mvinfo_matches_backward(mv, src)) + cand[cand_size++] = mv->b_mv; + } + + switch (cand_size) { + case 1: + b_mv.x = cand[0].x; + b_mv.y = cand[0].y; + break; + case 2: + b_mv.x = (cand[0].x + cand[1].x) >> 1; + b_mv.y = (cand[0].y + cand[1].y) >> 1; + break; + case 3: + mv_pred(&b_mv, cand[0], cand[1], cand[2]); + break; + default: + b_mv = (MV){0,0}; + break; + } + } else { + b_mv = (MV){0,0}; + } + + dst->b_mv.x = src->b_mv.x + b_mv.x; + dst->b_mv.y = src->b_mv.y + b_mv.y; +} + +static void reconstruct(RV60Context * s, const CUContext * cu, int size) +{ + int pu_size = size >> 3; + PUInfo pui; + int imode, mv_x, mv_y, mv_pos, count, mv_size; + unique_list_mvinfo skip_cand; + Dimensions dim; + MVInfo mv; + + pui.cu_type = cu->cu_type; + pui.pu_type = cu->pu_type; + + if (cu->cu_type == CU_INTRA && cu->pu_type == PU_QUARTERS) { + s->pu_info[cu->pu_pos] = pui; + for (int y = 0; y < 2; y++) + for (int x = 0; x < 2; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].imode = + reconstruct_intra(s, cu, 4, y*2 + x); + return; + } + + switch (cu->cu_type) { + case CU_INTRA: + imode = reconstruct_intra(s, cu, size, 0); + for (int y = 0; y < size >> 2; y++) + for (int x = 0; x < size >> 2; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].imode = imode; + break; + case CU_INTER_MV: + mv_x = cu->xpos >> 2; + mv_y = cu->ypos >> 2; + mv_pos = cu->blk_pos; + count = pu_type_num_parts(cu->pu_type); + for (int part_no = 0; part_no < count; part_no++) { + MVInfo mv; + get_mv_dimensions(&dim, cu->pu_type, part_no, size); + predict_mv(s, &mv, mv_x, mv_y, dim.w, &cu->mv[part_no]); + for (int y = 0; y < dim.h; y++) + for (int x = 0; x < dim.w; x++) + s->blk_info[mv_pos + y*s->blk_stride + x].mv = mv; + get_next_mv(s, &dim, cu->pu_type, part_no, &mv_pos, &mv_x, &mv_y); + } + break; + default: + unique_list_mvinfo_init(&skip_cand); + fill_mv_skip_cand(s, cu, &skip_cand, size); + mv = skip_cand.list[get_skip_mv_index(cu->mv[0].mvref)]; + mv_size = size >> 2; + for (int y = 0; y < mv_size; y++) + for (int x = 0; x < mv_size; x++) + s->blk_info[cu->blk_pos + y*s->blk_stride + x].mv = mv; + } + + for (int y = 0; y < pu_size; y++) + for (int x = 0; x < pu_size; x++) + s->pu_info[cu->pu_pos + y*s->pu_stride + x] = pui; +} + +static void read_mv(GetBitContext * gb, MV * mv) +{ + mv->x = get_interleaved_se_golomb(gb); + mv->y = get_interleaved_se_golomb(gb); +} + +static void read_mv_info(RV60Context *s, GetBitContext * gb, MVInfo * mvinfo, int size, enum PUType pu_type) +{ + if (s->pict_type != AV_PICTURE_TYPE_B) { + if (s->two_f_refs && get_bits1(gb)) + mvinfo->mvref = MVREF_REF1; + else + mvinfo->mvref = MVREF_REF0; + read_mv(gb, &mvinfo->f_mv); + mvinfo->b_mv.x = mvinfo->b_mv.y = 0; + } else { + if ((size <= 8 && (size != 8 || pu_type != PU_FULL)) || get_bits1(gb)) { + if (!get_bits1(gb)) { + mvinfo->mvref = MVREF_REF0; + read_mv(gb, &mvinfo->f_mv); + mvinfo->b_mv.x = mvinfo->b_mv.y = 0; + } else { + mvinfo->mvref = MVREF_BREF; + mvinfo->f_mv.x = mvinfo->f_mv.y = 0; + read_mv(gb, &mvinfo->b_mv); + } + } else { + mvinfo->mvref = MVREF_REF0ANDBREF; + read_mv(gb, &mvinfo->f_mv); + read_mv(gb, &mvinfo->b_mv); + } + } +} + +#define FILTER1(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +52 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 32) >> 6 + +#define FILTER2(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 16) >> 5 + +#define FILTER3(src, src_stride, src_y_ofs, step) \ + ( (src)[(y + src_y_ofs)*(src_stride) + x - 2*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x - 1*step] \ + +20 * (src)[(y + src_y_ofs)*(src_stride) + x ] \ + +52 * (src)[(y + src_y_ofs)*(src_stride) + x + 1*step] \ + - 5 * (src)[(y + src_y_ofs)*(src_stride) + x + 2*step] \ + + (src)[(y + src_y_ofs)*(src_stride) + x + 3*step] + 32) >> 6 + +#define FILTER_CASE(idx, dst, dst_stride, filter, w, h) \ + case idx: \ + for (int y = 0; y < h; y++) \ + for (int x = 0; x < w; x++) \ + (dst)[y*dst_stride + x] = av_clip_uint8(filter); \ + break; + +#define FILTER_BLOCK(dst, dst_stride, src, src_stride, src_y_ofs, w, h, cond, step) \ + switch (cond) { \ + FILTER_CASE(1, dst, dst_stride, FILTER1(src, src_stride, src_y_ofs, step), w, h) \ + FILTER_CASE(2, dst, dst_stride, FILTER2(src, src_stride, src_y_ofs, step), w, h) \ + FILTER_CASE(3, dst, dst_stride, FILTER3(src, src_stride, src_y_ofs, step), w, h) \ + } + +static void luma_mc(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h, int cx, int cy) +{ + if (!cx && !cy) { + for (int y = 0; y < h; y++) + memcpy(dst + y*dst_stride, src + y*src_stride, w); + } else if (!cy) { + FILTER_BLOCK(dst, dst_stride, src, src_stride, 0, w, h, cx, 1) + } else if (!cx) { + FILTER_BLOCK(dst, dst_stride, src, src_stride, 0, w, h, cy, src_stride) + } else if (cx != 3 || cy != 3) { + uint8_t tmp[70 * 64]; + FILTER_BLOCK(tmp, 64, src - src_stride * 2, src_stride, 0, w, h + 5, cx, 1) + FILTER_BLOCK(dst, dst_stride, tmp + 2*64, 64, 0, w, h, cy, 64) + } else { + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = ( + src[j*src_stride + i] + + src[j*src_stride + i + 1] + + src[(j + 1)*src_stride + i] + + src[(j + 1)*src_stride + i + 1] + 2) >> 2; + } +} + +static void chroma_mc(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h, int x, int y) +{ + if (!x && !y) { + for (int j = 0; j < h; j++) + memcpy(dst + j*dst_stride, src + j*src_stride, w); + } else if (x > 0 && y > 0) { + int a, b, c, d; + + if (x == 3 && y == 3) + y = 2; //reproduce bug in rv60 decoder. tested with realplayer version 18.1.7.344 and 22.0.0.321 + + a = (4 - x) * (4 - y); + b = x * (4 - y); + c = (4 - x) * y; + d = x * y; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = + (a * src[j*src_stride + i] + + b * src[j*src_stride + i + 1] + + c * src[(j + 1)*src_stride + i] + + d * src[(j + 1)*src_stride + i + 1] + 8) >> 4; + } else { + int a = (4 - x) * (4 - y); + int e = x * (4 - y) + (4 - x) * y; + int step = y > 0 ? src_stride : 1; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = + (a * src[j*src_stride + i] + + e * src[j*src_stride + i + step] + 8) >> 4; + } +} + +static int check_pos(int x, int y, int cw, int ch, int w, int h, int dx, int dy, int e0, int e1, int e2, int e3) +{ + int x2 = x + dx; + int y2 = y + dy; + return x2 - e0 >= 0 && x2 + cw + e1 <= w && y2 - e2 >= 0 && y2 + ch + e3 <= h; +} + +static void mc(RV60Context * s, uint8_t * frame_data[3], int frame_linesize[3], const AVFrame * ref, int x, int y, int w, int h, MV mv, int avg) +{ + { + int off = !avg ? y * frame_linesize[0] + x : 0; + int fw = s->awidth; + int fh = s->aheight; + int dx = mv.x >> 2; + int cx = mv.x & 3; + int dy = mv.y >> 2; + int cy = mv.y & 3; + + if (check_pos(x, y, w, h, fw, fh, dx, dy, rv60_edge1[cx], rv60_edge2[cx], rv60_edge1[cy], rv60_edge2[cy])) { + luma_mc( + frame_data[0] + off, + frame_linesize[0], + ref->data[0] + (y + dy) * ref->linesize[0] + x + dx, + ref->linesize[0], + w, h, cx, cy); + } else { + uint8_t buf[70*70]; + int xoff = x + dx - 2; + int yoff = y + dy - 2; + s->vdsp.emulated_edge_mc(buf, + ref->data[0] + yoff * ref->linesize[0] + xoff, + 70, ref->linesize[0], + w + 5, h + 5, + xoff, yoff, + fw, fh); + + luma_mc(frame_data[0] + off, frame_linesize[0], + buf + 70 * 2 + 2, 70, w, h, cx, cy); + } + } + { + int fw = s->awidth >> 1; + int fh = s->aheight >> 1; + int mvx = mv.x / 2; + int mvy = mv.y / 2; + int dx = mvx >> 2; + int cx = mvx & 3; + int dy = mvy >> 2; + int cy = mvy & 3; + int cw = w >> 1; + int ch = h >> 1; + + for (int plane = 1; plane < 3; plane++) { + int off = !avg ? (y >> 1) * frame_linesize[plane] + (x >> 1) : 0; + if (check_pos(x >> 1, y >> 1, cw, ch, fw, fh, dx, dy, 0, 1, 0, 1)) { + chroma_mc( + frame_data[plane] + off, + frame_linesize[plane], + ref->data[plane] + ((y >> 1) + dy) * ref->linesize[plane] + (x >> 1) + dx, + ref->linesize[plane], + cw, ch, cx, cy); + } else { + uint8_t buf[40*40]; + s->vdsp.emulated_edge_mc(buf, + ref->data[plane] + ((y >> 1) + dy) * ref->linesize[plane] + (x >> 1) + dx, + 40, ref->linesize[plane], + cw + 1, ch + 1, + (x >> 1) + dx, (y >> 1) + dy, + fw, fh); + chroma_mc(frame_data[plane] + off, frame_linesize[plane], buf, 40, cw, ch, cx, cy); + } + } + } +} + +static void avg_plane(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h) +{ + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + dst[j*dst_stride + i] = (dst[j*dst_stride + i] + src[j*src_stride + i]) >> 1; +} + +static void avg(AVFrame * frame, uint8_t * prev_frame_data[3], int prev_frame_linesize[3], int x, int y, int w, int h) +{ + for (int plane = 0; plane < 3; plane++) { + int shift = !plane ? 0 : 1; + avg_plane(frame->data[plane] + (y >> shift) * frame->linesize[plane] + (x >> shift), frame->linesize[plane], + prev_frame_data[plane], prev_frame_linesize[plane], + w >> shift, h >> shift); + } +} + +static int get_c4x4_set(int qp, int is_intra) +{ + if (is_intra) + return rv60_qp_to_idx[qp + 32]; + else + return rv60_qp_to_idx[qp]; +} + +static int quant(int v, int q) +{ + return (v * q + 8) >> 4; +} + +static int decode_coeff(GetBitContext * gb, const CoeffVLCs * vlcs, int inval, int val) +{ + int esc_sym; + + if (inval != val) + return inval && get_bits1(gb) ? -inval : inval; + + esc_sym = get_vlc2(gb, vlcs->esc, 9, 2); + if (esc_sym > 23) { + int esc_bits = esc_sym - 23; + val += (1 << esc_bits) + get_bits(gb, esc_bits) + 22; + } else + val += esc_sym; + + return get_bits1(gb) ? -val : val; +} + +static void decode_2x2_dc(GetBitContext * gb, const CoeffVLCs * vlcs, int16_t * coeffs, int stride, int block2, int dsc, int q_dc, int q_ac) +{ + const uint8_t * lx; + if (!dsc) + return; + + lx = rv60_dsc_to_lx[dsc - 1]; + + coeffs[0] = quant(decode_coeff(gb, vlcs, lx[0], 3), q_dc); + if (!block2) { + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } else { + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } + coeffs[stride + 1] = quant(decode_coeff(gb, vlcs, lx[3], 2), q_ac); +} + +static void decode_2x2(GetBitContext * gb, const CoeffVLCs * vlcs, int16_t * coeffs, int stride, int block2, int dsc, int q_ac) +{ + const uint8_t * lx; + if (!dsc) + return; + + lx = rv60_dsc_to_lx[dsc - 1]; + + coeffs[0] = quant(decode_coeff(gb, vlcs, lx[0], 3), q_ac); + if (!block2) { + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } else { + coeffs[stride] = quant(decode_coeff(gb, vlcs, lx[1], 2), q_ac); + coeffs[1] = quant(decode_coeff(gb, vlcs, lx[2], 2), q_ac); + } + coeffs[stride + 1] = quant(decode_coeff(gb, vlcs, lx[3], 2), q_ac); +} + +static void decode_4x4_block_dc(GetBitContext * gb, const CoeffVLCs * vlcs, int is_luma, int16_t * coeffs, int stride, int q_dc, int q_ac) +{ + int sym0 = get_vlc2(gb, vlcs->l0[!is_luma], 9, 2); + int grp0 = sym0 >> 3; + + if (grp0) + decode_2x2_dc(gb, vlcs, coeffs, stride, 0, grp0, q_dc, q_ac); + + if (sym0 & 4) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2, stride, 0, grp, q_ac); + } + if (sym0 & 2) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride, stride, 1, grp, q_ac); + } + if (sym0 & 1) { + int grp = get_vlc2(gb, vlcs->l3[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride + 2, stride, 0, grp, q_ac); + } +} + +static void decode_4x4_block(GetBitContext * gb, const CoeffVLCs * vlcs, int is_luma, int16_t * coeffs, int stride, int q_ac) +{ + int sym0 = get_vlc2(gb, vlcs->l0[!is_luma], 9, 2); + int grp0 = (sym0 >> 3); + + if (grp0) + decode_2x2(gb, vlcs, coeffs, stride, 0, grp0, q_ac); + + if (sym0 & 4) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2, stride, 0, grp, q_ac); + } + if (sym0 & 2) { + int grp = get_vlc2(gb, vlcs->l12[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride, stride, 1, grp, q_ac); + } + if (sym0 & 1) { + int grp = get_vlc2(gb, vlcs->l3[!is_luma], 9, 2); + decode_2x2(gb, vlcs, coeffs + 2*stride + 2, stride, 0, grp, q_ac); + } +} + +static void decode_cu_4x4in16x16(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int cbp) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*256); + for (int i = 0; i < 16; i++) + if ((cbp >> i) & 1) + decode_4x4_block(gb, vlc, 1, y_coeffs + i * 16 , 4, q_y); + + memset(u_coeffs, 0, sizeof(u_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((cbp >> (16 + i)) & 1) + decode_4x4_block_dc(gb, vlc, 0, u_coeffs + i * 16, 4, q_c_dc, q_c_ac); + + memset(v_coeffs, 0, sizeof(v_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((cbp >> (20 + i)) & 1) + decode_4x4_block_dc(gb, vlc, 0, v_coeffs + i * 16, 4, q_c_dc, q_c_ac); +} + +static int decode_cbp8(GetBitContext * gb, int subset, int qp) +{ + int cb_set = rv60_qp_to_idx[qp]; + return get_vlc2(gb, cbp8_vlc[cb_set][subset], 9, 2); +} + +static void decode_cu_8x8(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int ccbp, int mode4x4) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*64); + for (int i = 0; i < 4; i++) { + if ((ccbp >> i) & 1) { + int offset, stride; + if (mode4x4) { + offset = i*16; + stride = 4; + } else { + offset = (i & 1) * 4 + (i & 2) * 2 * 8; + stride = 8; + } + decode_4x4_block(gb, vlc, 1, y_coeffs + offset, stride, q_y); + } + } + + if ((ccbp >> 4) & 1) { + memset(u_coeffs, 0, sizeof(u_coeffs[0])*16); + decode_4x4_block_dc(gb, vlc, 0, u_coeffs, 4, q_c_dc, q_c_ac); + } + + if ((ccbp >> 5) & 1) { + memset(v_coeffs, 0, sizeof(u_coeffs[0])*16); + decode_4x4_block_dc(gb, vlc, 0, v_coeffs, 4, q_c_dc, q_c_ac); + } +} + +static void decode_cu_16x16(GetBitContext * gb, int is_intra, int qp, int sel_qp, int16_t * y_coeffs, int16_t * u_coeffs, int16_t * v_coeffs, int ccbp) +{ + int cb_set = get_c4x4_set(sel_qp, is_intra); + const CoeffVLCs * vlc = is_intra ? &intra_coeff_vlc[cb_set] : &inter_coeff_vlc[cb_set]; + int q_y = rv60_quants_b[qp]; + int q_c_dc = rv60_quants_b[rv60_chroma_quant_dc[qp]]; + int q_c_ac = rv60_quants_b[rv60_chroma_quant_ac[qp]]; + + memset(y_coeffs, 0, sizeof(y_coeffs[0])*256); + for (int i = 0; i < 16; i++) + if ((ccbp >> i) & 1) { + int off = (i & 3) * 4 + (i >> 2) * 4 * 16; + decode_4x4_block(gb, vlc, 1, y_coeffs + off, 16, q_y); + } + + memset(u_coeffs, 0, sizeof(u_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((ccbp >> (16 + i)) & 1) { + int off = (i & 1) * 4 + (i & 2) * 2 * 8; + if (!i) + decode_4x4_block_dc(gb, vlc, 0, u_coeffs + off, 8, q_c_dc, q_c_ac); + else + decode_4x4_block(gb, vlc, 0, u_coeffs + off, 8, q_c_ac); + } + + memset(v_coeffs, 0, sizeof(v_coeffs[0])*64); + for (int i = 0; i < 4; i++) + if ((ccbp >> (20 + i)) & 1) { + int off = (i & 1) * 4 + (i & 2) * 2 * 8; + if (!i) + decode_4x4_block_dc(gb, vlc, 0, v_coeffs + off, 8, q_c_dc, q_c_ac); + else + decode_4x4_block(gb, vlc, 0, v_coeffs + off, 8, q_c_ac); + } +} + +static int decode_super_cbp(GetBitContext * gb, const VLCElem * vlc[4]) +{ + int sym0 = get_vlc2(gb, vlc[0], 9, 2); + int sym1 = get_vlc2(gb, vlc[1], 9, 2); + int sym2 = get_vlc2(gb, vlc[2], 9, 2); + int sym3 = get_vlc2(gb, vlc[3], 9, 2); + return 0 + + ((sym0 & 0x03) << 0) + + ((sym0 & 0x0C) << 2) + + ((sym0 & 0x10) << 12) + + ((sym0 & 0x20) << 15) + + ((sym1 & 0x03) << 2) + + ((sym1 & 0x0C) << 4) + + ((sym1 & 0x10) << 13) + + ((sym1 & 0x20) << 16) + + ((sym2 & 0x03) << 8) + + ((sym2 & 0x0C) << 10) + + ((sym2 & 0x10) << 14) + + ((sym2 & 0x20) << 17) + + ((sym3 & 0x03) << 10) + + ((sym3 & 0x0C) << 12) + + ((sym3 & 0x10) << 15) + + ((sym3 & 0x20) << 18); +} + +static int decode_cbp16(GetBitContext * gb, int subset, int qp) +{ + int cb_set = rv60_qp_to_idx[qp]; + return decode_super_cbp(gb, cbp16_vlc[cb_set][subset]); +} + +static int decode_cu_r(RV60Context * s, AVFrame * frame, ThreadContext * thread, GetBitContext * gb, int xpos, int ypos, int log_size, int qp, int sel_qp) +{ + int size = 1 << log_size; + int split, ret, ttype, count, is_intra, cu_pos, subset, cbp8, imode, split_i4x4, num_clusters, cl_cbp, super_cbp, mv_x, mv_y, mv_pos; + int16_t y_coeffs[16*16], u_coeffs[8*8], v_coeffs[8*8]; + CUContext cu; + + if (xpos >= s->awidth || ypos >= s->aheight) + return 0; + + split = xpos + size > s->awidth || ypos + size > s->aheight || (size > 8 && get_bits1(gb)); + thread->cu_split[thread->cu_split_pos++] = split; + if (split) { + size >>= 1; + log_size -= 1; + if ((ret = decode_cu_r(s, frame, thread, gb, xpos, ypos, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos + size, ypos, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos, ypos + size, log_size, qp, sel_qp)) < 0 || + (ret = decode_cu_r(s, frame, thread, gb, xpos + size, ypos + size, log_size, qp, sel_qp)) < 0) + return ret; + return 0; + } + + cu.xpos = xpos; + cu.ypos = ypos; + cu.pu_pos = (xpos >> 3) + (ypos >> 3) * s->pu_stride; + cu.blk_pos = (xpos >> 2) + (ypos >> 2) * s->blk_stride; + cu.cu_type = s->pict_type != AV_PICTURE_TYPE_I ? get_bits(gb, 2) : CU_INTRA; + + switch (cu.cu_type) { + case CU_INTRA: + cu.pu_type = size == 8 && get_bits1(gb) ? PU_QUARTERS : PU_FULL; + if (cu.pu_type == PU_QUARTERS) + for (int i = 0; i < 4; i++) + cu.imode[i] = read_intra_mode(gb, &cu.imode_param[i]); + else if (size <= 32) + cu.imode[0] = read_intra_mode(gb, &cu.imode_param[0]); + else + cu.imode[0] = get_bits1(gb) ? INTRAMODE_PLANE64 : INTRAMODE_DC64; + break; + case CU_INTER_MV: + cu.pu_type = get_bits(gb, size == 8 ? 2 : 3); + count = pu_type_num_parts(cu.pu_type); + for (int i = 0; i < count; i++) + read_mv_info(s, gb, &cu.mv[i], size, cu.pu_type); + break; + default: + cu.pu_type = PU_FULL; + cu.mv[0].mvref = skip_mv_ref[get_unary(gb, 0, 3)]; + break; + } + + reconstruct(s, &cu, size); + + split_i4x4 = cu.cu_type == CU_INTRA && size == 8 && cu.pu_type == PU_QUARTERS; + + switch (cu.cu_type) { + case CU_INTRA: + imode = s->blk_info[cu.blk_pos].imode; + if (!split_i4x4) { + int off = ypos * frame->linesize[0] + xpos; + populate_ipred(s, &cu, frame->data[0], frame->linesize[0], 0, 0, size, 1); + if (pred_angle(&cu.ipred, frame->data[0] + off, frame->linesize[0], size, imode, 1) < 0) + return AVERROR_INVALIDDATA; + } + for (int plane = 1; plane < 3; plane++) { + int off = (ypos >> 1) * frame->linesize[plane] + (xpos >> 1); + populate_ipred(s, &cu, frame->data[plane], frame->linesize[plane], 0, 0, size >> 1, 0); + if (pred_angle(&cu.ipred, frame->data[plane] + off, frame->linesize[plane], size >> 1, imode, 0) < 0) + return AVERROR_INVALIDDATA; + } + break; + default: + mv_x = xpos >> 2; + mv_y = ypos >> 2; + mv_pos = mv_y * s->blk_stride + mv_x; + count = pu_type_num_parts(cu.pu_type); + for (int part_no = 0; part_no < count; part_no++) { + MVInfo mv; + Dimensions dim; + int bw, bh, bx, by; + + mv = s->blk_info[mv_pos].mv; + get_mv_dimensions(&dim, cu.pu_type, part_no, size); + bw = dim.w << 2; + bh = dim.h << 2; + bx = mv_x << 2; + by = mv_y << 2; + + if (!(mv.mvref & 2)) { + if (!s->last_frame[LAST_PIC]->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + } + if (mv.mvref & 6) { + if (!s->last_frame[NEXT_PIC]->data[0]) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + } + + switch (mv.mvref) { + case MVREF_REF0: + mc(s, frame->data, frame->linesize, s->last_frame[LAST_PIC], bx, by, bw, bh, mv.f_mv, 0); + break; + case MVREF_REF1: + mc(s, frame->data, frame->linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.f_mv, 0); + break; + case MVREF_BREF: + mc(s, frame->data, frame->linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.b_mv, 0); + break; + case MVREF_REF0ANDBREF: + mc(s, frame->data, frame->linesize, s->last_frame[LAST_PIC], bx, by, bw, bh, mv.f_mv, 0); + mc(s, thread->avg_data, thread->avg_linesize, s->last_frame[NEXT_PIC], bx, by, bw, bh, mv.b_mv, 1); + avg(frame, thread->avg_data, thread->avg_linesize, bx, by, bw, bh); + break; + default: + av_assert0(0); //should never reach here + } + get_next_mv(s, &dim, cu.pu_type, part_no, &mv_pos, &mv_x, &mv_y); + } + break; + } + + if (cu.cu_type == CU_SKIP) + ttype = TRANSFORM_NONE; + else if (size >= 32) + ttype = TRANSFORM_16X16; + else if (size == 16) + ttype = cu.cu_type == CU_INTRA || cu.pu_type == PU_FULL ? TRANSFORM_16X16 : TRANSFORM_4X4; + else + ttype = cu.pu_type == PU_FULL ? TRANSFORM_8X8 : TRANSFORM_4X4; + + is_intra = cu.cu_type == CU_INTRA; + if (qp >= 32) + return AVERROR_INVALIDDATA; + cu_pos = ((xpos & 63) >> 3) + ((ypos & 63) >> 3) * 8; + + switch (ttype) { + case TRANSFORM_4X4: + subset = is_intra ? 0 : 2; + if (size == 16) { + int cbp16 = get_bits1(gb) ? decode_cbp16(gb, subset, sel_qp) : 0; + if (cbp16) { + decode_cu_4x4in16x16(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp16); + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) { + int i = y*4 + x; + if ((cbp16 >> i) & 1) { + int off = (ypos + y * 4)*frame->linesize[0] + xpos + x * 4; + ff_rv60_idct4x4_add(y_coeffs + i*16, frame->data[0] + off, frame->linesize[0]); + thread->coded_blk[cu_pos + (y/2)*8 + (x/2)] = 1; + } + } + for (int y = 0; y < 2; y++) + for (int x = 0; x < 2; x++) { + int i = y * 2 + x; + int xoff = (xpos >> 1) + x * 4; + int yoff = (ypos >> 1) + y * 4; + if ((cbp16 >> (16 + i)) & 1) { + int off = yoff * frame->linesize[1] + xoff; + ff_rv60_idct4x4_add(u_coeffs + i * 16, frame->data[1] + off, frame->linesize[1]); + thread->coded_blk[cu_pos + y*8 + x] = 1; + } + if ((cbp16 >> (20 + i)) & 1) { + int off = yoff * frame->linesize[2] + xoff; + ff_rv60_idct4x4_add(v_coeffs + i * 16, frame->data[2] + off, frame->linesize[2]); + thread->coded_blk[cu_pos + y*8 + x] = 1; + } + } + } + } else { + cbp8 = decode_cbp8(gb, subset, sel_qp); + if (cbp8) { + thread->coded_blk[cu_pos] = 1; + decode_cu_8x8(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp8, 1); + } + for (int i = 0; i < 4; i++) { + int xoff = (i & 1) << 2; + int yoff = (i & 2) << 1; + if (split_i4x4) { + int off = (ypos + yoff) * frame->linesize[0] + xpos + xoff; + int imode = s->blk_info[cu.blk_pos + (i >> 1) * s->blk_stride + (i & 1)].imode; + populate_ipred(s, &cu, frame->data[0], frame->linesize[0], xoff, yoff, 4, 1); + if (pred_angle(&cu.ipred, frame->data[0] + off, frame->linesize[0], 4, imode, 1) < 0) + return AVERROR_INVALIDDATA; + } + if ((cbp8 >> i) & 1) { + int off = (ypos + yoff) * frame->linesize[0] + xpos + xoff; + ff_rv60_idct4x4_add(y_coeffs + i * 16, frame->data[0] + off, frame->linesize[0]); + } + } + if ((cbp8 >> 4) & 1) { + int off = (ypos >> 1) * frame->linesize[1] + (xpos >> 1); + ff_rv60_idct4x4_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((cbp8 >> 5) & 1) { + int off = (ypos >> 1) * frame->linesize[2] + (xpos >> 1); + ff_rv60_idct4x4_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + break; + case TRANSFORM_8X8: + subset = is_intra ? 1 : 3; + cbp8 = decode_cbp8(gb, subset, sel_qp); + if (cbp8) { + thread->coded_blk[cu_pos] = 1; + decode_cu_8x8(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, cbp8, 0); + if (cbp8 & 0xF) { + int off = ypos * frame->linesize[0] + xpos; + ff_rv60_idct8x8_add(y_coeffs, frame->data[0] + off, frame->linesize[0]); + } + if ((cbp8 >> 4) & 1) { + int off = (ypos >> 1) * frame->linesize[1] + (xpos >> 1); + ff_rv60_idct4x4_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((cbp8 >> 5) & 1) { + int off = (ypos >> 1) * frame->linesize[2] + (xpos >> 1); + ff_rv60_idct4x4_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + break; + case TRANSFORM_16X16: + subset = is_intra ? 1 : 3; + num_clusters = size >> 4; + cl_cbp = get_bits(gb, num_clusters * num_clusters); + for (int y = 0; y < num_clusters; y++) { + for (int x = 0; x < num_clusters; x++) { + if (!((cl_cbp >> (y*num_clusters + x)) & 1)) + continue; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 0] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 1] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 8] = 1; + thread->coded_blk[cu_pos + y*2*8 + x*2 + 9] = 1; + super_cbp = decode_cbp16(gb, subset, sel_qp); + if (super_cbp) { + decode_cu_16x16(gb, is_intra, qp, sel_qp, y_coeffs, u_coeffs, v_coeffs, super_cbp); + if (super_cbp & 0xFFFF) { + int off = (ypos + y * 16) * frame->linesize[0] + xpos + x * 16; + ff_rv60_idct16x16_add(y_coeffs, frame->data[0] + off, frame->linesize[0]); + } + if ((super_cbp >> 16) & 0xF) { + int off = ((ypos >> 1) + y * 8) * frame->linesize[1] + (xpos >> 1) + x * 8; + ff_rv60_idct8x8_add(u_coeffs, frame->data[1] + off, frame->linesize[1]); + } + if ((super_cbp >> 20) & 0xF) { + int off = ((ypos >> 1) + y * 8) * frame->linesize[2] + (xpos >> 1) + x * 8; + ff_rv60_idct8x8_add(v_coeffs, frame->data[2] + off, frame->linesize[2]); + } + } + } + } + break; + } + + return 0; +} + +static int deblock_get_pos(RV60Context * s, int xpos, int ypos) +{ + return (ypos >> 2) * s->dblk_stride + (xpos >> 2); +} + +static void deblock_set_strength(RV60Context * s, int xpos, int ypos, int size, int q, int strength) +{ + int pos = deblock_get_pos(s, xpos, ypos); + int dsize = size >> 2; + int dval = (q << 2) + strength; + + for (int x = 0; x < dsize; x++) { + s->top_str[pos + x] = dval; + s->top_str[pos + (dsize - 1)*s->dblk_stride + x] = dval; + } + + for (int y = 0; y < dsize; y++) { + s->left_str[pos + y*s->dblk_stride] = dval; + s->left_str[pos + y*s->dblk_stride + dsize - 1] = dval; + } +} + +static int deblock_get_top_strength(const RV60Context * s, int pos) +{ + return s->top_str[pos] & 3; +} + +static int deblock_get_left_strength(const RV60Context * s, int pos) +{ + return s->left_str[pos] & 3; +} + +static void deblock_set_top_strength(RV60Context * s, int pos, int strength) +{ + s->top_str[pos] |= strength; +} + +static void deblock_set_left_strength(RV60Context * s, int pos, int strength) +{ + s->left_str[pos] |= strength; +} + +static void derive_deblock_strength(RV60Context * s, int xpos, int ypos, int size) +{ + int blk_pos = (ypos >> 2) * s->blk_stride + (xpos >> 2); + int dblk_pos = deblock_get_pos(s, xpos, ypos); + if (ypos > 0) + for (int i = 0; i < size; i++) + if (!deblock_get_top_strength(s, dblk_pos - s->dblk_stride + i) && mvinfo_is_deblock_cand(&s->blk_info[blk_pos + i].mv, &s->blk_info[blk_pos - s->blk_stride + i].mv)) + deblock_set_top_strength(s, dblk_pos + i, 1); + if (xpos > 0) + for (int i = 0; i < size; i++) + if (!deblock_get_left_strength(s, dblk_pos + i *s->dblk_stride - 1) && mvinfo_is_deblock_cand(&s->blk_info[blk_pos + i*s->blk_stride].mv, &s->blk_info[blk_pos + i*s->blk_stride - 1].mv)) + deblock_set_left_strength(s, dblk_pos + i *s->dblk_stride, 1); +} + +#define STRENGTH(el, lim) (FFABS(el) < (lim) ? 3 : 1) +#define CLIP_SYMM(a, b) av_clip(a, -(b), b) + +static void filter_luma_edge(uint8_t * dst, int step, int stride, int mode1, int mode2, int lim1, int lim2) +{ + int16_t diff_q1q0[4]; + int16_t diff_p1p0[4]; + int str_p, str_q, msum, maxprod, weak; + + for (int i = 0; i < 4; i++) { + diff_q1q0[i] = dst[i * stride - 2*step] - dst[i*stride - step]; + diff_p1p0[i] = dst[i * stride + step] - dst[i*stride]; + } + + str_p = STRENGTH(diff_q1q0[0] + diff_q1q0[1] + diff_q1q0[2] + diff_q1q0[3], lim2); + str_q = STRENGTH(diff_p1p0[0] + diff_p1p0[1] + diff_p1p0[2] + diff_p1p0[3], lim2); + + if (str_p + str_q <= 2) + return; + + msum = (mode1 + mode2 + str_q + str_p) >> 1; + if (str_q == 1 || str_p == 1) { + maxprod = 384; + weak = 1; + } else { + maxprod = 256; + weak = 0; + } + + for (int y = 0; y < 4; y++) { + int diff_p0q0 = dst[0] - dst[-step]; + int result = (lim1 * FFABS(diff_p0q0)) & -128; + if (diff_p0q0 && result <= maxprod) { + int diff_q1q2 = dst[-2*step] - dst[-3*step]; + int diff_p1p2 = dst[step] - dst[2*step]; + int delta; + if (weak) { + delta = CLIP_SYMM((diff_p0q0 + 1) >> 1, msum >> 1); + } else { + int diff_strg = (dst[-2*step] - dst[step] + 4 * diff_p0q0 + 4) >> 3; + delta = CLIP_SYMM(diff_strg, msum); + } + dst[-step] = av_clip_uint8(dst[-step] + delta); + dst[0] = av_clip_uint8(dst[0] - delta); + if (str_p != 1 && FFABS(diff_q1q2) <= (lim2 >> 2)) { + int diff = (diff_q1q0[y] + diff_q1q2 - delta) >> 1; + int delta_q1 = weak ? CLIP_SYMM(diff, mode1 >> 1) : CLIP_SYMM(diff, mode1); + dst[-2 * step] = av_clip_uint8(dst[-2*step] - delta_q1); + } + if (str_q != 1 && FFABS(diff_p1p2) <= (lim2 >> 2)) { + int diff = (diff_p1p0[y] + diff_p1p2 + delta) >> 1; + int delta_p1 = weak ? CLIP_SYMM(diff, mode2 >> 1) : CLIP_SYMM(diff, mode2); + dst[step] = av_clip_uint8(dst[step] - delta_p1); + } + } + dst += stride; + } +} + +static void filter_chroma_edge(uint8_t * dst, int step, int stride, int mode1, int mode2, int lim1, int lim2) +{ + int diff_q = 4 * FFABS(dst[-2*step] - dst[-step]); + int diff_p = 4 * FFABS(dst[ step] - dst[0]); + int str_q = STRENGTH(diff_q, lim2); + int str_p = STRENGTH(diff_p, lim2); + int msum, maxprod, weak; + + if (str_p + str_q <= 2) + return; + + msum = (mode1 + mode2 + str_q + str_p) >> 1; + if (str_q == 1 || str_p == 1) { + maxprod = 384; + weak = 1; + } else { + maxprod = 256; + weak = 0; + } + + for (int y = 0; y < 2; y++) { + int diff_pq = dst[0] - dst[-step]; + int result = (lim1 * FFABS(diff_pq)) & -128; + if (diff_pq && result <= maxprod) { + int delta; + if (weak) { + delta = CLIP_SYMM((diff_pq + 1) >> 1, msum >> 1); + } else { + int diff_strg = (dst[-2*step] - dst[step] + 4 * diff_pq + 4) >> 3; + delta = CLIP_SYMM(diff_strg, msum); + } + dst[-step] = av_clip_uint8(dst[-step] + delta); + dst[ 0 ] = av_clip_uint8(dst[ 0 ] - delta); + } + dst += stride; + } +} + +static void deblock_edge_ver(AVFrame * frame, int xpos, int ypos, int dblk_l, int dblk_r, int deblock_chroma) +{ + int qp_l = dblk_l >> 2; + int str_l = dblk_l & 3; + int qp_r = dblk_r >> 2; + int str_r = dblk_r & 3; + const uint8_t * dl_l = rv60_deblock_limits[qp_l]; + const uint8_t * dl_r = rv60_deblock_limits[qp_r]; + int mode_l = str_l ? dl_l[str_l - 1] : 0; + int mode_r = str_r ? dl_r[str_r - 1] : 0; + int lim1 = dl_r[2]; + int lim2 = dl_r[3] * 4; + + filter_luma_edge(frame->data[0] + ypos * frame->linesize[0] + xpos, 1, frame->linesize[0], mode_l, mode_r, lim1, lim2); + if ((str_l | str_r) >= 2 && deblock_chroma) + for (int plane = 1; plane < 3; plane++) + filter_chroma_edge(frame->data[plane] + (ypos >> 1) * frame->linesize[plane] + (xpos >> 1), 1, frame->linesize[plane], mode_l, mode_r, lim1, lim2); +} + +static void deblock_edge_hor(AVFrame * frame, int xpos, int ypos, int dblk_t, int dblk_d, int deblock_chroma) +{ + int qp_t = dblk_t >> 2; + int str_t = dblk_t & 3; + int qp_d = dblk_d >> 2; + int str_d = dblk_d & 3; + const uint8_t * dl_t = rv60_deblock_limits[qp_t]; + const uint8_t * dl_d = rv60_deblock_limits[qp_d]; + int mode_t = str_t ? dl_t[str_t - 1] : 0; + int mode_d = str_d ? dl_d[str_d - 1] : 0; + int lim1 = dl_d[2]; + int lim2 = dl_d[3] * 4; + + filter_luma_edge(frame->data[0] + ypos * frame->linesize[0] + xpos, frame->linesize[0], 1, mode_t, mode_d, lim1, lim2); + if ((str_t | str_d) >= 2 && deblock_chroma) + for (int plane = 1; plane < 3; plane++) + filter_chroma_edge(frame->data[plane] + (ypos >> 1) * frame->linesize[plane] + (xpos >> 1), frame->linesize[plane], 1, mode_t, mode_d, lim1, lim2); +} + +static void deblock8x8(const RV60Context * s, AVFrame * frame, int xpos, int ypos, int dblkpos) +{ + if (xpos > 0) { + if (ypos > 0) { + int str_l = s->left_str[dblkpos - s->dblk_stride - 1]; + int str_r = s->left_str[dblkpos - s->dblk_stride]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos - 4, str_l, str_r, s->deblock_chroma); + } + { + int str_l = s->left_str[dblkpos - 1]; + int str_r = s->left_str[dblkpos]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos, str_l, str_r, s->deblock_chroma); + } + if (ypos + 8 >= s->aheight) { + int str_l = s->left_str[dblkpos + s->dblk_stride - 1]; + int str_r = s->left_str[dblkpos + s->dblk_stride]; + if ((str_l | str_r) & 3) + deblock_edge_ver(frame, xpos, ypos + 4, str_l, str_r, s->deblock_chroma); + } + } + if (ypos > 0) { + if (xpos > 0) { + int str_t = s->top_str[dblkpos - s->dblk_stride - 1]; + int str_d = s->top_str[dblkpos - 1]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos - 4, ypos, str_t, str_d, s->deblock_chroma); + } + { + int str_t = s->top_str[dblkpos - s->dblk_stride]; + int str_d = s->top_str[dblkpos]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos, ypos, str_t, str_d, s->deblock_chroma); + } + if (xpos + 8 >= s->awidth) { + int str_t = s->top_str[dblkpos - s->dblk_stride + 1]; + int str_d = s->top_str[dblkpos + 1]; + if ((str_t | str_d) & 3) + deblock_edge_hor(frame, xpos + 4, ypos, str_t, str_d, s->deblock_chroma); + } + } +} + +static void deblock(const RV60Context * s, AVFrame * frame, int xpos, int ypos, int size, int dpos) +{ + for (int x = 0; x < size >> 3; x++) + deblock8x8(s, frame, xpos + x * 8, ypos, dpos + x * 2); + + for (int y = 1; y < size >> 3; y++) + deblock8x8(s, frame, xpos, ypos + y * 8, dpos + y * 2 * s->dblk_stride); +} + +static void deblock_cu_r(RV60Context * s, AVFrame * frame, ThreadContext * thread, int xpos, int ypos, int log_size, int qp) +{ + int pu_pos, tsize, ntiles; + enum CUType cu_type; + + if (xpos >= s->awidth || ypos >= s->aheight) + return; + + if (thread->cu_split[thread->cu_split_pos++]) { + int hsize = 1 << (log_size - 1); + log_size--; + deblock_cu_r(s, frame, thread, xpos, ypos, log_size, qp); + deblock_cu_r(s, frame, thread, xpos + hsize, ypos, log_size, qp); + deblock_cu_r(s, frame, thread, xpos, ypos + hsize, log_size, qp); + deblock_cu_r(s, frame, thread, xpos + hsize, ypos + hsize, log_size, qp); + return; + } + + pu_pos = (ypos >> 3) * s->pu_stride + (xpos >> 3); + cu_type = s->pu_info[pu_pos].cu_type; + switch (log_size) { + case 3: tsize = 3; break; + case 4: tsize = cu_type && s->pu_info[pu_pos].pu_type ? 3 : 4; break; + case 5: + case 6: tsize = 4; break; + } + ntiles = 1 << (log_size - tsize); + + for (int ty = 0; ty < ntiles; ty++) + for (int tx = 0; tx < ntiles; tx++) { + int x = xpos + (tx << tsize); + int y = ypos + (ty << tsize); + int cu_pos = ((y & 63) >> 3) * 8 + ((x & 63) >> 3); + + if (cu_type == CU_INTRA) + deblock_set_strength(s, x, y, 1 << tsize, qp, 2); + else if (cu_type != CU_SKIP && thread->coded_blk[cu_pos]) + deblock_set_strength(s, x, y, 1 << tsize, qp, 1); + else { + deblock_set_strength(s, x, y, 1 << tsize, qp, 0); + derive_deblock_strength(s, x, y, 1 << (tsize - 2)); + } + + deblock(s, frame, x, y, 1 << tsize, deblock_get_pos(s, x, y)); + } +} + +static int read_qp_offset(GetBitContext *gb, int qp_off_type) +{ + int val; + + switch (qp_off_type) { + case 0: + return 0; + case 1: + val = read_code012(gb); + return val != 2 ? val : -1; + default: + if (!get_bits1(gb)) + return 0; + val = get_bits(gb, 2); + if (!(val & 2)) + return val + 1; + else + return -((val & 1) + 1); + } +} + +static int calc_sel_qp(int osvquant, int qp) +{ + switch (osvquant) { + case 0: return qp; + case 1: return qp <= 25 ? qp + 5 : qp; + default: + if (qp <= 18) + return qp + 10; + else if (qp <= 25) + return qp + 5; + else + return qp; + } +} + +static int decode_slice(AVCodecContext *avctx, void *tdata, int cu_y, int threadnr) +{ + RV60Context *s = avctx->priv_data; + AVFrame * frame = tdata; + ThreadContext thread; + GetBitContext gb; + int qp, sel_qp, ret; + + thread.avg_data[0] = thread.avg_buffer; + thread.avg_data[1] = thread.avg_buffer + 64*64; + thread.avg_data[2] = thread.avg_buffer + 64*64 + 32*32; + thread.avg_linesize[0] = 64; + thread.avg_linesize[1] = 32; + thread.avg_linesize[2] = 32; + + if ((ret = init_get_bits8(&gb, s->slice[cu_y].data, s->slice[cu_y].data_size)) < 0) + return ret; + + for (int cu_x = 0; cu_x < s->cu_width; cu_x++) { + if ((s->avctx->active_thread_type & FF_THREAD_SLICE) && cu_y) + ff_thread_progress_await(&s->progress[cu_y - 1], cu_x + 2); + + qp = s->qp + read_qp_offset(&gb, s->qp_off_type); + if (qp < 0) { + ret = AVERROR_INVALIDDATA; + break; + } + sel_qp = calc_sel_qp(s->osvquant, qp); + + memset(thread.coded_blk, 0, sizeof(thread.coded_blk)); + thread.cu_split_pos = 0; + + if ((ret = decode_cu_r(s, frame, &thread, &gb, cu_x << 6, cu_y << 6, 6, qp, sel_qp)) < 0) + break; + + if (s->deblock) { + thread.cu_split_pos = 0; + deblock_cu_r(s, frame, &thread, cu_x << 6, cu_y << 6, 6, qp); + } + + if (s->avctx->active_thread_type & FF_THREAD_SLICE) + ff_thread_progress_report(&s->progress[cu_y], cu_x + 1); + } + + if (s->avctx->active_thread_type & FF_THREAD_SLICE) + ff_thread_progress_report(&s->progress[cu_y], INT_MAX); + + return ret; +} + +static int rv60_decode_frame(AVCodecContext *avctx, AVFrame * frame, + int * got_frame, AVPacket * avpkt) +{ + RV60Context *s = avctx->priv_data; + GetBitContext gb; + int ret, header_size, width, height, ofs; + + if (avpkt->size == 0) { + if (s->last_frame[NEXT_PIC]->data[0]) { + av_frame_move_ref(frame, s->last_frame[NEXT_PIC]); + *got_frame = 1; + } + return 0; + } + + if (avpkt->size < 9) + return AVERROR_INVALIDDATA; + + header_size = avpkt->data[0] * 8 + 9; + if (avpkt->size < header_size) + return AVERROR_INVALIDDATA; + + if ((ret = init_get_bits8(&gb, avpkt->data + header_size, avpkt->size - header_size)) < 0) + return ret; + + if ((ret = read_frame_header(s, &gb, &width, &height)) < 0) + return ret; + + if (avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B || + avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I || + avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + + if (s->pict_type != AV_PICTURE_TYPE_B) + FFSWAP(AVFrame *, s->last_frame[NEXT_PIC], s->last_frame[LAST_PIC]); + + if ((s->pict_type == AV_PICTURE_TYPE_P && !s->last_frame[LAST_PIC]->data[0]) || + (s->pict_type == AV_PICTURE_TYPE_B && (!s->last_frame[LAST_PIC]->data[0] || !s->last_frame[NEXT_PIC]->data[0]))) { + av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n"); + return AVERROR_INVALIDDATA; + } + + s->last_frame[CUR_PIC]->pict_type = s->pict_type; + if (s->pict_type == AV_PICTURE_TYPE_I) + s->last_frame[CUR_PIC]->flags |= AV_FRAME_FLAG_KEY; + + if ((ret = update_dimensions_clear_info(s, width, height)) < 0) + return ret; + + if (!s->last_frame[CUR_PIC]->data[0]) + if ((ret = ff_get_buffer(avctx, s->last_frame[CUR_PIC], 0)) < 0) + return ret; + + if ((ret = read_slice_sizes(s, &gb)) < 0) + return ret; + + ofs = get_bits_count(&gb) / 8; + + for (int i = 0; i < s->cu_height; i++) { + if (ofs >= avpkt->size - header_size) + return AVERROR_INVALIDDATA; + s->slice[i].data = avpkt->data + header_size + ofs; + s->slice[i].data_size = FFMIN(s->slice[i].size, avpkt->size - header_size - ofs); + if (s->slice[i].size > INT32_MAX - ofs) + return AVERROR_INVALIDDATA; + ofs += s->slice[i].size; + } + + ret = progress_init(s, s->cu_height); + if (ret < 0) + return ret; + + s->avctx->execute2(s->avctx, decode_slice, s->last_frame[CUR_PIC], NULL, s->cu_height); + + ret = 0; + if (s->pict_type == AV_PICTURE_TYPE_B) + av_frame_move_ref(frame, s->last_frame[CUR_PIC]); + else if (s->last_frame[LAST_PIC]->data[0]) + ret = av_frame_ref(frame, s->last_frame[LAST_PIC]); + if (ret < 0) + return ret; + + if (frame->data[0]) + *got_frame = 1; + + if (s->pict_type != AV_PICTURE_TYPE_B) { + av_frame_unref(s->last_frame[NEXT_PIC]); + FFSWAP(AVFrame *, s->last_frame[CUR_PIC], s->last_frame[NEXT_PIC]); + } + + if (s->pict_type != AV_PICTURE_TYPE_B) { + s->ref_pts[0] = s->ref_pts[1]; + s->ref_pts[1] = avpkt->pts; + + s->ref_ts[0] = s->ref_ts[1]; + s->ref_ts[1] = s->ts; + + if (s->ref_pts[1] > s->ref_pts[0] && s->ref_ts[1] > s->ref_ts[0]) + s->ts_scale = (s->ref_pts[1] - s->ref_pts[0]) / (s->ref_ts[1] - s->ref_ts[0]); + } else { + frame->pts = s->ref_pts[0] + (s->ts - s->ref_ts[0]) * s->ts_scale; + } + + return avpkt->size; +} + +static void rv60_flush(AVCodecContext *avctx) +{ + RV60Context *s = avctx->priv_data; + + for (int i = 0; i < 3; i++) + av_frame_unref(s->last_frame[i]); +} + +static av_cold int rv60_decode_end(AVCodecContext * avctx) +{ + RV60Context *s = avctx->priv_data; + + for (int i = 0; i < 3; i++) + av_frame_free(&s->last_frame[i]); + + av_freep(&s->slice); + av_freep(&s->pu_info); + av_freep(&s->blk_info); + av_freep(&s->top_str); + av_freep(&s->left_str); + + for (int i = 0; i < s->nb_progress; i++) + ff_thread_progress_destroy(&s->progress[i]); + av_freep(&s->progress); + + return 0; +} + +const FFCodec ff_rv60_decoder = { + .p.name = "rv60", + CODEC_LONG_NAME("RealVideo 6.0"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_RV60, + .priv_data_size = sizeof(RV60Context), + .init = rv60_decode_init, + .close = rv60_decode_end, + FF_CODEC_DECODE_CB(rv60_decode_frame), + .flush = rv60_flush, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/rv60dsp.c b/libavcodec/rv60dsp.c new file mode 100644 index 0000000000..a891c0d092 --- /dev/null +++ b/libavcodec/rv60dsp.c @@ -0,0 +1,164 @@ +/* + * RV60 dsp routines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "rv60dsp.h" +#include "libavutil/common.h" + +void ff_rv60_idct4x4_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int tmp[16]; +#define IDCT4X4(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 4; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int t0 = 13 * (a + c); \ + int t1 = 13 * (a - c); \ + int t2 = 7 * b - 17 * d; \ + int t3 = 7 * d + 17 * b; \ + STORE(dst[y*dst_stride + 0*dst_step], (t0 + t3 + 16) >> 5); \ + STORE(dst[y*dst_stride + 1*dst_step], (t1 + t2 + 16) >> 5); \ + STORE(dst[y*dst_stride + 2*dst_step], (t1 - t2 + 16) >> 5); \ + STORE(dst[y*dst_stride + 3*dst_step], (t0 - t3 + 16) >> 5); \ + } +#define STORE(a, b) a = b + IDCT4X4(block, 1, 4, tmp, 1, 4) +#undef STORE +#define STORE(a, b) a = av_clip_uint8(a + (b)) + IDCT4X4(tmp, 4, 1, dst, dst_stride, 1) +#undef STORE +} + +void ff_rv60_idct8x8_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int tmp[64]; +#define IDCT8X8(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 8; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int e = src[y*src_stride + 4*src_step]; \ + int f = src[y*src_stride + 5*src_step]; \ + int g = src[y*src_stride + 6*src_step]; \ + int h = src[y*src_stride + 7*src_step]; \ + int t0 = 37 * (a + e); \ + int t1 = 37 * (a - e); \ + int t2 = 48 * c + 20 * g; \ + int t3 = 20 * c - 48 * g; \ + int t4 = t0 + t2; \ + int t5 = t0 - t2; \ + int t6 = t1 + t3; \ + int t7 = t1 - t3; \ + int t8 = 51 * b + 43 * d + 29 * f + 10 * h; \ + int t9 = 43 * b - 10 * d - 51 * f - 29 * h; \ + int ta = 29 * b - 51 * d + 10 * f + 43 * h; \ + int tb = 10 * b - 29 * d + 43 * f - 51 * h; \ + STORE(dst[y*dst_stride + 0*dst_step], (t4 + t8 + 64) >> 7); \ + STORE(dst[y*dst_stride + 1*dst_step], (t6 + t9 + 64) >> 7); \ + STORE(dst[y*dst_stride + 2*dst_step], (t7 + ta + 64) >> 7); \ + STORE(dst[y*dst_stride + 3*dst_step], (t5 + tb + 64) >> 7); \ + STORE(dst[y*dst_stride + 4*dst_step], (t5 - tb + 64) >> 7); \ + STORE(dst[y*dst_stride + 5*dst_step], (t7 - ta + 64) >> 7); \ + STORE(dst[y*dst_stride + 6*dst_step], (t6 - t9 + 64) >> 7); \ + STORE(dst[y*dst_stride + 7*dst_step], (t4 - t8 + 64) >> 7); \ + } +#define STORE(a, b) a = b + IDCT8X8(block, 1, 8, tmp, 1, 8) +#undef STORE +#define STORE(a, b) a = av_clip_uint8(a + (b)) + IDCT8X8(tmp, 8, 1, dst, dst_stride, 1) +#undef STORE +} + +void ff_rv60_idct16x16_add(const int16_t * block, uint8_t * dst, int dst_stride) +{ + int16_t tmp[256]; +#define IDCT16X16(src, src_stride, src_step, dst, dst_stride, dst_step) \ + for (int y = 0; y < 16; y++) { \ + int a = src[y*src_stride + 0*src_step]; \ + int b = src[y*src_stride + 1*src_step]; \ + int c = src[y*src_stride + 2*src_step]; \ + int d = src[y*src_stride + 3*src_step]; \ + int e = src[y*src_stride + 4*src_step]; \ + int f = src[y*src_stride + 5*src_step]; \ + int g = src[y*src_stride + 6*src_step]; \ + int h = src[y*src_stride + 7*src_step]; \ + int i = src[y*src_stride + 8*src_step]; \ + int j = src[y*src_stride + 9*src_step]; \ + int k = src[y*src_stride + 10*src_step]; \ + int l = src[y*src_stride + 11*src_step]; \ + int m = src[y*src_stride + 12*src_step]; \ + int n = src[y*src_stride + 13*src_step]; \ + int o = src[y*src_stride + 14*src_step]; \ + int p = src[y*src_stride + 15*src_step]; \ + int t0 = 26 * (a + i); \ + int t1 = 26 * (a - i); \ + int t2 = 14 * e - 34 * m; \ + int t3 = 34 * e + 14 * m; \ + int t4 = t0 + t3; \ + int t5 = t0 - t3; \ + int t6 = t1 + t2; \ + int t7 = t1 - t2; \ + int tmp00 = 31 * c - 7 * g - 36 * k - 20 * o; \ + int tmp01 = 36 * c + 31 * g + 20 * k + 7 * o; \ + int tmp02 = 20 * c - 36 * g + 7 * k + 31 * o; \ + int tmp03 = 7 * c - 20 * g + 31 * k - 36 * o; \ + int tm0 = t4 + tmp01; \ + int tm1 = t4 - tmp01; \ + int tm2 = t5 + tmp03; \ + int tm3 = t5 - tmp03; \ + int tm4 = t6 + tmp00; \ + int tm5 = t6 - tmp00; \ + int tm6 = t7 + tmp02; \ + int tm7 = t7 - tmp02; \ + int tt0 = 37 * b + 35 * d + 32 * f + 28 * h + 23 * j + 17 * l + 11 * n + 4 * p; \ + int tt1 = 35 * b + 23 * d + 4 * f - 17 * h - 32 * j - 37 * l - 28 * n - 11 * p; \ + int tt2 = 32 * b + 4 * d - 28 * f - 35 * h - 11 * j + 23 * l + 37 * n + 17 * p; \ + int tt3 = 28 * b - 17 * d - 35 * f + 4 * h + 37 * j + 11 * l - 32 * n - 23 * p; \ + int tt4 = 23 * b - 32 * d - 11 * f + 37 * h - 4 * j - 35 * l + 17 * n + 28 * p; \ + int tt5 = 17 * b - 37 * d + 23 * f + 11 * h - 35 * j + 28 * l + 4 * n - 32 * p; \ + int tt6 = 11 * b - 28 * d + 37 * f - 32 * h + 17 * j + 4 * l - 23 * n + 35 * p; \ + int tt7 = 4 * b - 11 * d + 17 * f - 23 * h + 28 * j - 32 * l + 35 * n - 37 * p; \ + STORE(dst[y*dst_stride+ 0*dst_step], (tm0 + tt0 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 1*dst_step], (tm4 + tt1 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 2*dst_step], (tm6 + tt2 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 3*dst_step], (tm2 + tt3 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 4*dst_step], (tm3 + tt4 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 5*dst_step], (tm7 + tt5 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 6*dst_step], (tm5 + tt6 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 7*dst_step], (tm1 + tt7 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 8*dst_step], (tm1 - tt7 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 9*dst_step], (tm5 - tt6 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 10*dst_step], (tm7 - tt5 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 11*dst_step], (tm3 - tt4 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 12*dst_step], (tm2 - tt3 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 13*dst_step], (tm6 - tt2 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 14*dst_step], (tm4 - tt1 + 64) >> 7); \ + STORE(dst[y*dst_stride+ 15*dst_step], (tm0 - tt0 + 64) >> 7); \ + } +#define STORE(a, x) a = av_clip_intp2(x, 15) + IDCT16X16(block, 1, 16, tmp, 1, 16) +#undef STORE +#define STORE(a, x) a = av_clip_uint8(a + (x)) + IDCT16X16(tmp, 16, 1, dst, dst_stride, 1) +#undef STORE +} diff --git a/libavcodec/rv60dsp.h b/libavcodec/rv60dsp.h new file mode 100644 index 0000000000..99448517b6 --- /dev/null +++ b/libavcodec/rv60dsp.h @@ -0,0 +1,30 @@ +/* + * RV60 dsp routines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_RV60DSP_H +#define AVCODEC_RV60DSP_H + +#include + +void ff_rv60_idct4x4_add(const int16_t * block, uint8_t * dst, int dst_stride); +void ff_rv60_idct8x8_add(const int16_t * block, uint8_t * dst, int dst_stride); +void ff_rv60_idct16x16_add(const int16_t * block, uint8_t * dst, int dst_stride); + +#endif /* AVCODEC_RV60DSP_H */ diff --git a/libavcodec/rv60vlcs.h b/libavcodec/rv60vlcs.h new file mode 100644 index 0000000000..d2a8a6d93e --- /dev/null +++ b/libavcodec/rv60vlcs.h @@ -0,0 +1,2315 @@ +/* + * RV60 decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RV60VLCS_H +#define AVCODEC_RV60VLCS_H + +#include + +static const uint8_t rv60_cbp8_lens[7][4][64] = { + { + { 7, 7, 7, 7, 7, 7, 8, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 4, + 9, 9, 9, 7, 9, 7, 8, 5, 9, 8, 7, 5, 7, 5, 5, 2 }, + { 7, 4, 9, 4, 12, 6, 10, 5, 14, 9, 12, 8, 12, 7, 11, 3, + 9, 5, 11, 6, 12, 6, 11, 4, 14, 9, 13, 8, 12, 7, 11, 3, + 10, 5, 12, 6, 14, 6, 13, 6, 15, 11, 15, 10, 15, 9, 13, 5, + 11, 5, 14, 5, 13, 5, 12, 4, 15, 10, 14, 8, 14, 7, 12, 3 }, + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6, 3, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 9, 9, 9, 10, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 9, 9, 10, 8, 9, 8, 9, 7, 9, 9, 9, 7, 8, 7, 7, 2 }, + { 8, 4, 7, 4, 10, 5, 9, 4, 12, 8, 10, 7, 11, 7, 9, 4, + 9, 5, 10, 5, 10, 6, 11, 5, 14, 9, 13, 8, 12, 7, 10, 3, + 11, 6, 12, 6, 13, 7, 13, 6, 15, 11, 14, 9, 14, 10, 13, 5, + 11, 6, 12, 6, 12, 6, 13, 5, 15, 10, 14, 9, 14, 8, 12, 2 } + }, + { + { 7, 7, 7, 7, 7, 7, 8, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 4, + 9, 9, 9, 7, 9, 7, 8, 5, 9, 8, 7, 5, 7, 5, 5, 2 }, + { 7, 4, 9, 4, 12, 6, 10, 5, 14, 9, 12, 8, 12, 7, 11, 3, + 9, 5, 11, 6, 12, 6, 11, 4, 14, 9, 13, 8, 12, 7, 11, 3, + 10, 5, 12, 6, 14, 6, 13, 6, 15, 11, 15, 10, 15, 9, 13, 5, + 11, 5, 14, 5, 13, 5, 12, 4, 15, 10, 14, 8, 14, 7, 12, 3 }, + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6, 3, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 9, 9, 9, 9, 10, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 9, 9, 10, 8, 9, 8, 9, 7, 9, 9, 9, 7, 8, 7, 7, 2 }, + { 8, 4, 7, 4, 10, 5, 9, 4, 12, 8, 10, 7, 11, 7, 9, 4, + 9, 5, 10, 5, 10, 6, 11, 5, 14, 9, 13, 8, 12, 7, 10, 3, + 11, 6, 12, 6, 13, 7, 13, 6, 15, 11, 14, 9, 14, 10, 13, 5, + 11, 6, 12, 6, 12, 6, 13, 5, 15, 10, 14, 9, 14, 8, 12, 2 } + }, + { + { 5, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 5, 6, 6, 5, 4, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 8, 8, 8, 9, 7, 8, 9, 8, 7, 8, 7, 7, 5, + 8, 8, 9, 7, 8, 7, 8, 6, 9, 8, 7, 6, 7, 6, 6, 2 }, + { 5, 2, 9, 5, 9, 5, 10, 4, 9, 7, 10, 6, 10, 6, 9, 3, + 8, 4, 11, 6, 9, 5, 11, 5, 11, 8, 12, 8, 11, 8, 11, 5, + 9, 5, 13, 7, 13, 7, 14, 7, 14, 10, 14, 9, 14, 9, 13, 6, + 10, 5, 14, 6, 12, 5, 14, 5, 14, 10, 14, 9, 14, 8, 14, 5 }, + { 4, 5, 6, 5, 5, 6, 6, 5, 5, 6, 5, 5, 5, 5, 5, 3, + 7, 7, 8, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 9, 9, 10, 9, 9, 9, 10, 8, 9, 10, 9, 8, 8, 8, 8, 5, + 10, 10, 10, 9, 10, 9, 10, 7, 10, 10, 9, 7, 9, 7, 7, 4 }, + { 6, 3, 7, 4, 8, 4, 8, 4, 9, 7, 9, 6, 8, 6, 7, 3, + 9, 5, 10, 6, 9, 5, 10, 5, 12, 9, 11, 8, 10, 6, 9, 3, + 10, 5, 12, 7, 12, 7, 12, 7, 14, 11, 13, 9, 13, 9, 11, 5, + 10, 6, 12, 7, 11, 7, 13, 6, 14, 11, 13, 9, 13, 8, 11, 4 } + }, + { + { 4, 5, 5, 5, 6, 6, 7, 6, 5, 6, 5, 5, 6, 5, 5, 4, + 7, 7, 7, 7, 8, 7, 8, 6, 8, 8, 7, 6, 7, 6, 6, 4, + 8, 8, 8, 8, 8, 8, 9, 7, 8, 9, 7, 7, 8, 7, 7, 5, + 8, 8, 9, 7, 8, 7, 9, 6, 9, 9, 7, 6, 7, 6, 6, 3 }, + { 3, 2, 9, 4, 9, 4, 11, 5, 9, 7, 10, 7, 11, 7, 10, 5, + 7, 4, 12, 6, 10, 5, 13, 6, 13, 9, 14, 9, 13, 9, 14, 6, + 7, 4, 13, 6, 12, 6, 14, 7, 14, 10, 14, 10, 14, 10, 15, 8, + 9, 4, 13, 6, 12, 6, 15, 6, 14, 10, 15, 9, 15, 9, 14, 6 }, + { 3, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 4, 5, 5, 3, + 7, 7, 8, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 7, 6, 4, + 8, 9, 9, 8, 9, 8, 9, 8, 9, 9, 8, 8, 8, 8, 8, 6, + 10, 10, 10, 9, 9, 8, 10, 8, 10, 10, 9, 8, 8, 8, 8, 5 }, + { 5, 2, 7, 4, 7, 4, 8, 4, 9, 6, 8, 6, 8, 5, 7, 3, + 8, 4, 10, 6, 9, 6, 10, 6, 12, 9, 11, 8, 10, 7, 9, 5, + 9, 5, 11, 7, 11, 7, 12, 7, 14, 10, 12, 9, 13, 9, 11, 6, + 10, 6, 12, 7, 11, 7, 12, 7, 14, 11, 13, 9, 13, 9, 12, 6 } + }, + { + { 4, 5, 5, 5, 5, 5, 6, 6, 5, 6, 5, 5, 5, 5, 5, 4, + 7, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 7, 6, 4, + 7, 8, 8, 8, 8, 8, 9, 7, 8, 9, 7, 7, 8, 7, 7, 5, + 8, 8, 8, 7, 8, 7, 9, 6, 9, 8, 7, 6, 7, 6, 6, 4 }, + { 3, 1, 9, 5, 10, 5, 13, 6, 11, 9, 12, 8, 15, 10, 14, 8, + 7, 4, 13, 6, 12, 6, 15, 7, 15, 11, 15, 11, 15, 11, 15, 8, + 7, 4, 13, 7, 13, 7, 15, 8, 15, 12, 15, 11, 15, 12, 15, 9, + 9, 5, 14, 6, 13, 7, 15, 7, 15, 12, 15, 11, 15, 11, 15, 7 }, + { 3, 4, 4, 4, 4, 5, 6, 5, 4, 6, 5, 5, 4, 5, 5, 4, + 7, 8, 8, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 6, + 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 6, + 10, 10, 10, 9, 9, 9, 10, 9, 10, 10, 9, 9, 9, 9, 9, 7 }, + { 5, 1, 7, 4, 7, 4, 8, 5, 10, 7, 8, 6, 8, 6, 7, 4, + 8, 5, 10, 6, 10, 7, 11, 7, 12, 10, 11, 9, 11, 9, 10, 7, + 9, 5, 11, 7, 11, 7, 11, 8, 13, 11, 12, 9, 12, 10, 11, 8, + 9, 7, 11, 8, 12, 8, 13, 8, 14, 12, 13, 10, 14, 11, 12, 8 } + }, + { + { 3, 5, 5, 5, 5, 5, 6, 6, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 5, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 9, 7, 7, 8, 7, 7, 6, + 8, 8, 8, 7, 8, 7, 9, 6, 8, 9, 7, 7, 8, 7, 7, 4 }, + { 2, 1, 10, 5, 10, 6, 15, 8, 14, 11, 14, 10, 15, 11, 15, 9, + 7, 4, 13, 7, 13, 7, 15, 8, 15, 13, 15, 12, 15, 12, 15, 10, + 7, 5, 13, 8, 13, 8, 15, 10, 15, 14, 15, 12, 15, 13, 15, 10, + 9, 5, 14, 7, 14, 8, 15, 8, 15, 13, 15, 12, 15, 12, 15, 9 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 4, 5, 5, 5, + 7, 8, 8, 8, 7, 8, 9, 8, 7, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 10, 8, 9, 8, 9, 9, 7, + 9, 10, 10, 10, 9, 9, 11, 9, 10, 11, 10, 10, 9, 10, 10, 8 }, + { 4, 1, 6, 4, 6, 4, 8, 5, 9, 8, 8, 7, 8, 7, 7, 6, + 8, 4, 9, 6, 9, 7, 11, 8, 12, 10, 11, 10, 11, 10, 11, 8, + 8, 5, 10, 7, 10, 8, 11, 9, 13, 11, 11, 10, 12, 10, 11, 9, + 9, 6, 11, 8, 12, 9, 13, 9, 14, 13, 13, 11, 14, 11, 13, 9 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 6, 4, 6, 5, 6, 5, 6, 5, 5, + 6, 7, 7, 7, 7, 8, 8, 8, 7, 8, 7, 8, 7, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7 }, + { 1, 2, 9, 5, 9, 6, 14, 8, 14, 11, 14, 11, 14, 11, 14, 10, + 6, 4, 12, 7, 13, 8, 14, 10, 14, 14, 14, 13, 14, 13, 14, 12, + 6, 5, 13, 8, 13, 9, 14, 11, 14, 14, 14, 13, 14, 14, 14, 12, + 7, 5, 14, 8, 14, 9, 14, 11, 14, 14, 14, 14, 14, 14, 14, 12 }, + { 1, 4, 4, 6, 4, 5, 6, 7, 4, 6, 5, 7, 5, 7, 7, 7, + 7, 8, 9, 9, 8, 9, 10, 10, 8, 10, 9, 11, 9, 10, 10, 10, + 7, 9, 9, 10, 9, 9, 10, 10, 9, 11, 10, 11, 10, 10, 10, 10, + 9, 11, 11, 11, 10, 11, 12, 12, 11, 12, 11, 12, 11, 12, 12, 11 }, + { 2, 1, 6, 4, 7, 5, 9, 8, 10, 9, 9, 8, 10, 9, 9, 8, + 8, 5, 11, 8, 11, 9, 13, 11, 14, 13, 13, 12, 14, 12, 14, 11, + 8, 5, 11, 8, 12, 9, 13, 11, 14, 13, 14, 12, 13, 13, 13, 12, + 9, 6, 12, 9, 13, 10, 14, 12, 14, 14, 14, 13, 14, 14, 14, 12 } + } +}; + +static const uint8_t rv60_cbp16_lens[7][3][4][64] = { + { + { + { 9, 6, 7, 4, 11, 6, 10, 5, 11, 8, 10, 6, 12, 8, 11, 5, + 10, 6, 9, 5, 12, 6, 11, 5, 12, 9, 11, 7, 13, 8, 11, 4, + 10, 7, 8, 5, 12, 7, 11, 5, 12, 9, 11, 7, 14, 9, 12, 3, + 11, 6, 10, 5, 13, 5, 13, 4, 14, 9, 13, 7, 13, 7, 12, 2 }, + { 1, 3, 6, 3, 6, 5, 8, 5, 9, 8, 10, 8, 9, 7, 10, 6, + 6, 7, 9, 6, 9, 8, 10, 8, 11, 11, 11, 10, 11, 8, 10, 7, + 6, 7, 11, 7, 11, 10, 14, 11, 15, 15, 15, 14, 15, 13, 16, 12, + 10, 9, 12, 8, 12, 10, 14, 9, 16, 14, 14, 11, 15, 11, 13, 9 }, + { 1, 3, 6, 5, 6, 5, 8, 6, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 6, 10, 8, 9, 7, 10, 7, 11, 10, 12, 9, 11, 8, 9, 5, + 5, 6, 10, 9, 10, 8, 12, 10, 12, 12, 14, 12, 13, 11, 14, 10, + 9, 8, 12, 9, 11, 7, 13, 8, 13, 12, 14, 11, 14, 9, 13, 6 }, + { 1, 4, 6, 6, 4, 4, 7, 5, 7, 7, 9, 8, 7, 5, 8, 5, + 7, 8, 10, 9, 9, 6, 9, 6, 11, 9, 10, 8, 9, 5, 8, 5, + 7, 12, 13, 13, 13, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 11, + 12, 12, 13, 12, 13, 11, 12, 10, 13, 12, 12, 10, 12, 10, 10, 8 } + }, + { + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 5, 7, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 } + }, + { + { 9, 6, 7, 4, 10, 7, 9, 5, 10, 7, 9, 6, 11, 7, 8, 3, + 10, 7, 9, 6, 10, 6, 10, 5, 12, 8, 10, 6, 11, 6, 9, 3, + 11, 8, 9, 7, 13, 8, 12, 7, 13, 10, 12, 8, 13, 9, 11, 4, + 11, 8, 10, 7, 12, 6, 11, 4, 13, 8, 12, 7, 12, 6, 10, 2 }, + { 2, 3, 6, 4, 5, 4, 7, 4, 7, 7, 9, 7, 8, 5, 8, 4, + 5, 6, 8, 7, 7, 6, 8, 6, 10, 9, 11, 9, 10, 7, 10, 5, + 7, 6, 11, 8, 9, 7, 11, 8, 13, 12, 14, 12, 13, 10, 13, 7, + 9, 8, 11, 9, 10, 8, 12, 7, 13, 12, 14, 10, 12, 9, 13, 5 }, + { 2, 3, 5, 4, 6, 5, 7, 5, 7, 7, 8, 6, 8, 7, 8, 4, + 5, 5, 7, 6, 8, 6, 9, 6, 9, 8, 10, 8, 10, 8, 9, 4, + 6, 6, 9, 7, 10, 8, 11, 8, 11, 10, 11, 9, 12, 10, 11, 7, + 9, 8, 10, 8, 10, 7, 11, 7, 12, 10, 12, 9, 12, 9, 11, 5 }, + { 1, 3, 5, 6, 5, 5, 7, 5, 7, 7, 9, 7, 8, 5, 9, 5, + 6, 8, 10, 10, 9, 7, 11, 6, 11, 10, 12, 9, 11, 6, 11, 5, + 8, 10, 12, 11, 11, 10, 13, 10, 14, 13, 14, 12, 14, 11, 14, 8, + 11, 12, 14, 13, 13, 11, 14, 9, 14, 14, 14, 12, 14, 10, 13, 6 } + } + }, + { + { + { 9, 6, 7, 4, 11, 6, 10, 5, 11, 8, 10, 6, 12, 8, 11, 5, + 10, 6, 9, 5, 12, 6, 11, 5, 12, 9, 11, 7, 13, 8, 11, 4, + 10, 7, 8, 5, 12, 7, 11, 5, 12, 9, 11, 7, 14, 9, 12, 3, + 11, 6, 10, 5, 13, 5, 13, 4, 14, 9, 13, 7, 13, 7, 12, 2 }, + { 1, 3, 6, 3, 6, 5, 8, 5, 9, 8, 10, 8, 9, 7, 10, 6, + 6, 7, 9, 6, 9, 8, 10, 8, 11, 11, 11, 10, 11, 8, 10, 7, + 6, 7, 11, 7, 11, 10, 14, 11, 15, 15, 15, 14, 15, 13, 16, 12, + 10, 9, 12, 8, 12, 10, 14, 9, 16, 14, 14, 11, 15, 11, 13, 9 }, + { 1, 3, 6, 5, 6, 5, 8, 6, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 6, 10, 8, 9, 7, 10, 7, 11, 10, 12, 9, 11, 8, 9, 5, + 5, 6, 10, 9, 10, 8, 12, 10, 12, 12, 14, 12, 13, 11, 14, 10, + 9, 8, 12, 9, 11, 7, 13, 8, 13, 12, 14, 11, 14, 9, 13, 6 }, + { 1, 4, 6, 6, 4, 4, 7, 5, 7, 7, 9, 8, 7, 5, 8, 5, + 7, 8, 10, 9, 9, 6, 9, 6, 11, 9, 10, 8, 9, 5, 8, 5, + 7, 12, 13, 13, 13, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 11, + 12, 12, 13, 12, 13, 11, 12, 10, 13, 12, 12, 10, 12, 10, 10, 8 } + }, + { + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 5, 7, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 }, + { 4, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 8, 9, 8, 8, 5, + 8, 9, 9, 8, 9, 8, 9, 7, 9, 9, 8, 7, 8, 7, 7, 2 } + }, + { + { 9, 6, 7, 4, 10, 7, 9, 5, 10, 7, 9, 6, 11, 7, 8, 3, + 10, 7, 9, 6, 10, 6, 10, 5, 12, 8, 10, 6, 11, 6, 9, 3, + 11, 8, 9, 7, 13, 8, 12, 7, 13, 10, 12, 8, 13, 9, 11, 4, + 11, 8, 10, 7, 12, 6, 11, 4, 13, 8, 12, 7, 12, 6, 10, 2 }, + { 2, 3, 6, 4, 5, 4, 7, 4, 7, 7, 9, 7, 8, 5, 8, 4, + 5, 6, 8, 7, 7, 6, 8, 6, 10, 9, 11, 9, 10, 7, 10, 5, + 7, 6, 11, 8, 9, 7, 11, 8, 13, 12, 14, 12, 13, 10, 13, 7, + 9, 8, 11, 9, 10, 8, 12, 7, 13, 12, 14, 10, 12, 9, 13, 5 }, + { 2, 3, 5, 4, 6, 5, 7, 5, 7, 7, 8, 6, 8, 7, 8, 4, + 5, 5, 7, 6, 8, 6, 9, 6, 9, 8, 10, 8, 10, 8, 9, 4, + 6, 6, 9, 7, 10, 8, 11, 8, 11, 10, 11, 9, 12, 10, 11, 7, + 9, 8, 10, 8, 10, 7, 11, 7, 12, 10, 12, 9, 12, 9, 11, 5 }, + { 1, 3, 5, 6, 5, 5, 7, 5, 7, 7, 9, 7, 8, 5, 9, 5, + 6, 8, 10, 10, 9, 7, 11, 6, 11, 10, 12, 9, 11, 6, 11, 5, + 8, 10, 12, 11, 11, 10, 13, 10, 14, 13, 14, 12, 14, 11, 14, 8, + 11, 12, 14, 13, 13, 11, 14, 9, 14, 14, 14, 12, 14, 10, 13, 6 } + } + }, + { + { + { 7, 4, 7, 4, 9, 5, 10, 4, 9, 7, 10, 7, 11, 7, 12, 5, + 7, 4, 9, 5, 8, 5, 10, 4, 9, 8, 11, 7, 10, 7, 11, 5, + 8, 5, 10, 6, 10, 6, 12, 5, 12, 9, 14, 8, 12, 8, 13, 5, + 9, 5, 11, 5, 10, 5, 11, 3, 11, 8, 12, 7, 11, 7, 14, 4 }, + { 1, 3, 4, 4, 4, 5, 6, 6, 6, 8, 7, 8, 8, 8, 8, 7, + 6, 7, 8, 7, 8, 8, 10, 8, 9, 10, 10, 11, 10, 10, 11, 10, + 8, 9, 12, 9, 12, 11, 14, 11, 14, 14, 14, 14, 14, 13, 14, 13, + 10, 9, 13, 9, 14, 10, 14, 10, 14, 14, 14, 13, 14, 13, 14, 10 }, + { 1, 3, 5, 5, 5, 5, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 8, 8, 7, 6, 8, 6, 8, 8, 9, 8, 8, 6, 8, 6, + 7, 8, 11, 11, 11, 10, 14, 12, 13, 14, 14, 12, 14, 13, 14, 11, + 10, 9, 13, 11, 11, 8, 13, 9, 14, 13, 14, 12, 13, 10, 14, 9 }, + { 1, 3, 5, 6, 3, 4, 7, 7, 6, 7, 9, 10, 7, 7, 10, 9, + 5, 7, 8, 9, 7, 7, 9, 10, 8, 9, 10, 11, 9, 9, 12, 10, + 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 13 } + }, + { + { 3, 4, 5, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 7, 7, 4, + 8, 9, 9, 8, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 6, + 9, 10, 10, 8, 10, 8, 10, 7, 10, 10, 9, 8, 9, 8, 8, 4 }, + { 3, 5, 4, 5, 5, 5, 6, 5, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 6, 7, 7, 7, 4, + 8, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 6, + 9, 10, 10, 8, 10, 9, 10, 7, 10, 10, 9, 7, 9, 8, 8, 4 }, + { 3, 4, 5, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 7, 4, + 7, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 8, 8, 8, 6, + 9, 9, 10, 9, 9, 9, 10, 7, 10, 10, 9, 8, 8, 7, 8, 4 }, + { 3, 5, 4, 5, 5, 5, 6, 6, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 7, 7, 7, 7, 6, 4, + 7, 9, 9, 9, 9, 9, 10, 8, 9, 10, 9, 8, 9, 8, 8, 5, + 9, 10, 10, 9, 10, 9, 10, 8, 10, 10, 9, 8, 8, 8, 7, 4 } + }, + { + { 7, 4, 6, 4, 8, 5, 8, 4, 9, 6, 8, 5, 9, 6, 7, 3, + 8, 4, 9, 5, 9, 5, 9, 5, 10, 7, 10, 6, 10, 7, 9, 4, + 9, 6, 10, 7, 11, 6, 11, 5, 13, 9, 11, 8, 12, 8, 10, 5, + 9, 6, 11, 6, 10, 6, 11, 5, 13, 8, 12, 7, 12, 7, 11, 4 }, + { 1, 3, 5, 5, 4, 4, 8, 5, 8, 8, 9, 7, 8, 7, 9, 5, + 6, 7, 9, 8, 8, 7, 11, 8, 11, 10, 12, 11, 11, 9, 12, 7, + 8, 9, 13, 10, 11, 9, 13, 10, 14, 14, 15, 13, 14, 11, 14, 8, + 10, 10, 12, 9, 12, 10, 13, 9, 15, 14, 15, 11, 15, 11, 14, 7 }, + { 1, 3, 5, 5, 6, 6, 7, 6, 6, 7, 7, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 9, 7, 9, 7, 10, 9, 10, 8, 9, 7, 8, 5, + 7, 8, 11, 10, 11, 9, 13, 10, 11, 12, 11, 11, 13, 11, 12, 8, + 9, 8, 12, 10, 11, 8, 12, 9, 14, 12, 14, 11, 13, 10, 12, 7 }, + { 1, 3, 6, 6, 4, 3, 7, 5, 7, 7, 9, 8, 8, 6, 9, 6, + 7, 8, 10, 10, 8, 7, 10, 8, 10, 9, 12, 10, 10, 8, 11, 7, + 10, 11, 13, 12, 11, 10, 14, 11, 14, 14, 14, 13, 14, 12, 13, 9, + 13, 13, 14, 13, 14, 11, 14, 11, 14, 13, 14, 13, 14, 11, 14, 9 } + } + }, + { + { + { 7, 3, 7, 4, 9, 4, 11, 4, 10, 8, 11, 7, 13, 7, 13, 5, + 6, 4, 9, 5, 9, 5, 12, 5, 11, 9, 13, 8, 13, 8, 15, 6, + 8, 5, 11, 5, 12, 6, 14, 6, 14, 10, 15, 9, 15, 9, 15, 6, + 8, 4, 12, 4, 12, 4, 15, 4, 13, 9, 15, 8, 15, 8, 15, 5 }, + { 1, 3, 4, 3, 5, 5, 7, 5, 8, 9, 8, 8, 9, 8, 9, 7, + 6, 7, 10, 7, 10, 8, 13, 9, 12, 13, 13, 13, 13, 13, 13, 11, + 9, 9, 12, 9, 12, 11, 13, 12, 13, 13, 13, 13, 13, 13, 13, 12, + 11, 9, 12, 9, 13, 11, 13, 10, 13, 13, 13, 13, 13, 13, 13, 11 }, + { 1, 3, 5, 5, 5, 5, 7, 7, 5, 7, 7, 7, 7, 8, 7, 8, + 4, 6, 8, 8, 6, 6, 9, 9, 8, 9, 11, 10, 9, 9, 11, 9, + 7, 9, 13, 12, 12, 9, 13, 12, 13, 14, 13, 12, 14, 14, 14, 12, + 10, 9, 13, 11, 12, 9, 13, 11, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 3, 5, 6, 3, 4, 7, 7, 6, 7, 10, 9, 8, 7, 10, 8, + 4, 9, 11, 11, 8, 10, 11, 12, 10, 11, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 5, 5, 6, 5, 5, 5, 6, 6, 4, + 6, 7, 7, 7, 7, 7, 8, 7, 7, 8, 8, 7, 7, 7, 8, 6, + 7, 9, 9, 8, 9, 9, 10, 8, 9, 10, 9, 9, 9, 9, 9, 6, + 9, 10, 10, 9, 10, 9, 10, 8, 10, 10, 9, 9, 9, 9, 9, 6 }, + { 2, 4, 4, 5, 5, 5, 6, 5, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 7, 7, 7, 8, 8, 9, 7, 8, 9, 8, 7, 7, 8, 7, 6, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 8, 9, 9, 8, 6, + 9, 10, 10, 9, 10, 9, 10, 9, 10, 10, 9, 8, 9, 9, 9, 6 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 6, 5, 5, 6, 4, + 6, 7, 8, 7, 7, 8, 9, 7, 8, 9, 8, 8, 7, 7, 8, 6, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 9, 9, 8, 9, 7, + 9, 10, 10, 9, 10, 9, 11, 9, 10, 11, 10, 9, 9, 8, 9, 6 }, + { 2, 5, 4, 5, 4, 5, 6, 6, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 8, 7, 8, 7, 5, + 7, 9, 9, 9, 9, 9, 10, 9, 9, 10, 9, 8, 9, 9, 8, 6, + 9, 10, 10, 9, 10, 9, 10, 9, 10, 10, 9, 9, 9, 9, 8, 6 } + }, + { + { 6, 2, 6, 4, 7, 4, 8, 4, 9, 6, 8, 6, 9, 6, 8, 4, + 7, 4, 9, 5, 9, 5, 10, 6, 11, 8, 10, 7, 11, 7, 10, 5, + 8, 5, 10, 6, 10, 6, 11, 6, 12, 9, 12, 8, 12, 9, 11, 6, + 9, 6, 11, 7, 10, 6, 11, 6, 12, 10, 12, 8, 12, 9, 11, 6 }, + { 1, 3, 5, 4, 4, 5, 6, 5, 7, 8, 9, 7, 8, 7, 8, 5, + 6, 7, 10, 8, 9, 8, 11, 8, 12, 12, 13, 10, 13, 10, 12, 8, + 8, 9, 12, 9, 11, 10, 13, 9, 14, 14, 14, 11, 14, 12, 13, 9, + 10, 10, 11, 9, 12, 11, 13, 9, 14, 14, 14, 11, 14, 12, 13, 8 }, + { 1, 3, 5, 5, 5, 5, 7, 6, 6, 7, 6, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 7, 7, 9, 7, 9, 9, 10, 9, 9, 8, 9, 7, + 7, 9, 11, 11, 11, 9, 12, 11, 11, 12, 12, 11, 13, 11, 12, 9, + 9, 8, 12, 11, 10, 9, 13, 10, 13, 13, 13, 12, 13, 11, 12, 9 }, + { 1, 3, 5, 6, 3, 4, 7, 5, 7, 7, 9, 8, 8, 6, 9, 6, + 6, 8, 11, 11, 9, 9, 12, 10, 11, 10, 13, 11, 12, 11, 12, 9, + 9, 11, 12, 11, 11, 10, 13, 11, 13, 13, 12, 12, 12, 12, 12, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10 } + } + }, + { + { + { 8, 2, 7, 4, 9, 4, 12, 4, 12, 9, 14, 8, 14, 8, 15, 5, + 7, 4, 10, 5, 11, 5, 14, 5, 13, 10, 15, 9, 15, 9, 15, 6, + 8, 4, 12, 6, 12, 6, 15, 6, 15, 11, 15, 10, 15, 10, 15, 7, + 9, 4, 13, 5, 13, 5, 15, 5, 15, 10, 15, 9, 15, 8, 15, 5 }, + { 1, 2, 4, 4, 5, 6, 8, 6, 10, 10, 11, 9, 11, 10, 12, 8, + 7, 7, 11, 8, 12, 9, 13, 9, 13, 13, 13, 13, 13, 13, 13, 9, + 8, 8, 12, 9, 13, 11, 13, 10, 13, 13, 13, 13, 13, 13, 13, 12, + 10, 9, 13, 9, 13, 10, 13, 10, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 5, 5, 5, 5, 9, 7, 6, 8, 8, 8, 8, 9, 10, 8, + 6, 6, 11, 9, 8, 7, 12, 9, 13, 11, 13, 11, 12, 10, 13, 9, + 7, 8, 13, 11, 13, 9, 13, 11, 13, 13, 13, 11, 13, 12, 13, 11, + 10, 9, 13, 11, 13, 9, 13, 10, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 6, 7, 3, 5, 9, 7, 8, 10, 10, 10, 10, 9, 11, 9, + 7, 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, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 10 } + }, + { + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 5, 5, 5, 4, + 6, 7, 8, 7, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 9, 8, 8, 8, 10, 8, 8, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 9, 10, 9, 11, 9, 10, 11, 10, 10, 10, 10, 10, 8 }, + { 2, 4, 4, 4, 4, 5, 6, 5, 4, 6, 5, 5, 5, 6, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 9, 9, 10, 9, 9, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 10, 10, 10, 11, 10, 10, 11, 10, 9, 10, 10, 10, 8 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 6, 4, 5, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 8, 9, 9, 8, 8, 10, 9, 9, 10, 9, 9, 9, 9, 9, 7, + 9, 10, 10, 10, 10, 9, 11, 10, 10, 11, 10, 10, 10, 10, 10, 8 }, + { 2, 4, 4, 5, 4, 5, 6, 5, 4, 6, 5, 5, 4, 6, 5, 4, + 6, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 8, 7, + 7, 9, 9, 9, 8, 9, 10, 9, 8, 10, 9, 9, 9, 9, 8, 7, + 9, 10, 10, 10, 10, 10, 11, 10, 10, 11, 10, 10, 10, 10, 9, 8 } + }, + { + { 7, 1, 7, 4, 7, 4, 9, 5, 9, 7, 9, 6, 10, 7, 9, 5, + 7, 4, 9, 6, 9, 6, 10, 7, 11, 9, 11, 8, 11, 9, 11, 7, + 8, 5, 10, 7, 10, 7, 11, 7, 12, 10, 11, 9, 12, 10, 11, 7, + 9, 6, 11, 7, 11, 8, 12, 8, 13, 10, 12, 9, 13, 10, 12, 8 }, + { 1, 3, 4, 4, 4, 5, 6, 5, 8, 8, 8, 7, 9, 8, 8, 6, + 7, 8, 9, 8, 10, 9, 11, 8, 13, 12, 12, 10, 13, 11, 12, 8, + 7, 9, 10, 8, 11, 10, 12, 9, 14, 14, 13, 10, 14, 12, 12, 9, + 9, 10, 11, 9, 12, 11, 14, 9, 14, 14, 14, 11, 14, 12, 13, 9 }, + { 1, 3, 4, 5, 5, 5, 7, 6, 6, 7, 6, 6, 7, 7, 7, 5, + 6, 6, 9, 8, 8, 8, 11, 9, 10, 10, 11, 10, 11, 10, 11, 9, + 7, 8, 10, 11, 10, 9, 13, 11, 11, 12, 12, 12, 12, 11, 12, 10, + 8, 9, 12, 11, 10, 9, 13, 12, 13, 13, 13, 13, 13, 12, 13, 11 }, + { 1, 2, 5, 6, 4, 4, 7, 7, 7, 8, 8, 8, 8, 7, 8, 7, + 8, 10, 12, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, + 9, 11, 12, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 } + } + }, + { + { + { 9, 2, 7, 4, 9, 4, 13, 5, 12, 10, 14, 9, 14, 9, 15, 6, + 7, 3, 11, 5, 12, 5, 15, 6, 15, 11, 15, 10, 15, 10, 15, 7, + 7, 4, 12, 6, 12, 6, 15, 7, 15, 11, 15, 11, 15, 11, 15, 8, + 9, 3, 13, 5, 13, 5, 15, 6, 15, 11, 15, 10, 15, 10, 15, 6 }, + { 1, 2, 4, 4, 6, 5, 9, 6, 10, 11, 12, 10, 11, 9, 12, 8, + 8, 7, 10, 8, 12, 9, 12, 9, 12, 12, 12, 12, 12, 12, 12, 10, + 7, 8, 12, 9, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 9, 12, 8, 12, 11, 12, 11, 12, 12, 12, 12, 12, 12, 12, 12 }, + { 1, 2, 5, 5, 6, 4, 10, 7, 8, 9, 9, 8, 10, 11, 11, 7, + 6, 6, 10, 9, 10, 8, 11, 10, 11, 11, 11, 10, 11, 11, 11, 10, + 7, 8, 11, 10, 11, 10, 11, 11, 11, 11, 10, 11, 11, 11, 11, 11, + 10, 8, 11, 10, 11, 9, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 3, 7, 5, 4, 5, 8, 7, 8, 7, 8, 8, 8, 8, 8, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } + }, + { + { 1, 4, 4, 5, 4, 5, 6, 6, 5, 7, 6, 7, 5, 7, 7, 6, + 6, 8, 8, 8, 8, 9, 10, 9, 8, 10, 9, 10, 9, 9, 9, 9, + 7, 9, 9, 9, 9, 9, 11, 9, 9, 10, 10, 10, 10, 10, 10, 9, + 9, 10, 10, 10, 10, 10, 12, 10, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 4, 5, 5, 6, 6, 6, 4, 7, 5, 6, 5, 7, 6, 6, + 7, 8, 8, 9, 9, 9, 10, 9, 8, 10, 9, 9, 9, 10, 10, 9, + 7, 9, 9, 9, 9, 10, 10, 10, 9, 11, 9, 10, 10, 10, 10, 9, + 9, 10, 10, 11, 11, 11, 12, 11, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 5, 5, 4, 5, 7, 6, 4, 7, 6, 7, 5, 6, 6, 6, + 6, 8, 9, 9, 8, 9, 10, 9, 8, 10, 9, 10, 9, 9, 10, 9, + 7, 9, 9, 10, 9, 9, 11, 10, 9, 11, 10, 10, 9, 10, 10, 9, + 9, 10, 11, 11, 10, 10, 12, 11, 11, 12, 11, 11, 11, 11, 11, 10 }, + { 1, 4, 4, 5, 5, 6, 6, 7, 4, 7, 5, 6, 5, 7, 6, 6, + 6, 8, 8, 9, 8, 9, 10, 10, 8, 10, 9, 10, 9, 10, 9, 9, + 7, 9, 9, 10, 9, 10, 10, 10, 9, 11, 9, 10, 9, 10, 10, 9, + 9, 11, 11, 11, 11, 11, 12, 11, 10, 12, 11, 12, 11, 12, 11, 10 } + }, + { + { 6, 1, 6, 4, 7, 4, 8, 5, 9, 7, 9, 6, 10, 7, 9, 6, + 6, 4, 9, 6, 9, 6, 10, 7, 11, 9, 11, 9, 12, 9, 11, 7, + 7, 5, 9, 7, 10, 7, 11, 8, 12, 10, 11, 9, 12, 10, 12, 8, + 8, 6, 10, 8, 10, 8, 12, 8, 12, 10, 12, 10, 13, 11, 13, 9 }, + { 1, 3, 4, 3, 5, 5, 7, 6, 8, 9, 8, 7, 9, 9, 9, 7, + 7, 7, 9, 7, 10, 9, 11, 9, 12, 12, 12, 10, 13, 12, 12, 10, + 7, 8, 10, 8, 11, 10, 12, 10, 13, 13, 12, 10, 13, 13, 12, 10, + 8, 9, 10, 8, 12, 12, 13, 10, 13, 13, 13, 11, 13, 13, 13, 11 }, + { 1, 3, 4, 6, 5, 4, 7, 7, 5, 7, 7, 7, 7, 7, 7, 6, + 5, 6, 9, 10, 9, 8, 12, 11, 10, 11, 11, 11, 12, 11, 11, 10, + 6, 9, 11, 12, 10, 10, 13, 11, 11, 13, 12, 12, 12, 11, 12, 11, + 8, 9, 12, 13, 11, 10, 13, 12, 13, 13, 13, 13, 13, 12, 13, 12 }, + { 1, 2, 5, 6, 4, 5, 7, 7, 7, 7, 8, 7, 7, 7, 8, 6, + 8, 10, 11, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 } + } + }, + { + { + { 9, 1, 8, 5, 8, 4, 14, 7, 13, 10, 13, 10, 15, 10, 15, 8, + 6, 3, 12, 7, 11, 6, 15, 8, 14, 12, 15, 11, 15, 11, 15, 9, + 6, 4, 12, 7, 12, 7, 15, 9, 15, 12, 15, 11, 15, 12, 15, 10, + 7, 4, 13, 6, 12, 6, 15, 8, 15, 12, 15, 11, 15, 11, 15, 8 }, + { 1, 2, 5, 4, 6, 5, 10, 6, 10, 10, 10, 10, 10, 10, 10, 10, + 7, 7, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 6, 8, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11 }, + { 1, 2, 5, 5, 6, 5, 9, 8, 8, 8, 8, 8, 9, 8, 9, 8, + 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 6, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, + { 1, 4, 7, 8, 6, 7, 8, 8, 8, 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, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8 } + }, + { + { 1, 3, 4, 5, 4, 6, 7, 7, 4, 7, 6, 8, 6, 8, 8, 8, + 6, 9, 9, 10, 9, 9, 11, 11, 9, 11, 10, 11, 10, 11, 11, 11, + 6, 9, 9, 10, 9, 10, 12, 11, 9, 11, 10, 12, 11, 11, 12, 11, + 8, 11, 11, 10, 11, 11, 12, 12, 11, 13, 12, 13, 12, 13, 13, 12 }, + { 1, 4, 4, 5, 4, 6, 6, 7, 4, 7, 5, 7, 5, 7, 7, 7, + 6, 8, 8, 9, 9, 9, 11, 10, 9, 11, 9, 11, 10, 11, 11, 11, + 6, 9, 9, 10, 9, 10, 11, 11, 9, 11, 10, 11, 10, 12, 12, 11, + 8, 11, 10, 11, 11, 11, 13, 12, 11, 12, 11, 12, 12, 13, 12, 11 }, + { 1, 4, 4, 5, 4, 5, 7, 7, 4, 7, 6, 7, 5, 7, 7, 7, + 6, 8, 9, 10, 8, 9, 11, 10, 8, 11, 10, 11, 9, 11, 11, 10, + 6, 8, 9, 10, 8, 10, 11, 11, 9, 11, 10, 12, 10, 10, 11, 11, + 8, 10, 11, 11, 10, 11, 12, 12, 10, 12, 11, 12, 11, 11, 12, 11 }, + { 1, 4, 4, 5, 4, 6, 6, 7, 4, 7, 5, 7, 5, 7, 7, 7, + 6, 9, 9, 10, 8, 10, 11, 11, 8, 12, 9, 11, 9, 11, 10, 11, + 6, 9, 9, 10, 9, 10, 11, 11, 9, 11, 10, 11, 10, 11, 11, 11, + 8, 11, 11, 12, 10, 11, 12, 12, 10, 12, 11, 12, 11, 12, 12, 11 } + }, + { + { 6, 1, 6, 4, 6, 4, 9, 6, 9, 8, 10, 8, 10, 8, 11, 8, + 5, 4, 9, 7, 9, 7, 11, 9, 11, 10, 12, 10, 12, 11, 14, 10, + 5, 4, 9, 7, 9, 7, 12, 9, 12, 10, 13, 11, 13, 12, 14, 11, + 7, 5, 10, 8, 10, 8, 13, 10, 12, 11, 13, 11, 14, 12, 14, 11 }, + { 1, 2, 4, 4, 5, 7, 8, 8, 8, 9, 8, 8, 9, 9, 9, 8, + 6, 8, 10, 8, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 7, 9, 10, 9, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, + 9, 11, 11, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 2, 5, 7, 5, 5, 9, 9, 5, 7, 6, 7, 7, 7, 8, 8, + 6, 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 6, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 9, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 }, + { 1, 3, 5, 6, 4, 5, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9 } + } + } +}; + +typedef struct { + uint8_t l0[2][864]; + uint8_t l12[2][108]; + uint8_t l3[2][108]; + uint8_t esc[32]; +} CoeffLens; + +static const CoeffLens rv60_intra_lens[5] = { + { + { + { 0, 7, 5, 7, 5, 7, 6, 6, 7, 9, 7, 8, 8, 9, 7, 7, + 10, 13, 10, 12, 11, 12, 10, 10, 6, 9, 6, 8, 7, 8, 7, 7, + 9, 11, 8, 9, 9, 10, 8, 8, 12, 14, 12, 13, 13, 13, 11, 10, + 9, 12, 9, 11, 10, 11, 9, 9, 12, 14, 10, 11, 12, 12, 10, 9, + 12, 15, 12, 13, 13, 14, 11, 10, 6, 9, 7, 8, 7, 8, 7, 7, + 8, 11, 9, 9, 9, 9, 8, 8, 12, 14, 12, 13, 12, 13, 11, 10, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 10, 11, 13, 11, 11, 12, 12, 10, 9, + 13, 15, 11, 12, 13, 13, 11, 10, 15, 15, 13, 13, 14, 15, 12, 10, + 9, 12, 10, 11, 9, 11, 9, 9, 12, 14, 12, 12, 11, 12, 10, 9, + 12, 15, 12, 14, 12, 13, 11, 10, 11, 14, 11, 12, 11, 12, 10, 9, + 13, 15, 12, 13, 12, 12, 11, 10, 15, 15, 14, 14, 13, 14, 12, 10, + 12, 15, 12, 13, 12, 13, 11, 10, 14, 15, 13, 13, 13, 14, 11, 10, + 14, 15, 13, 14, 14, 14, 11, 9, 5, 8, 6, 7, 7, 8, 7, 7, + 8, 10, 8, 9, 9, 9, 8, 8, 12, 14, 11, 12, 12, 13, 11, 10, + 6, 10, 7, 8, 8, 9, 8, 7, 9, 11, 9, 10, 10, 10, 9, 8, + 13, 15, 12, 13, 13, 13, 11, 10, 10, 13, 10, 11, 11, 12, 10, 9, + 12, 14, 11, 11, 12, 13, 10, 9, 14, 15, 12, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 9, 11, 9, 10, 9, 10, 9, 8, + 13, 15, 13, 13, 13, 13, 11, 10, 8, 11, 9, 10, 9, 10, 8, 8, + 10, 12, 10, 11, 10, 11, 9, 8, 14, 15, 13, 13, 13, 14, 12, 11, + 11, 14, 11, 11, 12, 12, 10, 9, 12, 15, 11, 12, 12, 13, 10, 9, + 15, 15, 13, 13, 14, 15, 12, 10, 10, 13, 11, 12, 10, 11, 10, 9, + 12, 14, 12, 13, 11, 12, 10, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 11, 14, 12, 12, 11, 12, 10, 9, 12, 15, 12, 13, 12, 12, 11, 10, + 15, 15, 14, 14, 13, 13, 11, 10, 13, 15, 12, 13, 13, 13, 11, 10, + 14, 15, 13, 13, 13, 13, 11, 10, 15, 15, 13, 13, 13, 14, 10, 9, + 7, 10, 8, 10, 9, 10, 9, 8, 10, 12, 10, 11, 11, 11, 10, 9, + 12, 15, 12, 14, 13, 14, 12, 11, 9, 12, 9, 10, 10, 11, 9, 9, + 11, 13, 11, 11, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 11, 14, 10, 12, 11, 12, 10, 9, 13, 15, 12, 12, 13, 13, 11, 10, + 14, 15, 13, 14, 14, 15, 12, 10, 9, 12, 9, 10, 10, 11, 9, 9, + 11, 13, 11, 11, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 10, 12, 10, 11, 10, 11, 10, 9, 11, 14, 11, 12, 11, 12, 11, 10, + 15, 15, 14, 14, 14, 15, 12, 11, 12, 15, 11, 12, 12, 13, 11, 10, + 13, 15, 12, 13, 13, 13, 11, 10, 15, 15, 13, 14, 15, 15, 12, 10, + 11, 14, 11, 12, 11, 12, 10, 10, 13, 15, 13, 13, 12, 13, 11, 10, + 14, 15, 14, 15, 13, 14, 12, 11, 12, 15, 12, 13, 11, 13, 11, 10, + 13, 15, 13, 13, 12, 13, 11, 10, 15, 15, 14, 15, 13, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 10, 14, 15, 13, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 13, 14, 10, 9, 10, 13, 10, 11, 11, 11, 10, 9, + 12, 14, 12, 12, 12, 12, 10, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 13, 10, 11, 10, 11, 10, 9, 12, 14, 12, 12, 12, 12, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 11, 14, 11, 11, 11, 12, 10, 8, + 13, 15, 11, 12, 12, 12, 10, 9, 15, 15, 13, 13, 13, 14, 10, 8, + 10, 13, 10, 11, 11, 12, 10, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 10, 13, 10, 11, 11, 12, 10, 9, + 12, 15, 11, 12, 12, 12, 10, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 11, 14, 11, 11, 11, 12, 10, 8, 12, 15, 11, 12, 12, 12, 10, 8, + 15, 15, 12, 12, 13, 13, 10, 8, 11, 14, 11, 12, 11, 12, 10, 9, + 13, 15, 12, 12, 12, 12, 10, 9, 15, 15, 13, 14, 13, 13, 10, 9, + 11, 14, 11, 12, 11, 12, 10, 9, 12, 15, 12, 12, 11, 12, 10, 9, + 15, 15, 13, 13, 12, 13, 10, 8, 12, 14, 11, 11, 11, 12, 9, 8, + 11, 14, 10, 11, 11, 12, 9, 7, 13, 15, 10, 11, 10, 11, 8, 6 }, + { 0, 7, 4, 8, 5, 9, 8, 9, 6, 10, 8, 10, 9, 12, 10, 11, + 14, 15, 14, 14, 15, 15, 14, 13, 5, 10, 6, 10, 8, 11, 9, 10, + 9, 12, 9, 11, 11, 13, 11, 11, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 14, 10, 12, 12, 14, 11, 12, 12, 15, 11, 13, 14, 15, 12, 13, + 15, 15, 14, 15, 15, 15, 14, 14, 5, 10, 8, 10, 7, 11, 9, 10, + 9, 12, 10, 11, 10, 13, 11, 11, 15, 15, 14, 15, 15, 15, 14, 14, + 8, 12, 9, 11, 10, 12, 10, 11, 10, 14, 11, 12, 11, 14, 11, 12, + 15, 15, 14, 15, 15, 15, 14, 14, 12, 15, 11, 13, 13, 15, 12, 13, + 13, 15, 12, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 10, 14, 12, 13, 10, 13, 11, 12, 12, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 12, 15, 12, 14, 12, 14, 12, 13, + 13, 15, 13, 14, 12, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 14, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 13, 2, 8, 5, 9, 6, 10, 8, 10, + 7, 11, 8, 10, 9, 12, 10, 11, 15, 15, 14, 14, 14, 15, 13, 13, + 5, 10, 7, 10, 8, 11, 9, 10, 9, 12, 9, 11, 11, 13, 11, 11, + 15, 15, 14, 14, 15, 15, 14, 14, 10, 14, 9, 12, 12, 14, 11, 12, + 12, 15, 11, 13, 13, 15, 12, 13, 15, 15, 14, 15, 15, 15, 14, 14, + 5, 10, 8, 10, 8, 11, 9, 10, 9, 13, 10, 12, 10, 13, 11, 11, + 15, 15, 14, 15, 15, 15, 14, 14, 7, 12, 9, 11, 10, 12, 10, 11, + 10, 14, 10, 12, 11, 13, 11, 12, 15, 15, 14, 15, 15, 15, 14, 14, + 11, 15, 11, 13, 13, 15, 12, 12, 13, 15, 12, 14, 14, 15, 12, 13, + 15, 15, 14, 15, 15, 15, 14, 14, 10, 14, 12, 13, 10, 13, 11, 12, + 12, 15, 13, 14, 12, 14, 12, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 11, 15, 12, 13, 12, 14, 12, 12, 13, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 13, 13, + 4, 10, 7, 10, 8, 11, 9, 10, 9, 12, 10, 12, 10, 13, 11, 11, + 15, 15, 14, 15, 15, 15, 14, 14, 7, 12, 8, 11, 10, 12, 10, 11, + 10, 13, 10, 12, 12, 14, 11, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 10, 15, 10, 13, 12, 15, 12, 12, 12, 15, 12, 13, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 7, 12, 9, 11, 9, 12, 10, 11, + 10, 14, 11, 12, 11, 13, 11, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 8, 13, 10, 12, 10, 13, 11, 12, 10, 14, 11, 13, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 14, 11, 15, 11, 13, 13, 15, 12, 13, + 12, 15, 12, 14, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 15, 12, 13, 10, 14, 12, 12, 12, 15, 13, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 11, 15, 12, 14, 12, 14, 12, 13, + 12, 15, 13, 15, 12, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 7, 11, 8, 11, 9, 12, 10, 10, + 10, 13, 10, 12, 11, 13, 11, 11, 15, 15, 14, 14, 14, 15, 13, 13, + 8, 12, 9, 11, 10, 12, 10, 11, 10, 14, 11, 12, 11, 13, 11, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 10, 14, 10, 12, 11, 13, 10, 11, + 12, 15, 11, 13, 12, 14, 11, 12, 15, 15, 14, 14, 14, 15, 12, 12, + 8, 12, 9, 11, 9, 12, 10, 11, 10, 14, 11, 12, 11, 13, 11, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 8, 13, 10, 12, 10, 13, 10, 11, + 10, 14, 11, 12, 11, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 10, 14, 10, 12, 11, 14, 11, 11, 11, 15, 11, 13, 12, 14, 11, 11, + 15, 15, 13, 14, 14, 15, 12, 12, 9, 14, 10, 12, 10, 13, 10, 11, + 12, 15, 12, 13, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 12, + 10, 14, 11, 13, 10, 13, 10, 11, 11, 15, 12, 13, 11, 13, 11, 11, + 14, 15, 14, 15, 13, 14, 12, 12, 11, 15, 11, 13, 11, 13, 10, 10, + 11, 15, 11, 13, 11, 13, 10, 10, 13, 15, 11, 12, 11, 12, 10, 9 } + }, + { + { 0, 4, 7, 3, 5, 9, 6, 8, 9, 3, 5, 9, 5, 6, 9, 8, + 9, 10, 6, 8, 9, 7, 9, 10, 9, 10, 10, 3, 5, 8, 4, 6, + 9, 7, 8, 10, 5, 6, 9, 6, 7, 10, 8, 9, 10, 7, 8, 10, + 8, 9, 10, 9, 10, 10, 6, 8, 9, 7, 8, 11, 8, 9, 10, 7, + 8, 11, 8, 9, 11, 9, 10, 11, 8, 10, 10, 9, 10, 11, 10, 10, + 10, 8, 9, 10, 8, 9, 10, 8, 9, 9, 8, 9, 11, 8, 9, 10, + 8, 9, 9, 9, 9, 10, 9, 9, 9, 8, 8, 7 }, + { 0, 4, 10, 2, 6, 10, 7, 9, 12, 3, 6, 10, 6, 8, 11, 9, + 10, 12, 8, 9, 12, 9, 10, 13, 12, 12, 13, 2, 6, 10, 4, 7, + 11, 8, 10, 12, 5, 7, 11, 6, 8, 11, 9, 10, 13, 8, 10, 12, + 10, 11, 13, 12, 12, 13, 6, 8, 12, 7, 9, 12, 9, 11, 13, 7, + 9, 12, 8, 10, 13, 10, 11, 13, 10, 11, 13, 11, 11, 13, 12, 12, + 13, 8, 10, 12, 9, 10, 13, 10, 11, 12, 9, 11, 13, 9, 11, 13, + 10, 11, 12, 10, 11, 13, 11, 11, 13, 11, 11, 12 } + }, + { + { 0, 4, 6, 3, 5, 8, 5, 8, 9, 4, 6, 8, 5, 7, 9, 8, + 9, 11, 6, 9, 9, 8, 9, 10, 9, 10, 10, 2, 5, 8, 4, 6, + 9, 7, 9, 10, 5, 7, 9, 6, 7, 10, 9, 9, 11, 8, 9, 10, + 9, 10, 11, 10, 11, 11, 5, 8, 9, 7, 9, 11, 8, 10, 11, 7, + 9, 11, 8, 9, 11, 10, 11, 12, 8, 11, 11, 10, 11, 12, 10, 11, + 11, 8, 10, 11, 9, 10, 11, 10, 10, 11, 9, 10, 11, 10, 10, 11, + 10, 10, 11, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 5, 12, 2, 7, 13, 8, 11, 15, 4, 8, 13, 7, 9, 13, 11, + 12, 15, 10, 12, 15, 11, 12, 15, 13, 13, 15, 1, 7, 12, 4, 8, + 13, 9, 12, 15, 6, 9, 13, 8, 10, 13, 11, 12, 15, 11, 12, 15, + 11, 13, 15, 13, 14, 14, 7, 9, 13, 8, 10, 14, 11, 13, 15, 9, + 11, 14, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 11, 13, 11, 12, 14, 13, 14, 15, 12, 12, 14, 12, 13, 14, + 13, 14, 15, 13, 14, 15, 13, 14, 15, 14, 14, 14 } + }, + { 1, 2, 4, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 13, 15, 15, 14 } + }, + { + { + { 0, 6, 4, 7, 5, 7, 6, 6, 6, 9, 7, 9, 8, 9, 8, 8, + 12, 15, 13, 14, 13, 14, 12, 11, 5, 9, 6, 8, 7, 8, 7, 7, + 8, 11, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 12, 12, + 10, 13, 9, 11, 11, 12, 10, 10, 12, 15, 10, 12, 12, 13, 11, 10, + 15, 15, 13, 13, 14, 15, 12, 11, 5, 9, 7, 8, 7, 8, 7, 7, + 8, 11, 9, 10, 9, 10, 8, 9, 14, 15, 13, 14, 13, 14, 12, 11, + 7, 11, 8, 10, 8, 10, 8, 8, 9, 12, 10, 11, 10, 11, 9, 9, + 15, 15, 13, 14, 13, 14, 12, 11, 11, 14, 11, 12, 12, 13, 11, 10, + 12, 15, 11, 13, 13, 14, 11, 11, 15, 15, 13, 14, 14, 15, 12, 11, + 10, 13, 11, 12, 9, 11, 10, 10, 12, 14, 12, 13, 10, 12, 11, 10, + 14, 15, 14, 15, 13, 13, 12, 11, 12, 14, 12, 13, 11, 12, 10, 10, + 12, 15, 12, 14, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 10, + 13, 15, 13, 14, 13, 14, 11, 10, 14, 15, 13, 14, 13, 14, 11, 10, + 15, 15, 13, 14, 13, 14, 11, 9, 4, 8, 6, 8, 6, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 8, 8, 14, 15, 13, 14, 13, 14, 12, 11, + 6, 10, 7, 9, 8, 9, 8, 8, 9, 12, 9, 11, 10, 11, 9, 9, + 15, 15, 13, 14, 14, 14, 12, 11, 10, 13, 10, 11, 11, 13, 10, 10, + 12, 15, 11, 12, 12, 13, 11, 10, 15, 15, 13, 14, 14, 15, 12, 11, + 6, 10, 8, 9, 7, 9, 8, 8, 9, 12, 9, 11, 9, 11, 9, 9, + 15, 15, 14, 14, 13, 14, 12, 11, 8, 11, 9, 10, 9, 10, 9, 9, + 10, 12, 10, 11, 10, 11, 10, 10, 15, 15, 13, 14, 13, 14, 12, 11, + 11, 14, 11, 12, 12, 13, 10, 10, 12, 15, 11, 12, 12, 14, 11, 10, + 15, 15, 12, 14, 14, 15, 11, 10, 10, 14, 11, 12, 10, 11, 10, 10, + 12, 15, 12, 13, 11, 12, 11, 10, 15, 15, 14, 15, 13, 13, 12, 11, + 11, 14, 12, 13, 11, 12, 11, 10, 12, 15, 12, 13, 11, 13, 11, 10, + 15, 15, 14, 15, 12, 13, 11, 10, 13, 15, 13, 14, 13, 14, 11, 10, + 14, 15, 12, 14, 12, 14, 11, 10, 15, 15, 13, 14, 13, 14, 10, 9, + 7, 11, 8, 10, 9, 11, 9, 9, 10, 13, 10, 12, 11, 12, 10, 10, + 15, 15, 14, 15, 14, 15, 13, 12, 8, 12, 9, 11, 9, 11, 10, 10, + 11, 13, 11, 12, 11, 12, 11, 10, 15, 15, 14, 15, 15, 15, 13, 12, + 11, 14, 10, 12, 12, 13, 11, 10, 12, 15, 11, 13, 13, 14, 11, 11, + 15, 15, 13, 14, 15, 15, 12, 11, 9, 12, 10, 11, 9, 11, 10, 10, + 11, 14, 11, 12, 11, 12, 11, 10, 15, 15, 15, 15, 14, 15, 13, 12, + 9, 13, 10, 12, 10, 12, 10, 10, 11, 14, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 11, 13, 12, 13, 11, 11, + 12, 15, 11, 13, 13, 14, 11, 11, 15, 15, 13, 14, 14, 15, 12, 11, + 11, 15, 12, 13, 11, 12, 11, 10, 12, 15, 13, 14, 11, 13, 11, 11, + 15, 15, 15, 15, 13, 14, 12, 11, 12, 15, 12, 14, 11, 13, 11, 11, + 12, 15, 13, 14, 11, 13, 11, 11, 15, 15, 14, 15, 13, 14, 12, 11, + 13, 15, 13, 14, 13, 14, 11, 10, 13, 15, 12, 14, 12, 14, 11, 10, + 15, 15, 12, 13, 13, 14, 10, 9, 10, 13, 10, 11, 10, 12, 10, 10, + 12, 15, 12, 13, 12, 13, 11, 10, 15, 15, 14, 14, 14, 15, 12, 11, + 10, 13, 10, 12, 10, 12, 10, 10, 12, 15, 11, 12, 11, 13, 11, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 11, 14, 10, 12, 11, 12, 10, 9, + 12, 15, 11, 12, 11, 13, 10, 9, 15, 15, 13, 13, 13, 14, 10, 9, + 10, 14, 10, 12, 10, 12, 10, 10, 12, 15, 11, 13, 12, 13, 11, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 10, 14, 10, 12, 10, 12, 10, 10, + 11, 15, 11, 13, 11, 13, 11, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 11, 14, 10, 12, 11, 12, 10, 9, 11, 15, 10, 12, 11, 13, 10, 9, + 14, 15, 11, 13, 13, 14, 10, 9, 11, 14, 11, 12, 10, 12, 10, 9, + 12, 15, 11, 13, 11, 12, 10, 9, 15, 15, 13, 14, 13, 13, 10, 9, + 11, 15, 11, 12, 10, 12, 10, 9, 12, 15, 11, 13, 11, 12, 10, 9, + 14, 15, 13, 13, 12, 13, 10, 9, 11, 15, 10, 12, 10, 12, 9, 8, + 11, 15, 10, 12, 10, 12, 9, 8, 12, 15, 9, 11, 10, 11, 8, 6 }, + { 0, 8, 5, 9, 5, 10, 8, 10, 7, 11, 8, 11, 9, 12, 11, 12, + 14, 15, 14, 15, 15, 15, 15, 15, 4, 10, 6, 10, 9, 12, 10, 11, + 9, 13, 9, 12, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 13, 12, 15, 12, 14, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 8, 11, 7, 11, 10, 11, + 9, 13, 10, 13, 10, 13, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 12, 9, 12, 10, 13, 11, 13, 10, 14, 11, 14, 11, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 14, 15, 11, 15, 12, 15, 13, 15, 13, 14, + 13, 15, 12, 15, 14, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 10, 15, 12, 14, 10, 14, 12, 14, 12, 15, 13, 15, 11, 14, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 13, 15, 12, 15, 13, 14, + 12, 15, 14, 15, 12, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 14, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 2, 9, 6, 9, 6, 11, 9, 11, + 7, 11, 9, 11, 10, 12, 11, 12, 15, 15, 15, 15, 15, 15, 14, 15, + 5, 11, 7, 11, 9, 12, 10, 12, 9, 13, 10, 12, 11, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 9, 14, 12, 15, 12, 13, + 12, 15, 11, 14, 14, 15, 13, 14, 15, 15, 14, 15, 15, 15, 15, 15, + 5, 11, 8, 11, 7, 12, 10, 12, 9, 13, 10, 13, 10, 13, 11, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 13, 9, 12, 10, 13, 11, 13, + 9, 14, 10, 14, 11, 14, 12, 13, 15, 15, 14, 15, 15, 15, 14, 15, + 11, 15, 11, 14, 13, 15, 13, 14, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 14, 15, 15, 15, 14, 15, 9, 15, 12, 14, 9, 14, 12, 13, + 12, 15, 13, 15, 11, 14, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 11, 15, 13, 15, 11, 15, 12, 14, 12, 15, 13, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 13, 14, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 14, 15, 14, 15, 13, 13, + 4, 11, 7, 11, 8, 12, 10, 12, 9, 13, 10, 12, 10, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 12, 8, 12, 9, 13, 11, 12, + 10, 14, 11, 13, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 10, 14, 12, 15, 12, 13, 12, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 12, 9, 12, 8, 13, 11, 12, + 10, 14, 11, 14, 11, 14, 12, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 13, 10, 13, 10, 14, 11, 13, 10, 14, 11, 14, 11, 14, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 11, 15, 13, 15, 13, 14, + 12, 15, 12, 15, 14, 15, 13, 14, 15, 15, 14, 15, 15, 15, 14, 14, + 10, 15, 12, 15, 10, 14, 12, 13, 12, 15, 13, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 13, 15, 11, 15, 13, 14, + 12, 15, 13, 15, 11, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 13, 15, 13, 15, 14, 15, 13, 14, 13, 15, 14, 15, 13, 15, 13, 14, + 15, 15, 14, 15, 14, 15, 13, 13, 6, 12, 8, 12, 9, 12, 10, 12, + 10, 14, 10, 13, 11, 13, 11, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 7, 13, 9, 13, 9, 13, 10, 12, 10, 14, 11, 13, 11, 14, 11, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 9, 15, 9, 13, 10, 13, 11, 12, + 11, 15, 11, 14, 12, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 7, 13, 9, 12, 9, 13, 10, 12, 10, 14, 11, 14, 11, 14, 11, 13, + 15, 15, 14, 15, 14, 15, 13, 13, 8, 13, 10, 13, 10, 13, 11, 12, + 10, 14, 11, 14, 11, 14, 11, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 9, 15, 10, 13, 11, 14, 11, 12, 10, 15, 10, 13, 11, 14, 11, 12, + 14, 15, 13, 14, 14, 15, 12, 12, 9, 14, 10, 13, 9, 13, 10, 12, + 11, 15, 12, 14, 11, 14, 11, 12, 15, 15, 14, 15, 13, 15, 13, 12, + 9, 15, 11, 14, 10, 13, 11, 12, 10, 15, 11, 14, 10, 13, 11, 12, + 14, 15, 14, 15, 12, 14, 12, 12, 10, 15, 11, 13, 11, 13, 10, 11, + 10, 14, 11, 13, 10, 13, 10, 11, 12, 14, 11, 12, 11, 12, 10, 10 } + }, + { + { 0, 4, 9, 3, 5, 10, 7, 9, 10, 3, 5, 10, 5, 6, 10, 8, + 9, 10, 7, 8, 10, 8, 9, 10, 10, 10, 10, 3, 5, 10, 4, 6, + 10, 7, 8, 10, 4, 6, 10, 6, 7, 10, 8, 9, 10, 7, 9, 10, + 8, 9, 10, 9, 10, 9, 6, 8, 11, 7, 8, 11, 8, 9, 11, 7, + 8, 11, 8, 9, 11, 9, 9, 10, 9, 10, 11, 9, 10, 10, 10, 10, + 9, 8, 9, 10, 8, 9, 10, 8, 8, 9, 8, 9, 10, 8, 9, 10, + 8, 8, 9, 8, 9, 9, 8, 9, 9, 8, 8, 7 }, + { 0, 5, 12, 3, 7, 13, 8, 11, 14, 3, 7, 13, 6, 9, 14, 11, + 12, 14, 9, 11, 15, 11, 12, 15, 13, 14, 15, 1, 6, 13, 4, 8, + 13, 9, 11, 14, 5, 8, 13, 7, 9, 13, 11, 11, 14, 10, 12, 14, + 11, 12, 15, 13, 13, 15, 6, 9, 13, 8, 10, 14, 10, 12, 14, 8, + 11, 14, 9, 11, 14, 11, 12, 15, 11, 13, 15, 12, 13, 15, 13, 13, + 15, 9, 11, 13, 10, 11, 13, 11, 12, 14, 10, 11, 14, 10, 12, 14, + 11, 12, 14, 11, 13, 15, 12, 13, 14, 12, 13, 14 } + }, + { + { 0, 4, 9, 3, 5, 10, 7, 9, 11, 3, 5, 10, 5, 7, 11, 9, + 10, 12, 8, 9, 11, 9, 10, 11, 10, 11, 11, 2, 5, 10, 4, 7, + 11, 8, 9, 11, 4, 7, 11, 6, 8, 11, 9, 10, 11, 9, 10, 11, + 9, 10, 11, 10, 10, 10, 6, 8, 11, 7, 9, 12, 9, 10, 12, 7, + 9, 12, 8, 9, 12, 10, 10, 12, 9, 10, 12, 10, 11, 12, 11, 11, + 11, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 9, 10, 11, + 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9 }, + { 0, 5, 12, 2, 7, 13, 10, 12, 15, 4, 7, 14, 6, 9, 14, 11, + 12, 15, 10, 12, 15, 11, 12, 15, 13, 13, 15, 1, 6, 12, 5, 8, + 14, 10, 12, 15, 5, 8, 13, 8, 9, 13, 11, 12, 15, 11, 12, 15, + 11, 12, 15, 13, 13, 15, 7, 9, 12, 9, 11, 14, 12, 13, 15, 9, + 10, 14, 10, 11, 13, 13, 13, 15, 12, 13, 15, 12, 14, 15, 14, 15, + 15, 11, 11, 12, 12, 12, 13, 14, 15, 15, 12, 13, 14, 12, 13, 14, + 14, 14, 15, 13, 14, 15, 14, 14, 15, 14, 14, 15 } + }, + { 1, 3, 3, 4, 4, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 14, 14, 14, 14 } + }, + { + { + { 0, 9, 5, 9, 5, 9, 8, 9, 7, 11, 8, 11, 8, 11, 9, 10, + 14, 15, 13, 14, 13, 14, 12, 11, 5, 11, 6, 10, 8, 11, 9, 10, + 8, 12, 9, 11, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 9, 15, 9, 12, 11, 14, 10, 10, 11, 15, 9, 12, 12, 14, 10, 11, + 14, 15, 12, 13, 13, 14, 11, 11, 5, 11, 8, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 7, 13, 8, 12, 9, 12, 9, 10, 9, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 12, 14, 12, 11, 11, 15, 10, 13, 12, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 10, 11, 14, 15, 12, 13, 13, 14, 11, 10, + 9, 15, 11, 13, 8, 12, 10, 10, 10, 15, 12, 14, 9, 12, 10, 11, + 14, 15, 13, 15, 12, 13, 11, 11, 11, 15, 11, 14, 10, 13, 10, 10, + 11, 15, 12, 14, 10, 13, 10, 11, 14, 15, 13, 14, 12, 13, 11, 10, + 13, 15, 12, 14, 12, 14, 11, 10, 13, 15, 12, 14, 12, 14, 10, 10, + 15, 15, 12, 13, 12, 13, 10, 9, 3, 10, 6, 10, 6, 10, 9, 10, + 8, 12, 9, 11, 9, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 13, 14, 12, 11, 9, 15, 9, 12, 11, 13, 10, 10, + 11, 15, 9, 12, 12, 14, 10, 11, 14, 15, 12, 13, 13, 15, 11, 10, + 6, 12, 8, 11, 7, 11, 9, 10, 8, 13, 10, 12, 9, 11, 10, 10, + 14, 15, 13, 14, 13, 13, 12, 11, 7, 13, 9, 12, 9, 12, 10, 10, + 9, 13, 9, 12, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 11, + 10, 15, 10, 13, 11, 14, 10, 10, 11, 15, 10, 12, 12, 14, 10, 10, + 14, 15, 11, 13, 13, 14, 11, 10, 9, 15, 11, 13, 8, 12, 10, 10, + 11, 15, 12, 14, 9, 12, 10, 10, 14, 15, 13, 15, 12, 13, 11, 10, + 10, 15, 11, 14, 10, 13, 10, 10, 11, 15, 11, 14, 10, 13, 10, 11, + 14, 15, 13, 14, 11, 13, 11, 10, 13, 15, 12, 14, 12, 14, 10, 10, + 13, 15, 11, 13, 12, 13, 10, 10, 14, 15, 11, 13, 12, 13, 10, 9, + 6, 13, 8, 12, 8, 12, 10, 10, 10, 14, 10, 12, 10, 12, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 12, 7, 13, 8, 12, 9, 12, 10, 11, + 10, 14, 10, 12, 11, 13, 11, 11, 15, 15, 14, 14, 14, 14, 12, 12, + 10, 15, 9, 13, 11, 13, 10, 10, 11, 15, 10, 13, 12, 14, 11, 11, + 15, 15, 12, 14, 14, 15, 11, 11, 7, 13, 9, 12, 9, 12, 10, 11, + 10, 14, 10, 13, 10, 13, 11, 11, 15, 15, 14, 14, 14, 14, 12, 12, + 8, 14, 9, 12, 9, 13, 10, 11, 10, 14, 10, 13, 10, 13, 11, 11, + 15, 15, 13, 14, 13, 14, 12, 11, 10, 15, 10, 13, 11, 14, 10, 11, + 10, 15, 9, 13, 12, 14, 11, 11, 14, 15, 11, 13, 13, 15, 11, 10, + 10, 15, 11, 13, 9, 12, 10, 10, 11, 15, 12, 14, 10, 13, 11, 11, + 14, 15, 14, 15, 12, 13, 11, 11, 10, 15, 11, 14, 10, 13, 10, 11, + 10, 15, 12, 14, 10, 13, 11, 11, 14, 15, 13, 15, 11, 13, 11, 10, + 12, 15, 12, 14, 12, 14, 10, 10, 11, 15, 11, 13, 11, 13, 10, 10, + 13, 15, 11, 12, 11, 13, 9, 9, 9, 14, 10, 13, 10, 13, 10, 10, + 11, 15, 11, 13, 11, 13, 10, 11, 15, 15, 14, 14, 13, 14, 12, 10, + 9, 14, 10, 13, 9, 13, 10, 10, 11, 15, 11, 13, 11, 13, 10, 10, + 15, 15, 14, 14, 13, 14, 12, 10, 10, 14, 9, 12, 10, 12, 9, 9, + 11, 15, 10, 13, 11, 13, 9, 9, 14, 15, 12, 13, 13, 13, 10, 9, + 9, 15, 9, 13, 10, 13, 10, 10, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 13, 14, 12, 10, 8, 15, 9, 13, 9, 13, 10, 10, + 10, 15, 11, 13, 10, 13, 10, 11, 15, 15, 13, 14, 13, 14, 11, 10, + 9, 15, 9, 12, 10, 12, 9, 9, 10, 15, 9, 12, 10, 13, 9, 9, + 13, 15, 11, 12, 12, 13, 10, 9, 10, 15, 10, 12, 9, 12, 9, 9, + 11, 15, 10, 13, 10, 13, 9, 9, 14, 15, 13, 13, 12, 13, 10, 9, + 10, 15, 10, 12, 9, 12, 9, 9, 10, 15, 10, 12, 9, 12, 9, 9, + 14, 15, 12, 13, 11, 12, 10, 9, 10, 15, 9, 12, 10, 12, 8, 8, + 9, 14, 9, 11, 9, 11, 8, 8, 10, 14, 8, 10, 9, 10, 7, 6 }, + { 0, 11, 6, 13, 6, 12, 11, 14, 8, 13, 11, 14, 10, 14, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 5, 14, 8, 14, 10, 15, 12, 14, + 9, 15, 11, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 10, 15, 8, 14, 12, 15, + 9, 15, 12, 15, 11, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 14, 15, 14, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 14, 15, 11, 15, 14, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 12, 15, 14, 15, + 13, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 12, 7, 13, 7, 13, 12, 13, + 8, 13, 11, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 14, 8, 14, 10, 15, 12, 14, 9, 15, 11, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 10, 15, 13, 15, 13, 15, + 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 14, 10, 15, 8, 14, 12, 14, 9, 15, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 11, 15, 10, 15, 13, 15, + 9, 15, 12, 15, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 13, 15, 13, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 13, 15, 10, 15, 14, 15, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 14, 15, 12, 15, 14, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 4, 14, 9, 14, 8, 14, 12, 14, 9, 14, 11, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 9, 15, 10, 15, 13, 14, + 10, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 15, 13, 15, 13, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 13, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 12, 15, 14, 15, 14, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 13, 15, 10, 15, 13, 15, 12, 15, 15, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 14, 15, + 12, 15, 14, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 14, 10, 15, 9, 15, 12, 14, + 10, 15, 12, 15, 11, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 14, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 10, 15, 11, 15, 12, 14, + 12, 15, 12, 15, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 7, 15, 10, 15, 10, 15, 12, 14, 11, 15, 12, 15, 11, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 11, 15, 10, 15, 12, 14, + 10, 15, 12, 15, 11, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 10, 15, 12, 15, 12, 14, 11, 15, 11, 15, 12, 15, 12, 14, + 15, 15, 14, 15, 15, 15, 14, 15, 9, 15, 11, 15, 10, 15, 12, 14, + 12, 15, 13, 15, 12, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 9, 15, 12, 15, 10, 15, 12, 14, 11, 15, 12, 15, 11, 15, 12, 14, + 15, 15, 15, 15, 14, 15, 14, 15, 11, 15, 12, 15, 12, 15, 11, 13, + 11, 15, 12, 14, 12, 14, 12, 13, 13, 15, 13, 14, 12, 14, 12, 13 } + }, + { + { 0, 5, 10, 3, 6, 10, 7, 8, 10, 4, 6, 10, 6, 7, 10, 8, + 8, 10, 8, 9, 10, 9, 9, 10, 9, 9, 10, 2, 6, 10, 4, 6, + 10, 7, 8, 10, 5, 7, 10, 6, 7, 10, 8, 8, 10, 8, 9, 10, + 9, 9, 10, 9, 9, 9, 5, 7, 10, 6, 8, 10, 7, 8, 10, 6, + 8, 11, 7, 8, 11, 8, 8, 10, 8, 9, 10, 9, 9, 10, 9, 9, + 9, 7, 8, 10, 7, 8, 10, 7, 8, 9, 7, 9, 10, 7, 8, 10, + 8, 8, 9, 8, 9, 9, 8, 9, 9, 8, 8, 7 }, + { 0, 6, 14, 3, 7, 15, 8, 11, 15, 3, 8, 14, 7, 9, 15, 10, + 12, 15, 9, 12, 15, 11, 13, 15, 13, 14, 14, 1, 6, 13, 4, 8, + 14, 8, 11, 15, 5, 9, 15, 7, 9, 14, 10, 12, 15, 10, 12, 15, + 11, 12, 15, 15, 15, 15, 5, 9, 14, 7, 10, 14, 10, 12, 15, 7, + 10, 15, 8, 11, 15, 11, 13, 15, 11, 13, 15, 12, 13, 15, 15, 14, + 15, 8, 11, 14, 9, 11, 15, 11, 13, 15, 9, 12, 15, 10, 12, 15, + 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 13, 15 } + }, + { + { 0, 5, 10, 3, 7, 10, 7, 9, 11, 3, 7, 10, 5, 7, 11, 8, + 9, 11, 8, 9, 11, 8, 9, 11, 9, 10, 10, 2, 6, 10, 4, 7, + 10, 7, 9, 11, 4, 7, 10, 6, 8, 10, 8, 9, 11, 8, 9, 11, + 8, 9, 11, 9, 10, 10, 5, 7, 10, 6, 8, 11, 8, 9, 11, 6, + 8, 11, 7, 9, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 10, 10, + 10, 7, 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 8, 9, 10, + 9, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 12, 3, 8, 13, 10, 14, 14, 3, 7, 14, 6, 8, 13, 10, + 12, 13, 9, 12, 14, 10, 13, 14, 12, 13, 14, 1, 5, 12, 5, 9, + 13, 11, 13, 14, 5, 8, 12, 7, 9, 14, 12, 12, 14, 10, 14, 14, + 11, 12, 13, 14, 12, 14, 6, 8, 10, 9, 10, 13, 14, 13, 13, 8, + 11, 13, 10, 12, 13, 13, 14, 14, 12, 12, 14, 12, 14, 14, 14, 14, + 14, 10, 10, 12, 14, 14, 14, 14, 14, 14, 12, 12, 13, 12, 11, 14, + 14, 14, 14, 14, 14, 14, 13, 14, 14, 14, 14, 14 } + }, + { 1, 2, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 10, 11, + 11, 11, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 16, 16 } + }, + { + { + { 0, 9, 5, 10, 5, 10, 8, 9, 7, 11, 8, 11, 8, 11, 9, 10, + 14, 15, 13, 14, 13, 14, 12, 12, 5, 12, 6, 10, 8, 11, 9, 10, + 8, 13, 8, 11, 9, 12, 10, 10, 14, 15, 13, 14, 13, 14, 12, 12, + 9, 15, 9, 12, 11, 14, 10, 11, 11, 15, 9, 12, 12, 14, 11, 11, + 14, 15, 12, 13, 13, 15, 11, 11, 4, 11, 8, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 8, 11, 10, 10, 14, 15, 13, 14, 13, 14, 12, 12, + 7, 13, 9, 11, 9, 12, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 14, 15, 13, 14, 12, 14, 12, 11, 11, 15, 10, 13, 12, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 11, 11, 15, 15, 12, 13, 13, 15, 11, 11, + 9, 15, 11, 14, 9, 12, 10, 10, 10, 15, 12, 14, 9, 12, 10, 11, + 14, 15, 13, 15, 12, 13, 11, 11, 11, 15, 12, 14, 10, 13, 10, 11, + 11, 15, 12, 14, 10, 13, 11, 11, 14, 15, 13, 14, 12, 13, 11, 11, + 13, 15, 12, 14, 12, 14, 11, 11, 13, 15, 12, 14, 12, 14, 11, 10, + 15, 15, 12, 14, 12, 14, 11, 10, 3, 11, 6, 10, 6, 10, 9, 10, + 8, 12, 9, 11, 9, 11, 10, 10, 15, 15, 13, 14, 13, 13, 12, 12, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 9, 12, 10, 10, + 15, 15, 13, 14, 13, 14, 12, 12, 9, 15, 9, 12, 11, 14, 10, 10, + 11, 15, 9, 12, 12, 14, 10, 11, 14, 15, 12, 13, 13, 15, 11, 11, + 5, 12, 8, 11, 7, 11, 9, 10, 8, 13, 10, 12, 9, 12, 10, 10, + 15, 15, 13, 14, 13, 13, 12, 12, 7, 13, 9, 12, 8, 12, 9, 10, + 8, 13, 9, 12, 9, 12, 10, 10, 14, 15, 12, 14, 13, 14, 12, 11, + 10, 15, 10, 13, 11, 14, 10, 11, 11, 15, 9, 12, 12, 14, 10, 11, + 14, 15, 11, 13, 13, 14, 11, 11, 9, 15, 11, 13, 8, 12, 10, 10, + 11, 15, 12, 14, 9, 12, 10, 11, 14, 15, 13, 15, 12, 13, 11, 11, + 11, 15, 11, 14, 10, 13, 10, 11, 11, 15, 11, 14, 9, 13, 10, 11, + 14, 15, 13, 14, 11, 13, 11, 11, 13, 15, 12, 14, 12, 14, 11, 10, + 12, 15, 12, 14, 12, 14, 10, 10, 14, 15, 11, 13, 12, 13, 10, 9, + 6, 13, 8, 12, 8, 12, 10, 10, 10, 14, 10, 12, 10, 12, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 12, 7, 13, 8, 12, 9, 12, 10, 11, + 10, 14, 10, 12, 10, 13, 11, 11, 15, 15, 14, 14, 14, 15, 12, 12, + 10, 15, 9, 13, 11, 13, 10, 11, 11, 15, 10, 13, 12, 14, 11, 11, + 15, 15, 13, 14, 14, 15, 12, 11, 7, 14, 9, 12, 9, 12, 10, 11, + 10, 14, 10, 13, 10, 13, 11, 11, 15, 15, 14, 14, 14, 14, 13, 12, + 8, 14, 9, 12, 9, 13, 10, 11, 9, 14, 10, 13, 10, 13, 11, 11, + 15, 15, 13, 15, 13, 15, 12, 12, 10, 15, 10, 13, 11, 14, 10, 11, + 10, 15, 9, 13, 12, 14, 11, 11, 14, 15, 11, 13, 13, 15, 11, 11, + 10, 15, 11, 14, 9, 13, 10, 11, 11, 15, 12, 14, 10, 13, 11, 11, + 15, 15, 14, 15, 13, 14, 12, 11, 10, 15, 12, 14, 10, 13, 11, 11, + 10, 15, 12, 14, 10, 13, 10, 11, 14, 15, 13, 15, 12, 13, 11, 11, + 12, 15, 12, 14, 12, 14, 11, 10, 11, 15, 11, 13, 11, 14, 10, 10, + 13, 15, 11, 13, 11, 13, 10, 9, 8, 15, 10, 13, 10, 13, 10, 11, + 11, 15, 11, 13, 11, 13, 11, 11, 15, 15, 14, 14, 13, 14, 12, 11, + 9, 15, 10, 13, 9, 13, 10, 11, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 11, 10, 15, 9, 12, 10, 13, 9, 10, + 12, 15, 10, 13, 11, 13, 10, 10, 15, 15, 13, 13, 13, 14, 10, 10, + 9, 15, 10, 13, 10, 13, 10, 11, 11, 15, 11, 13, 11, 13, 11, 11, + 15, 15, 14, 14, 14, 14, 12, 11, 8, 15, 10, 13, 9, 13, 10, 11, + 10, 15, 11, 13, 10, 13, 10, 11, 15, 15, 13, 14, 14, 14, 12, 11, + 9, 15, 9, 12, 10, 13, 9, 10, 10, 15, 9, 12, 10, 13, 9, 10, + 14, 15, 11, 12, 12, 13, 10, 9, 10, 15, 10, 13, 9, 13, 9, 10, + 11, 15, 11, 13, 10, 13, 10, 10, 14, 15, 13, 14, 12, 13, 10, 9, + 10, 15, 10, 13, 9, 13, 9, 10, 10, 15, 11, 13, 9, 13, 10, 10, + 14, 15, 13, 13, 11, 13, 10, 9, 10, 15, 10, 12, 10, 12, 8, 8, + 9, 14, 9, 11, 9, 12, 8, 8, 10, 14, 9, 10, 9, 11, 8, 7 }, + { 0, 11, 7, 13, 7, 13, 12, 14, 8, 13, 11, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 8, 15, 10, 15, 13, 15, + 9, 15, 11, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 10, 15, 8, 14, 13, 15, + 9, 14, 13, 15, 11, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 12, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 14, 15, 11, 15, 14, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 12, 7, 13, 7, 13, 12, 14, + 8, 13, 11, 15, 11, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 8, 15, 10, 15, 13, 15, 9, 15, 11, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 14, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 10, 15, 8, 14, 13, 15, 9, 15, 13, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 11, 15, 11, 15, 13, 15, + 9, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 13, 15, 14, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 14, 15, 10, 15, 14, 15, + 13, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 12, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 4, 14, 9, 15, 9, 15, 13, 15, 9, 14, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 9, 15, 10, 15, 13, 15, + 10, 15, 12, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 13, 15, 14, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 13, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 11, 15, 11, 15, 13, 15, 10, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 12, 15, 14, 15, 14, 15, + 12, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 15, 13, 15, 10, 15, 14, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 15, 15, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 9, 15, 12, 15, + 10, 15, 12, 15, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 15, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 10, 15, 12, 15, 12, 15, + 12, 15, 12, 15, 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 12, 15, 11, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 11, 15, 10, 15, 12, 15, + 10, 15, 12, 15, 12, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 12, 15, 12, 15, 11, 15, 11, 15, 13, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 10, 15, 12, 15, + 12, 15, 14, 15, 12, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 12, 15, 11, 15, 13, 15, 11, 15, 13, 15, 11, 15, 13, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 11, 15, 12, 15, 12, 15, 12, 14, + 11, 15, 12, 15, 12, 15, 12, 14, 14, 15, 13, 15, 13, 15, 13, 14 } + }, + { + { 0, 5, 10, 3, 6, 10, 7, 8, 11, 4, 6, 10, 6, 7, 10, 8, + 9, 10, 8, 9, 10, 9, 9, 10, 10, 10, 10, 2, 6, 10, 4, 6, + 10, 7, 8, 10, 4, 7, 10, 6, 7, 10, 8, 8, 10, 8, 9, 10, + 8, 9, 10, 10, 9, 10, 5, 7, 10, 6, 8, 11, 7, 9, 11, 6, + 8, 11, 7, 8, 11, 8, 9, 11, 8, 9, 11, 9, 9, 11, 10, 9, + 10, 7, 8, 10, 7, 9, 10, 8, 9, 10, 7, 9, 10, 8, 8, 10, + 8, 8, 9, 8, 9, 10, 8, 9, 10, 8, 8, 8 }, + { 0, 6, 14, 3, 7, 14, 8, 11, 14, 3, 8, 14, 7, 9, 14, 10, + 12, 14, 9, 12, 14, 11, 13, 14, 14, 14, 14, 1, 6, 13, 4, 8, + 14, 9, 11, 14, 5, 8, 14, 7, 9, 14, 11, 12, 14, 9, 12, 14, + 12, 13, 14, 14, 14, 14, 5, 8, 14, 7, 10, 14, 10, 13, 14, 7, + 10, 14, 9, 11, 14, 12, 12, 14, 11, 13, 14, 12, 14, 14, 14, 14, + 14, 8, 11, 14, 9, 12, 14, 11, 14, 14, 9, 12, 14, 10, 12, 14, + 13, 13, 14, 12, 14, 14, 13, 14, 14, 14, 13, 14 } + }, + { + { 0, 5, 10, 3, 6, 11, 7, 9, 12, 3, 6, 11, 5, 7, 11, 8, + 9, 11, 8, 9, 11, 8, 9, 11, 10, 10, 11, 2, 5, 10, 4, 7, + 10, 8, 9, 12, 4, 7, 11, 6, 7, 11, 8, 9, 11, 8, 9, 11, + 9, 9, 11, 10, 10, 11, 5, 7, 10, 6, 8, 11, 9, 10, 12, 6, + 8, 11, 7, 9, 11, 9, 10, 12, 9, 10, 12, 9, 10, 12, 10, 11, + 11, 8, 9, 10, 8, 9, 11, 10, 10, 11, 8, 9, 11, 9, 10, 11, + 10, 10, 11, 10, 10, 11, 10, 10, 11, 10, 10, 10 }, + { 0, 4, 14, 3, 7, 14, 11, 15, 15, 3, 7, 15, 6, 9, 12, 11, + 12, 15, 11, 14, 14, 12, 14, 14, 14, 14, 14, 1, 5, 9, 5, 9, + 14, 11, 14, 14, 5, 8, 14, 7, 9, 14, 12, 14, 14, 14, 12, 14, + 14, 14, 14, 12, 14, 14, 6, 7, 10, 8, 10, 14, 12, 12, 14, 9, + 11, 14, 11, 12, 14, 14, 14, 14, 12, 14, 14, 11, 14, 14, 14, 14, + 14, 12, 10, 12, 12, 12, 14, 14, 14, 14, 14, 12, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 12, 12, 12, + 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 15 } + }, + { + { + { 0, 9, 5, 10, 5, 10, 9, 10, 7, 11, 8, 11, 8, 11, 10, 11, + 15, 15, 14, 15, 14, 14, 13, 13, 4, 12, 6, 11, 8, 11, 9, 10, + 8, 13, 9, 12, 9, 12, 10, 11, 15, 15, 13, 14, 14, 15, 13, 13, + 10, 15, 9, 13, 12, 14, 11, 12, 11, 15, 10, 13, 12, 15, 11, 12, + 15, 15, 13, 14, 14, 15, 13, 13, 4, 11, 8, 11, 6, 11, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 11, 15, 15, 14, 15, 14, 14, 13, 13, + 7, 13, 9, 12, 9, 12, 10, 11, 8, 13, 9, 12, 9, 12, 10, 11, + 14, 15, 13, 15, 13, 14, 12, 13, 11, 15, 11, 14, 12, 15, 11, 12, + 12, 15, 10, 14, 12, 15, 11, 12, 15, 15, 13, 14, 14, 15, 13, 13, + 9, 15, 12, 14, 9, 13, 11, 11, 11, 15, 13, 15, 10, 13, 11, 12, + 15, 15, 15, 15, 13, 14, 13, 13, 11, 15, 12, 14, 10, 14, 11, 12, + 12, 15, 13, 15, 11, 14, 11, 12, 15, 15, 15, 15, 13, 14, 12, 12, + 14, 15, 13, 15, 13, 15, 12, 12, 14, 15, 13, 15, 13, 15, 12, 12, + 15, 15, 14, 15, 14, 15, 12, 12, 2, 11, 6, 11, 6, 10, 9, 10, + 8, 12, 9, 12, 9, 11, 10, 11, 15, 15, 14, 14, 14, 14, 13, 13, + 5, 12, 7, 11, 8, 11, 9, 10, 8, 13, 9, 12, 10, 12, 10, 11, + 15, 15, 13, 14, 14, 15, 13, 13, 9, 15, 9, 13, 11, 14, 10, 11, + 11, 15, 10, 13, 12, 14, 11, 12, 15, 15, 13, 14, 15, 15, 13, 12, + 5, 12, 8, 12, 7, 11, 9, 10, 8, 13, 10, 12, 9, 12, 10, 11, + 15, 15, 14, 15, 13, 14, 13, 13, 7, 13, 9, 12, 9, 12, 10, 11, + 8, 13, 9, 12, 9, 12, 10, 11, 15, 15, 13, 14, 13, 15, 12, 13, + 11, 15, 10, 14, 12, 14, 11, 12, 11, 15, 10, 13, 12, 14, 11, 12, + 15, 15, 12, 14, 14, 15, 12, 12, 9, 15, 12, 14, 8, 13, 10, 11, + 11, 15, 12, 15, 10, 13, 11, 12, 15, 15, 15, 15, 13, 14, 13, 12, + 11, 15, 12, 14, 10, 14, 11, 12, 11, 15, 12, 15, 10, 13, 11, 12, + 15, 15, 14, 15, 12, 14, 12, 12, 13, 15, 13, 15, 13, 15, 12, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 13, 14, 13, 14, 12, 11, + 6, 13, 8, 12, 8, 12, 10, 11, 10, 14, 10, 13, 10, 13, 11, 12, + 15, 15, 15, 15, 14, 15, 13, 13, 7, 14, 8, 13, 9, 13, 10, 11, + 10, 15, 10, 13, 11, 13, 11, 12, 15, 15, 14, 15, 15, 15, 14, 13, + 10, 15, 9, 13, 11, 14, 11, 12, 12, 15, 11, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 7, 14, 9, 13, 9, 13, 10, 11, + 10, 14, 11, 14, 10, 13, 11, 12, 15, 15, 15, 15, 14, 15, 13, 13, + 8, 14, 10, 13, 9, 13, 11, 12, 9, 15, 10, 13, 10, 13, 11, 12, + 15, 15, 14, 15, 14, 15, 13, 13, 10, 15, 10, 14, 12, 14, 11, 12, + 10, 15, 9, 14, 12, 14, 11, 12, 15, 15, 12, 14, 15, 15, 13, 12, + 10, 15, 11, 14, 9, 13, 11, 11, 12, 15, 13, 15, 11, 14, 11, 12, + 15, 15, 15, 15, 14, 15, 13, 13, 11, 15, 12, 15, 10, 14, 11, 12, + 11, 15, 12, 15, 10, 13, 11, 12, 15, 15, 15, 15, 13, 14, 13, 12, + 13, 15, 13, 15, 13, 15, 12, 12, 12, 15, 12, 14, 12, 14, 12, 12, + 13, 15, 12, 13, 12, 14, 11, 11, 8, 15, 10, 14, 10, 14, 11, 12, + 11, 15, 12, 14, 11, 14, 11, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 9, 15, 10, 14, 10, 13, 11, 12, 11, 15, 11, 14, 11, 14, 11, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 10, 15, 10, 13, 11, 13, 10, 11, + 12, 15, 11, 14, 11, 14, 11, 11, 15, 15, 14, 14, 14, 15, 12, 11, + 9, 15, 10, 14, 10, 14, 11, 12, 12, 15, 11, 14, 11, 14, 11, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 9, 15, 10, 14, 10, 14, 11, 12, + 11, 15, 11, 14, 11, 14, 11, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 9, 15, 9, 13, 11, 13, 10, 11, 11, 15, 9, 13, 11, 14, 10, 11, + 15, 15, 12, 14, 13, 14, 12, 11, 10, 15, 11, 13, 10, 14, 10, 11, + 12, 15, 12, 14, 11, 14, 11, 11, 15, 15, 14, 15, 14, 14, 12, 11, + 10, 15, 11, 14, 10, 14, 10, 11, 11, 15, 11, 14, 10, 14, 10, 11, + 15, 15, 14, 14, 13, 14, 12, 11, 10, 15, 10, 13, 11, 13, 9, 10, + 10, 15, 10, 12, 10, 13, 10, 10, 12, 15, 11, 11, 11, 12, 10, 9 }, + { 0, 12, 7, 14, 7, 14, 13, 14, 8, 13, 11, 14, 11, 15, 14, 15, + 15, 15, 14, 14, 14, 14, 14, 14, 5, 14, 8, 14, 11, 14, 14, 14, + 10, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 11, 14, 11, 14, 14, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 4, 15, 11, 15, 8, 15, 14, 15, + 10, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 12, 15, 12, 15, 13, 15, 10, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 14, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 15, 15, 11, 15, 15, 15, 14, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 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, 1, 13, 8, 14, 7, 15, 13, 15, + 8, 13, 12, 15, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 9, 15, 10, 15, 13, 15, 10, 15, 12, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 15, 11, 15, 8, 15, 14, 15, 10, 15, 13, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 12, 15, 11, 15, 14, 15, + 9, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 13, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 15, 15, 11, 15, 15, 15, + 13, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 3, 15, 9, 15, 9, 15, 13, 15, 9, 14, 12, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 10, 15, 14, 15, + 11, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 11, 15, 14, 15, 15, 15, 13, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 11, 15, 9, 15, 13, 15, + 11, 15, 14, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 15, 12, 15, 11, 15, 14, 15, 10, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 15, 15, 10, 15, 15, 15, 13, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 6, 15, 10, 15, 10, 15, 13, 15, + 10, 15, 12, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 10, 15, 10, 15, 13, 15, 11, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 11, 15, 12, 15, 13, 15, + 14, 15, 13, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 15, 11, 15, 10, 15, 13, 15, 11, 15, 13, 15, 12, 15, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 11, 14, 10, 14, 13, 14, + 11, 14, 13, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 11, 14, 13, 14, 13, 14, 12, 14, 12, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 12, 14, 10, 14, 13, 14, + 13, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 13, 14, 11, 14, 13, 14, 12, 14, 13, 14, 11, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 13, 14, 13, 14, 13, 14, + 12, 14, 14, 14, 12, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14 } + }, + { + { 0, 6, 12, 3, 7, 12, 8, 10, 13, 4, 7, 12, 6, 8, 12, 9, + 10, 12, 9, 10, 12, 10, 10, 12, 11, 12, 13, 1, 6, 11, 4, 7, + 12, 8, 9, 13, 5, 8, 12, 6, 8, 12, 9, 10, 12, 8, 10, 12, + 10, 10, 12, 11, 11, 12, 6, 8, 12, 7, 9, 12, 9, 10, 13, 7, + 9, 12, 7, 9, 12, 10, 10, 13, 9, 11, 12, 10, 10, 13, 11, 11, + 12, 8, 10, 12, 9, 10, 12, 9, 10, 12, 9, 10, 12, 9, 10, 12, + 10, 10, 12, 10, 11, 12, 10, 10, 12, 10, 11, 11 }, + { 0, 6, 14, 3, 8, 15, 9, 12, 15, 3, 8, 15, 7, 9, 15, 11, + 12, 15, 10, 13, 14, 12, 14, 15, 15, 15, 15, 1, 7, 12, 4, 8, + 13, 10, 12, 13, 4, 9, 15, 8, 9, 15, 12, 13, 15, 10, 13, 15, + 12, 14, 15, 14, 15, 14, 5, 9, 13, 7, 10, 15, 11, 12, 13, 7, + 11, 15, 9, 12, 15, 12, 15, 15, 10, 13, 14, 13, 13, 14, 13, 15, + 15, 9, 11, 14, 10, 13, 15, 11, 13, 14, 9, 13, 15, 11, 12, 15, + 13, 15, 15, 13, 13, 15, 12, 13, 14, 14, 14, 14 } + }, + { + { 0, 5, 12, 3, 7, 12, 9, 11, 13, 3, 7, 12, 6, 8, 12, 9, + 11, 13, 9, 10, 13, 10, 10, 14, 11, 12, 13, 1, 6, 11, 5, 7, + 12, 9, 11, 13, 5, 8, 11, 6, 8, 12, 10, 11, 13, 9, 11, 13, + 10, 11, 13, 12, 12, 13, 6, 8, 12, 8, 9, 12, 10, 12, 13, 8, + 9, 12, 8, 10, 12, 11, 12, 14, 10, 12, 13, 11, 12, 13, 12, 13, + 14, 9, 10, 12, 10, 11, 12, 13, 13, 13, 10, 11, 12, 11, 12, 13, + 12, 13, 13, 12, 12, 13, 12, 12, 14, 12, 13, 13 }, + { 0, 5, 14, 3, 10, 14, 14, 14, 14, 3, 8, 14, 6, 8, 14, 9, + 14, 14, 9, 14, 14, 14, 14, 14, 14, 14, 14, 1, 5, 14, 5, 9, + 14, 8, 14, 14, 4, 9, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 5, 7, 14, 9, 9, 14, 14, 14, 14, 14, + 14, 14, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 12, 12, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 14 } + } +}; + +static const CoeffLens rv60_inter_lens[7] = { + { + { + { 0, 6, 4, 6, 5, 6, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 11, 13, 11, 11, 12, 11, 10, 8, 6, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 10, 12, 9, 10, 11, 11, 9, 8, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 6, 8, 7, 8, 7, 8, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 12, 13, 13, 11, 9, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 12, 12, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 12, 10, 11, 10, 11, 9, 8, 12, 14, 12, 12, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 13, 11, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 14, 15, 13, 12, 13, 12, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 14, 12, 9, 5, 8, 6, 7, 6, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 12, 14, 12, 12, 12, 12, 11, 9, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 12, 12, 13, 13, 11, 9, 11, 13, 10, 11, 12, 12, 10, 9, + 13, 15, 12, 12, 13, 13, 11, 9, 15, 15, 13, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 9, 9, 11, 9, 10, 10, 10, 9, 8, + 11, 13, 11, 11, 11, 11, 10, 8, 15, 15, 13, 13, 14, 13, 12, 10, + 13, 14, 11, 12, 13, 13, 11, 9, 14, 15, 12, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 15, 14, 12, 10, 11, 13, 11, 11, 11, 11, 10, 8, + 13, 15, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 14, 13, 12, 10, + 13, 15, 12, 12, 12, 12, 11, 9, 14, 15, 13, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 14, 12, 9, + 8, 11, 9, 10, 9, 10, 9, 8, 11, 13, 11, 11, 11, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 10, 12, 10, 11, 11, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 15, 11, 12, 13, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 10, 13, 11, 11, 10, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 14, 11, 12, 12, 12, 11, 9, 13, 15, 13, 13, 13, 13, 11, 10, + 15, 15, 15, 14, 15, 14, 13, 11, 14, 15, 12, 13, 14, 14, 12, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 12, 15, 12, 13, 12, 12, 11, 10, 14, 15, 14, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 14, 13, 10, 14, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 15, 15, 15, 14, 15, 15, 12, 10, 11, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 13, 13, 12, 10, 15, 15, 14, 14, 15, 15, 13, 11, + 12, 14, 12, 12, 12, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 12, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 12, 14, 12, 13, 12, 13, 11, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 13, 13, 14, 14, 12, 10, 15, 15, 13, 14, 15, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 12, 10, 13, 15, 13, 14, 12, 13, 11, 10, + 15, 15, 14, 14, 13, 13, 12, 10, 15, 15, 15, 15, 15, 14, 12, 10, + 14, 15, 14, 14, 13, 13, 12, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9, + 15, 15, 14, 14, 14, 14, 11, 9, 15, 15, 13, 13, 14, 13, 11, 8 }, + { 0, 6, 3, 7, 4, 7, 6, 7, 5, 9, 7, 9, 8, 10, 8, 9, + 13, 15, 13, 13, 14, 14, 12, 12, 4, 9, 6, 8, 7, 10, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 11, 14, 11, 12, 13, 14, 11, 11, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 5, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 8, 11, 9, 10, 10, 11, 10, 10, 11, 13, 11, 11, 11, 12, 11, 11, + 15, 15, 14, 14, 15, 15, 13, 13, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 14, 14, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 14, 12, 13, 11, 13, 12, 11, 14, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 5, 8, 6, 9, 7, 8, + 7, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 13, 14, 14, 13, 12, + 6, 10, 7, 9, 8, 10, 9, 9, 9, 12, 10, 11, 11, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 12, 12, 14, 11, 12, 13, 14, 12, 11, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 6, 10, 8, 10, 8, 10, 9, 9, 9, 12, 10, 11, 10, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 13, 9, 12, 9, 11, 10, 12, 10, 10, + 11, 13, 11, 12, 12, 13, 11, 11, 15, 15, 14, 14, 15, 15, 14, 13, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 12, 15, 12, 13, 11, 13, 12, 12, + 14, 15, 14, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 13, 14, 13, 14, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 7, 11, 9, 10, 9, 11, 10, 10, 11, 13, 11, 12, 12, 13, 11, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 11, 11, 13, 11, 11, + 12, 14, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 13, 15, 12, 14, 14, 15, 13, 12, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 13, 10, 12, 10, 12, 11, 11, + 12, 14, 12, 13, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 14, 12, 12, 12, 13, 12, 11, 13, 15, 13, 13, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 13, 15, 14, 14, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 10, 14, 11, 13, 12, 14, 12, 12, + 13, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 12, 13, 13, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 13, 13, 12, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 14, 15, 15, 15, 14, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 14, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 13, 12 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 8, 8, + 8, 9, 6, 7, 9, 7, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 9, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 9, 7, 8, 9, + 8, 9, 9, 9, 9, 9, 6, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 10, 9, 10, 11, 9, 10, 10, 9, 10, 10, 9, 10, 11, + 10, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 9, 2, 6, 10, 8, 9, 12, 3, 6, 10, 5, 7, 10, 9, + 10, 12, 8, 9, 11, 9, 10, 12, 11, 12, 13, 2, 5, 10, 4, 7, + 10, 8, 10, 12, 5, 7, 10, 6, 8, 11, 10, 10, 12, 8, 10, 12, + 9, 10, 12, 12, 12, 13, 7, 9, 11, 8, 9, 12, 10, 11, 13, 8, + 9, 12, 9, 10, 12, 11, 12, 13, 10, 11, 13, 11, 12, 13, 13, 13, + 13, 10, 11, 13, 11, 12, 14, 12, 13, 14, 10, 12, 13, 11, 12, 14, + 12, 13, 14, 11, 12, 14, 12, 13, 14, 13, 13, 13 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 9, 7, + 8, 9, 6, 8, 9, 8, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 8, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 10, 7, 8, 9, + 8, 9, 10, 9, 10, 9, 5, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 10, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 10, 10, 11, + 10, 10, 10, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 3, 10, 2, 6, 11, 7, 10, 13, 3, 6, 11, 5, 8, 12, 9, + 11, 14, 9, 10, 13, 10, 11, 14, 13, 13, 15, 2, 6, 11, 4, 7, + 12, 8, 10, 14, 5, 8, 12, 7, 9, 12, 10, 11, 14, 10, 11, 14, + 11, 12, 14, 13, 14, 15, 7, 9, 12, 8, 10, 13, 11, 13, 15, 9, + 10, 13, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 12, 14, 12, 13, 15, 14, 14, 15, 12, 13, 15, 13, 14, 15, + 14, 15, 15, 14, 14, 15, 14, 14, 15, 15, 15, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 12, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 6, 4, 6, 5, 6, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 11, 13, 11, 11, 12, 11, 10, 8, 6, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 10, 12, 9, 10, 11, 11, 9, 8, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 6, 8, 7, 8, 7, 8, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 7, 13, 14, 12, 12, 13, 12, 11, 9, + 8, 10, 8, 9, 9, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 12, 13, 13, 11, 9, 12, 14, 11, 11, 12, 12, 10, 9, + 14, 15, 12, 12, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 10, 12, 10, 11, 10, 11, 9, 8, 12, 14, 12, 12, 12, 12, 10, 9, + 14, 15, 13, 13, 14, 13, 11, 9, 12, 14, 11, 12, 12, 12, 10, 9, + 14, 15, 13, 12, 13, 12, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 13, 15, 12, 13, 13, 13, 11, 9, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 14, 12, 9, 5, 8, 6, 7, 6, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 7, 12, 14, 12, 12, 12, 12, 11, 9, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 12, 12, 13, 13, 11, 9, 11, 13, 10, 11, 12, 12, 10, 9, + 13, 15, 12, 12, 13, 13, 11, 9, 15, 15, 13, 13, 14, 14, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 7, 10, 12, 10, 10, 10, 10, 9, 8, + 14, 15, 13, 13, 13, 13, 11, 9, 9, 11, 9, 10, 10, 10, 9, 8, + 11, 13, 11, 11, 11, 11, 10, 8, 15, 15, 13, 13, 14, 13, 12, 10, + 13, 14, 11, 12, 13, 13, 11, 9, 14, 15, 12, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 15, 14, 12, 10, 11, 13, 11, 11, 11, 11, 10, 8, + 13, 15, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 14, 13, 12, 10, + 13, 15, 12, 12, 12, 12, 11, 9, 14, 15, 13, 13, 13, 13, 11, 9, + 15, 15, 14, 14, 14, 14, 12, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 14, 12, 9, + 8, 11, 9, 10, 9, 10, 9, 8, 11, 13, 11, 11, 11, 12, 10, 9, + 14, 15, 13, 13, 14, 14, 12, 10, 10, 12, 10, 11, 11, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 15, 11, 12, 13, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 10, 13, 11, 11, 10, 11, 10, 9, + 13, 14, 12, 12, 12, 12, 11, 9, 15, 15, 14, 14, 15, 14, 12, 10, + 12, 14, 11, 12, 12, 12, 11, 9, 13, 15, 13, 13, 13, 13, 11, 10, + 15, 15, 15, 14, 15, 14, 13, 11, 14, 15, 12, 13, 14, 14, 12, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 12, 15, 12, 13, 12, 12, 11, 10, 14, 15, 14, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 14, 13, 10, 14, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 15, 15, 15, 14, 15, 15, 12, 10, 11, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 13, 13, 12, 10, 15, 15, 14, 14, 15, 15, 13, 11, + 12, 14, 12, 12, 12, 13, 11, 10, 14, 15, 13, 13, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 12, 13, 13, 14, 11, 10, + 15, 15, 13, 13, 14, 14, 12, 10, 15, 15, 14, 14, 15, 15, 12, 10, + 12, 14, 12, 13, 12, 13, 11, 10, 14, 15, 13, 14, 13, 13, 12, 10, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 13, 13, 13, 13, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 13, 13, 14, 14, 12, 10, 15, 15, 13, 14, 15, 14, 12, 10, + 15, 15, 14, 14, 15, 15, 12, 10, 13, 15, 13, 14, 12, 13, 11, 10, + 15, 15, 14, 14, 13, 13, 12, 10, 15, 15, 15, 15, 15, 14, 12, 10, + 14, 15, 14, 14, 13, 13, 12, 10, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 15, 15, 15, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9, + 15, 15, 14, 14, 14, 14, 11, 9, 15, 15, 13, 13, 14, 13, 11, 8 }, + { 0, 6, 3, 7, 4, 7, 6, 7, 5, 9, 7, 9, 8, 10, 8, 9, + 13, 15, 13, 13, 14, 14, 12, 12, 4, 9, 6, 8, 7, 10, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 11, 14, 11, 12, 13, 14, 11, 11, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 5, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 10, 10, 11, 10, 10, 15, 15, 14, 14, 14, 15, 13, 12, + 8, 11, 9, 10, 10, 11, 10, 10, 11, 13, 11, 11, 11, 12, 11, 11, + 15, 15, 14, 14, 15, 15, 13, 13, 13, 15, 12, 13, 14, 15, 12, 12, + 15, 15, 14, 14, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 14, 12, 13, 11, 13, 12, 11, 14, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 14, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 5, 8, 6, 9, 7, 8, + 7, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 13, 14, 14, 13, 12, + 6, 10, 7, 9, 8, 10, 9, 9, 9, 12, 10, 11, 11, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 12, 12, 14, 11, 12, 13, 14, 12, 11, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 6, 10, 8, 10, 8, 10, 9, 9, 9, 12, 10, 11, 10, 12, 10, 10, + 15, 15, 14, 14, 15, 15, 13, 13, 9, 12, 9, 11, 10, 12, 10, 10, + 11, 13, 11, 12, 12, 13, 11, 11, 15, 15, 14, 14, 15, 15, 14, 13, + 14, 15, 13, 13, 14, 15, 13, 12, 15, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 12, 15, 12, 13, 11, 13, 12, 12, + 14, 15, 14, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 13, 14, 13, 14, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 7, 11, 9, 10, 9, 11, 10, 10, 11, 13, 11, 12, 12, 13, 11, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 11, 11, 13, 11, 11, + 12, 14, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 13, 15, 12, 14, 14, 15, 13, 12, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 13, 10, 12, 10, 12, 11, 11, + 12, 14, 12, 13, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 14, 12, 12, 12, 13, 12, 11, 13, 15, 13, 13, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 14, 14, 15, 15, 14, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 13, 15, 14, 14, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 15, 15, 15, 15, 15, 15, 15, 14, 10, 14, 11, 13, 12, 14, 12, 12, + 13, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 12, 13, 13, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 15, 13, 14, 15, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 12, 15, 13, 13, 12, 14, 12, 12, 14, 15, 14, 14, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 13, 14, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 14, 15, 15, 15, 14, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 13, 15, 14, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 15, 15, 15, 15, 15, 15, 13, 12 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 8, 8, + 8, 9, 6, 7, 9, 7, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 9, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 9, 7, 8, 9, + 8, 9, 9, 9, 9, 9, 6, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 9, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 10, 9, 10, 11, 9, 10, 10, 9, 10, 10, 9, 10, 11, + 10, 10, 10, 9, 10, 10, 9, 10, 10, 9, 9, 9 }, + { 0, 4, 9, 2, 6, 10, 8, 9, 12, 3, 6, 10, 5, 7, 10, 9, + 10, 12, 8, 9, 11, 9, 10, 12, 11, 12, 13, 2, 5, 10, 4, 7, + 10, 8, 10, 12, 5, 7, 10, 6, 8, 11, 10, 10, 12, 8, 10, 12, + 9, 10, 12, 12, 12, 13, 7, 9, 11, 8, 9, 12, 10, 11, 13, 8, + 9, 12, 9, 10, 12, 11, 12, 13, 10, 11, 13, 11, 12, 13, 13, 13, + 13, 10, 11, 13, 11, 12, 14, 12, 13, 14, 10, 12, 13, 11, 12, 14, + 12, 13, 14, 11, 12, 14, 12, 13, 14, 13, 13, 13 } + }, + { + { 0, 4, 7, 3, 5, 8, 6, 8, 9, 3, 5, 8, 5, 6, 9, 7, + 8, 9, 6, 8, 9, 8, 8, 9, 8, 9, 9, 3, 5, 8, 4, 6, + 8, 7, 8, 9, 5, 6, 8, 6, 7, 9, 8, 9, 10, 7, 8, 9, + 8, 9, 10, 9, 10, 9, 5, 8, 9, 7, 8, 10, 8, 9, 10, 7, + 8, 10, 8, 9, 10, 9, 10, 10, 8, 10, 10, 9, 10, 10, 10, 10, + 10, 8, 10, 11, 9, 10, 11, 9, 10, 10, 9, 10, 11, 10, 10, 11, + 10, 10, 10, 10, 11, 11, 10, 11, 11, 10, 10, 9 }, + { 0, 3, 10, 2, 6, 11, 7, 10, 13, 3, 6, 11, 5, 8, 12, 9, + 11, 14, 9, 10, 13, 10, 11, 14, 13, 13, 15, 2, 6, 11, 4, 7, + 12, 8, 10, 14, 5, 8, 12, 7, 9, 12, 10, 11, 14, 10, 11, 14, + 11, 12, 14, 13, 14, 15, 7, 9, 12, 8, 10, 13, 11, 13, 15, 9, + 10, 13, 10, 11, 14, 12, 13, 15, 12, 13, 15, 12, 13, 15, 14, 14, + 15, 11, 12, 14, 12, 13, 15, 14, 14, 15, 12, 13, 15, 13, 14, 15, + 14, 15, 15, 14, 14, 15, 14, 14, 15, 15, 15, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 12, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 5, 4, 5, 4, 5, 5, 5, 6, 8, 7, 8, 7, 8, 7, 6, + 12, 14, 12, 12, 12, 12, 11, 10, 5, 8, 6, 7, 7, 8, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 11, 13, 10, 11, 11, 12, 10, 9, 13, 15, 12, 12, 13, 13, 11, 10, + 15, 15, 14, 14, 15, 15, 13, 11, 5, 8, 6, 8, 6, 7, 7, 6, + 8, 10, 9, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 8, 10, 8, 9, 9, 9, 8, 8, 10, 12, 10, 11, 10, 11, 10, 9, + 15, 15, 14, 14, 14, 14, 12, 11, 12, 15, 12, 12, 13, 13, 11, 10, + 14, 15, 13, 13, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 11, 13, 11, 12, 10, 11, 10, 9, 13, 14, 12, 13, 12, 12, 11, 10, + 15, 15, 14, 14, 14, 14, 13, 11, 12, 15, 12, 13, 12, 12, 11, 10, + 14, 15, 13, 13, 13, 13, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 15, 15, 14, 14, 14, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 4, 8, 6, 7, 6, 7, 7, 6, + 8, 10, 8, 9, 9, 9, 8, 8, 13, 15, 13, 13, 13, 13, 12, 10, + 7, 10, 8, 9, 8, 9, 8, 8, 10, 12, 10, 10, 10, 11, 9, 9, + 14, 15, 14, 14, 14, 14, 12, 11, 11, 14, 10, 12, 12, 13, 11, 10, + 13, 15, 12, 13, 13, 14, 12, 10, 15, 15, 15, 15, 15, 15, 13, 11, + 7, 10, 8, 9, 8, 9, 8, 8, 10, 12, 10, 11, 10, 10, 9, 9, + 14, 15, 14, 14, 14, 14, 12, 11, 9, 12, 10, 10, 10, 10, 9, 9, + 11, 13, 11, 12, 11, 12, 10, 9, 15, 15, 14, 14, 14, 14, 13, 11, + 13, 15, 12, 13, 13, 13, 12, 10, 14, 15, 13, 13, 14, 14, 12, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 12, 14, 12, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 12, 13, 12, 10, 15, 15, 15, 15, 15, 14, 13, 11, + 13, 15, 13, 13, 12, 13, 11, 10, 14, 15, 14, 14, 13, 13, 12, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 14, 15, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 8, 11, 9, 11, 10, 11, 10, 9, 11, 14, 11, 12, 12, 12, 11, 10, + 15, 15, 15, 15, 15, 15, 14, 12, 10, 13, 10, 12, 11, 12, 11, 10, + 13, 15, 12, 13, 13, 13, 12, 11, 15, 15, 15, 15, 15, 15, 14, 12, + 13, 15, 12, 13, 14, 14, 12, 11, 15, 15, 13, 14, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 10, 13, 11, 12, 11, 12, 11, 10, + 13, 15, 13, 13, 12, 13, 12, 11, 15, 15, 15, 15, 15, 15, 14, 12, + 12, 14, 12, 13, 12, 13, 11, 11, 13, 15, 13, 14, 13, 14, 12, 11, + 15, 15, 15, 15, 15, 15, 14, 12, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 14, 14, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 13, 15, 13, 14, 12, 13, 12, 11, 15, 15, 14, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 15, 15, 14, 12, 14, 15, 14, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 14, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 11, 11, 13, 11, 13, 12, 13, 11, 11, + 13, 15, 13, 14, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 12, 15, 12, 13, 13, 14, 12, 11, 14, 15, 14, 14, 14, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 13, 15, 12, 13, 14, 14, 12, 11, + 15, 15, 13, 14, 15, 15, 13, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 12, 15, 13, 14, 12, 13, 12, 11, 14, 15, 14, 15, 14, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 13, 15, 13, 14, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 14, 15, 13, 14, 14, 15, 12, 11, 15, 15, 14, 14, 15, 15, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 13, 15, 14, 14, 12, 13, 12, 11, + 15, 15, 15, 15, 13, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 11, + 14, 15, 14, 15, 13, 14, 12, 11, 15, 15, 15, 15, 13, 14, 13, 11, + 15, 15, 15, 15, 15, 15, 13, 11, 15, 15, 14, 14, 14, 14, 12, 10, + 15, 15, 14, 14, 14, 14, 12, 10, 15, 15, 13, 14, 14, 14, 11, 9 }, + { 0, 5, 3, 7, 4, 7, 6, 8, 5, 9, 7, 9, 8, 10, 9, 10, + 13, 15, 13, 14, 14, 15, 14, 14, 4, 9, 6, 9, 7, 10, 8, 9, + 8, 11, 9, 11, 10, 12, 10, 11, 15, 15, 14, 15, 15, 15, 15, 15, + 11, 14, 11, 13, 13, 15, 13, 13, 14, 15, 13, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 7, 9, 7, 9, 8, 9, + 8, 11, 9, 11, 9, 11, 10, 11, 15, 15, 14, 15, 15, 15, 14, 15, + 8, 11, 9, 11, 10, 12, 10, 11, 10, 13, 11, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 13, 15, 14, 15, 14, 14, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 14, 11, 14, 12, 13, 14, 15, 14, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 14, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 14, 15, 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, 2, 8, 5, 8, 6, 9, 7, 9, + 7, 10, 8, 10, 9, 11, 10, 11, 14, 15, 14, 15, 15, 15, 14, 14, + 6, 10, 7, 10, 9, 11, 9, 10, 9, 12, 10, 12, 11, 13, 11, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 11, 14, 14, 15, 13, 13, + 14, 15, 13, 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 10, 8, 10, 8, 11, 9, 10, 9, 12, 10, 12, 10, 12, 11, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 12, 10, 12, 10, 12, 11, 12, + 11, 14, 11, 13, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 11, 14, 13, 13, + 14, 15, 15, 15, 13, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 13, 15, 14, 14, 15, 15, 15, 15, 14, 15, 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, + 7, 11, 9, 11, 9, 12, 10, 11, 10, 13, 11, 13, 12, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 10, 12, 11, 13, 11, 12, + 12, 15, 12, 14, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 12, 15, 14, 15, 14, 14, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 10, 13, 10, 13, 11, 12, + 12, 15, 13, 14, 12, 14, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 14, 12, 14, 13, 13, 12, 15, 13, 15, 13, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 12, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 14, 15, + 15, 15, 15, 15, 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, 10, 14, 12, 14, 12, 14, 13, 13, + 13, 15, 13, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 15, 13, 15, 13, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 14, 15, 14, 14, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 12, 15, 13, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 13, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 14, 14, 15, 15, 14, 15, 15, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 12, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 15, 15, 13, 15, 14, 14, 14, 15, 15, 15, 13, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 15, 15, 15, 14, 15, 14, 14, 15, 15, 15, 15, 14, 15, 14, 13 } + }, + { + { 0, 3, 8, 3, 5, 9, 7, 9, 10, 3, 5, 9, 5, 7, 9, 9, + 9, 11, 7, 8, 10, 8, 9, 10, 10, 11, 11, 2, 5, 9, 5, 7, + 10, 8, 9, 11, 5, 6, 9, 6, 7, 10, 9, 10, 11, 8, 9, 10, + 9, 9, 11, 10, 11, 11, 7, 8, 11, 8, 9, 11, 9, 10, 12, 8, + 9, 11, 9, 10, 11, 10, 11, 12, 9, 10, 11, 10, 11, 11, 11, 11, + 11, 9, 11, 12, 10, 11, 12, 10, 11, 11, 10, 11, 12, 10, 11, 12, + 11, 11, 11, 10, 11, 11, 10, 11, 11, 11, 10, 10 }, + { 0, 3, 10, 2, 6, 11, 9, 10, 14, 3, 6, 11, 6, 8, 12, 10, + 12, 14, 8, 10, 13, 10, 11, 14, 13, 14, 15, 2, 5, 11, 5, 7, + 12, 9, 11, 14, 4, 7, 12, 7, 8, 12, 11, 12, 14, 9, 11, 13, + 11, 11, 14, 13, 14, 15, 7, 9, 13, 9, 11, 14, 11, 13, 15, 8, + 10, 14, 10, 11, 14, 12, 13, 15, 10, 12, 14, 12, 13, 14, 14, 14, + 14, 11, 12, 14, 12, 13, 14, 13, 14, 14, 11, 13, 14, 12, 13, 14, + 13, 14, 15, 12, 14, 15, 13, 14, 14, 14, 14, 14 } + }, + { + { 0, 3, 8, 3, 5, 9, 7, 9, 10, 3, 5, 9, 5, 7, 10, 9, + 10, 11, 7, 9, 10, 9, 10, 11, 10, 11, 11, 2, 5, 9, 4, 7, + 10, 8, 9, 11, 5, 7, 10, 6, 8, 10, 9, 10, 11, 8, 9, 11, + 9, 10, 11, 11, 11, 11, 6, 9, 11, 8, 9, 11, 10, 11, 12, 8, + 10, 11, 9, 10, 12, 11, 11, 12, 10, 11, 12, 11, 11, 12, 12, 12, + 12, 10, 11, 12, 11, 11, 12, 11, 12, 12, 11, 12, 13, 11, 12, 13, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11 }, + { 0, 5, 12, 2, 7, 13, 10, 12, 16, 3, 8, 13, 7, 10, 14, 12, + 13, 16, 11, 12, 16, 12, 14, 16, 15, 16, 16, 1, 7, 13, 5, 9, + 14, 11, 13, 16, 6, 9, 14, 8, 11, 15, 13, 14, 16, 12, 13, 16, + 13, 14, 16, 15, 15, 16, 9, 11, 14, 11, 12, 16, 14, 15, 16, 11, + 13, 16, 12, 13, 16, 15, 16, 16, 14, 15, 16, 15, 15, 16, 16, 16, + 16, 14, 15, 16, 15, 15, 16, 16, 16, 16, 15, 16, 16, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, 12, 12, 12, 13, 14, 14, 14, 14 } + }, + { + { + { 0, 5, 3, 5, 4, 5, 5, 5, 5, 8, 6, 8, 7, 8, 7, 7, + 13, 14, 12, 13, 13, 13, 12, 11, 5, 8, 6, 7, 7, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 12, 11, + 11, 14, 10, 12, 12, 13, 11, 10, 13, 15, 12, 13, 13, 14, 12, 11, + 15, 15, 14, 15, 15, 15, 13, 12, 5, 8, 6, 8, 6, 7, 7, 7, + 8, 10, 9, 10, 9, 9, 9, 9, 14, 15, 13, 13, 13, 13, 12, 11, + 8, 10, 8, 10, 9, 10, 9, 9, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 12, 15, 12, 13, 13, 14, 12, 11, + 14, 15, 13, 14, 14, 15, 12, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 13, 11, 12, 10, 11, 10, 10, 12, 15, 13, 13, 12, 12, 11, 11, + 15, 15, 14, 15, 14, 14, 13, 12, 12, 15, 13, 13, 12, 13, 12, 11, + 14, 15, 13, 14, 13, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 4, 7, 6, 7, 6, 8, 7, 7, + 8, 10, 8, 10, 9, 10, 9, 9, 14, 15, 13, 14, 14, 14, 13, 11, + 7, 10, 7, 9, 8, 10, 8, 8, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 11, 14, 10, 12, 12, 13, 11, 11, + 13, 15, 12, 13, 14, 14, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 7, 10, 8, 10, 8, 9, 8, 8, 10, 12, 10, 11, 10, 11, 10, 10, + 15, 15, 14, 14, 14, 14, 13, 12, 9, 12, 10, 11, 10, 11, 10, 10, + 11, 13, 11, 12, 11, 12, 11, 10, 15, 15, 14, 15, 14, 15, 13, 12, + 13, 15, 12, 13, 13, 14, 12, 11, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 11, 14, 12, 13, 10, 12, 11, 11, + 13, 15, 13, 14, 12, 13, 12, 11, 15, 15, 15, 15, 15, 15, 13, 12, + 13, 15, 13, 14, 12, 13, 12, 11, 14, 15, 14, 15, 13, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 11, + 8, 12, 9, 11, 10, 11, 10, 10, 11, 14, 12, 13, 12, 13, 12, 11, + 15, 15, 15, 15, 15, 15, 14, 13, 10, 13, 10, 12, 11, 12, 11, 11, + 12, 15, 12, 13, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 11, 13, 13, 15, 12, 12, 14, 15, 13, 14, 15, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 10, 13, 11, 12, 10, 12, 11, 11, + 12, 15, 13, 14, 12, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 14, 12, 13, 12, 13, 12, 11, 13, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 14, 15, 13, 14, 14, 15, 13, 12, + 14, 15, 13, 15, 15, 15, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 13, 14, 11, 13, 12, 11, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 14, 15, 14, 15, 13, 14, 13, 12, + 14, 15, 15, 15, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 12, + 15, 15, 15, 15, 15, 15, 14, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 11, 10, 13, 11, 13, 11, 13, 12, 12, + 13, 15, 13, 14, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 14, 15, 13, 15, 14, 15, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 12, 14, 13, 15, 12, 11, + 15, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 15, 12, 14, 12, 13, 12, 12, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 13, 14, 13, 14, 13, 12, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 13, 15, 13, 14, 14, 15, 12, 12, 14, 15, 13, 14, 14, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 11, 12, 15, 13, 15, 11, 13, 12, 11, + 14, 15, 14, 15, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 13, 11, + 13, 15, 14, 15, 12, 14, 12, 11, 14, 15, 14, 15, 13, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 11, 14, 15, 13, 14, 13, 14, 12, 11, + 14, 15, 13, 14, 13, 14, 12, 11, 15, 15, 13, 14, 13, 13, 11, 9 }, + { 0, 6, 3, 7, 3, 7, 7, 9, 5, 9, 7, 10, 8, 10, 10, 11, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 6, 10, 8, 11, 9, 11, + 8, 12, 10, 12, 10, 13, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 12, 15, 14, 15, 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 9, 7, 10, 6, 10, 9, 11, + 8, 12, 10, 13, 10, 12, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 12, 10, 13, 10, 13, 11, 13, 10, 14, 12, 14, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 11, 15, 13, 15, 14, 15, 15, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 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, 2, 8, 5, 9, 6, 9, 8, 10, + 7, 11, 9, 12, 9, 12, 11, 12, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 11, 7, 11, 9, 12, 10, 12, 9, 13, 11, 13, 11, 14, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 14, 15, 14, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 11, 8, 12, 8, 11, 10, 12, 9, 13, 11, 14, 10, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 13, 11, 13, 10, 13, 12, 13, + 10, 15, 12, 15, 12, 14, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 14, 15, 11, 15, 13, 15, + 14, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 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, + 6, 12, 9, 13, 9, 13, 11, 13, 11, 14, 12, 14, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 14, 10, 14, 11, 14, 12, 14, + 12, 15, 13, 15, 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 12, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 14, 11, 14, 10, 14, 12, 13, + 12, 15, 13, 15, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 12, 15, 12, 15, 13, 14, 12, 15, 13, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 14, 15, 11, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 12, 15, 13, 14, + 13, 15, 14, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 12, 15, 13, 15, 13, 14, 14, 15, 14, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 14, 15, 14, 15, + 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 13, 14, 13, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 13, 15, 13, 15, 14, 15, + 14, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 11, 15, 13, 14, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 14, 15, 14, 15, 15, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 14, 14 } + }, + { + { 0, 3, 8, 3, 5, 9, 8, 9, 11, 3, 5, 9, 5, 7, 10, 9, + 10, 11, 7, 8, 10, 9, 10, 11, 11, 11, 11, 2, 5, 9, 5, 7, + 10, 8, 9, 11, 4, 7, 10, 6, 8, 11, 9, 10, 11, 8, 9, 11, + 9, 10, 11, 11, 11, 11, 7, 9, 11, 8, 9, 12, 10, 11, 12, 8, + 9, 12, 9, 10, 12, 10, 11, 12, 9, 10, 12, 10, 11, 12, 11, 11, + 11, 9, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12, + 11, 11, 11, 10, 11, 12, 10, 11, 12, 11, 11, 10 }, + { 0, 4, 12, 3, 7, 13, 10, 12, 15, 3, 6, 13, 6, 9, 14, 12, + 13, 15, 9, 11, 14, 11, 12, 15, 15, 15, 15, 1, 6, 12, 5, 8, + 14, 10, 12, 15, 4, 8, 14, 8, 10, 14, 12, 13, 15, 9, 12, 15, + 12, 13, 15, 15, 15, 15, 8, 10, 14, 9, 12, 15, 12, 13, 15, 9, + 11, 15, 11, 12, 15, 13, 13, 15, 11, 13, 15, 13, 14, 15, 15, 15, + 15, 11, 13, 15, 13, 14, 15, 14, 15, 15, 12, 14, 15, 13, 14, 15, + 14, 15, 15, 13, 15, 15, 14, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 5, 10, 5, 7, 11, 9, + 10, 12, 8, 10, 12, 10, 10, 12, 11, 12, 13, 2, 6, 10, 5, 7, + 11, 9, 10, 12, 5, 7, 11, 7, 9, 11, 10, 11, 12, 9, 10, 12, + 10, 11, 12, 12, 12, 13, 7, 9, 12, 9, 10, 12, 11, 12, 13, 9, + 10, 12, 10, 11, 13, 11, 12, 13, 11, 12, 13, 12, 12, 13, 13, 13, + 13, 11, 12, 13, 11, 12, 13, 12, 13, 13, 11, 12, 13, 12, 13, 13, + 12, 13, 13, 12, 13, 13, 12, 13, 13, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 15, 12, 14, 16, 3, 8, 15, 7, 11, 16, 13, + 15, 16, 12, 14, 16, 13, 15, 16, 16, 16, 16, 1, 7, 14, 6, 11, + 15, 13, 15, 16, 6, 10, 15, 10, 12, 15, 14, 16, 16, 13, 15, 16, + 14, 16, 16, 16, 16, 16, 10, 12, 15, 12, 14, 16, 15, 16, 16, 12, + 14, 16, 13, 15, 16, 16, 16, 16, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 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 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 11, 12, 12, 12, 13, 13, 13, 13, 12, 12, 13, 15, 15, 15, 15 } + }, + { + { + { 0, 5, 3, 6, 3, 6, 5, 6, 5, 8, 7, 8, 7, 8, 8, 8, + 13, 15, 13, 13, 13, 13, 12, 12, 5, 8, 6, 8, 7, 9, 8, 8, + 8, 11, 9, 10, 9, 11, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 11, 14, 10, 12, 12, 14, 11, 11, 12, 15, 12, 13, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 5, 8, 7, 8, 6, 8, 8, 8, + 8, 11, 9, 10, 9, 10, 9, 10, 14, 15, 13, 14, 13, 14, 13, 12, + 8, 11, 9, 10, 9, 11, 9, 10, 10, 13, 10, 12, 11, 12, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 12, 14, 13, 14, 12, 12, + 14, 15, 13, 14, 14, 15, 13, 12, 15, 15, 15, 15, 15, 15, 13, 13, + 10, 14, 12, 13, 10, 12, 11, 11, 12, 15, 13, 14, 11, 13, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 12, 15, 13, 14, 12, 13, 12, 12, + 13, 15, 13, 15, 13, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 14, 15, 14, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 13, 12, 3, 8, 6, 8, 6, 8, 7, 8, + 8, 11, 9, 10, 9, 10, 10, 10, 14, 15, 14, 14, 14, 14, 13, 12, + 6, 10, 7, 10, 8, 10, 9, 9, 10, 13, 10, 12, 11, 12, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 13, 11, 15, 10, 13, 12, 14, 11, 11, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 6, 10, 8, 10, 8, 10, 9, 9, 10, 12, 10, 12, 10, 11, 11, 11, + 15, 15, 14, 15, 14, 15, 13, 12, 9, 12, 10, 12, 10, 12, 10, 11, + 10, 14, 11, 13, 11, 13, 11, 11, 15, 15, 14, 15, 14, 15, 13, 13, + 13, 15, 12, 14, 13, 15, 12, 12, 13, 15, 12, 14, 14, 15, 13, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 11, 14, 12, 14, 10, 12, 11, 11, + 13, 15, 13, 14, 12, 13, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 13, 15, 13, 14, 12, 14, 12, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 15, 15, 14, 15, 14, 15, 13, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 7, 12, 9, 12, 9, 12, 10, 11, 11, 14, 12, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 10, 13, 11, 13, 11, 11, + 12, 15, 12, 14, 13, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 11, 14, 13, 15, 12, 12, 14, 15, 13, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 9, 13, 11, 13, 10, 12, 11, 11, + 12, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 12, 15, 13, 14, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 13, 15, 13, 15, 14, 15, 13, 13, + 14, 15, 13, 15, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 12, 15, 13, 15, 11, 13, 12, 12, 14, 15, 14, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 13, 15, 14, 15, 13, 14, 13, 12, + 14, 15, 14, 15, 13, 14, 13, 13, 15, 15, 15, 15, 14, 15, 14, 13, + 15, 15, 15, 15, 15, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 14, 15, 14, 15, 13, 12, 9, 14, 11, 14, 11, 13, 12, 12, + 13, 15, 13, 15, 13, 14, 13, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 14, 12, 12, 13, 15, 13, 15, 13, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 11, 14, 13, 15, 12, 12, + 14, 15, 13, 14, 14, 15, 12, 12, 15, 15, 15, 15, 15, 15, 13, 12, + 11, 15, 12, 14, 11, 14, 12, 12, 13, 15, 14, 15, 13, 14, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 13, 15, 12, 14, 13, 12, + 13, 15, 14, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 12, 15, 12, 14, 13, 15, 12, 12, 13, 15, 12, 15, 14, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 12, 12, 15, 13, 15, 11, 13, 12, 11, + 14, 15, 14, 15, 12, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 12, 15, 13, 15, 12, 14, 12, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 13, 15, 13, 14, 13, 14, 12, 11, + 13, 15, 12, 14, 12, 14, 12, 11, 14, 15, 12, 13, 12, 13, 11, 10 }, + { 0, 6, 4, 9, 4, 9, 8, 10, 5, 10, 9, 12, 8, 12, 11, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 7, 11, 8, 12, 11, 13, + 9, 13, 11, 14, 11, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 8, 12, 7, 11, 10, 13, + 9, 13, 11, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 14, 11, 15, 11, 14, 13, 14, 11, 15, 13, 15, 13, 15, 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, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 9, 6, 11, 6, 11, 10, 12, + 7, 11, 10, 13, 10, 13, 12, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 12, 8, 13, 10, 13, 12, 13, 10, 15, 12, 15, 12, 15, 13, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 12, 10, 13, 8, 13, 11, 13, 10, 15, 12, 15, 11, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 11, 15, 13, 15, + 11, 15, 13, 15, 12, 15, 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, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 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, + 7, 14, 10, 14, 10, 14, 13, 14, 11, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 11, 15, 12, 15, 13, 15, + 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 11, 15, 13, 15, + 12, 15, 14, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 13, 15, 14, 15, 12, 15, 14, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 12, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 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, 9, 15, 13, 15, 12, 15, 14, 15, + 13, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 11, 15, 13, 15, 13, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 14, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 14, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 14, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 3, 6, 10, 8, 9, 12, 2, 6, 10, 6, 7, 11, 10, + 10, 12, 7, 9, 11, 9, 10, 12, 11, 12, 12, 2, 6, 10, 5, 7, + 11, 8, 10, 12, 5, 7, 11, 7, 8, 11, 10, 10, 12, 8, 10, 12, + 10, 10, 12, 11, 12, 12, 7, 9, 12, 8, 10, 12, 10, 11, 13, 8, + 10, 12, 9, 10, 13, 11, 11, 13, 9, 11, 13, 11, 11, 13, 12, 12, + 12, 9, 11, 12, 10, 11, 13, 10, 11, 12, 10, 11, 13, 11, 11, 13, + 11, 11, 12, 10, 11, 12, 11, 11, 12, 11, 11, 11 }, + { 0, 5, 14, 3, 8, 15, 11, 13, 15, 2, 7, 15, 7, 10, 15, 13, + 14, 15, 10, 12, 15, 13, 14, 15, 15, 15, 15, 1, 7, 14, 6, 10, + 15, 12, 14, 15, 5, 10, 15, 9, 11, 15, 13, 14, 15, 10, 13, 15, + 13, 14, 15, 15, 15, 15, 8, 11, 15, 10, 13, 15, 13, 15, 15, 10, + 13, 15, 11, 13, 15, 14, 15, 15, 12, 14, 15, 14, 15, 15, 15, 15, + 15, 12, 15, 15, 13, 15, 15, 15, 15, 15, 13, 15, 15, 14, 15, 15, + 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 6, 10, 5, 7, 11, 9, + 10, 12, 8, 10, 12, 10, 11, 12, 12, 12, 13, 2, 5, 10, 5, 7, + 11, 9, 10, 12, 5, 7, 11, 7, 9, 11, 10, 11, 13, 9, 10, 12, + 10, 11, 13, 12, 12, 13, 7, 9, 12, 8, 10, 12, 11, 12, 14, 9, + 10, 12, 10, 11, 13, 12, 12, 14, 11, 12, 13, 12, 12, 13, 13, 13, + 14, 11, 12, 13, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, + 13, 13, 14, 12, 13, 14, 13, 13, 14, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 16, 13, 16, 16, 3, 8, 16, 7, 11, 16, 14, + 16, 16, 12, 14, 16, 13, 15, 16, 16, 16, 16, 1, 7, 14, 6, 10, + 16, 13, 16, 16, 6, 10, 15, 10, 12, 16, 15, 16, 16, 14, 16, 16, + 14, 16, 16, 16, 16, 16, 10, 12, 15, 12, 14, 16, 16, 16, 16, 12, + 14, 16, 13, 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 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, 12, 12, 12, 13, 14, 14, 14, 14 } + }, + { + { + { 0, 5, 4, 6, 3, 6, 6, 7, 5, 8, 7, 9, 7, 9, 8, 9, + 13, 15, 13, 14, 13, 14, 12, 12, 4, 9, 6, 9, 7, 9, 8, 9, + 8, 11, 9, 11, 9, 11, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 10, 15, 10, 13, 12, 14, 11, 12, 12, 15, 12, 13, 13, 14, 12, 12, + 15, 15, 14, 15, 14, 15, 13, 13, 4, 8, 7, 9, 6, 8, 8, 8, + 8, 11, 9, 11, 8, 10, 10, 10, 14, 15, 13, 14, 13, 14, 13, 12, + 7, 11, 9, 11, 9, 11, 10, 10, 9, 13, 10, 12, 10, 12, 11, 11, + 14, 15, 14, 15, 14, 14, 13, 13, 12, 15, 12, 14, 13, 14, 12, 12, + 13, 15, 12, 14, 13, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 10, 14, 11, 13, 9, 12, 11, 11, 12, 15, 12, 14, 11, 13, 12, 12, + 15, 15, 14, 15, 13, 15, 13, 12, 12, 15, 13, 14, 11, 13, 12, 12, + 13, 15, 13, 15, 12, 14, 12, 12, 15, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 15, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 13, 12, 3, 8, 6, 8, 6, 8, 8, 8, + 7, 11, 9, 11, 9, 10, 10, 10, 14, 15, 14, 14, 13, 14, 13, 12, + 6, 11, 7, 10, 8, 10, 9, 10, 9, 12, 10, 12, 10, 12, 10, 11, + 15, 15, 14, 15, 14, 15, 13, 13, 10, 15, 10, 13, 12, 14, 11, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 14, 15, 15, 15, 13, 13, + 6, 10, 8, 10, 7, 10, 9, 10, 9, 12, 10, 12, 10, 11, 10, 11, + 15, 15, 14, 15, 14, 14, 13, 13, 8, 12, 10, 12, 9, 12, 10, 11, + 10, 13, 10, 13, 10, 12, 11, 11, 15, 15, 14, 15, 14, 15, 13, 13, + 12, 15, 12, 14, 13, 14, 12, 12, 13, 15, 12, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 13, 10, 15, 12, 14, 9, 12, 11, 11, + 12, 15, 13, 14, 11, 13, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 12, 15, 13, 15, 11, 13, 12, 12, 12, 15, 13, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 15, 13, 12, 14, 15, 14, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 12, 15, 15, 14, 15, 14, 15, 13, 12, + 7, 12, 9, 12, 9, 12, 10, 11, 10, 14, 11, 13, 11, 13, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 8, 13, 10, 13, 10, 13, 11, 11, + 11, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 11, 14, 12, 15, 12, 12, 13, 15, 12, 15, 14, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 13, 8, 13, 10, 13, 10, 12, 11, 11, + 11, 15, 12, 14, 11, 13, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 10, 14, 11, 13, 11, 13, 12, 12, 11, 15, 12, 14, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 12, 14, 13, 15, 12, 13, + 13, 15, 12, 15, 14, 15, 13, 13, 15, 15, 14, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 10, 13, 11, 12, 13, 15, 14, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 12, 15, 13, 15, 12, 14, 12, 12, + 13, 15, 14, 15, 12, 14, 13, 12, 15, 15, 15, 15, 14, 15, 13, 13, + 14, 15, 14, 15, 14, 15, 13, 13, 14, 15, 14, 15, 14, 15, 13, 13, + 15, 15, 13, 15, 13, 15, 12, 12, 9, 14, 11, 13, 10, 13, 11, 12, + 12, 15, 12, 14, 12, 14, 12, 12, 15, 15, 15, 15, 15, 15, 14, 13, + 10, 14, 11, 14, 11, 14, 12, 12, 13, 15, 13, 15, 13, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 11, 14, 12, 14, 11, 12, + 13, 15, 12, 14, 13, 15, 12, 12, 15, 15, 14, 15, 15, 15, 13, 12, + 10, 14, 12, 14, 11, 13, 12, 12, 13, 15, 13, 15, 12, 14, 13, 12, + 15, 15, 15, 15, 15, 15, 14, 13, 11, 15, 12, 14, 12, 14, 12, 12, + 13, 15, 13, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 13, + 11, 15, 12, 14, 12, 15, 12, 12, 13, 15, 12, 14, 13, 15, 12, 12, + 15, 15, 14, 15, 15, 15, 13, 12, 11, 15, 12, 14, 10, 13, 11, 11, + 13, 15, 13, 15, 12, 14, 12, 12, 15, 15, 15, 15, 14, 15, 13, 12, + 11, 15, 13, 14, 11, 14, 12, 12, 13, 15, 13, 15, 12, 14, 12, 12, + 15, 15, 15, 15, 14, 14, 13, 12, 12, 15, 12, 15, 12, 14, 11, 11, + 12, 15, 12, 14, 12, 14, 11, 11, 13, 15, 12, 13, 12, 13, 11, 10 }, + { 0, 7, 4, 9, 4, 9, 9, 11, 5, 10, 9, 12, 9, 12, 12, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 7, 12, 9, 13, 11, 13, + 9, 14, 11, 14, 12, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 4, 11, 9, 13, 7, 12, 11, 13, + 9, 14, 12, 15, 11, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 14, 11, 15, 11, 15, 13, 15, 11, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 10, 6, 11, 6, 11, 10, 12, + 8, 12, 10, 14, 10, 14, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 13, 8, 14, 10, 14, 12, 14, 10, 15, 12, 15, 13, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 13, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 5, 13, 10, 14, 8, 13, 12, 14, 10, 15, 13, 15, 12, 15, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 12, 15, 12, 15, 14, 15, + 10, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 6, 14, 10, 15, 10, 14, 13, 14, 11, 15, 13, 15, 13, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 11, 15, 12, 15, 14, 15, + 12, 15, 14, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 15, 12, 15, 11, 15, 14, 15, + 12, 15, 15, 15, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 13, 15, 15, 15, 12, 15, 14, 15, 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, + 12, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 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, 8, 15, 12, 15, 12, 15, 14, 15, + 13, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 13, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 13, 15, 12, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 13, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 14, 15, 12, 15, 15, 15, + 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 13, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 3, 6, 10, 8, 9, 12, 3, 5, 10, 6, 7, 11, 9, + 10, 12, 7, 9, 11, 9, 10, 12, 11, 12, 12, 2, 5, 10, 4, 7, + 11, 8, 10, 12, 4, 7, 11, 6, 8, 11, 10, 10, 12, 8, 9, 12, + 10, 10, 12, 11, 11, 12, 6, 9, 12, 7, 9, 12, 9, 11, 13, 7, + 9, 12, 9, 10, 12, 10, 11, 13, 9, 11, 13, 10, 11, 13, 12, 12, + 12, 9, 11, 12, 10, 11, 13, 10, 11, 12, 9, 11, 12, 10, 11, 13, + 11, 11, 12, 10, 11, 12, 11, 11, 12, 11, 11, 11 }, + { 0, 5, 14, 3, 8, 15, 11, 14, 15, 2, 7, 15, 7, 10, 15, 13, + 15, 15, 10, 13, 15, 13, 15, 15, 15, 15, 15, 1, 7, 15, 6, 10, + 15, 12, 15, 15, 5, 10, 15, 9, 11, 15, 14, 14, 15, 10, 14, 15, + 14, 15, 15, 15, 15, 15, 8, 11, 15, 10, 13, 15, 13, 15, 15, 9, + 13, 15, 12, 13, 15, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, 15, + 15, 12, 15, 15, 14, 15, 15, 15, 15, 15, 13, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 3, 9, 2, 6, 10, 8, 10, 12, 3, 6, 11, 5, 7, 11, 10, + 11, 13, 8, 10, 12, 10, 11, 13, 12, 12, 13, 2, 5, 10, 5, 7, + 11, 9, 11, 13, 5, 7, 11, 7, 9, 12, 10, 11, 13, 9, 10, 13, + 10, 11, 13, 12, 13, 13, 7, 9, 12, 8, 10, 13, 11, 12, 14, 8, + 10, 13, 9, 11, 13, 12, 12, 14, 11, 12, 14, 12, 12, 14, 13, 13, + 14, 10, 11, 13, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, + 13, 13, 14, 12, 13, 14, 13, 13, 14, 13, 13, 13 }, + { 0, 4, 14, 2, 8, 16, 13, 16, 16, 3, 8, 16, 7, 11, 16, 15, + 15, 16, 12, 15, 16, 13, 15, 16, 15, 16, 16, 1, 6, 16, 7, 10, + 16, 15, 16, 16, 6, 10, 16, 10, 13, 16, 16, 16, 16, 14, 16, 16, + 14, 16, 16, 16, 16, 16, 10, 11, 15, 12, 15, 16, 16, 16, 16, 12, + 13, 16, 13, 15, 16, 16, 16, 16, 16, 16, 16, 15, 16, 16, 16, 16, + 16, 16, 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, 15 } + }, + { 1, 2, 3, 4, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 10, 11, + 11, 12, 12, 12, 13, 13, 13, 13, 13, 12, 13, 14, 14, 15, 15, 14 } + }, + { + { + { 0, 6, 4, 8, 4, 7, 7, 8, 6, 9, 8, 10, 7, 10, 9, 10, + 14, 15, 14, 15, 13, 15, 13, 14, 4, 10, 6, 10, 7, 10, 9, 10, + 7, 12, 9, 12, 9, 12, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 10, 15, 10, 14, 12, 14, 12, 13, 12, 15, 12, 14, 13, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 4, 9, 7, 10, 6, 9, 9, 10, + 7, 11, 9, 12, 9, 11, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 7, 12, 9, 12, 9, 12, 10, 11, 9, 13, 10, 13, 10, 13, 11, 12, + 15, 15, 14, 15, 14, 15, 14, 14, 12, 15, 12, 15, 13, 15, 12, 13, + 13, 15, 13, 15, 14, 15, 13, 14, 15, 15, 15, 15, 15, 15, 14, 15, + 10, 15, 12, 14, 10, 13, 11, 12, 11, 15, 13, 15, 11, 14, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 11, 15, 13, 15, 12, 14, 12, 13, + 13, 15, 14, 15, 12, 14, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 14, 14, 15, 15, 15, 15, 15, 15, 14, 14, + 15, 15, 15, 15, 15, 15, 14, 14, 2, 9, 6, 9, 6, 9, 8, 9, + 7, 11, 9, 11, 9, 11, 10, 11, 14, 15, 14, 15, 14, 15, 14, 14, + 5, 11, 7, 11, 8, 11, 9, 11, 9, 13, 10, 12, 10, 13, 11, 12, + 15, 15, 15, 15, 14, 15, 14, 14, 10, 15, 10, 14, 12, 15, 12, 13, + 12, 15, 12, 15, 13, 15, 13, 14, 15, 15, 15, 15, 15, 15, 15, 14, + 5, 11, 8, 11, 7, 11, 9, 11, 8, 13, 10, 13, 9, 12, 11, 12, + 15, 15, 15, 15, 14, 15, 14, 14, 7, 12, 9, 13, 9, 12, 11, 12, + 9, 13, 10, 13, 10, 13, 11, 12, 14, 15, 14, 15, 14, 15, 14, 14, + 12, 15, 12, 15, 13, 15, 13, 14, 12, 15, 11, 15, 13, 15, 13, 14, + 15, 15, 14, 15, 15, 15, 14, 14, 10, 15, 12, 14, 9, 13, 11, 12, + 12, 15, 13, 15, 11, 14, 12, 13, 15, 15, 15, 15, 14, 15, 14, 14, + 11, 15, 13, 15, 11, 14, 12, 13, 12, 15, 13, 15, 11, 14, 13, 13, + 15, 15, 15, 15, 14, 15, 14, 14, 14, 15, 14, 15, 14, 15, 14, 14, + 14, 15, 14, 15, 14, 15, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 6, 12, 9, 12, 8, 12, 10, 11, 10, 14, 11, 13, 11, 13, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 14, 9, 13, 10, 13, 11, 12, + 11, 15, 12, 14, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 15, 10, 14, 12, 15, 12, 13, 13, 15, 12, 15, 14, 15, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 8, 13, 10, 13, 9, 13, 11, 12, + 11, 15, 12, 14, 11, 14, 12, 13, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 14, 11, 14, 11, 14, 12, 13, 11, 15, 12, 14, 12, 14, 12, 13, + 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 12, 15, 13, 15, 13, 14, + 12, 15, 11, 15, 13, 15, 13, 14, 15, 15, 13, 15, 15, 15, 14, 15, + 10, 15, 12, 15, 10, 14, 12, 13, 13, 15, 13, 15, 12, 14, 13, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 13, 15, 12, 15, 13, 13, + 12, 15, 13, 15, 11, 14, 13, 14, 15, 15, 15, 15, 14, 15, 14, 14, + 14, 15, 15, 15, 14, 15, 14, 14, 13, 15, 14, 15, 14, 15, 13, 14, + 14, 15, 13, 15, 14, 15, 13, 14, 8, 14, 11, 14, 10, 14, 12, 13, + 12, 15, 12, 15, 12, 14, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 9, 15, 11, 14, 11, 14, 12, 13, 13, 15, 13, 15, 13, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 10, 15, 10, 14, 12, 15, 12, 13, + 13, 15, 12, 15, 14, 15, 13, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 9, 15, 12, 14, 11, 14, 12, 13, 12, 15, 13, 15, 12, 15, 13, 13, + 15, 15, 15, 15, 15, 15, 14, 14, 10, 15, 12, 15, 11, 15, 12, 13, + 12, 15, 13, 15, 13, 15, 13, 13, 15, 15, 15, 15, 15, 15, 15, 14, + 11, 15, 11, 15, 12, 15, 12, 13, 12, 15, 11, 15, 13, 15, 13, 13, + 15, 15, 14, 15, 15, 15, 14, 13, 10, 15, 12, 15, 10, 14, 11, 12, + 13, 15, 14, 15, 12, 14, 12, 13, 15, 15, 15, 15, 15, 15, 14, 14, + 11, 15, 12, 15, 11, 14, 12, 13, 12, 15, 13, 15, 12, 15, 12, 13, + 15, 15, 15, 15, 14, 15, 14, 13, 12, 15, 12, 15, 13, 15, 12, 13, + 12, 15, 12, 15, 12, 15, 12, 12, 13, 15, 12, 13, 13, 14, 12, 12 }, + { 0, 7, 5, 10, 4, 10, 9, 12, 6, 11, 10, 13, 10, 13, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 4, 12, 7, 13, 10, 14, 12, 14, + 9, 14, 12, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 4, 12, 10, 14, 7, 13, 12, 14, + 9, 14, 13, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 9, 14, 12, 14, 12, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 14, 14, 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, 14, 14, 14, 1, 11, 7, 12, 6, 12, 11, 13, + 7, 12, 11, 14, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 13, 9, 14, 10, 14, 13, 14, 10, 14, 12, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 13, 14, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 14, 11, 14, 8, 14, 13, 14, 10, 14, 14, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 12, 14, 13, 14, 14, 14, + 10, 14, 14, 14, 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, 12, 14, 14, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 5, 14, 10, 14, 9, 14, 13, 14, 10, 14, 13, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 8, 14, 11, 14, 12, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 12, 14, 10, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 14, 14, 13, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 11, 14, 14, 14, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 12, 14, 11, 14, 14, 14, + 12, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 10, 14, 12, 14, 13, 14, 14, 14, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 12, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 9, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 14, 14, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 11, 14, 14, 14, 12, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 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, 14 } + }, + { + { 0, 4, 11, 3, 7, 12, 9, 11, 14, 3, 7, 12, 6, 8, 13, 11, + 12, 14, 9, 10, 13, 11, 12, 14, 13, 14, 15, 1, 6, 12, 5, 8, + 13, 9, 11, 14, 5, 8, 13, 7, 9, 14, 11, 12, 14, 9, 11, 14, + 11, 12, 14, 13, 14, 15, 6, 9, 13, 8, 10, 14, 10, 12, 15, 8, + 10, 14, 9, 11, 15, 11, 12, 15, 10, 12, 15, 12, 12, 15, 14, 13, + 15, 10, 11, 14, 11, 12, 14, 11, 13, 15, 10, 12, 14, 11, 12, 15, + 12, 13, 15, 11, 13, 15, 12, 13, 14, 13, 13, 14 }, + { 0, 5, 14, 3, 7, 15, 11, 13, 15, 2, 8, 15, 7, 10, 15, 15, + 15, 15, 11, 13, 15, 14, 15, 15, 15, 15, 15, 1, 7, 13, 6, 9, + 15, 12, 14, 15, 5, 10, 15, 9, 11, 15, 14, 14, 15, 11, 14, 15, + 15, 15, 15, 15, 15, 15, 8, 10, 15, 11, 13, 15, 15, 15, 15, 9, + 11, 15, 13, 13, 15, 14, 14, 15, 12, 15, 15, 15, 15, 15, 15, 15, + 15, 14, 14, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 } + }, + { + { 0, 4, 12, 3, 6, 12, 10, 12, 15, 3, 6, 12, 6, 8, 13, 11, + 13, 15, 9, 11, 14, 10, 12, 15, 14, 14, 15, 1, 5, 11, 5, 8, + 13, 11, 13, 15, 5, 8, 13, 8, 9, 14, 12, 13, 15, 10, 12, 14, + 11, 12, 15, 14, 14, 15, 7, 9, 12, 9, 11, 14, 13, 14, 15, 9, + 11, 14, 11, 12, 15, 13, 14, 15, 12, 14, 15, 13, 14, 15, 15, 15, + 15, 12, 13, 14, 13, 14, 15, 15, 15, 15, 12, 13, 15, 13, 14, 15, + 15, 15, 15, 14, 14, 15, 15, 15, 15, 15, 15, 15 }, + { 0, 4, 14, 3, 8, 14, 15, 15, 15, 2, 9, 15, 7, 10, 15, 15, + 15, 15, 11, 15, 15, 15, 12, 15, 15, 15, 15, 1, 6, 15, 7, 11, + 15, 15, 15, 15, 6, 10, 15, 9, 12, 15, 15, 15, 15, 12, 15, 15, + 15, 15, 15, 15, 15, 15, 11, 11, 15, 15, 15, 15, 15, 15, 15, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 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 } + }, + { 1, 2, 3, 4, 5, 6, 8, 8, 9, 9, 10, 10, 11, 11, 12, 14, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 15, 15, 14 } + } +}; + +#endif /* AVCODEC_RV60VLCS_H */ diff --git a/libavcodec/s302menc.c b/libavcodec/s302menc.c index 4b8996f9ac..ba84ab73b6 100644 --- a/libavcodec/s302menc.c +++ b/libavcodec/s302menc.c @@ -181,8 +181,6 @@ const FFCodec ff_s302m_encoder = { .priv_data_size = sizeof(S302MEncContext), .init = s302m_encode_init, FF_CODEC_ENCODE_CB(s302m_encode2_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 48000, 0 }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES(48000), }; diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index 8b7c0d9556..e4308af647 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -264,7 +264,7 @@ typedef struct SANMVideoContext { AVCodecContext *avctx; GetByteContext gb; - int version, subversion; + int version, subversion, have_dimensions, first_fob; uint32_t pal[PALETTE_SIZE]; int16_t delta_pal[PALETTE_DELTA]; @@ -274,9 +274,9 @@ typedef struct SANMVideoContext { int prev_seq; AVFrame *frame; - uint16_t *frm0, *frm1, *frm2; + uint16_t *fbuf, *frm0, *frm1, *frm2; uint8_t *stored_frame; - uint32_t frm0_size, frm1_size, frm2_size; + uint32_t fbuf_size, frm0_size, frm1_size, frm2_size; uint32_t stored_frame_size; uint8_t *rle_buf; @@ -291,6 +291,10 @@ typedef struct SANMVideoContext { int8_t p4x4glyphs[NGLYPHS][16]; int8_t p8x8glyphs[NGLYPHS][64]; + uint8_t c47itbl[0x10000]; + uint8_t c23lut[256]; + uint8_t c4tbl[2][256][16]; + uint16_t c4param; } SANMVideoContext; typedef struct SANMFrameHeader { @@ -449,6 +453,7 @@ static void init_sizes(SANMVideoContext *ctx, int width, int height) static void destroy_buffers(SANMVideoContext *ctx) { + av_freep(&ctx->fbuf); av_freep(&ctx->frm0); av_freep(&ctx->frm1); av_freep(&ctx->frm2); @@ -462,6 +467,7 @@ static void destroy_buffers(SANMVideoContext *ctx) static av_cold int init_buffers(SANMVideoContext *ctx) { + av_fast_padded_mallocz(&ctx->fbuf, &ctx->fbuf_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size); av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size); @@ -478,6 +484,137 @@ static av_cold int init_buffers(SANMVideoContext *ctx) return 0; } +static void codec33_gen_tiles(SANMVideoContext *ctx, int8_t param1) +{ + uint8_t *dst = &(ctx->c4tbl[0][0][0]); + int i, j, k, l, m, n, o, p; + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + p = (j + l) >> 1; + n = (j + p) >> 1; + m = (p + l) >> 1; + + *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j; + *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j; + *dst++ = m; *dst++ = m; *dst++ = p; *dst++ = j; + *dst++ = l; *dst++ = l; *dst++ = m; *dst++ = p; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + n = (j + l) >> 1; + m = (l + n) >> 1; + + *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = j; + *dst++ = n; *dst++ = n; *dst++ = n; *dst++ = n; + *dst++ = m; *dst++ = m; *dst++ = m; *dst++ = m; + *dst++ = l; *dst++ = l; *dst++ = l; *dst++ = l; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + m = (j + l) >> 1; + n = (j + m) >> 1; + o = (l + m) >> 1; + + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; + *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; + } + } + + for (i = 0; i < 8; i++) { + for (k = 0; k < 8; k++) { + j = i + param1; + l = k + param1; + m = (j + l) >> 1; + n = (l + m) >> 1; + + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; + } + } +} + +static void codec4_gen_tiles(SANMVideoContext *ctx, uint16_t param1) +{ + uint8_t *dst = &(ctx->c4tbl[0][0][0]); + int i, j, k, l, m, n, o; + + for (i = 1; i < 16; i += 2) { + for (k = 0; k < 16; k++) { + j = i + param1; + l = k + param1; + m = (j + l) / 2; + n = (j + m) / 2; + o = (l + m) / 2; + if (j == m || l == m) { + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = j; + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = l; *dst++ = l; *dst++ = j; *dst++ = l; + } else { + *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; + *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; + *dst++ = o; *dst++ = o; *dst++ = m; *dst++ = n; + *dst++ = l; *dst++ = l; *dst++ = o; *dst++ = m; + } + } + } + + for (i = 0; i < 16; i += 2) { + for (k = 0; k < 16; k++) { + j = i + param1; + l = k + param1; + m = (j + l) / 2; + n = (j + m) / 2; + o = (l + m) / 2; + if (m == j || m == l) { + *dst++ = j; *dst++ = j; *dst++ = l; *dst++ = j; + *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = l; + *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = l; + *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = l; + } else { + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; + *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; + *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; + } + } + } +} + + +static int codec4_load_tiles(SANMVideoContext *ctx, GetByteContext *gb, + uint16_t param2, uint8_t clr) +{ + uint8_t c, *dst = (uint8_t *)&(ctx->c4tbl[1][0][0]); + uint32_t loop = param2 * 8; + + if ((param2 > 256) || (bytestream2_get_bytes_left(gb) < loop)) + return AVERROR_INVALIDDATA; + + while (loop--) { + c = bytestream2_get_byteu(gb); + *dst++ = (c >> 4) + clr; + *dst++ = (c & 0xf) + clr; + } + + return 0; +} + static void rotate_bufs(SANMVideoContext *ctx, int rotate_code) { if (rotate_code == 2) @@ -514,7 +651,10 @@ static av_cold int decode_init(AVCodecContext *avctx) ctx->subversion = AV_RL16(avctx->extradata); for (i = 0; i < PALETTE_SIZE; i++) ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; } + ctx->c4param = 0xffff; return 0; } @@ -528,23 +668,89 @@ static av_cold int decode_end(AVCodecContext *avctx) return 0; } -static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) +static int old_codec4(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int w, int h, uint8_t param, uint16_t param2, int codec) +{ + const uint16_t p = ctx->pitch; + const uint32_t maxpxo = ctx->height * p; + uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->fbuf; + int i, j, k, l, bit, ret; + int32_t pxoff, pxo2; + + if (ctx->c4param != param) { + if (codec > 32) + codec33_gen_tiles(ctx, param); + else + codec4_gen_tiles(ctx, param); + ctx->c4param = param; + } + if (param2 > 0) { + ret = codec4_load_tiles(ctx, gb, param2, param); + if (ret) + return ret; + } + + if (codec > 32) + codec -= 29; + + for (j = 0; j < w; j += 4) { + mask = bits = 0; + for (i = 0; i < h; i += 4) { + pxoff = j + left + ((top + i) * p); + if (param2 > 0) { + if (bits == 0) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + mask = bytestream2_get_byteu(gb); + bits = 8; + } + bit = !!(mask & 0x80); + mask <<= 1; + bits--; + } else { + bit = 0; + } + + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + idx = bytestream2_get_byteu(gb); + if ((bit == 0) && (idx == 0x80) && (codec != 5)) + continue; + + gs = &(ctx->c4tbl[bit][idx][0]); + pxo2 = pxoff; + for (k = 0; k < 4; k++) { + for (l = 0; l < 4; l++) { + if (pxo2 >= 0 && pxo2 < maxpxo) { + *(dst + pxo2) = *gs; + } + gs++; + pxo2++; + } + pxo2 = pxo2 - 4 + p; + } + } + } + return 0; +} + +static int rle_decode(SANMVideoContext *ctx, GetByteContext *gb, uint8_t *dst, const int out_size) { int opcode, color, run_len, left = out_size; while (left > 0) { - opcode = bytestream2_get_byte(&ctx->gb); + opcode = bytestream2_get_byte(gb); run_len = (opcode >> 1) + 1; - if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0) + if (run_len > left || bytestream2_get_bytes_left(gb) <= 0) return AVERROR_INVALIDDATA; if (opcode & 1) { - color = bytestream2_get_byte(&ctx->gb); + color = bytestream2_get_byte(gb); memset(dst, color, run_len); } else { - if (bytestream2_get_bytes_left(&ctx->gb) < run_len) + if (bytestream2_get_bytes_left(gb) < run_len) return AVERROR_INVALIDDATA; - bytestream2_get_bufferu(&ctx->gb, dst, run_len); + bytestream2_get_bufferu(gb, dst, run_len); } dst += run_len; @@ -554,53 +760,247 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) return 0; } -static int old_codec1(SANMVideoContext *ctx, int top, - int left, int width, int height) +static int old_codec23(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height, uint8_t param, uint16_t param2) { - uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch; - int i, j, len, flag, code, val, pos, end; + const uint32_t maxpxo = ctx->height * ctx->pitch; + uint8_t *dst, lut[256], c; + int i, j, k, pc, sk; + int32_t pxoff; + + if (ctx->subversion < 2) { + /* Rebel Assault 1: constant offset + 0xd0 */ + for (i = 0; i < 256; i++) + lut[i] = (i + param + 0xd0) & 0xff; + } else if (param2 == 256) { + if (bytestream2_get_bytes_left(gb) < 256) + return AVERROR_INVALIDDATA; + bytestream2_get_bufferu(gb, ctx->c23lut, 256); + } else if (param2 < 256) { + for (i = 0; i < 256; i++) + lut[i] = (i + param2) & 0xff; + } else { + memcpy(lut, ctx->c23lut, 256); + } + if (bytestream2_get_bytes_left(gb) < 1) + return 0; /* some c23 frames just set up the LUT */ + + dst = (uint8_t *)ctx->fbuf; + for (i = 0; i < height; i++) { + if (bytestream2_get_bytes_left(gb) < 2) + return 0; + pxoff = left + ((top + i) * ctx->pitch); + k = bytestream2_get_le16u(gb); + sk = 1; + pc = 0; + while (k > 0 && pc <= width) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + j = bytestream2_get_byteu(gb); + if (sk) { + pxoff += j; + pc += j; + } else { + while (j--) { + if (pxoff >=0 && pxoff < maxpxo) { + c = *(dst + pxoff); + *(dst + pxoff) = lut[c]; + } + pxoff++; + pc++; + } + } + sk ^= 1; + } + } + return 0; +} + +static int old_codec21(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, + int width, int height) +{ + const uint32_t maxpxo = ctx->height * ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf, c; + int i, j, k, pc, sk, pxoff; + + dst = (uint8_t *)ctx->fbuf; + for (i = 0; i < height; i++) { + if (bytestream2_get_bytes_left(gb) < 2) + return 0; + pxoff = left + ((top + i) * ctx->pitch); + k = bytestream2_get_le16u(gb); + sk = 1; + pc = 0; + while (k > 0 && pc <= width) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + j = bytestream2_get_le16u(gb); + k -= 2; + if (sk) { + pxoff += j; + pc += j; + } else { + if (bytestream2_get_bytes_left(gb) < (j + 1)) + return AVERROR_INVALIDDATA; + do { + c = bytestream2_get_byteu(gb); + if (pxoff >=0 && pxoff < maxpxo) { + *(dst + pxoff) = c; + } + pxoff++; + pc++; + j--; + k--; + } while (j > -1); + } + sk ^= 1; + } + } + return 0; +} + +static int old_codec1(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height, int opaque) +{ + int i, j, len, flag, code, val, end, pxoff; + const int maxpxo = ctx->height * ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf; for (i = 0; i < height; i++) { - pos = 0; - - if (bytestream2_get_bytes_left(&ctx->gb) < 2) + if (bytestream2_get_bytes_left(gb) < 2) return AVERROR_INVALIDDATA; - len = bytestream2_get_le16u(&ctx->gb); - end = bytestream2_tell(&ctx->gb) + len; + len = bytestream2_get_le16u(gb); + end = bytestream2_tell(gb) + len; - while (bytestream2_tell(&ctx->gb) < end) { - if (bytestream2_get_bytes_left(&ctx->gb) < 2) + pxoff = left + ((top + i) * ctx->pitch); + while (bytestream2_tell(gb) < end) { + if (bytestream2_get_bytes_left(gb) < 2) return AVERROR_INVALIDDATA; - code = bytestream2_get_byteu(&ctx->gb); + code = bytestream2_get_byteu(gb); flag = code & 1; code = (code >> 1) + 1; - if (pos + code > width) - return AVERROR_INVALIDDATA; if (flag) { - val = bytestream2_get_byteu(&ctx->gb); - if (val) - memset(dst + pos, val, code); - pos += code; + val = bytestream2_get_byteu(gb); + if (val || opaque) { + for (j = 0; j < code; j++) { + if (pxoff >= 0 && pxoff < maxpxo) + *(dst + pxoff) = val; + pxoff++; + } + } else { + pxoff += code; + } } else { - if (bytestream2_get_bytes_left(&ctx->gb) < code) + if (bytestream2_get_bytes_left(gb) < code) return AVERROR_INVALIDDATA; for (j = 0; j < code; j++) { - val = bytestream2_get_byteu(&ctx->gb); - if (val) - dst[pos] = val; - pos++; + val = bytestream2_get_byteu(gb); + if ((pxoff >= 0) && (pxoff < maxpxo) && (val || opaque)) + *(dst + pxoff) = val; + pxoff++; } } } - dst += ctx->pitch; } ctx->rotate_code = 0; return 0; } +static int old_codec31(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height, int p1, int opaque) +{ + int i, j, len, flag, code, val, end, pxoff; + const int maxpxo = ctx->height * ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->fbuf; + + for (i = 0; i < height; i++) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + + len = bytestream2_get_le16u(gb); + end = bytestream2_tell(gb) + len; + + pxoff = left + ((top + i) * ctx->pitch); + while (bytestream2_tell(gb) < end) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + + code = bytestream2_get_byteu(gb); + flag = code & 1; + code = (code >> 1) + 1; + if (flag) { + val = bytestream2_get_byteu(gb); + for (j = 0; j < code; j++) { + if ((0 != (val & 0xf)) || opaque) { + if (pxoff >= 0 && pxoff < maxpxo) + *(dst + pxoff) = p1 + (val & 0xf); + } + pxoff++; + if ((0 != (val >> 4)) || opaque) { + if (pxoff >= 0 && pxoff < maxpxo) + *(dst + pxoff) = p1 + (val >> 4); + } + pxoff++; + } + } else { + if (bytestream2_get_bytes_left(gb) < code) + return AVERROR_INVALIDDATA; + for (j = 0; j < code; j++) { + val = bytestream2_get_byteu(gb); + if ((pxoff >= 0) && (pxoff < maxpxo) && ((0 != (val & 0xf)) || opaque)) + *(dst + pxoff) = p1 + (val & 0xf); + pxoff++; + if ((pxoff >= 0) && (pxoff < maxpxo) && ((0 != (val >> 4)) || opaque)) + *(dst + pxoff) = p1 + (val >> 4); + pxoff++; + } + } + } + } + ctx->rotate_code = 0; + + return 0; +} + +static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top, + int left, int width, int height) +{ + uint8_t *dst = (uint8_t *)ctx->fbuf, col; + int16_t xpos = left, ypos = top; + + while (bytestream2_get_bytes_left(gb) > 3) { + xpos += bytestream2_get_le16u(gb); + ypos += bytestream2_get_byteu(gb); + col = bytestream2_get_byteu(gb); + if (xpos >= 0 && ypos >= 0 && + xpos < ctx->width && ypos < ctx->height) { + *(dst + xpos + ypos * ctx->pitch) = col; + } + } + return 0; +} + +static int old_codec20(SANMVideoContext *ctx, int w, int h) +{ + uint8_t *dst = (uint8_t *)ctx->fbuf; + + if (bytestream2_get_bytes_left(&ctx->gb) < w * h) + return AVERROR_INVALIDDATA; + + if (w == ctx->pitch) { + bytestream2_get_bufferu(&ctx->gb, dst, w * h); + } else { + for (int i = 0; i < h; i++) { + bytestream2_get_bufferu(&ctx->gb, dst, w); + dst += ctx->pitch; + } + } + return 0; +} + static inline void codec37_mv(uint8_t *dst, const uint8_t *src, int height, int stride, int x, int y) { @@ -620,11 +1020,10 @@ static inline void codec37_mv(uint8_t *dst, const uint8_t *src, } } -static int old_codec37(SANMVideoContext *ctx, int top, - int left, int width, int height) +static int old_codec37(SANMVideoContext *ctx, int width, int height) { + int i, j, k, l, t, run, len, code, skip, mx, my; ptrdiff_t stride = ctx->pitch; - int i, j, k, t; uint8_t *dst, *prev; int skip_run = 0; int compr = bytestream2_get_byte(&ctx->gb); @@ -637,18 +1036,19 @@ static int old_codec37(SANMVideoContext *ctx, int top, flags = bytestream2_get_byte(&ctx->gb); bytestream2_skip(&ctx->gb, 3); - if (decoded_size > ctx->height * stride - left - top * stride) { - decoded_size = ctx->height * stride - left - top * stride; + if (decoded_size > ctx->height * stride) { + decoded_size = ctx->height * stride; av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); } ctx->rotate_code = 0; - if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) - rotate_bufs(ctx, 1); + if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) { + FFSWAP(uint16_t*, ctx->frm0, ctx->frm2); + } - dst = ((uint8_t*)ctx->frm0) + left + top * stride; - prev = ((uint8_t*)ctx->frm2) + left + top * stride; + dst = ((uint8_t*)ctx->frm0); + prev = ((uint8_t*)ctx->frm2); if (mvoff > 2) { av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff); @@ -661,100 +1061,118 @@ static int old_codec37(SANMVideoContext *ctx, int top, bytestream2_get_buffer(&ctx->gb, dst, width); dst += stride; } - memset(ctx->frm1, 0, ctx->height * stride); memset(ctx->frm2, 0, ctx->height * stride); break; + case 1: + run = 0; + len = -1; + code = 0; + + for (j = 0; j < height; j += 4) { + for (i = 0; i < width; i += 4) { + if (len < 0) { + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(&ctx->gb); + len = code >> 1; + run = code & 1; + skip = 0; + } else { + skip = run; + } + + if (!skip) { + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(&ctx->gb); + if (code == 0xff) { + len--; + for (k = 0; k < 4; k++) { + for (l = 0; l < 4; l++) { + if (len < 0) { + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(&ctx->gb); + len = code >> 1; + run = code & 1; + if (run) { + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(&ctx->gb); + } + } + if (!run) { + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byte(&ctx->gb); + } + *(dst + i + (k * stride) + l) = code; + len--; + } + } + continue; + } + } + /* 4x4 block copy from prev with MV */ + mx = c37_mv[(mvoff * 255 + code) * 2]; + my = c37_mv[(mvoff * 255 + code) * 2 + 1]; + codec37_mv(dst + i, prev + i + mx + my * stride, + ctx->height, stride, i + mx, j + my); + len--; + } + dst += stride * 4; + prev += stride * 4; + } + break; case 2: - if (rle_decode(ctx, dst, decoded_size)) + if (rle_decode(ctx, &ctx->gb, dst, decoded_size)) return AVERROR_INVALIDDATA; - memset(ctx->frm1, 0, ctx->frm1_size); memset(ctx->frm2, 0, ctx->frm2_size); break; case 3: case 4: - if (flags & 4) { - for (j = 0; j < height; j += 4) { - for (i = 0; i < width; i += 4) { - int code; - if (skip_run) { - skip_run--; - copy_block4(dst + i, prev + i, stride, stride, 4); - continue; - } + for (j = 0; j < height; j += 4) { + for (i = 0; i < width; i += 4) { + int code; + if (skip_run) { + skip_run--; + copy_block4(dst + i, prev + i, stride, stride, 4); + continue; + } + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return AVERROR_INVALIDDATA; + code = bytestream2_get_byteu(&ctx->gb); + if (code == 0xFF) { + if (bytestream2_get_bytes_left(&ctx->gb) < 16) + return AVERROR_INVALIDDATA; + for (k = 0; k < 4; k++) + bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); + } else if ((flags & 4) && (code == 0xFE)) { + if (bytestream2_get_bytes_left(&ctx->gb) < 4) + return AVERROR_INVALIDDATA; + for (k = 0; k < 4; k++) + memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4); + } else if ((flags & 4) && (code == 0xFD)) { if (bytestream2_get_bytes_left(&ctx->gb) < 1) return AVERROR_INVALIDDATA; - code = bytestream2_get_byteu(&ctx->gb); - switch (code) { - case 0xFF: - if (bytestream2_get_bytes_left(&ctx->gb) < 16) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); - break; - case 0xFE: - if (bytestream2_get_bytes_left(&ctx->gb) < 4) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4); - break; - case 0xFD: + t = bytestream2_get_byteu(&ctx->gb); + for (k = 0; k < 4; k++) + memset(dst + i + k * stride, t, 4); + } else { + mx = c37_mv[(mvoff * 255 + code) * 2]; + my = c37_mv[(mvoff * 255 + code) * 2 + 1]; + codec37_mv(dst + i, prev + i + mx + my * stride, + ctx->height, stride, i + mx, j + my); + + if ((compr == 4) && (code == 0)) { if (bytestream2_get_bytes_left(&ctx->gb) < 1) return AVERROR_INVALIDDATA; - t = bytestream2_get_byteu(&ctx->gb); - for (k = 0; k < 4; k++) - memset(dst + i + k * stride, t, 4); - break; - default: - if (compr == 4 && !code) { - if (bytestream2_get_bytes_left(&ctx->gb) < 1) - return AVERROR_INVALIDDATA; - skip_run = bytestream2_get_byteu(&ctx->gb) + 1; - i -= 4; - } else { - int mx, my; - - mx = c37_mv[(mvoff * 255 + code) * 2]; - my = c37_mv[(mvoff * 255 + code) * 2 + 1]; - codec37_mv(dst + i, prev + i + mx + my * stride, - ctx->height, stride, i + mx, j + my); - } + skip_run = bytestream2_get_byteu(&ctx->gb); } } - dst += stride * 4; - prev += stride * 4; - } - } else { - for (j = 0; j < height; j += 4) { - for (i = 0; i < width; i += 4) { - int code; - if (skip_run) { - skip_run--; - copy_block4(dst + i, prev + i, stride, stride, 4); - continue; - } - code = bytestream2_get_byte(&ctx->gb); - if (code == 0xFF) { - if (bytestream2_get_bytes_left(&ctx->gb) < 16) - return AVERROR_INVALIDDATA; - for (k = 0; k < 4; k++) - bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); - } else if (compr == 4 && !code) { - if (bytestream2_get_bytes_left(&ctx->gb) < 1) - return AVERROR_INVALIDDATA; - skip_run = bytestream2_get_byteu(&ctx->gb) + 1; - i -= 4; - } else { - int mx, my; - - mx = c37_mv[(mvoff * 255 + code) * 2]; - my = c37_mv[(mvoff * 255 + code) * 2 + 1]; - codec37_mv(dst + i, prev + i + mx + my * stride, - ctx->height, stride, i + mx, j + my); - } - } - dst += stride * 4; - prev += stride * 4; } + dst += stride * 4; + prev += stride * 4; } break; default: @@ -856,36 +1274,90 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, return 0; } -static int old_codec47(SANMVideoContext *ctx, int top, - int left, int width, int height) +static void codec47_read_interptable(SANMVideoContext *ctx) +{ + uint8_t *p1, *p2, *itbl = ctx->c47itbl; + int i, j; + + for (i = 0; i < 256; i++) { + p1 = p2 = itbl + i; + for (j = 256 - i; j; j--) { + *p1 = *p2 = bytestream2_get_byte(&ctx->gb); + p1 += 1; + p2 += 256; + } + itbl += 256; + } +} + +static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width, + int height, ptrdiff_t stride) +{ + uint8_t p1, *dst, *itbl = ctx->c47itbl; + uint16_t px; + int i, j; + + dst = dst_in + stride; + for (i = 0; i < height; i += 2) { + p1 = bytestream2_get_byte(&ctx->gb); + *dst++ = p1; + *dst++ = p1; + px = p1; + for (j = 2; j < width; j += 2) { + p1 = bytestream2_get_byte(&ctx->gb); + px = (px << 8) | p1; + *dst++ = itbl[px]; + *dst++ = p1; + } + dst += stride; + } + + memcpy(dst_in, dst_in + stride, width); + dst = dst_in + stride + stride; + for (i = 2; i < height - 1; i += 2) { + for (j = 0; j < width; j++) { + px = (*(dst - stride) << 8) | *(dst + stride); + *dst++ = itbl[px]; + } + dst += stride; + } +} + +static int old_codec47(SANMVideoContext *ctx, int width, int height) { uint32_t decoded_size; int i, j; ptrdiff_t stride = ctx->pitch; - uint8_t *dst = (uint8_t *)ctx->frm0 + left + top * stride; + uint8_t *dst = (uint8_t *)ctx->frm0; uint8_t *prev1 = (uint8_t *)ctx->frm1; uint8_t *prev2 = (uint8_t *)ctx->frm2; + uint8_t auxcol[2]; int tbl_pos = bytestream2_tell(&ctx->gb); int seq = bytestream2_get_le16(&ctx->gb); int compr = bytestream2_get_byte(&ctx->gb); int new_rot = bytestream2_get_byte(&ctx->gb); int skip = bytestream2_get_byte(&ctx->gb); - bytestream2_skip(&ctx->gb, 9); + bytestream2_skip(&ctx->gb, 7); + auxcol[0] = bytestream2_get_byteu(&ctx->gb); + auxcol[1] = bytestream2_get_byteu(&ctx->gb); decoded_size = bytestream2_get_le32(&ctx->gb); bytestream2_skip(&ctx->gb, 8); - if (decoded_size > ctx->height * stride - left - top * stride) { - decoded_size = ctx->height * stride - left - top * stride; + if (decoded_size > ctx->height * stride) { + decoded_size = ctx->height * stride; av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); } - if (skip & 1) - bytestream2_skip(&ctx->gb, 0x8080); + if (skip & 1) { + if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080) + return AVERROR_INVALIDDATA; + codec47_read_interptable(ctx); + } if (!seq) { ctx->prev_seq = -1; - memset(prev1, 0, ctx->height * stride); - memset(prev2, 0, ctx->height * stride); + memset(prev1, auxcol[0], ctx->height * stride); + memset(prev2, auxcol[1], ctx->height * stride); } switch (compr) { @@ -900,15 +1372,7 @@ static int old_codec47(SANMVideoContext *ctx, int top, case 1: if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) return AVERROR_INVALIDDATA; - for (j = 0; j < height; j += 2) { - for (i = 0; i < width; i += 2) { - dst[i] = - dst[i + 1] = - dst[stride + i] = - dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); - } - dst += stride * 2; - } + codec47_comp1(ctx, dst, width, height, stride); break; case 2: if (seq == ctx->prev_seq + 1) { @@ -930,7 +1394,7 @@ static int old_codec47(SANMVideoContext *ctx, int top, memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height); break; case 5: - if (rle_decode(ctx, dst, decoded_size)) + if (rle_decode(ctx, &ctx->gb, dst, decoded_size)) return AVERROR_INVALIDDATA; break; default: @@ -947,45 +1411,500 @@ static int old_codec47(SANMVideoContext *ctx, int top, return 0; } -static int process_frame_obj(SANMVideoContext *ctx) +// scale 4x4 input block to an 8x8 output block +static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w) { - uint16_t codec = bytestream2_get_le16u(&ctx->gb); - uint16_t left = bytestream2_get_le16u(&ctx->gb); - uint16_t top = bytestream2_get_le16u(&ctx->gb); - uint16_t w = bytestream2_get_le16u(&ctx->gb); - uint16_t h = bytestream2_get_le16u(&ctx->gb); + uint16_t p; + // dst is always at least 16bit aligned + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 8; j += 2) { + p = *src++; + p = (p << 8) | p; + *((uint16_t *)(dst + w * 0 + j)) = p; + *((uint16_t *)(dst + w * 1 + j)) = p; + } + dst += w * 2; + } +} - if (!w || !h) { - av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n"); +static int check_mv(int x, int y, const uint16_t w, int h, int blocksize, int mvofs) { + if (mvofs < -x + -y*w) + return AVERROR_INVALIDDATA; + + if (mvofs > w-x-blocksize + w*(h-y-blocksize)) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, int x, int y, + const uint16_t w, int h) +{ + uint8_t opc, sb[16]; + int i, j, k, l; + int16_t mvofs; + uint32_t ofs; + + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return 1; + + opc = bytestream2_get_byteu(&ctx->gb); + switch (opc) { + case 0xFF: // 1x1 -> 8x8 block scale + if (bytestream2_get_bytes_left(&ctx->gb) < 1) + return 1; + + opc = bytestream2_get_byteu(&ctx->gb); + for (i = 0; i < 16; i++) + sb[i] = opc; + c48_4to8(dst, sb, w); + break; + case 0xFE: // 1x 8x8 copy from deltabuf, 16bit mv from source + if (bytestream2_get_bytes_left(&ctx->gb) < 2) + return 1; + mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x, y, w, h, 8, mvofs)) + return 1; + for (i = 0; i < 8; i++) { + ofs = w * i; + for (k = 0; k < 8; k++) + *(dst + ofs + k) = *(db + ofs + k + mvofs); + } + break; + case 0xFD: // 2x2 -> 8x8 block scale + if (bytestream2_get_bytes_left(&ctx->gb) < 4) + return 1; + sb[ 5] = bytestream2_get_byteu(&ctx->gb); + sb[ 7] = bytestream2_get_byteu(&ctx->gb); + sb[13] = bytestream2_get_byteu(&ctx->gb); + sb[15] = bytestream2_get_byteu(&ctx->gb); + + sb[0] = sb[1] = sb[4] = sb[5]; + sb[2] = sb[3] = sb[6] = sb[7]; + sb[8] = sb[9] = sb[12] = sb[13]; + sb[10] = sb[11] = sb[14] = sb[15]; + c48_4to8(dst, sb, w); + break; + case 0xFC: // 4x copy 4x4 block, per-block c37_mv from source + if (bytestream2_get_bytes_left(&ctx->gb) < 4) + return 1; + for (i = 0; i < 8; i += 4) { + for (k = 0; k < 8; k += 4) { + opc = bytestream2_get_byteu(&ctx->gb); + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x+k, y+i, w, h, 4, mvofs)) + return 1; + for (j = 0; j < 4; j++) { + ofs = (w * (j + i)) + k; + for (l = 0; l < 4; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + } + } + break; + case 0xFB: // Copy 4x 4x4 blocks, per-block mv from source + if (bytestream2_get_bytes_left(&ctx->gb) < 8) + return 1; + for (i = 0; i < 8; i += 4) { + for (k = 0; k < 8; k += 4) { + mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x+k, y+i, w, h, 4, mvofs)) + return 1; + for (j = 0; j < 4; j++) { + ofs = (w * (j + i)) + k; + for (l = 0; l < 4; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + } + } + break; + case 0xFA: // scale 4x4 input block to 8x8 dest block + if (bytestream2_get_bytes_left(&ctx->gb) < 16) + return 1; + bytestream2_get_bufferu(&ctx->gb, sb, 16); + c48_4to8(dst, sb, w); + break; + case 0xF9: // 16x 2x2 copy from delta, per-block c37_mv from source + if (bytestream2_get_bytes_left(&ctx->gb) < 16) + return 1; + for (i = 0; i < 8; i += 2) { + for (j = 0; j < 8; j += 2) { + ofs = (w * i) + j; + opc = bytestream2_get_byteu(&ctx->gb); + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x+j, y+i, w, h, 2, mvofs)) + return 1; + for (l = 0; l < 2; l++) { + *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); + *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); + } + } + } + break; + case 0xF8: // 16x 2x2 blocks copy, 16bit mv from source + if (bytestream2_get_bytes_left(&ctx->gb) < 32) + return 1; + for (i = 0; i < 8; i += 2) { + for (j = 0; j < 8; j += 2) { + ofs = w * i + j; + mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x+j, y+i, w, h, 2, mvofs)) + return 1; + for (l = 0; l < 2; l++) { + *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); + *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); + } + } + } + break; + case 0xF7: // copy 8x8 block from src to dest + if (bytestream2_get_bytes_left(&ctx->gb) < 64) + return 1; + for (i = 0; i < 8; i++) { + ofs = i * w; + for (l = 0; l < 8; l++) + *(dst + ofs + l) = bytestream2_get_byteu(&ctx->gb); + } + break; + default: // copy 8x8 block from prev, c37_mv from source + mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x, y, w, h, 8, mvofs)) + return 1; + for (i = 0; i < 8; i++) { + ofs = i * w; + for (l = 0; l < 8; l++) + *(dst + ofs + l) = *(db + ofs + l + mvofs); + } + break; + } + return 0; +} + +static int old_codec48(SANMVideoContext *ctx, int width, int height) +{ + uint8_t *dst, *prev; + int compr = bytestream2_get_byte(&ctx->gb); + int mvidx = bytestream2_get_byte(&ctx->gb); + int seq = bytestream2_get_le16(&ctx->gb); + uint32_t decoded_size = bytestream2_get_le32(&ctx->gb); + int i, j, flags; + + // all codec48 videos use 1, but just to be safe... + if (mvidx != 1) { + av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvidx); return AVERROR_INVALIDDATA; } - if (ctx->width < left + w || ctx->height < top + h) { - int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width), - FFMAX(top + h, ctx->height)); - if (ret < 0) - return ret; - init_sizes(ctx, FFMAX(left + w, ctx->width), - FFMAX(top + h, ctx->height)); - if (init_buffers(ctx)) { - av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n"); - return AVERROR(ENOMEM); + bytestream2_skip(&ctx->gb, 4); + flags = bytestream2_get_byte(&ctx->gb); + bytestream2_skip(&ctx->gb, 3); + + if (flags & 8) { + if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080) + return AVERROR_INVALIDDATA; + codec47_read_interptable(ctx); + } + + dst = (uint8_t*)ctx->frm0; + prev = (uint8_t*)ctx->frm2; + + if (!seq) { + ctx->prev_seq = -1; + memset(prev, 0, ctx->aligned_height * width); + } + + switch (compr) { + case 0: + if (bytestream2_get_bytes_left(&ctx->gb) < width * height) + return AVERROR_INVALIDDATA; + for (j = 0; j < height; j++) { + bytestream2_get_bufferu(&ctx->gb, dst, width); + dst += width; + } + break; + case 2: + if (decoded_size > ctx->buf_size) { + av_log(ctx->avctx, AV_LOG_ERROR, "Decoded size %u is too large.\n", decoded_size); + return AVERROR_INVALIDDATA; + } + + if (rle_decode(ctx, &ctx->gb, dst, decoded_size)) + return AVERROR_INVALIDDATA; + break; + case 3: + if (seq == ctx->prev_seq + 1) { + for (j = 0; j < height; j += 8) { + for (i = 0; i < width; i += 8) { + if (codec48_block(ctx, dst + i, prev + i, i, j, width, height)) + return AVERROR_INVALIDDATA; + } + dst += width * 8; + prev += width * 8; + } + } + break; + case 5: + if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) + return AVERROR_INVALIDDATA; + codec47_comp1(ctx, dst, width, height, width); + break; + case 6: // in some videos of "Star Wars - Making Magic", ignored. + break; + default: + avpriv_report_missing_feature(ctx->avctx, + "Subcodec 48 compression %d", compr); + return AVERROR_PATCHWELCOME; + } + ctx->rotate_code = 1; // swap frm[0] and frm[2] + ctx->prev_seq = seq; + return 0; +} + +static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb) +{ + uint16_t w, h, parm2; + uint8_t codec, param; + int16_t left, top; + int fsc, sote, ret; + + codec = bytestream2_get_byteu(gb); + param = bytestream2_get_byteu(gb); + left = bytestream2_get_le16u(gb); + top = bytestream2_get_le16u(gb); + w = bytestream2_get_le16u(gb); + h = bytestream2_get_le16u(gb); + bytestream2_skip(gb, 2); + parm2 = bytestream2_get_le16u(gb); + + if (w < 1 || h < 1 || w > 800 || h > 600 || left > 800 || top > 600 || left + w <= 0 || top + h <= 0) { + av_log(ctx->avctx, AV_LOG_WARNING, + "ignoring invalid fobj dimensions: c%d %d %d @ %d %d\n", + codec, w, h, left, top); + return 0; + } + + /* codecs with their own buffers */ + fsc = (codec == 37 || codec == 47 || codec == 48); + + /* special case for "Shadows of the Empire" videos */ + sote = ((w == 640) && (h == 272) && (codec == 47)); + if (sote) + left = top = 0; + + if (!ctx->have_dimensions) { + int xres, yres; + if (ctx->subversion < 2) { + /* Rebel Assault 1: 384x242 internal size */ + xres = 384; + yres = 242; + if (w > xres || h > yres) + return AVERROR_INVALIDDATA; + ctx->have_dimensions = 1; + } else if (codec == 37 || codec == 47 || codec == 48) { + /* these codecs work on full frames, trust their dimensions */ + xres = w; + yres = h; + ctx->have_dimensions = 1; + } else { + /* detect common sizes */ + xres = w + left; + yres = h + top; + if (sote) { + /* SotE: has top=60 at all times to center video + * inside the 640x480 game window + */ + xres = w; + yres = h; + ctx->have_dimensions = 1; + } else if (((xres == 424) && (yres == 260)) || /* RA1 */ + ((xres == 320) && (yres == 200)) || /* ft/dig/... */ + ((xres == 640) && (yres == 480))) { /* ol/comi/mots... */ + ctx->have_dimensions = 1; + } + + xres = FFMAX(xres, ctx->width); + yres = FFMAX(yres, ctx->height); + } + + if (ctx->width < xres || ctx->height < yres) { + int ret = ff_set_dimensions(ctx->avctx, xres, yres); + if (ret < 0) + return ret; + init_sizes(ctx, xres, yres); + if (init_buffers(ctx)) { + av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n"); + return AVERROR(ENOMEM); + } + } + } else { + if (((left + w > ctx->width) || (top + h > ctx->height)) && (fsc || codec == 20)) { + /* correct unexpected overly large frames: this happens + * for instance with The Dig's sq1.san video: it has a few + * (all black) 640x480 frames halfway in, while the rest is + * 320x200. + */ + av_log(ctx->avctx, AV_LOG_WARNING, + "resizing too large fobj: c%d %d %d @ %d %d\n", codec, w, h, left, top); + w = ctx->width; + h = ctx->height; } } - bytestream2_skip(&ctx->gb, 4); + + /* clear the main buffer on the first fob */ + if (ctx->first_fob) { + ctx->first_fob = 0; + if (!fsc) + memset(ctx->fbuf, 0, ctx->frm0_size); + } + + if (w + FFMAX(left, 0) > ctx->avctx->width || h + FFMAX(top, 0) > ctx->avctx->height) { + avpriv_request_sample(ctx->avctx, "overly large frame\n"); + return AVERROR_PATCHWELCOME; + } switch (codec) { case 1: case 3: - return old_codec1(ctx, top, left, w, h); + return old_codec1(ctx, gb, top, left, w, h, codec == 3); + case 2: + return old_codec2(ctx, gb, top, left, w, h); + case 4: + case 5: + case 33: + case 34: + return old_codec4(ctx, gb, top, left, w, h, param, parm2, codec); + case 20: + return old_codec20(ctx, w, h); + case 21: + return old_codec21(ctx, gb, top, left, w, h); + case 23: + return old_codec23(ctx, gb, top, left, w, h, param, parm2); + case 31: + case 32: + return old_codec31(ctx, gb, top, left, w, h, param, (codec == 32)); case 37: - return old_codec37(ctx, top, left, w, h); + ret = old_codec37(ctx, w, h); break; + case 45: + return 0; case 47: - return old_codec47(ctx, top, left, w, h); + ret = old_codec47(ctx, w, h); break; + case 48: + ret = old_codec48(ctx, w, h); break; default: avpriv_request_sample(ctx->avctx, "Subcodec %d", codec); - return AVERROR_PATCHWELCOME; + ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT; + return 0; } + if (ret) + return ret; + + /* copy the codec37/47/48 result to main buffer */ + if ((w == ctx->width) && (h == ctx->height)) { + memcpy(ctx->fbuf, ctx->frm0, ctx->fbuf_size); + } else { + const uint8_t *src = (uint8_t *)ctx->frm0; + const int cw = FFMIN(w, ctx->width - left); + const int ch = FFMIN(h, ctx->height - top); + if ((cw > 0) && (ch > 0) && (left >= 0) && (top >= 0)) { + uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * ctx->pitch; + for (int i = 0; i < ch; i++) { + memcpy(dst, src, cw); + dst += ctx->pitch; + src += w; + } + } + } + return 0; +} + +static int process_ftch(SANMVideoContext *ctx, int size) +{ + uint8_t *sf = ctx->stored_frame; + int xoff, yoff, left, top, ret; + GetByteContext gb; + uint32_t sz; + + /* FTCH defines additional x/y offsets */ + if (size != 12) { + if (bytestream2_get_bytes_left(&ctx->gb) < 6) + return AVERROR_INVALIDDATA; + bytestream2_skip(&ctx->gb, 2); + xoff = bytestream2_get_le16u(&ctx->gb); + yoff = bytestream2_get_le16u(&ctx->gb); + } else { + if (bytestream2_get_bytes_left(&ctx->gb) < 12) + return AVERROR_INVALIDDATA; + bytestream2_skip(&ctx->gb, 4); + xoff = bytestream2_get_be32u(&ctx->gb); + yoff = bytestream2_get_be32u(&ctx->gb); + } + + sz = *(uint32_t *)(sf + 0); + if ((sz > 0) && (sz <= ctx->stored_frame_size - 4)) { + /* add the FTCH offsets to the left/top values of the stored FOBJ */ + left = av_le2ne16(*(int16_t *)(sf + 4 + 2)); + top = av_le2ne16(*(int16_t *)(sf + 4 + 4)); + *(int16_t *)(sf + 4 + 2) = av_le2ne16(left + xoff); + *(int16_t *)(sf + 4 + 4) = av_le2ne16(top + yoff); + + /* decode the stored FOBJ */ + bytestream2_init(&gb, sf + 4, sz); + ret = process_frame_obj(ctx, &gb); + + /* now restore the original left/top values again */ + *(int16_t *)(sf + 4 + 2) = av_le2ne16(left); + *(int16_t *)(sf + 4 + 4) = av_le2ne16(top); + } else { + /* this happens a lot in RA1: The individual files are meant to + * be played in sequence, with some referencing objects STORed + * by previous files, e.g. the cockpit codec21 object in RA1 LVL8. + * But spamming the log with errors is also not helpful, so + * here we simply ignore this case. + */ + ret = 0; + } + return ret; +} + +static int process_xpal(SANMVideoContext *ctx, int size) +{ + int16_t *dp = ctx->delta_pal; + uint32_t *pal = ctx->pal; + uint16_t cmd; + uint8_t c[3]; + int i, j; + + bytestream2_skip(&ctx->gb, 2); + cmd = bytestream2_get_be16(&ctx->gb); + + if (cmd == 1) { + for (i = 0; i < PALETTE_DELTA; i += 3) { + c[0] = (*pal >> 16) & 0xFF; + c[1] = (*pal >> 8) & 0xFF; + c[2] = (*pal >> 0) & 0xFF; + for (j = 0; j < 3; j++) { + int cl = (c[j] * 129) + *dp++; + c[j] = av_clip_uint8(cl / 128) & 0xFF; + } + *pal++ = 0xFFU << 24 | c[0] << 16 | c[1] << 8 | c[2]; + } + } else if (cmd == 2) { + if (size < PALETTE_DELTA * 2 + 4) { + av_log(ctx->avctx, AV_LOG_ERROR, + "Incorrect palette change block size %"PRIu32".\n", size); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < PALETTE_DELTA; i++) + dp[i] = bytestream2_get_le16u(&ctx->gb); + + if (size >= PALETTE_DELTA * 2 + 4 + PALETTE_SIZE * 3) { + for (i = 0; i < PALETTE_SIZE; i++) + ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; + } + } + return 0; } static int decode_0(SANMVideoContext *ctx) @@ -1155,6 +2074,20 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) mx = motion_vectors[opcode][0]; my = motion_vectors[opcode][1]; + /* The original implementation of this codec precomputes a table + * of int16_t all motion vectors for given image width. + * For larger widths, starting with 762 pixels, the calculation of + * mv table indices 1+ and 255- overflow the int16_t, inverting the + * sign of the offset. This is actively exploited in e.g. the + * "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine". + * Therefore let the overflow happen and extract x/y components from + * the new value. + */ + if (ctx->width > 761) { + index = (int16_t)(my * ctx->width + mx); + mx = index % ctx->width; + my = index / ctx->width; + } if (good_mvec(ctx, cx, cy, mx, my, blk_size)) { copy_block(ctx->frm0 + cx + ctx->pitch * cy, ctx->frm2 + cx + mx + ctx->pitch * (cy + my), @@ -1257,7 +2190,7 @@ static int decode_5(SANMVideoContext *ctx) #endif uint8_t *dst = (uint8_t*)ctx->frm0; - if (rle_decode(ctx, dst, ctx->buf_size)) + if (rle_decode(ctx, &ctx->gb, dst, ctx->buf_size)) return AVERROR_INVALIDDATA; #if HAVE_BIGENDIAN @@ -1300,7 +2233,7 @@ static int decode_8(SANMVideoContext *ctx) } rsrc = ctx->rle_buf; - if (rle_decode(ctx, rsrc, npixels)) + if (rle_decode(ctx, &ctx->gb, rsrc, npixels)) return AVERROR_INVALIDDATA; while (npixels--) @@ -1367,7 +2300,7 @@ static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color) static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr) { uint8_t *dst; - const uint8_t *src = (uint8_t*) ctx->frm0; + const uint8_t *src = hdr ? (uint8_t *)ctx->frm0 : (uint8_t *)ctx->fbuf; int ret, height = ctx->height; ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1); @@ -1396,7 +2329,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream2_init(&ctx->gb, pkt->data, pkt->size); if (!ctx->version) { - int to_store = 0; + int to_store = 0, have_img = 0; + + ctx->first_fob = 1; while (bytestream2_get_bytes_left(&ctx->gb) >= 8) { uint32_t sig, size; @@ -1419,48 +2354,54 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } for (i = 0; i < PALETTE_SIZE; i++) ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); + if (ctx->subversion < 2) + ctx->pal[0] = 0xFFU << 24; break; case MKBETAG('F', 'O', 'B', 'J'): if (size < 16) return AVERROR_INVALIDDATA; - if (ret = process_frame_obj(ctx)) + if (ret = process_frame_obj(ctx, &ctx->gb)) return ret; - break; - case MKBETAG('X', 'P', 'A', 'L'): - if (size == 6 || size == 4) { - uint8_t tmp[3]; - int j; + have_img = 1; - for (i = 0; i < PALETTE_SIZE; i++) { - for (j = 0; j < 3; j++) { - int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF; - tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7); + /* STOR: for ANIMv0/1 store the whole FOBJ datablock, as it + * needs to be replayed on FTCH, since none of the codecs + * it uses work on the full buffer. + * For ANIMv2, it's enough to store the current framebuffer. + */ + if (to_store) { + to_store = 0; + if (ctx->subversion < 2) { + if (size + 4 <= ctx->stored_frame_size) { + int pos2 = bytestream2_tell(&ctx->gb); + bytestream2_seek(&ctx->gb, pos, SEEK_SET); + *(uint32_t *)(ctx->stored_frame) = size; + bytestream2_get_bufferu(&ctx->gb, ctx->stored_frame + 4, size); + bytestream2_seek(&ctx->gb, pos2, SEEK_SET); + } else { + av_log(avctx, AV_LOG_ERROR, "FOBJ too large for STOR\n"); + ret = AVERROR(ENOMEM); } - ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp); - } - } else { - if (size < PALETTE_DELTA * 2 + 4) { - av_log(avctx, AV_LOG_ERROR, - "Incorrect palette change block size %"PRIu32".\n", - size); - return AVERROR_INVALIDDATA; - } - bytestream2_skipu(&ctx->gb, 4); - for (i = 0; i < PALETTE_DELTA; i++) - ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb); - if (size >= PALETTE_DELTA * 5 + 4) { - for (i = 0; i < PALETTE_SIZE; i++) - ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); } else { - memset(ctx->pal, 0, sizeof(ctx->pal)); + memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size); } } break; + case MKBETAG('X', 'P', 'A', 'L'): + if (ret = process_xpal(ctx, size)) + return ret; + break; case MKBETAG('S', 'T', 'O', 'R'): to_store = 1; break; case MKBETAG('F', 'T', 'C', 'H'): - memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size); + if (ctx->subversion < 2) { + if (ret = process_ftch(ctx, size)) + return ret; + } else { + memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size); + } + have_img = 1; break; default: bytestream2_skip(&ctx->gb, size); @@ -1469,15 +2410,24 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, break; } + /* the sizes of chunks are usually a multiple of 2. However + * there are a few unaligned FOBJs in RA1 L2PLAY.ANM only (looks + * like a game bug) and IACT audio chunks which have odd sizes + * but are padded with a zero byte. + */ bytestream2_seek(&ctx->gb, pos + size, SEEK_SET); - if (size & 1) - bytestream2_skip(&ctx->gb, 1); + if ((pos + size) & 1) { + if (0 != bytestream2_get_byteu(&ctx->gb)) + bytestream2_seek(&ctx->gb, pos + size, SEEK_SET); + } + } + + if (have_img) { + if ((ret = copy_output(ctx, NULL))) + return ret; + memcpy(ctx->frame->data[1], ctx->pal, 1024); + *got_frame_ptr = 1; } - if (to_store) - memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size); - if ((ret = copy_output(ctx, NULL))) - return ret; - memcpy(ctx->frame->data[1], ctx->pal, 1024); } else { SANMFrameHeader header; @@ -1508,12 +2458,13 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = copy_output(ctx, &header))) return ret; + + *got_frame_ptr = 1; + } if (ctx->rotate_code) rotate_bufs(ctx, ctx->rotate_code); - *got_frame_ptr = 1; - return pkt->size; } diff --git a/libavcodec/sbcdec.c b/libavcodec/sbcdec.c index 033a8380d6..d39319966c 100644 --- a/libavcodec/sbcdec.c +++ b/libavcodec/sbcdec.c @@ -229,10 +229,10 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state, /* Distribute the new matrix value to the shifted position */ v[offset[i]] = - (int)( (unsigned)ff_synmatrix4[i][0] * frame->sb_sample[blk][ch][0] + - (unsigned)ff_synmatrix4[i][1] * frame->sb_sample[blk][ch][1] + - (unsigned)ff_synmatrix4[i][2] * frame->sb_sample[blk][ch][2] + - (unsigned)ff_synmatrix4[i][3] * frame->sb_sample[blk][ch][3] ) >> 15; + (int)( (unsigned)synmatrix4[i][0] * frame->sb_sample[blk][ch][0] + + (unsigned)synmatrix4[i][1] * frame->sb_sample[blk][ch][1] + + (unsigned)synmatrix4[i][2] * frame->sb_sample[blk][ch][2] + + (unsigned)synmatrix4[i][3] * frame->sb_sample[blk][ch][3] ) >> 15; } /* Compute the samples */ @@ -241,16 +241,16 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state, /* Store in output, Q0 */ AV_WN16A(&output_frame->data[ch][blk * 8 + i * 2], av_clip_int16( - (int)( (unsigned)v[offset[i] + 0] * ff_sbc_proto_4_40m0[idx + 0] + - (unsigned)v[offset[k] + 1] * ff_sbc_proto_4_40m1[idx + 0] + - (unsigned)v[offset[i] + 2] * ff_sbc_proto_4_40m0[idx + 1] + - (unsigned)v[offset[k] + 3] * ff_sbc_proto_4_40m1[idx + 1] + - (unsigned)v[offset[i] + 4] * ff_sbc_proto_4_40m0[idx + 2] + - (unsigned)v[offset[k] + 5] * ff_sbc_proto_4_40m1[idx + 2] + - (unsigned)v[offset[i] + 6] * ff_sbc_proto_4_40m0[idx + 3] + - (unsigned)v[offset[k] + 7] * ff_sbc_proto_4_40m1[idx + 3] + - (unsigned)v[offset[i] + 8] * ff_sbc_proto_4_40m0[idx + 4] + - (unsigned)v[offset[k] + 9] * ff_sbc_proto_4_40m1[idx + 4] ) >> 15)); + (int)( (unsigned)v[offset[i] + 0] * sbc_proto_4_40m0[idx + 0] + + (unsigned)v[offset[k] + 1] * sbc_proto_4_40m1[idx + 0] + + (unsigned)v[offset[i] + 2] * sbc_proto_4_40m0[idx + 1] + + (unsigned)v[offset[k] + 3] * sbc_proto_4_40m1[idx + 1] + + (unsigned)v[offset[i] + 4] * sbc_proto_4_40m0[idx + 2] + + (unsigned)v[offset[k] + 5] * sbc_proto_4_40m1[idx + 2] + + (unsigned)v[offset[i] + 6] * sbc_proto_4_40m0[idx + 3] + + (unsigned)v[offset[k] + 7] * sbc_proto_4_40m1[idx + 3] + + (unsigned)v[offset[i] + 8] * sbc_proto_4_40m0[idx + 4] + + (unsigned)v[offset[k] + 9] * sbc_proto_4_40m1[idx + 4] ) >> 15)); } } @@ -272,14 +272,14 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, /* Distribute the new matrix value to the shifted position */ v[offset[i]] = - (int)( (unsigned)ff_synmatrix8[i][0] * frame->sb_sample[blk][ch][0] + - (unsigned)ff_synmatrix8[i][1] * frame->sb_sample[blk][ch][1] + - (unsigned)ff_synmatrix8[i][2] * frame->sb_sample[blk][ch][2] + - (unsigned)ff_synmatrix8[i][3] * frame->sb_sample[blk][ch][3] + - (unsigned)ff_synmatrix8[i][4] * frame->sb_sample[blk][ch][4] + - (unsigned)ff_synmatrix8[i][5] * frame->sb_sample[blk][ch][5] + - (unsigned)ff_synmatrix8[i][6] * frame->sb_sample[blk][ch][6] + - (unsigned)ff_synmatrix8[i][7] * frame->sb_sample[blk][ch][7] ) >> 15; + (int)( (unsigned)synmatrix8[i][0] * frame->sb_sample[blk][ch][0] + + (unsigned)synmatrix8[i][1] * frame->sb_sample[blk][ch][1] + + (unsigned)synmatrix8[i][2] * frame->sb_sample[blk][ch][2] + + (unsigned)synmatrix8[i][3] * frame->sb_sample[blk][ch][3] + + (unsigned)synmatrix8[i][4] * frame->sb_sample[blk][ch][4] + + (unsigned)synmatrix8[i][5] * frame->sb_sample[blk][ch][5] + + (unsigned)synmatrix8[i][6] * frame->sb_sample[blk][ch][6] + + (unsigned)synmatrix8[i][7] * frame->sb_sample[blk][ch][7] ) >> 15; } /* Compute the samples */ @@ -288,16 +288,16 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, /* Store in output, Q0 */ AV_WN16A(&output_frame->data[ch][blk * 16 + i * 2], av_clip_int16( - (int)( (unsigned)v[offset[i] + 0] * ff_sbc_proto_8_80m0[idx + 0] + - (unsigned)v[offset[k] + 1] * ff_sbc_proto_8_80m1[idx + 0] + - (unsigned)v[offset[i] + 2] * ff_sbc_proto_8_80m0[idx + 1] + - (unsigned)v[offset[k] + 3] * ff_sbc_proto_8_80m1[idx + 1] + - (unsigned)v[offset[i] + 4] * ff_sbc_proto_8_80m0[idx + 2] + - (unsigned)v[offset[k] + 5] * ff_sbc_proto_8_80m1[idx + 2] + - (unsigned)v[offset[i] + 6] * ff_sbc_proto_8_80m0[idx + 3] + - (unsigned)v[offset[k] + 7] * ff_sbc_proto_8_80m1[idx + 3] + - (unsigned)v[offset[i] + 8] * ff_sbc_proto_8_80m0[idx + 4] + - (unsigned)v[offset[k] + 9] * ff_sbc_proto_8_80m1[idx + 4] ) >> 15)); + (int)( (unsigned)v[offset[i] + 0] * sbc_proto_8_80m0[idx + 0] + + (unsigned)v[offset[k] + 1] * sbc_proto_8_80m1[idx + 0] + + (unsigned)v[offset[i] + 2] * sbc_proto_8_80m0[idx + 1] + + (unsigned)v[offset[k] + 3] * sbc_proto_8_80m1[idx + 1] + + (unsigned)v[offset[i] + 4] * sbc_proto_8_80m0[idx + 2] + + (unsigned)v[offset[k] + 5] * sbc_proto_8_80m1[idx + 2] + + (unsigned)v[offset[i] + 6] * sbc_proto_8_80m0[idx + 3] + + (unsigned)v[offset[k] + 7] * sbc_proto_8_80m1[idx + 3] + + (unsigned)v[offset[i] + 8] * sbc_proto_8_80m0[idx + 4] + + (unsigned)v[offset[k] + 9] * sbc_proto_8_80m1[idx + 4] ) >> 15)); } } @@ -321,7 +321,7 @@ static void sbc_synthesize_audio(struct sbc_decoder_state *state, } } -static int sbc_decode_init(AVCodecContext *avctx) +static av_cold int sbc_decode_init(AVCodecContext *avctx) { SBCDecContext *sbc = avctx->priv_data; int i, ch; @@ -371,10 +371,7 @@ const FFCodec ff_sbc_decoder = { .init = sbc_decode_init, FF_CODEC_DECODE_CB(sbc_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P), + CODEC_SAMPLERATES(16000, 32000, 44100, 48000), }; diff --git a/libavcodec/sbcdec_data.c b/libavcodec/sbcdec_data.c deleted file mode 100644 index 2152162207..0000000000 --- a/libavcodec/sbcdec_data.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 index 1b79d1de23..d8ae062214 100644 --- a/libavcodec/sbcdec_data.h +++ b/libavcodec/sbcdec_data.h @@ -33,12 +33,99 @@ #define AVCODEC_SBCDEC_DATA_H #include +#include "sbc.h" -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]; +#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) + +static const int32_t 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) +}; + +static const int32_t 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) +}; + +static const int32_t 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) +}; + +static const int32_t 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) +}; + +static const int32_t 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) } +}; + +static const int32_t 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) } +}; #endif /* AVCODEC_SBCDEC_DATA_H */ diff --git a/libavcodec/sbcdsp.c b/libavcodec/sbcdsp.c index 400526ce62..00f9c4c68d 100644 --- a/libavcodec/sbcdsp.c +++ b/libavcodec/sbcdsp.c @@ -107,26 +107,26 @@ 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); + s->sbc_analyze_4(x + 12, out, sbcdsp_analysis_consts_fixed4_simd_odd); out += out_stride; - s->sbc_analyze_4(x + 8, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); + s->sbc_analyze_4(x + 8, out, sbcdsp_analysis_consts_fixed4_simd_even); out += out_stride; - s->sbc_analyze_4(x + 4, out, ff_sbcdsp_analysis_consts_fixed4_simd_odd); + s->sbc_analyze_4(x + 4, out, sbcdsp_analysis_consts_fixed4_simd_odd); out += out_stride; - s->sbc_analyze_4(x + 0, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); + s->sbc_analyze_4(x + 0, out, 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); + s->sbc_analyze_8(x + 24, out, sbcdsp_analysis_consts_fixed8_simd_odd); out += out_stride; - s->sbc_analyze_8(x + 16, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8(x + 16, out, sbcdsp_analysis_consts_fixed8_simd_even); out += out_stride; - s->sbc_analyze_8(x + 8, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + s->sbc_analyze_8(x + 8, out, sbcdsp_analysis_consts_fixed8_simd_odd); out += out_stride; - s->sbc_analyze_8(x + 0, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8(x + 0, out, sbcdsp_analysis_consts_fixed8_simd_even); } static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s, @@ -137,7 +137,7 @@ 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_8(x, out, sbcdsp_analysis_consts_fixed8_simd_odd); s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even; } @@ -145,7 +145,7 @@ 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_8(x, out, sbcdsp_analysis_consts_fixed8_simd_even); s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; } diff --git a/libavcodec/sbcdsp.h b/libavcodec/sbcdsp.h index 24264df51d..20266bf25e 100644 --- a/libavcodec/sbcdsp.h +++ b/libavcodec/sbcdsp.h @@ -32,10 +32,11 @@ #ifndef AVCODEC_SBCDSP_H #define AVCODEC_SBCDSP_H +#include + #include "libavutil/mem_internal.h" #include "sbc.h" -#include "sbcdsp_data.h" #define SCALE_OUT_BITS 15 #define SBC_X_BUFFER_SIZE 328 diff --git a/libavcodec/sbcdsp_data.c b/libavcodec/sbcdsp_data.c deleted file mode 100644 index ad6390c7cf..0000000000 --- a/libavcodec/sbcdsp_data.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * 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 "libavutil/mem_internal.h" - -#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 index 10fad5caa5..006b5f9ccf 100644 --- a/libavcodec/sbcdsp_data.h +++ b/libavcodec/sbcdsp_data.h @@ -32,11 +32,18 @@ #ifndef AVCODEC_SBCDSP_DATA_H #define AVCODEC_SBCDSP_DATA_H +#include + +#include "libavutil/mem_internal.h" + #include "sbc.h" #define SBC_PROTO_FIXED_SCALE 16 #define SBC_COS_TABLE_FIXED_SCALE 15 +#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: @@ -47,9 +54,288 @@ * 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[]; +DECLARE_ALIGNED(SBC_ALIGN, static const int16_t, 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, static const int16_t, 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, static const int16_t, 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, static const int16_t, 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 +}; #endif /* AVCODEC_SBCDSP_DATA_H */ diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c index f2c4fbe329..fb810c4c52 100644 --- a/libavcodec/sbcenc.c +++ b/libavcodec/sbcenc.c @@ -49,6 +49,8 @@ typedef struct SBCEncContext { DECLARE_ALIGNED(SBC_ALIGN, SBCDSPContext, dsp); } SBCEncContext; +static const int sbc_samplerates[] = { 16000, 32000, 44100, 48000, 0 }; + static int sbc_analyze_audio(SBCDSPContext *s, struct sbc_frame *frame) { int ch, blk; @@ -194,7 +196,7 @@ static size_t sbc_pack_frame(AVPacket *avpkt, struct sbc_frame *frame, return put_bytes_output(&pb); } -static int sbc_encode_init(AVCodecContext *avctx) +static av_cold int sbc_encode_init(AVCodecContext *avctx) { SBCEncContext *sbc = avctx->priv_data; struct sbc_frame *frame = &sbc->frame; @@ -260,8 +262,8 @@ static int sbc_encode_init(AVCodecContext *avctx) 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]) + for (int i = 0; sbc_samplerates[i]; i++) + if (avctx->sample_rate == sbc_samplerates[i]) frame->frequency = i; frame->channels = avctx->ch_layout.nb_channels; @@ -354,12 +356,9 @@ const FFCodec ff_sbc_encoder = { .priv_data_size = sizeof(SBCEncContext), .init = sbc_encode_init, FF_CODEC_ENCODE_CB(sbc_encode_frame), - .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, - AV_CHANNEL_LAYOUT_STEREO, - { 0 } }, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_NONE }, - .p.supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, + CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), + CODEC_SAMPLERATES_ARRAY(sbc_samplerates), .p.priv_class = &sbc_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_sbc_profiles), }; diff --git a/libavcodec/scpr3.c b/libavcodec/scpr3.c index e91c198308..369d2653c2 100644 --- a/libavcodec/scpr3.c +++ b/libavcodec/scpr3.c @@ -1167,7 +1167,7 @@ static int decompress_p3(AVCodecContext *avctx, } } else { int run, bx = x * 16 + sx1, by = y * 16 + sy1; - uint32_t clr, ptype = 0, r, g, b; + uint32_t clr = 0, ptype = 0, r, g, b; if (bx >= avctx->width) return AVERROR_INVALIDDATA; diff --git a/libavcodec/sga.c b/libavcodec/sga.c index c828f7147f..b6902452d3 100644 --- a/libavcodec/sga.c +++ b/libavcodec/sga.c @@ -254,7 +254,7 @@ static int decode_palmapdata(AVCodecContext *avctx) const int bits = (s->nb_pal + 1) / 2; GetByteContext *gb = &s->gb; GetBitContext pm; - int ret; + av_unused int ret; bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->palmapdata_size) @@ -279,7 +279,7 @@ static int decode_tiledata(AVCodecContext *avctx) SGAVideoContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; GetBitContext tm; - int ret; + av_unused int ret; bytestream2_seek(gb, s->tiledata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->tiledata_size) @@ -501,11 +501,6 @@ static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif frame->pict_type = AV_PICTURE_TYPE_I; frame->flags |= AV_FRAME_FLAG_KEY; diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c index 0901cf58b3..93ec9ff6cf 100644 --- a/libavcodec/sgienc.c +++ b/libavcodec/sgienc.c @@ -281,11 +281,8 @@ const FFCodec ff_sgi_encoder = { .p.priv_class = &sgi_class, .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, - AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, - AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, + AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, + AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8), }; diff --git a/libavcodec/shorten.c b/libavcodec/shorten.c index 46d3b7a615..bed9293680 100644 --- a/libavcodec/shorten.c +++ b/libavcodec/shorten.c @@ -584,7 +584,7 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avpkt->size) { int max_framesize = s->blocksize * s->channels * 8; void *tmp_ptr; - + unsigned old_allocated_bitstream_size = s->allocated_bitstream_size; tmp_ptr = av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, max_framesize + AV_INPUT_BUFFER_PADDING_SIZE); if (!tmp_ptr) { @@ -592,9 +592,8 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR(ENOMEM); } s->bitstream = tmp_ptr; - if (max_framesize > s->max_framesize) - memset(s->bitstream + s->max_framesize, 0, (max_framesize - s->max_framesize) + - AV_INPUT_BUFFER_PADDING_SIZE); + if (s->allocated_bitstream_size > old_allocated_bitstream_size) + memset(s->bitstream + old_allocated_bitstream_size, 0, s->allocated_bitstream_size - old_allocated_bitstream_size); s->max_framesize = FFMAX(s->max_framesize, max_framesize); *got_frame_ptr = 0; goto finish_frame; @@ -817,11 +816,6 @@ const FFCodec ff_shorten_decoder = { FF_CODEC_DECODE_CB(shorten_decode_frame), .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DELAY | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DR1, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_U8P), }; diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c index eb13cff146..5253afc6df 100644 --- a/libavcodec/simple_idct.c +++ b/libavcodec/simple_idct.c @@ -37,11 +37,6 @@ #define BIT_DEPTH 10 #include "simple_idct_template.c" - -#define EXTRA_SHIFT 2 -#include "simple_idct_template.c" - -#undef EXTRA_SHIFT #undef BIT_DEPTH #define BIT_DEPTH 12 @@ -235,35 +230,3 @@ void ff_simple_idct44_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) idct4col_add(dest + i, line_size, block + i); } } - -void ff_prores_idct_10(int16_t *block, const int16_t *qmat) -{ - int i; - - for (i = 0; i < 64; i++) - block[i] *= qmat[i]; - - for (i = 0; i < 8; i++) - idctRowCondDC_extrashift_10(block + i*8, 2); - - for (i = 0; i < 8; i++) { - block[i] += 8192; - idctSparseCol_extrashift_10(block + i); - } -} - -void ff_prores_idct_12(int16_t *block, const int16_t *qmat) -{ - int i; - - for (i = 0; i < 64; i++) - block[i] *= qmat[i]; - - for (i = 0; i < 8; i++) - idctRowCondDC_int16_12bit(block + i*8, 0); - - for (i = 0; i < 8; i++) { - block[i] += 8192; - idctSparseCol_int16_12bit(block + i); - } -} diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h index 20578b3347..a3f6cf9111 100644 --- a/libavcodec/simple_idct.h +++ b/libavcodec/simple_idct.h @@ -47,14 +47,6 @@ void ff_simple_idct_put_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t 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_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. - */ -void ff_prores_idct_10(int16_t *block, const int16_t *qmat); -void ff_prores_idct_12(int16_t *block, const int16_t *qmat); - void ff_simple_idct248_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); void ff_simple_idct84_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c index 5ddd0b45a2..e189ef1a8e 100644 --- a/libavcodec/simple_idct_template.c +++ b/libavcodec/simple_idct_template.c @@ -28,8 +28,6 @@ /* Based upon some commented-out C code from mpeg2dec (idct_mmx.c * written by Aaron Holtzman ). */ -#include "simple_idct.h" - #include "bit_depth_template.c" #undef W1 @@ -261,6 +259,25 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) #ifdef EXTRA_SHIFT static inline void FUNC(idctSparseCol_extrashift)(int16_t *col) #else +static inline void FUNC6(idctSparseCol)(idctin *col) +#endif +{ + unsigned a0, a1, a2, a3, b0, b1, b2, b3; + + IDCT_COLS; + + col[0 ] = ((int)(a0 + b0) >> COL_SHIFT); + col[8 ] = ((int)(a1 + b1) >> COL_SHIFT); + col[16] = ((int)(a2 + b2) >> COL_SHIFT); + col[24] = ((int)(a3 + b3) >> COL_SHIFT); + col[32] = ((int)(a3 - b3) >> COL_SHIFT); + col[40] = ((int)(a2 - b2) >> COL_SHIFT); + col[48] = ((int)(a1 - b1) >> COL_SHIFT); + col[56] = ((int)(a0 - b0) >> COL_SHIFT); +} + +#ifndef PRORES_ONLY +#ifndef EXTRA_SHIFT static inline void FUNC6(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, idctin *col) { @@ -309,24 +326,6 @@ static inline void FUNC6(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, dest[0] = av_clip_pixel(dest[0] + ((int)(a0 - b0) >> COL_SHIFT)); } -static inline void FUNC6(idctSparseCol)(idctin *col) -#endif -{ - unsigned a0, a1, a2, a3, b0, b1, b2, b3; - - IDCT_COLS; - - col[0 ] = ((int)(a0 + b0) >> COL_SHIFT); - col[8 ] = ((int)(a1 + b1) >> COL_SHIFT); - col[16] = ((int)(a2 + b2) >> COL_SHIFT); - col[24] = ((int)(a3 + b3) >> COL_SHIFT); - col[32] = ((int)(a3 - b3) >> COL_SHIFT); - col[40] = ((int)(a2 - b2) >> COL_SHIFT); - col[48] = ((int)(a1 - b1) >> COL_SHIFT); - col[56] = ((int)(a0 - b0) >> COL_SHIFT); -} - -#ifndef EXTRA_SHIFT void FUNC6(ff_simple_idct_put)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block_) { idctin *block = (idctin *)block_; @@ -369,3 +368,4 @@ void FUNC6(ff_simple_idct)(int16_t *block) } #endif #endif +#endif /* PRORES_ONLY */ diff --git a/libavcodec/sipr.c b/libavcodec/sipr.c index 3ddc579f09..ebd7dab03c 100644 --- a/libavcodec/sipr.c +++ b/libavcodec/sipr.c @@ -412,9 +412,9 @@ static void decode_frame(SiprContext *ctx, SiprParameters *params, convolute_with_sparse(fixed_vector, &fixed_cb, impulse_response, SUBFR_SIZE); - avg_energy = (0.01 + avpriv_scalarproduct_float_c(fixed_vector, - fixed_vector, - SUBFR_SIZE)) / + avg_energy = (0.01 + ff_scalarproduct_float_c(fixed_vector, + fixed_vector, + SUBFR_SIZE)) / SUBFR_SIZE; ctx->past_pitch_gain = pitch_gain = gain_cb[params->gc_index[i]][0]; @@ -456,9 +456,9 @@ static void decode_frame(SiprContext *ctx, SiprParameters *params, if (ctx->mode == MODE_5k0) { for (i = 0; i < subframe_count; i++) { - float energy = avpriv_scalarproduct_float_c(ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, - ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, - SUBFR_SIZE); + float energy = ff_scalarproduct_float_c(ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, + ctx->postfilter_syn5k0 + LP_FILTER_ORDER + i * SUBFR_SIZE, + SUBFR_SIZE); ff_adaptive_gain_control(&synth[i * SUBFR_SIZE], &synth[i * SUBFR_SIZE], energy, SUBFR_SIZE, 0.9, &ctx->postfilter_agc); diff --git a/libavcodec/sipr16k.c b/libavcodec/sipr16k.c index 9c8f684003..ab892d0547 100644 --- a/libavcodec/sipr16k.c +++ b/libavcodec/sipr16k.c @@ -163,11 +163,11 @@ static float acelp_decode_gain_codef(float gain_corr_factor, const float *fc_v, const float *ma_prediction_coeff, int subframe_size, int ma_pred_order) { - mr_energy += avpriv_scalarproduct_float_c(quant_energy, ma_prediction_coeff, - ma_pred_order); + mr_energy += ff_scalarproduct_float_c(quant_energy, ma_prediction_coeff, + ma_pred_order); mr_energy = gain_corr_factor * exp(M_LN10 / 20. * mr_energy) / - sqrt((0.01 + avpriv_scalarproduct_float_c(fc_v, fc_v, subframe_size))); + sqrt((0.01 + ff_scalarproduct_float_c(fc_v, fc_v, subframe_size))); return mr_energy; } diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c index 8f198d6957..e0c4dac350 100644 --- a/libavcodec/smacker.c +++ b/libavcodec/smacker.c @@ -393,11 +393,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, pal = (uint32_t*)smk->pic->data[1]; bytestream2_init(&gb2, avpkt->data, avpkt->size); flags = bytestream2_get_byteu(&gb2); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - smk->pic->palette_has_changed = flags & 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (flags & 2) { smk->pic->flags |= AV_FRAME_FLAG_KEY; smk->pic->pict_type = AV_PICTURE_TYPE_I; @@ -646,10 +641,6 @@ static int smka_decode_frame(AVCodecContext *avctx, AVFrame *frame, "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; - samples = (int16_t *)frame->data[0]; - samples8 = frame->data[0]; // Initialize for(i = 0; i < (1 << (bits + stereo)); i++) { @@ -671,6 +662,16 @@ static int smka_decode_frame(AVCodecContext *avctx, AVFrame *frame, } else values[i] = h.entries[0].value; } + if (get_bits_left(&gb) < (stereo+1) * (bits+1) * 8) { + ret = AVERROR_INVALIDDATA; + goto error; + } + + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + goto error; + samples = (int16_t *)frame->data[0]; + samples8 = frame->data[0]; + /* this codec relies on wraparound instead of clipping audio */ if(bits) { //decode 16-bit data for(i = stereo; i >= 0; i--) diff --git a/libavcodec/smc.c b/libavcodec/smc.c index 3e8a89ced1..673d7a5e18 100644 --- a/libavcodec/smc.c +++ b/libavcodec/smc.c @@ -437,14 +437,7 @@ static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) return ret; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = -#endif ff_copy_palette(s->pal, avpkt, avctx); -#if FF_API_PALETTE_HAS_CHANGED -FF_ENABLE_DEPRECATION_WARNINGS -#endif bytestream2_init(&gb, buf, buf_size); ret = smc_decode_stream(s, &gb); diff --git a/libavcodec/smcenc.c b/libavcodec/smcenc.c index f8a3322bb1..dfa1c17d2d 100644 --- a/libavcodec/smcenc.c +++ b/libavcodec/smcenc.c @@ -515,7 +515,7 @@ static void smc_encode_stream(SMCContext *s, const AVFrame *frame, } } -static int smc_encode_init(AVCodecContext *avctx) +static av_cold int smc_encode_init(AVCodecContext *avctx) { SMCContext *s = avctx->priv_data; @@ -580,7 +580,7 @@ static int smc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } -static int smc_encode_end(AVCodecContext *avctx) +static av_cold int smc_encode_end(AVCodecContext *avctx) { SMCContext *s = avctx->priv_data; @@ -599,6 +599,5 @@ const FFCodec ff_smc_encoder = { .init = smc_encode_init, FF_CODEC_ENCODE_CB(smc_encode_frame), .close = smc_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE}, + CODEC_PIXFMTS(AV_PIX_FMT_PAL8), }; diff --git a/libavcodec/smpte_436m.c b/libavcodec/smpte_436m.c new file mode 100644 index 0000000000..b2324cac18 --- /dev/null +++ b/libavcodec/smpte_436m.c @@ -0,0 +1,475 @@ +/* + * MXF SMPTE-436M VBI/ANC parsing functions + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/smpte_436m.h" +#include "bytestream.h" +#include "libavcodec/packet.h" +#include "libavutil/avassert.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" + +static int validate_smpte_436m_anc_wrapping_type(AVSmpte436mWrappingType wrapping_type) +{ + switch (wrapping_type) { + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2: + case AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2: + case AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME: + return 0; + default: + return AVERROR_INVALIDDATA; + } +} + +static int validate_smpte_436m_anc_payload_sample_coding(AVSmpte436mPayloadSampleCoding payload_sample_coding) +{ + switch (payload_sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + // not allowed for ANC packets + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + return 0; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc) +{ + int ret = validate_smpte_436m_anc_wrapping_type(anc->wrapping_type); + if (ret < 0) + return ret; + ret = validate_smpte_436m_anc_payload_sample_coding(anc->payload_sample_coding); + if (ret < 0) + return ret; + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + ret = av_smpte_436m_coded_anc_payload_size(anc->payload_sample_coding, anc->payload_sample_count); + if (ret < 0) + return ret; + if (anc->payload_array_length < ret) + return AVERROR_INVALIDDATA; + return 0; +} + +// Based off Table 7 (page 13) of: +// https://pub.smpte.org/latest/st436/s436m-2006.pdf +#define SMPTE_436M_ANC_ENTRY_HEADER_SIZE ( \ + 2 /* line_number */ \ + + 1 /* wrapping_type */ \ + + 1 /* payload_sample_coding */ \ + + 2 /* payload_sample_count */ \ + + 4 /* payload_array_length */ \ + + 4 /* payload_array_element_size */ \ +) + +/** + * Decode an ANC packet. + * @param[in] in Input bytes. + * @param[in] size the size of in. + * @param[out] anc the decoded ANC packet + * @return The number of read bytes on success, AVERROR_INVALIDDATA otherwise. + */ +static int smpte_436m_anc_decode_entry(const uint8_t *in, int size, AVSmpte436mCodedAnc *anc) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (SMPTE_436M_ANC_ENTRY_HEADER_SIZE > size) + return AVERROR_INVALIDDATA; + int needed_size = SMPTE_436M_ANC_ENTRY_HEADER_SIZE; + anc->line_number = AV_RB16(in); + in += 2; + anc->wrapping_type = AV_RB8(in); + in++; + anc->payload_sample_coding = AV_RB8(in); + in++; + anc->payload_sample_count = AV_RB16(in); + in += 2; + anc->payload_array_length = AV_RB32(in); + in += 4; + uint32_t payload_array_element_size = AV_RB32(in); + in += 4; + if (payload_array_element_size != 1) + return AVERROR_INVALIDDATA; + needed_size += anc->payload_array_length; + if (needed_size > size) + return AVERROR_INVALIDDATA; + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + memcpy(anc->payload, in, anc->payload_array_length); + int ret = av_smpte_436m_coded_anc_validate(anc); + if (ret < 0) + return ret; + return needed_size; +} + +/** + * Encode an ANC packet. + * @param[in] anc the ANC packet to encode + * @param[in] size the size of out. ignored if out is NULL. + * @param[out] out Output bytes. Doesn't write anything if out is NULL. + * @return the number of bytes written on success, AVERROR codes otherwise. + * If out is NULL, returns the number of bytes it would have written. + */ +static int smpte_436m_anc_encode_entry(uint8_t *out, int size, const AVSmpte436mCodedAnc *anc) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (anc->payload_array_length > AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY) + return AVERROR_INVALIDDATA; + int needed_size = SMPTE_436M_ANC_ENTRY_HEADER_SIZE + (int)anc->payload_array_length; + if (!out) + return needed_size; + if (needed_size > size) + return AVERROR_BUFFER_TOO_SMALL; + AV_WB16(out, anc->line_number); + out += 2; + AV_WB8(out, anc->wrapping_type); + out++; + AV_WB8(out, anc->payload_sample_coding); + out++; + AV_WB16(out, anc->payload_sample_count); + out += 2; + AV_WB32(out, anc->payload_array_length); + out += 4; + AV_WB32(out, 1); // payload_array_element_size + out += 4; + memcpy(out, anc->payload, anc->payload_array_length); + return needed_size; +} + +int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (anc_packet_count < 0 || anc_packet_count >= (1L << 16) || size < 0) + return AVERROR_INVALIDDATA; + + int needed_size = 2; + if (out) { + if (size < needed_size) + return AVERROR_BUFFER_TOO_SMALL; + AV_WB16(out, anc_packet_count); + out += 2; + size -= 2; + } + for (int i = 0; i < anc_packet_count; i++) { + int ret = smpte_436m_anc_encode_entry(out, size, &anc_packets[i]); + if (ret < 0) + return ret; + needed_size += ret; + if (out) { + size -= ret; + out += ret; + } + } + return needed_size; +} + +int av_smpte_436m_anc_append(AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets) +{ + int final_packet_count = 0; + int write_start = 2; + if (pkt->size >= 2) { + final_packet_count = AV_RB16(pkt->data); + write_start = pkt->size; + } else if (pkt->size != 0) // if packet isn't empty + return AVERROR_INVALIDDATA; + if (anc_packet_count < 0 || anc_packet_count >= (1L << 16)) + return AVERROR_INVALIDDATA; + final_packet_count += anc_packet_count; + if (final_packet_count >= (1L << 16)) + return AVERROR_INVALIDDATA; + int ret, additional_size = write_start - pkt->size; + for (int i = 0; i < anc_packet_count; i++) { + ret = smpte_436m_anc_encode_entry(NULL, 0, &anc_packets[i]); + if (ret < 0) + return ret; + additional_size += ret; + } + ret = av_grow_packet(pkt, additional_size); + if (ret < 0) + return ret; + for (int i = 0; i < anc_packet_count; i++) { + ret = smpte_436m_anc_encode_entry(pkt->data + write_start, pkt->size - write_start, &anc_packets[i]); + av_assert0(ret >= 0); + write_start += ret; + } + AV_WB16(pkt->data, final_packet_count); + return 0; +} + +int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size) +{ + // Based off Table 7 (page 13) of: + // https://pub.smpte.org/latest/st436/s436m-2006.pdf + if (buf_size < 2) + return AVERROR_INVALIDDATA; + *iter = (AVSmpte436mAncIterator){ + .anc_packets_left = AV_RB16(buf), + .size_left = buf_size - 2, + .data_left = buf + 2, + }; + if (iter->anc_packets_left > iter->size_left) + return AVERROR_INVALIDDATA; + return 0; +} + +int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc) +{ + if (iter->anc_packets_left <= 0) + return AVERROR_EOF; + iter->anc_packets_left--; + int ret = smpte_436m_anc_decode_entry(iter->data_left, iter->size_left, anc); + if (ret < 0) { + iter->anc_packets_left = 0; + return ret; + } + iter->data_left += ret; + iter->size_left -= ret; + return 0; +} + +int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count) +{ + if (sample_count > AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY) + return AVERROR_INVALIDDATA; + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + // "The Payload Byte Array shall be padded to achieve UInt32 alignment." + // section 4.4 of https://pub.smpte.org/latest/st436/s436m-2006.pdf + return (sample_count + 3) & -4; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + // encoded with 3 10-bit samples in a UInt32. + // "The Payload Byte Array shall be padded to achieve UInt32 alignment." + // section 4.4 of https://pub.smpte.org/latest/st436/s436m-2006.pdf + return 4 * ((sample_count + 2) / 3); + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, + AVSmpte436mPayloadSampleCoding sample_coding, + uint16_t sample_count, + const uint8_t *payload, + void *log_ctx) +{ + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + { + if (sample_count < 3) + return AVERROR_INVALIDDATA; + out->did = *payload++; + out->sdid_or_dbn = *payload++; + out->data_count = *payload++; + if (sample_count < out->data_count + 3) + return AVERROR_INVALIDDATA; + memcpy(out->payload, payload, out->data_count); + // the checksum isn't stored in 8-bit mode, so calculate it. + av_smpte_291m_anc_8bit_fill_checksum(out); + return 0; + } + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "decoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc) +{ + uint8_t checksum = anc->did + anc->sdid_or_dbn + anc->data_count; + for (unsigned i = 0; i < anc->data_count; i++) { + checksum += anc->payload[i]; + } + anc->checksum = checksum; +} + +int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, + AVSmpte436mPayloadSampleCoding sample_coding, + void *log_ctx) +{ + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + // 3 for did, sdid_or_dbn, and data_count; checksum isn't stored in 8-bit modes + return 3 + anc->data_count; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "encoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, + uint16_t line_number, + AVSmpte436mWrappingType wrapping_type, + AVSmpte436mPayloadSampleCoding sample_coding, + const AVSmpte291mAnc8bit *payload, + void *log_ctx) +{ + out->line_number = line_number; + out->wrapping_type = wrapping_type; + out->payload_sample_coding = sample_coding; + + int ret = av_smpte_291m_anc_8bit_get_sample_count(payload, sample_coding, log_ctx); + if (ret < 0) + return ret; + + out->payload_sample_count = ret; + + ret = av_smpte_436m_coded_anc_payload_size(sample_coding, out->payload_sample_count); + if (ret < 0) + return ret; + + out->payload_array_length = ret; + + switch (sample_coding) { + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF: + return AVERROR_INVALIDDATA; + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR: + { + // fill trailing padding with zeros + av_assert0(out->payload_array_length >= 4); + memset(out->payload + out->payload_array_length - 4, 0, 4); + + out->payload[0] = payload->did; + out->payload[1] = payload->sdid_or_dbn; + out->payload[2] = payload->data_count; + + memcpy(out->payload + 3, payload->payload, payload->data_count); + return 0; + } + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF: + case AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF: + av_log(log_ctx, + AV_LOG_ERROR, + "encoding an ANC packet using the 10-bit SMPTE 436M sample coding isn't implemented.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_INVALIDDATA; + } +} + +int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx) +{ + if (anc->did != AV_SMPTE_291M_ANC_DID_CTA_708 || anc->sdid_or_dbn != AV_SMPTE_291M_ANC_SDID_CTA_708) + return AVERROR(EAGAIN); + GetByteContext gb; + bytestream2_init(&gb, anc->payload, anc->data_count); + // based on Caption Distribution Packet (CDP) Definition: + // https://pub.smpte.org/latest/st334-2/st0334-2-2015.pdf + uint16_t cdp_identifier = bytestream2_get_be16(&gb); + if (cdp_identifier != 0x9669) { // CDPs always have this value + av_log(log_ctx, AV_LOG_ERROR, "wrong cdp identifier %x\n", cdp_identifier); + return AVERROR_INVALIDDATA; + } + bytestream2_get_byte(&gb); // cdp_length + bytestream2_get_byte(&gb); // cdp_frame_rate and reserved + bytestream2_get_byte(&gb); // flags + bytestream2_get_be16(&gb); // cdp_hdr_sequence_cntr + unsigned section_id = bytestream2_get_byte(&gb); + + const unsigned TIME_CODE_SECTION_ID = 0x71; + if (section_id == TIME_CODE_SECTION_ID) { + bytestream2_skip(&gb, 4); // skip time code section + section_id = bytestream2_get_byte(&gb); + } + const unsigned CC_DATA_SECTION_ID = 0x72; + if (section_id == CC_DATA_SECTION_ID) { + if (bytestream2_get_bytes_left(&gb) < 1) + goto too_short; + // 0x1F for lower 5 bits, upper 3 bits are marker bits + unsigned cc_count = bytestream2_get_byte(&gb) & 0x1F; + unsigned data_length = cc_count * 3; // EIA-608/CTA-708 triples are 3 bytes long + if (bytestream2_get_bytes_left(&gb) < data_length) + goto too_short; + if (cc_data) + bytestream2_get_bufferu(&gb, cc_data, data_length); + return cc_count; + } + return AVERROR(EAGAIN); + +too_short: + av_log(log_ctx, AV_LOG_ERROR, "not enough bytes in cdp\n"); + return AVERROR_INVALIDDATA; +} diff --git a/libavcodec/smpte_436m.h b/libavcodec/smpte_436m.h new file mode 100644 index 0000000000..9c0e2a5a05 --- /dev/null +++ b/libavcodec/smpte_436m.h @@ -0,0 +1,254 @@ +/* + * MXF SMPTE-436M VBI/ANC parsing functions + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_SMPTE_436M_H +#define AVCODEC_SMPTE_436M_H + +#include + +/** + * Iterator over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data + */ +typedef struct AVSmpte436mAncIterator { + uint16_t anc_packets_left; + int size_left; + const uint8_t *data_left; +} AVSmpte436mAncIterator; + +/** + * Wrapping Type from Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mWrappingType +{ + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME = 1, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1 = 2, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2 = 3, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME = 4, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME = 0x11, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1 = 0x12, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2 = 0x13, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME = 0x14, + /** not a real wrapping type, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_WRAPPING_TYPE_MAX = 0xFF, +} AVSmpte436mWrappingType; + +/** + * Payload Sample Coding from Table 4 (page 10) and Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mPayloadSampleCoding +{ + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA = 1, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF = 2, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF = 3, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA = 4, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF = 5, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF = 6, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA = 7, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF = 8, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF = 9, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR = 10, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR = 11, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR = 12, + /** not a real sample coding, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_MAX = 0xFF, +} AVSmpte436mPayloadSampleCoding; + +/** the payload capacity of AVSmpte291mAnc8bit (and of AVSmpte291mAnc10bit when that gets added) */ +#define AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY 0xFF + +/** + * An ANC packet with an 8-bit payload. + * This can be decoded from AVSmpte436mCodedAnc::payload. + * + * Note: Some ANC packets need a 10-bit payload, if stored in this struct, + * the most-significant 2 bits of each sample are discarded. + */ +typedef struct AVSmpte291mAnc8bit { + uint8_t did; + uint8_t sdid_or_dbn; + uint8_t data_count; + uint8_t payload[AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY]; + uint8_t checksum; +} AVSmpte291mAnc8bit; + +/** max number of samples that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY \ + (AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY + 4) /* 4 for did, sdid_or_dbn, data_count, and checksum */ +/** max number of bytes that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY (((AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY + 2) / 3) * 4) + +/** + * An encoded ANC packet within a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * The repeated section of Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef struct AVSmpte436mCodedAnc { + uint16_t line_number; + AVSmpte436mWrappingType wrapping_type; + AVSmpte436mPayloadSampleCoding payload_sample_coding; + uint16_t payload_sample_count; + uint32_t payload_array_length; + /** the payload, has size payload_array_length. + * can be decoded into AVSmpte291mAnc8bit + */ + uint8_t payload[AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY]; +} AVSmpte436mCodedAnc; + +/** + * Validate a AVSmpte436mCodedAnc structure. Doesn't check if the payload is valid. + * @param[in] anc ANC packet to validate + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc); + +/** + * Encode ANC packets into a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param[in] size the size of out. ignored if out is NULL. + * @param[out] out Output bytes. Doesn't write anything if out is NULL. + * @return the number of bytes written on success, AVERROR codes otherwise. + * If out is NULL, returns the number of bytes it would have written. + */ +int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +struct AVPacket; + +/** + * Append more ANC packets to a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param pkt the AVPacket to append to. + * it must either be size 0 or contain valid SMPTE_436M_ANC data. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_append(struct AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +/** + * Set up iteration over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] buf Pointer to the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[in] buf_size Size of the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[out] iter Pointer to the iterator. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size); + +/** + * Get the next ANC packet from the iterator, advancing the iterator. + * @param[in,out] iter Pointer to the iterator. + * @param[out] anc The returned ANC packet. + * @return 0 on success, AVERROR_EOF when the iterator has reached the end, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc); + +/** + * Get the minimum number of bytes needed to store a AVSmpte436mCodedAnc payload. + * @param sample_coding the payload sample coding + * @param sample_count the number of samples stored in the payload + * @return returns the minimum number of bytes needed, on error returns < 0. + * always <= SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY + */ +int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count); + +/** + * Decode a AVSmpte436mCodedAnc payload into AVSmpte291mAnc8bit + * @param[in] sample_coding the payload sample coding + * @param[in] sample_count the number of samples stored in the payload + * @param[in] payload the bytes storing the payload, + * the needed size can be obtained from + avpriv_smpte_436m_coded_anc_payload_size + * @param[in] log_ctx context pointer for av_log + * @param[out] out The decoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, + AVSmpte436mPayloadSampleCoding sample_coding, + uint16_t sample_count, + const uint8_t *payload, + void *log_ctx); + +/** + * Fill in the correct checksum for a AVSmpte291mAnc8bit + * @param[in,out] anc The ANC packet. + */ +void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc); + +/** + * Compute the sample count needed to encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc payload + * @param[in] anc The ANC packet. + * @param[in] sample_coding The sample coding. + * @param[in] log_ctx context pointer for av_log + * @return returns the sample count on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, + AVSmpte436mPayloadSampleCoding sample_coding, + void *log_ctx); + +/** + * Encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc + * @param[in] line_number the line number the ANC packet is on + * @param[in] wrapping_type the wrapping type + * @param[in] sample_coding the payload sample coding + * @param[in] payload the ANC packet to encode. + * @param[in] log_ctx context pointer for av_log + * @param[out] out The encoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, + uint16_t line_number, + AVSmpte436mWrappingType wrapping_type, + AVSmpte436mPayloadSampleCoding sample_coding, + const AVSmpte291mAnc8bit *payload, + void *log_ctx); + +/** AVSmpte291mAnc8bit::did when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_DID_CTA_708 0x61 + +/** AVSmpte291mAnc8bit::sdid_or_dbn when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_SDID_CTA_708 0x1 + +/** + * Try to decode an ANC packet into EIA-608/CTA-708 data (AV_CODEC_ID_EIA_608). This + * @param[in] anc The ANC packet. + * @param[in] log_ctx Context pointer for av_log + * @param[out] cc_data the buffer to store the extracted EIA-608/CTA-708 data, + * you can pass NULL to not store the data. + * the required size is 3 * cc_count bytes. + * SMPTE_291M_ANC_PAYLOAD_CAPACITY is always enough size. + * @return returns cc_count (>= 0) on success, AVERROR(EAGAIN) if it wasn't a CTA-708 ANC packet, < 0 on error. + */ +int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx); + +#endif /* AVCODEC_SMPTE_436M_H */ diff --git a/libavcodec/smpte_436m_internal.h b/libavcodec/smpte_436m_internal.h new file mode 100644 index 0000000000..7481949fb6 --- /dev/null +++ b/libavcodec/smpte_436m_internal.h @@ -0,0 +1,98 @@ +/* + * MXF SMPTE-436M VBI/ANC internals + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_SMPTE_436M_INTERNAL_H +#define AVCODEC_SMPTE_436M_INTERNAL_H + +#include "smpte_436m.h" + +// clang-format off +#define FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(flags, unit_name) \ + { "vanc_frame", "VANC frame (interlaced or segmented progressive frame)", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_field_1", "VANC field 1", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_field_2", "VANC field 2", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2}, 0, 0xFF, flags, .unit = unit_name }, \ + { "vanc_progressive_frame", "VANC progressive frame", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_WRAPPING_TYPE_HANC_AVOPTIONS(flags, unit_name) \ + { "hanc_frame", "HANC frame (interlaced or segmented progressive frame)", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_field_1", "HANC field 1", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_field_2", "HANC field 2", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2}, 0, 0xFF, flags, .unit = unit_name }, \ + { "hanc_progressive_frame", "HANC progressive frame", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_WRAPPING_TYPE_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_WRAPPING_TYPE_HANC_AVOPTIONS(flags, unit_name) +// clang-format on + +// clang-format off +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name) \ + { "1bit_luma", "1-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "1bit_color_diff", "1-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "1bit_luma_and_color_diff", "1-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name) \ + { "8bit_luma", "8-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_color_diff", "8-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_luma_and_color_diff", "8-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_luma", "10-bit component luma samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_color_diff", "10-bit component color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name }, \ + { "10bit_luma_and_color_diff", "10-bit component luma and color difference samples", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) \ + { "8bit_luma_parity_error", "8-bit component luma samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_color_diff_parity_error", "8-bit component color difference samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name }, \ + { "8bit_luma_and_color_diff_parity_error", "8-bit component luma and color difference samples with parity error", 0, AV_OPT_TYPE_CONST, \ + {.i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR}, 0, 0xFF, flags, .unit = unit_name } + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_VBI_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name) + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ANC_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) + +#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_AVOPTIONS(flags, unit_name) \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_VBI_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_SHARED_AVOPTIONS(flags, unit_name), \ + FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ONLY_IN_ANC_AVOPTIONS(flags, unit_name) +// clang-format on + +#endif /* AVCODEC_SMPTE_436M_INTERNAL_H */ diff --git a/libavcodec/snow.c b/libavcodec/snow.c index af6214d077..e0ce83eb9c 100644 --- a/libavcodec/snow.c +++ b/libavcodec/snow.c @@ -511,27 +511,18 @@ int ff_snow_common_init_after_header(AVCodecContext *avctx) { return 0; } -void ff_snow_release_buffer(AVCodecContext *avctx) -{ - SnowContext *s = avctx->priv_data; - - if(s->last_picture[s->max_ref_frames-1]->data[0]){ - av_frame_unref(s->last_picture[s->max_ref_frames-1]); - } -} - int ff_snow_frames_prepare(SnowContext *s) { AVFrame *tmp; - ff_snow_release_buffer(s->avctx); - tmp= s->last_picture[s->max_ref_frames-1]; for (int i = s->max_ref_frames - 1; i > 0; i--) s->last_picture[i] = s->last_picture[i-1]; s->last_picture[0] = s->current_picture; s->current_picture = tmp; + av_frame_unref(s->current_picture); + if(s->keyframe){ s->ref_frames= 0; s->current_picture->flags |= AV_FRAME_FLAG_KEY; @@ -566,9 +557,6 @@ av_cold void ff_snow_common_end(SnowContext *s) av_freep(&s->emu_edge_buffer); for(i=0; ilast_picture[i] && s->last_picture[i]->data[0]) { - av_assert0(s->last_picture[i]->data[0] != s->current_picture->data[0]); - } av_frame_free(&s->last_picture[i]); } diff --git a/libavcodec/snow.h b/libavcodec/snow.h index a5e2c138cb..9b19e70bd5 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -181,7 +181,6 @@ extern int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES]; int ff_snow_common_init(AVCodecContext *avctx); int ff_snow_common_init_after_header(AVCodecContext *avctx); void ff_snow_common_end(SnowContext *s); -void ff_snow_release_buffer(AVCodecContext *avctx); void ff_snow_reset_contexts(SnowContext *s); int ff_snow_alloc_blocks(SnowContext *s); int ff_snow_frames_prepare(SnowContext *s); @@ -273,7 +272,8 @@ static av_always_inline void add_yblock(SnowContext *s, int sliced, slice_buffer if(!sliced && offset_dst) dst += src_x + src_y*dst_stride; - dst8+= src_x + src_y*src_stride; + if (sliced || add) + dst8+= src_x + src_y*src_stride; // src += src_x + src_y*src_stride; ptmp= tmp + 3*tmp_step; diff --git a/libavcodec/snow_dwt.c b/libavcodec/snow_dwt.c index 1250597ee0..eb4d1e4d36 100644 --- a/libavcodec/snow_dwt.c +++ b/libavcodec/snow_dwt.c @@ -741,7 +741,7 @@ void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height, decomposition_count, y); } -static inline int w_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, +static inline int w_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int w, int h, int type) { int s, i, j; @@ -810,32 +810,32 @@ static inline int w_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8 return s >> 9; } -static int w53_8_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w53_8_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 8, h, 1); } -static int w97_8_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w97_8_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 8, h, 0); } -static int w53_16_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w53_16_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 16, h, 1); } -static int w97_16_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +static int w97_16_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 16, h, 0); } -int ff_w53_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +int ff_w53_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 32, h, 1); } -int ff_w97_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) +int ff_w97_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h) { return w_c(v, pix1, pix2, line_size, 32, h, 0); } @@ -858,5 +858,3 @@ av_cold void ff_dwt_init(SnowDWTContext *c) ff_dwt_init_x86(c); #endif } - - diff --git a/libavcodec/snow_dwt.h b/libavcodec/snow_dwt.h index 6e7d22c71a..b5803bc99a 100644 --- a/libavcodec/snow_dwt.h +++ b/libavcodec/snow_dwt.h @@ -26,7 +26,7 @@ #include "libavutil/attributes.h" -struct MpegEncContext; +typedef struct MPVEncContext MPVEncContext; typedef int DWTELEM; typedef short IDWTELEM; @@ -144,8 +144,8 @@ void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, int src_y, int src_stride, slice_buffer *sb, int add, uint8_t *dst8); -int ff_w53_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); -int ff_w97_32_c(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); +int ff_w53_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); +int ff_w97_32_c(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t line_size, int h); void ff_spatial_dwt(int *buffer, int *temp, int width, int height, int stride, int type, int decomposition_count); diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index 50dcaf8b93..c16e824c73 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -481,14 +481,16 @@ static int decode_header(SnowContext *s){ }else if(s->chroma_h_shift == 2 && s->chroma_v_shift==2){ s->avctx->pix_fmt= AV_PIX_FMT_YUV410P; } else { - av_log(s, AV_LOG_ERROR, "unsupported color subsample mode %d %d\n", s->chroma_h_shift, s->chroma_v_shift); + av_log(s->avctx, AV_LOG_ERROR, + "unsupported color subsample mode %d %d\n", + s->chroma_h_shift, s->chroma_v_shift); s->chroma_h_shift = s->chroma_v_shift = 1; s->avctx->pix_fmt= AV_PIX_FMT_YUV420P; return AVERROR_INVALIDDATA; } s->nb_planes = 3; } else { - av_log(s, AV_LOG_ERROR, "unsupported color space\n"); + av_log(s->avctx, AV_LOG_ERROR, "unsupported color space\n"); s->chroma_h_shift = s->chroma_v_shift = 1; s->avctx->pix_fmt= AV_PIX_FMT_YUV420P; return AVERROR_INVALIDDATA; @@ -779,7 +781,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, emms_c(); - ff_snow_release_buffer(avctx); + av_frame_unref(s->last_picture[s->max_ref_frames - 1]); if(!(s->avctx->debug&2048)) res = av_frame_ref(picture, s->current_picture); diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 0623c9d196..238b78539b 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -61,13 +61,15 @@ typedef struct SnowEncContext { int scenechange_threshold; MECmpContext mecc; - MpegEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to eventually make the motion estimation independent of MpegEncContext, so this will be removed then (FIXME/XXX) + MPVMainEncContext m; // needed for motion estimation, should not be used for anything else, the idea is to eventually make the motion estimation independent of MPVEncContext, so this will be removed then (FIXME/XXX) MPVPicture cur_pic, last_pic; #define ME_CACHE_SIZE 1024 unsigned me_cache[ME_CACHE_SIZE]; unsigned me_cache_generation; uint64_t encoding_error[SNOW_MAX_PLANES]; + + IDWTELEM obmc_scratchpad[MB_SIZE * MB_SIZE * 12 * 2]; } SnowEncContext; static void init_ref(MotionEstContext *c, const uint8_t *const src[3], @@ -160,7 +162,7 @@ static av_cold int encode_init(AVCodecContext *avctx) { SnowEncContext *const enc = avctx->priv_data; SnowContext *const s = &enc->com; - MpegEncContext *const mpv = &enc->m; + MPVEncContext *const mpv = &enc->m.s; int plane_index, ret; int i; @@ -217,7 +219,7 @@ static av_cold int encode_init(AVCodecContext *avctx) mcf(12,12) ff_me_cmp_init(&enc->mecc, avctx); - ret = ff_me_init(&enc->m.me, avctx, &enc->mecc, 0); + ret = ff_me_init(&mpv->me, avctx, &enc->mecc, 0); if (ret < 0) return ret; ff_mpegvideoencdsp_init(&enc->mpvencdsp, avctx); @@ -226,21 +228,18 @@ static av_cold int encode_init(AVCodecContext *avctx) s->version=0; - mpv->avctx = avctx; - mpv->bit_rate= avctx->bit_rate; - mpv->lmin = avctx->mb_lmin; - mpv->lmax = avctx->mb_lmax; - mpv->mb_num = (avctx->width * avctx->height + 255) / 256; // For ratecontrol + mpv->c.avctx = avctx; + enc->m.bit_rate = avctx->bit_rate; + enc->m.lmin = avctx->mb_lmin; + enc->m.lmax = avctx->mb_lmax; + mpv->c.mb_num = (avctx->width * avctx->height + 255) / 256; // For ratecontrol mpv->me.temp = mpv->me.scratchpad = av_calloc(avctx->width + 64, 2*16*2*sizeof(uint8_t)); - mpv->sc.obmc_scratchpad= av_mallocz(MB_SIZE*MB_SIZE*12*sizeof(uint32_t)); - mpv->me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*mpv->me.map)); - if (!mpv->me.scratchpad || !mpv->me.map || !mpv->sc.obmc_scratchpad) + if (!mpv->me.scratchpad) return AVERROR(ENOMEM); - mpv->me.score_map = mpv->me.map + ME_MAP_SIZE; - ff_h263_encode_init(mpv); //mv_penalty + mpv->me.mv_penalty = ff_h263_get_mv_penalty(); s->max_ref_frames = av_clip(avctx->refs, 1, MAX_REF_FRAMES); @@ -252,7 +251,7 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } if((avctx->flags&AV_CODEC_FLAG_PASS2) || !(avctx->flags&AV_CODEC_FLAG_QSCALE)){ - ret = ff_rate_control_init(mpv); + ret = ff_rate_control_init(&enc->m); if(ret < 0) return ret; } @@ -369,7 +368,7 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) { SnowContext *const s = &enc->com; - MotionEstContext *const c = &enc->m.me; + MotionEstContext *const c = &enc->m.s.me; uint8_t p_buffer[1024]; uint8_t i_buffer[1024]; uint8_t p_state[sizeof(s->block_state)]; @@ -435,9 +434,9 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) last_mv[2][0]= bottom->mx; last_mv[2][1]= bottom->my; - enc->m.mb_stride = 2; - enc->m.mb_x = - enc->m.mb_y = 0; + enc->m.s.c.mb_stride = 2; + enc->m.s.c.mb_x = + enc->m.s.c.mb_y = 0; c->skip= 0; av_assert1(c-> stride == stride); @@ -446,7 +445,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) c->penalty_factor = get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->me_cmp); c->sub_penalty_factor= get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->me_sub_cmp); c->mb_penalty_factor = get_penalty_factor(enc->lambda, enc->lambda2, c->avctx->mb_cmp); - c->current_mv_penalty = c->mv_penalty[enc->m.f_code=1] + MAX_DMV; + c->current_mv_penalty = c->mv_penalty[enc->m.s.f_code=1] + MAX_DMV; c->xmin = - x*block_w - 16+3; c->ymin = - y*block_w - 16+3; @@ -482,7 +481,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) for(ref=0; refref_frames; ref++){ init_ref(c, current_data, s->last_picture[ref]->data, NULL, block_w*x, block_w*y, 0); - ref_score= ff_epzs_motion_search(&enc->m, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv, + ref_score = ff_epzs_motion_search(&enc->m.s, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv, (1<<16)>>shift, level-LOG2_MB_SIZE+4, block_w); av_assert2(ref_mx >= c->xmin); @@ -490,8 +489,10 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) av_assert2(ref_my >= c->ymin); av_assert2(ref_my <= c->ymax); - ref_score= c->sub_motion_search(&enc->m, &ref_mx, &ref_my, ref_score, 0, 0, level-LOG2_MB_SIZE+4, block_w); - ref_score= ff_get_mb_score(&enc->m, ref_mx, ref_my, 0, 0, level-LOG2_MB_SIZE+4, block_w, 0); + ref_score = c->sub_motion_search(&enc->m.s, &ref_mx, &ref_my, ref_score, + 0, 0, level-LOG2_MB_SIZE+4, block_w); + ref_score = ff_get_mb_score(&enc->m.s, ref_mx, ref_my, 0, 0, + level-LOG2_MB_SIZE+4, block_w, 0); ref_score+= 2*av_log2(2*ref)*c->penalty_factor; if(s->ref_mvs[ref]){ s->ref_mvs[ref][index][0]= ref_mx; @@ -567,7 +568,7 @@ static int encode_q_branch(SnowEncContext *enc, int level, int x, int y) if (vard <= 64 || vard < varc) c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); else - c->scene_change_score += enc->m.qscale; + c->scene_change_score += enc->m.s.c.qscale; } if(level!=s->block_max_depth){ @@ -670,7 +671,7 @@ static int get_dc(SnowEncContext *enc, int mb_x, int mb_y, int plane_index) const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size; const int ref_stride= s->current_picture->linesize[plane_index]; const uint8_t *src = s->input_picture->data[plane_index]; - IDWTELEM *dst= (IDWTELEM*)enc->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4; //FIXME change to unsigned + IDWTELEM *dst = enc->obmc_scratchpad + plane_index * block_size * block_size * 4; //FIXME change to unsigned const int b_stride = s->b_width << s->block_max_depth; const int w= p->width; const int h= p->height; @@ -768,7 +769,7 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, const int ref_stride= s->current_picture->linesize[plane_index]; uint8_t *dst= s->current_picture->data[plane_index]; const uint8_t *src = s->input_picture->data[plane_index]; - IDWTELEM *pred= (IDWTELEM*)enc->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4; + IDWTELEM *pred = enc->obmc_scratchpad + plane_index * block_size * block_size * 4; uint8_t *cur = s->scratchbuf; uint8_t *tmp = s->emu_edge_buffer; const int b_stride = s->b_width << s->block_max_depth; @@ -786,7 +787,7 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, int y1= FFMIN(block_h*2, h-sy); int i,x,y; - av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below chckinhg only block_w + av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumptions below chckinhg only block_w ff_snow_pred_block(s, cur, tmp, ref_stride, sx, sy, block_w*2, block_h*2, &s->block[mb_x + mb_y*b_stride], plane_index, w, h); @@ -831,19 +832,19 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, * to improve the score of the whole frame, thus iterative motion * estimation does not always converge. */ if(s->avctx->me_cmp == FF_CMP_W97) - distortion = ff_w97_32_c(&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); + distortion = ff_w97_32_c(&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); else if(s->avctx->me_cmp == FF_CMP_W53) - distortion = ff_w53_32_c(&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); + distortion = ff_w53_32_c(&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32); else{ distortion = 0; for(i=0; i<4; i++){ int off = sx+16*(i&1) + (sy+16*(i>>1))*ref_stride; - distortion += enc->m.me.me_cmp[0](&enc->m, src + off, dst + off, ref_stride, 16); + distortion += enc->m.s.me.me_cmp[0](&enc->m.s, src + off, dst + off, ref_stride, 16); } } }else{ av_assert2(block_w==8); - distortion = enc->m.me.me_cmp[0](&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); + distortion = enc->m.s.me.me_cmp[0](&enc->m.s, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); } if(plane_index==0){ @@ -883,7 +884,7 @@ static int get_4block_rd(SnowEncContext *enc, int mb_x, int mb_y, int plane_inde int rate= 0; const int penalty_factor= get_penalty_factor(enc->lambda, enc->lambda2, s->avctx->me_cmp); - av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below + av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumptions below for(i=0; i<9; i++){ int mb_x2= mb_x + (i%3) - 1; @@ -909,7 +910,7 @@ static int get_4block_rd(SnowEncContext *enc, int mb_x, int mb_y, int plane_inde } av_assert1(block_w== 8 || block_w==16); - distortion += enc->m.me.me_cmp[block_w==8](&enc->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h); + distortion += enc->m.s.me.me_cmp[block_w==8](&enc->m.s, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h); } if(plane_index==0){ @@ -1757,7 +1758,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, { SnowEncContext *const enc = avctx->priv_data; SnowContext *const s = &enc->com; - MpegEncContext *const mpv = &enc->m; + MPVEncContext *const mpv = &enc->m.s; RangeCoder * const c= &s->c; AVCodecInternal *avci = avctx->internal; AVFrame *pic; @@ -1793,16 +1794,16 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, mpv->picture_number = avctx->frame_num; if(avctx->flags&AV_CODEC_FLAG_PASS2){ - mpv->pict_type = pic->pict_type = mpv->rc_context.entry[avctx->frame_num].new_pict_type; + mpv->c.pict_type = pic->pict_type = enc->m.rc_context.entry[avctx->frame_num].new_pict_type; s->keyframe = pic->pict_type == AV_PICTURE_TYPE_I; if(!(avctx->flags&AV_CODEC_FLAG_QSCALE)) { - pic->quality = ff_rate_estimate_qscale(mpv, 0); + pic->quality = ff_rate_estimate_qscale(&enc->m, 0); if (pic->quality < 0) return -1; } }else{ s->keyframe= avctx->gop_size==0 || avctx->frame_num % avctx->gop_size == 0; - mpv->pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + mpv->c.pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; } if (enc->pass1_rc && avctx->frame_num == 0) @@ -1839,9 +1840,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (ret < 0) return ret; - mpv->cur_pic.ptr = &enc->cur_pic; - mpv->cur_pic.ptr->f = s->current_picture; - mpv->cur_pic.ptr->f->pts = pict->pts; + mpv->c.cur_pic.ptr = &enc->cur_pic; + mpv->c.cur_pic.ptr->f = s->current_picture; + mpv->c.cur_pic.ptr->f->pts = pict->pts; if(pic->pict_type == AV_PICTURE_TYPE_P){ int block_width = (width +15)>>4; int block_height= (height+15)>>4; @@ -1850,35 +1851,34 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, av_assert0(s->current_picture->data[0]); av_assert0(s->last_picture[0]->data[0]); - mpv->avctx = s->avctx; - mpv->last_pic.ptr = &enc->last_pic; - mpv->last_pic.ptr->f = s->last_picture[0]; + mpv->c.avctx = s->avctx; + mpv->c.last_pic.ptr = &enc->last_pic; + mpv->c.last_pic.ptr->f = s->last_picture[0]; mpv-> new_pic = s->input_picture; - mpv->linesize = stride; - mpv->uvlinesize = s->current_picture->linesize[1]; - mpv->width = width; - mpv->height = height; - mpv->mb_width = block_width; - mpv->mb_height = block_height; - mpv->mb_stride = mpv->mb_width + 1; - mpv->b8_stride = 2 * mpv->mb_width + 1; - mpv->f_code = 1; - mpv->pict_type = pic->pict_type; - mpv->motion_est = enc->motion_est; - mpv->me.scene_change_score = 0; + mpv->c.linesize = stride; + mpv->c.uvlinesize = s->current_picture->linesize[1]; + mpv->c.width = width; + mpv->c.height = height; + mpv->c.mb_width = block_width; + mpv->c.mb_height = block_height; + mpv->c.mb_stride = mpv->c.mb_width + 1; + mpv->c.b8_stride = 2 * mpv->c.mb_width + 1; + mpv->f_code = 1; + mpv->c.pict_type = pic->pict_type; + mpv->me.motion_est = enc->motion_est; mpv->me.dia_size = avctx->dia_size; - mpv->quarter_sample = (s->avctx->flags & AV_CODEC_FLAG_QPEL)!=0; - mpv->out_format = FMT_H263; - mpv->unrestricted_mv = 1; + mpv->c.quarter_sample = (s->avctx->flags & AV_CODEC_FLAG_QPEL)!=0; + mpv->c.out_format = FMT_H263; + mpv->me.unrestricted_mv = 1; - mpv->lambda = enc->lambda; - mpv->qscale = (mpv->lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7); + mpv->lambda = enc->lambda; + mpv->c.qscale = (mpv->lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7); enc->lambda2 = mpv->lambda2 = (mpv->lambda*mpv->lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT; - mpv->qdsp = enc->qdsp; //move - mpv->hdsp = s->hdsp; - ff_me_init_pic(&enc->m); - s->hdsp = mpv->hdsp; + mpv->c.qdsp = enc->qdsp; //move + mpv->c.hdsp = s->hdsp; + ff_me_init_pic(mpv); + s->hdsp = mpv->c.hdsp; } if (enc->pass1_rc) { @@ -1899,7 +1899,7 @@ redo_frame: return AVERROR(EINVAL); } - mpv->pict_type = pic->pict_type; + mpv->c.pict_type = pic->pict_type; s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0; ff_snow_common_init_after_header(avctx); @@ -2039,22 +2039,24 @@ redo_frame: update_last_header_values(s); - ff_snow_release_buffer(avctx); + av_frame_unref(s->last_picture[s->max_ref_frames - 1]); s->current_picture->pict_type = pic->pict_type; s->current_picture->quality = pic->quality; - mpv->frame_bits = 8 * (s->c.bytestream - s->c.bytestream_start); - mpv->p_tex_bits = mpv->frame_bits - mpv->misc_bits - mpv->mv_bits; - mpv->total_bits += 8*(s->c.bytestream - s->c.bytestream_start); + enc->m.frame_bits = 8 * (s->c.bytestream - s->c.bytestream_start); + mpv->p_tex_bits = enc->m.frame_bits - mpv->misc_bits - mpv->mv_bits; + enc->m.total_bits += 8*(s->c.bytestream - s->c.bytestream_start); enc->cur_pic.display_picture_number = enc->cur_pic.coded_picture_number = avctx->frame_num; enc->cur_pic.f->quality = pic->quality; - if (enc->pass1_rc) - if (ff_rate_estimate_qscale(mpv, 0) < 0) - return -1; + if (enc->pass1_rc) { + ret = ff_rate_estimate_qscale(&enc->m, 0); + if (ret < 0) + return ret; + } if(avctx->flags&AV_CODEC_FLAG_PASS1) - ff_write_pass1_stats(mpv); - mpv->last_pict_type = mpv->pict_type; + ff_write_pass1_stats(&enc->m); + enc->m.last_pict_type = mpv->c.pict_type; emms_c(); @@ -2088,10 +2090,8 @@ static av_cold int encode_end(AVCodecContext *avctx) av_freep(&s->ref_scores[i]); } - enc->m.me.temp = NULL; - av_freep(&enc->m.me.scratchpad); - av_freep(&enc->m.me.map); - av_freep(&enc->m.sc.obmc_scratchpad); + enc->m.s.me.temp = NULL; + av_freep(&enc->m.s.me.scratchpad); av_freep(&avctx->stats_out); @@ -2108,7 +2108,7 @@ static const AVOption options[] = { { "iter", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ITER }, 0, 0, VE, .unit = "motion_est" }, { "memc_only", "Only do ME/MC (I frames -> ref, P frame -> ME+MC).", OFFSET(memc_only), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "no_bitstream", "Skip final bitstream writeout.", OFFSET(no_bitstream), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "intra_penalty", "Penalty for intra blocks in block decission", OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "intra_penalty", "Penalty for intra blocks in block decision", OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "iterative_dia_size", "Dia size for the iterative ME", OFFSET(iterative_dia_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "sc_threshold", "Scene change threshold", OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, VE }, { "pred", "Spatial decomposition type", OFFSET(pred), AV_OPT_TYPE_INT, { .i64 = 0 }, DWT_97, DWT_53, VE, .unit = "pred" }, @@ -2118,7 +2118,7 @@ static const AVOption options[] = { "defined in the section 'Expression Evaluation', the following functions are available: " "bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " "fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", - OFFSET(m.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, + OFFSET(m.rc_context.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, { NULL }, }; @@ -2141,11 +2141,8 @@ const FFCodec ff_snow_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_GRAY8), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &snowenc_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/sonic.c b/libavcodec/sonic.c index 46c15b5fb1..08549aacfe 100644 --- a/libavcodec/sonic.c +++ b/libavcodec/sonic.c @@ -96,411 +96,6 @@ static inline int shift_down(int a,int b) return (a>>b)+(a<0); } -static av_always_inline av_flatten void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed, uint64_t rc_stat[256][2], uint64_t rc_stat2[32][2]){ - int i; - -#define put_rac(C,S,B) \ -do{\ - if(rc_stat){\ - rc_stat[*(S)][B]++;\ - rc_stat2[(S)-state][B]++;\ - }\ - put_rac(C,S,B);\ -}while(0) - - if(v){ - const int a= FFABS(v); - const int e= av_log2(a); - put_rac(c, state+0, 0); - if(e<=9){ - for(i=0; i=0; i--){ - put_rac(c, state+22+i, (a>>i)&1); //22..31 - } - - if(is_signed) - put_rac(c, state+11 + e, v < 0); //11..21 - }else{ - for(i=0; i=0; i--){ - put_rac(c, state+22+FFMIN(i,9), (a>>i)&1); //22..31 - } - - if(is_signed) - put_rac(c, state+11 + 10, v < 0); //11..21 - } - }else{ - put_rac(c, state+0, 1); - } -#undef put_rac -} - -static inline av_flatten int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){ - if(get_rac(c, state+0)) - return 0; - else{ - int i, e; - unsigned a; - e= 0; - while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10 - e++; - if (e > 31) - return AVERROR_INVALIDDATA; - } - - a= 1; - for(i=e-1; i>=0; i--){ - a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31 - } - - e= -(is_signed && get_rac(c, state+11 + FFMIN(e, 10))); //11..21 - return (a^e)-e; - } -} - -#if 1 -static inline int intlist_write(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - put_symbol(c, state, buf[i], 1, NULL, NULL); - - return 1; -} - -static inline int intlist_read(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - buf[i] = get_symbol(c, state, 1); - - return 1; -} -#elif 1 -static inline int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - set_se_golomb(pb, buf[i]); - - return 1; -} - -static inline int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part) -{ - int i; - - for (i = 0; i < entries; i++) - buf[i] = get_se_golomb(gb); - - return 1; -} - -#else - -#define ADAPT_LEVEL 8 - -static int bits_to_store(uint64_t x) -{ - int res = 0; - - while(x) - { - res++; - x >>= 1; - } - return res; -} - -static void write_uint_max(PutBitContext *pb, unsigned int value, unsigned int max) -{ - int i, bits; - - if (!max) - return; - - bits = bits_to_store(max); - - for (i = 0; i < bits-1; i++) - put_bits(pb, 1, value & (1 << i)); - - if ( (value | (1 << (bits-1))) <= max) - put_bits(pb, 1, value & (1 << (bits-1))); -} - -static unsigned int read_uint_max(GetBitContext *gb, int max) -{ - int i, bits, value = 0; - - if (!max) - return 0; - - bits = bits_to_store(max); - - for (i = 0; i < bits-1; i++) - if (get_bits1(gb)) - value += 1 << i; - - if ( (value | (1<<(bits-1))) <= max) - if (get_bits1(gb)) - value += 1 << (bits-1); - - return value; -} - -static int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part) -{ - int i, j, x = 0, low_bits = 0, max = 0; - int step = 256, pos = 0, dominant = 0, any = 0; - int *copy, *bits; - - copy = av_calloc(entries, sizeof(*copy)); - if (!copy) - return AVERROR(ENOMEM); - - if (base_2_part) - { - int energy = 0; - - for (i = 0; i < entries; i++) - energy += abs(buf[i]); - - low_bits = bits_to_store(energy / (entries * 2)); - if (low_bits > 15) - low_bits = 15; - - put_bits(pb, 4, low_bits); - } - - for (i = 0; i < entries; i++) - { - put_bits(pb, low_bits, abs(buf[i])); - copy[i] = abs(buf[i]) >> low_bits; - if (copy[i] > max) - max = abs(copy[i]); - } - - bits = av_calloc(entries*max, sizeof(*bits)); - if (!bits) - { - av_free(copy); - return AVERROR(ENOMEM); - } - - for (i = 0; i <= max; i++) - { - for (j = 0; j < entries; j++) - if (copy[j] >= i) - bits[x++] = copy[j] > i; - } - - // store bitstream - while (pos < x) - { - int steplet = step >> 8; - - if (pos + steplet > x) - steplet = x - pos; - - for (i = 0; i < steplet; i++) - if (bits[i+pos] != dominant) - any = 1; - - put_bits(pb, 1, any); - - if (!any) - { - pos += steplet; - step += step / ADAPT_LEVEL; - } - else - { - int interloper = 0; - - while (((pos + interloper) < x) && (bits[pos + interloper] == dominant)) - interloper++; - - // note change - write_uint_max(pb, interloper, (step >> 8) - 1); - - pos += interloper + 1; - step -= step / ADAPT_LEVEL; - } - - if (step < 256) - { - step = 65536 / step; - dominant = !dominant; - } - } - - // store signs - for (i = 0; i < entries; i++) - if (buf[i]) - put_bits(pb, 1, buf[i] < 0); - - av_free(bits); - av_free(copy); - - return 0; -} - -static int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part) -{ - int i, low_bits = 0, x = 0; - int n_zeros = 0, step = 256, dominant = 0; - int pos = 0, level = 0; - int *bits = av_calloc(entries, sizeof(*bits)); - - if (!bits) - return AVERROR(ENOMEM); - - if (base_2_part) - { - low_bits = get_bits(gb, 4); - - if (low_bits) - for (i = 0; i < entries; i++) - buf[i] = get_bits(gb, low_bits); - } - -// av_log(NULL, AV_LOG_INFO, "entries: %d, low bits: %d\n", entries, low_bits); - - while (n_zeros < entries) - { - int steplet = step >> 8; - - if (!get_bits1(gb)) - { - for (i = 0; i < steplet; i++) - bits[x++] = dominant; - - if (!dominant) - n_zeros += steplet; - - step += step / ADAPT_LEVEL; - } - else - { - int actual_run = read_uint_max(gb, steplet-1); - -// av_log(NULL, AV_LOG_INFO, "actual run: %d\n", actual_run); - - for (i = 0; i < actual_run; i++) - bits[x++] = dominant; - - bits[x++] = !dominant; - - if (!dominant) - n_zeros += actual_run; - else - n_zeros++; - - step -= step / ADAPT_LEVEL; - } - - if (step < 256) - { - step = 65536 / step; - dominant = !dominant; - } - } - - // reconstruct unsigned values - n_zeros = 0; - for (i = 0; n_zeros < entries; i++) - { - while(1) - { - if (pos >= entries) - { - pos = 0; - level += 1 << low_bits; - } - - if (buf[pos] >= level) - break; - - pos++; - } - - if (bits[i]) - buf[pos] += 1 << low_bits; - else - n_zeros++; - - pos++; - } - av_free(bits); - - // read signs - for (i = 0; i < entries; i++) - if (buf[i] && get_bits1(gb)) - buf[i] = -buf[i]; - -// av_log(NULL, AV_LOG_INFO, "zeros: %d pos: %d\n", n_zeros, pos); - - return 0; -} -#endif - -static void predictor_init_state(int *k, int *state, int order) -{ - int i; - - for (i = order-2; i >= 0; i--) - { - int j, p, x = state[i]; - - for (j = 0, p = i+1; p < order; j++,p++) - { - int tmp = x + shift_down(k[j] * (unsigned)state[p], LATTICE_SHIFT); - state[p] += shift_down(k[j]* (unsigned)x, LATTICE_SHIFT); - x = tmp; - } - } -} - -static int predictor_calc_error(int *k, int *state, int order, int error) -{ - int i, x = error - (unsigned)shift_down(k[order-1] * (unsigned)state[order-1], LATTICE_SHIFT); - -#if 1 - int *k_ptr = &(k[order-2]), - *state_ptr = &(state[order-2]); - for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--) - { - int k_value = *k_ptr, state_value = *state_ptr; - x -= (unsigned)shift_down(k_value * (unsigned)state_value, LATTICE_SHIFT); - state_ptr[1] = state_value + shift_down(k_value * (unsigned)x, LATTICE_SHIFT); - } -#else - for (i = order-2; i >= 0; i--) - { - x -= (unsigned)shift_down(k[i] * state[i], LATTICE_SHIFT); - state[i+1] = state[i] + shift_down(k[i] * x, LATTICE_SHIFT); - } -#endif - - // don't drift too far, to avoid overflows - if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16); - if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16); - - state[0] = x; - - return x; -} #if CONFIG_SONIC_ENCODER || CONFIG_SONIC_LS_ENCODER // Heavily modified Levinson-Durbin algorithm which @@ -519,7 +114,6 @@ static void modified_levinson_durbin(int *window, int window_entries, { int step = (i+1)*channels, k, j; double xx = 0.0, xy = 0.0; -#if 1 int *x_ptr = &(window[step]); int *state_ptr = &(state[0]); j = window_entries - step; @@ -530,17 +124,6 @@ static void modified_levinson_durbin(int *window, int window_entries, xx += state_value*state_value; xy += x_value*state_value; } -#else - for (j = 0; j <= (window_entries - step); j++); - { - double stepval = window[step+j]; - double stateval = window[j]; -// xx += (double)window[j]*(double)window[j]; -// xy += (double)window[step+j]*(double)window[j]; - xx += stateval*stateval; - xy += stepval*stateval; - } -#endif if (xx == 0.0) k = 0; else @@ -554,7 +137,6 @@ static void modified_levinson_durbin(int *window, int window_entries, out[i] = k; k *= tap_quant[i]; -#if 1 x_ptr = &(window[step]); state_ptr = &(state[0]); j = window_entries - step; @@ -565,15 +147,6 @@ static void modified_levinson_durbin(int *window, int window_entries, *x_ptr = x_value + shift_down(k*state_value,LATTICE_SHIFT); *state_ptr = state_value + shift_down(k*x_value, LATTICE_SHIFT); } -#else - for (j=0; j <= (window_entries - step); j++) - { - int stepval = window[step+j]; - int stateval=state[j]; - window[step+j] += shift_down(k * stateval, LATTICE_SHIFT); - state[j] += shift_down(k * stepval, LATTICE_SHIFT); - } -#endif } } @@ -718,6 +291,63 @@ static av_cold int sonic_encode_close(AVCodecContext *avctx) return 0; } +static av_always_inline av_flatten void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed, uint64_t rc_stat[256][2], uint64_t rc_stat2[32][2]){ + int i; + +#define put_rac(C,S,B) \ +do{\ + if(rc_stat){\ + rc_stat[*(S)][B]++;\ + rc_stat2[(S)-state][B]++;\ + }\ + put_rac(C,S,B);\ +}while(0) + + if(v){ + const int a= FFABS(v); + const int e= av_log2(a); + put_rac(c, state+0, 0); + if(e<=9){ + for(i=0; i=0; i--){ + put_rac(c, state+22+i, (a>>i)&1); //22..31 + } + + if(is_signed) + put_rac(c, state+11 + e, v < 0); //11..21 + }else{ + for(i=0; i=0; i--){ + put_rac(c, state+22+FFMIN(i,9), (a>>i)&1); //22..31 + } + + if(is_signed) + put_rac(c, state+11 + 10, v < 0); //11..21 + } + }else{ + put_rac(c, state+0, 1); + } +#undef put_rac +} + +static inline int intlist_write(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) +{ + int i; + + for (i = 0; i < entries; i++) + put_symbol(c, state, buf[i], 1, NULL, NULL); + + return 1; +} + static int sonic_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { @@ -924,6 +554,9 @@ static av_cold int sonic_decode_init(AVCodecContext *avctx) if (get_bits1(&gb)) // XXX FIXME av_log(avctx, AV_LOG_INFO, "Custom quant table\n"); + if (s->num_taps > 128) + return AVERROR_INVALIDDATA; + s->block_align = 2048LL*s->samplerate/(44100*s->downsampling); s->frame_size = s->channels*s->block_align*s->downsampling; // avctx->frame_size = s->block_align; @@ -981,6 +614,78 @@ static av_cold int sonic_decode_close(AVCodecContext *avctx) return 0; } +static inline av_flatten int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){ + if(get_rac(c, state+0)) + return 0; + else{ + int i, e; + unsigned a; + e= 0; + while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10 + e++; + if (e > 31) + return AVERROR_INVALIDDATA; + } + + a= 1; + for(i=e-1; i>=0; i--){ + a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31 + } + + e= -(is_signed && get_rac(c, state+11 + FFMIN(e, 10))); //11..21 + return (a^e)-e; + } +} + +static inline int intlist_read(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part) +{ + int i; + + for (i = 0; i < entries; i++) + buf[i] = get_symbol(c, state, 1); + + return 1; +} + +static void predictor_init_state(int *k, int *state, int order) +{ + int i; + + for (i = order-2; i >= 0; i--) + { + int j, p, x = state[i]; + + for (j = 0, p = i+1; p < order; j++,p++) + { + int tmp = x + shift_down(k[j] * (unsigned)state[p], LATTICE_SHIFT); + state[p] += shift_down(k[j]* (unsigned)x, LATTICE_SHIFT); + x = tmp; + } + } +} + +static int predictor_calc_error(int *k, int *state, int order, int error) +{ + int i, x = error - (unsigned)shift_down(k[order-1] * (unsigned)state[order-1], LATTICE_SHIFT); + + int *k_ptr = &(k[order-2]), + *state_ptr = &(state[order-2]); + for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--) + { + int k_value = *k_ptr, state_value = *state_ptr; + x -= (unsigned)shift_down(k_value * (unsigned)state_value, LATTICE_SHIFT); + state_ptr[1] = state_value + shift_down(k_value * (unsigned)x, LATTICE_SHIFT); + } + + // don't drift too far, to avoid overflows + if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16); + if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16); + + state[0] = x; + + return x; +} + static int sonic_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { @@ -1102,7 +807,7 @@ const FFCodec ff_sonic_encoder = { .priv_data_size = sizeof(SonicContext), .init = sonic_encode_init, FF_CODEC_ENCODE_CB(sonic_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .close = sonic_encode_close, }; @@ -1119,7 +824,7 @@ const FFCodec ff_sonic_ls_encoder = { .priv_data_size = sizeof(SonicContext), .init = sonic_encode_init, FF_CODEC_ENCODE_CB(sonic_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .close = sonic_encode_close, }; diff --git a/libavcodec/sparc/README b/libavcodec/sparc/README deleted file mode 100644 index f9f2349cd4..0000000000 --- a/libavcodec/sparc/README +++ /dev/null @@ -1,6 +0,0 @@ -SPARC optimizations have been removed in -commit b4dd424d96f09f9bafb88e47f37df65dc4529143 -The last revission with the optimizations is fb1b70c1ed50951c5fc1a309c3c446b2eaaf564b - -If you want to maintain these (or other) SPARC optimizations in ffmpeg, then please -contact ffmpeg-devel@ffmpeg.org diff --git a/libavcodec/speedhqenc.c b/libavcodec/speedhqenc.c index 81a5151b75..da7aba6ec9 100644 --- a/libavcodec/speedhqenc.c +++ b/libavcodec/speedhqenc.c @@ -27,15 +27,18 @@ * SpeedHQ encoder. */ +#include "libavutil/avassert.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" +#include "mathops.h" #include "mpeg12data.h" #include "mpeg12vlc.h" #include "mpegvideo.h" #include "mpegvideodata.h" #include "mpegvideoenc.h" +#include "put_bits.h" #include "rl.h" #include "speedhq.h" #include "speedhqenc.h" @@ -59,7 +62,7 @@ static uint32_t speedhq_chr_dc_uni[512]; static uint8_t uni_speedhq_ac_vlc_len[64 * 64 * 2]; typedef struct SpeedHQEncContext { - MpegEncContext m; + MPVMainEncContext m; int slice_start; } SpeedHQEncContext; @@ -95,64 +98,24 @@ static av_cold void speedhq_init_static_data(void) ff_speedhq_vlc_table, uni_speedhq_ac_vlc_len); } -av_cold int ff_speedhq_encode_init(MpegEncContext *s) +static int speedhq_encode_picture_header(MPVMainEncContext *const m) { - static AVOnce init_static_once = AV_ONCE_INIT; + SpeedHQEncContext *const ctx = (SpeedHQEncContext*)m; + MPVEncContext *const s = &m->s; - if (s->width > 65500 || s->height > 65500) { - av_log(s, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); - return AVERROR(EINVAL); - } + put_bits_assume_flushed(&s->pb); - // border is not implemented correctly at the moment, see ticket #10078 - if (s->width % 16) { - av_log(s, AV_LOG_ERROR, "width must be a multiple of 16\n"); - return AVERROR_PATCHWELCOME; - } - - s->min_qcoeff = -2048; - s->max_qcoeff = 2047; - - ff_thread_once(&init_static_once, speedhq_init_static_data); - - s->intra_ac_vlc_length = - s->intra_ac_vlc_last_length = - s->intra_chroma_ac_vlc_length = - s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; - - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg12_dc_scale_table[3]; - - switch (s->avctx->pix_fmt) { - case AV_PIX_FMT_YUV420P: - s->avctx->codec_tag = MKTAG('S','H','Q','0'); - break; - case AV_PIX_FMT_YUV422P: - s->avctx->codec_tag = MKTAG('S','H','Q','2'); - break; - case AV_PIX_FMT_YUV444P: - s->avctx->codec_tag = MKTAG('S','H','Q','4'); - break; - default: - av_assert0(0); - } - - return 0; -} - -void ff_speedhq_encode_picture_header(MpegEncContext *s) -{ - SpeedHQEncContext *ctx = (SpeedHQEncContext*)s; - - put_bits_le(&s->pb, 8, 100 - s->qscale * 2); /* FIXME why doubled */ + put_bits_le(&s->pb, 8, 100 - s->c.qscale * 2); /* FIXME why doubled */ put_bits_le(&s->pb, 24, 4); /* no second field */ ctx->slice_start = 4; /* length of first slice, will be filled out later */ put_bits_le(&s->pb, 24, 0); + + return 0; } -void ff_speedhq_end_slice(MpegEncContext *s) +void ff_speedhq_end_slice(MPVEncContext *const s) { SpeedHQEncContext *ctx = (SpeedHQEncContext*)s; int slice_len; @@ -200,7 +163,7 @@ static inline void encode_dc(PutBitContext *pb, int diff, int component) } } -static void encode_block(MpegEncContext *s, int16_t *block, int n) +static void encode_block(MPVEncContext *const s, const int16_t block[], int n) { int alevel, level, last_non_zero, dc, i, j, run, last_index, sign; int code; @@ -209,16 +172,16 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) /* DC coef */ component = (n <= 3 ? 0 : (n&1) + 1); dc = block[0]; /* overflow is impossible */ - val = s->last_dc[component] - dc; /* opposite of most codecs */ + val = s->c.last_dc[component] - dc; /* opposite of most codecs */ encode_dc(&s->pb, val, component); - s->last_dc[component] = dc; + s->c.last_dc[component] = dc; /* now quantify & encode AC coefs */ last_non_zero = 0; - last_index = s->block_last_index[n]; + last_index = s->c.block_last_index[n]; for (i = 1; i <= last_index; i++) { - j = s->intra_scantable.permutated[i]; + j = s->c.intra_scantable.permutated[i]; level = block[j]; /* encode using VLC */ @@ -236,11 +199,10 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) ff_speedhq_vlc_table[code][0] | (sign << ff_speedhq_vlc_table[code][1])); } else { /* escape seems to be pretty rare <5% so I do not optimize it; - * the values correspond to ff_speedhq_vlc_table[121] */ - put_bits_le(&s->pb, 6, 32); - /* escape: only clip in this case */ - put_bits_le(&s->pb, 6, run); - put_bits_le(&s->pb, 12, level + 2048); + * The following encodes the escape value 100000b together with + * run and level. */ + put_bits_le(&s->pb, 6 + 6 + 12, 0x20 | run << 6 | + (level + 2048) << 12); } last_non_zero = i; } @@ -249,13 +211,14 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n) put_bits_le(&s->pb, 4, 6); } -void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) +static void speedhq_encode_mb(MPVEncContext *const s, int16_t block[12][64], + int unused_x, int unused_y) { int i; for(i=0;i<6;i++) { encode_block(s, block[i], i); } - if (s->chroma_format == CHROMA_444) { + if (s->c.chroma_format == CHROMA_444) { encode_block(s, block[8], 8); encode_block(s, block[9], 9); @@ -264,7 +227,7 @@ void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) encode_block(s, block[10], 10); encode_block(s, block[11], 11); - } else if (s->chroma_format == CHROMA_422) { + } else if (s->c.chroma_format == CHROMA_422) { encode_block(s, block[6], 6); encode_block(s, block[7], 7); } @@ -272,20 +235,59 @@ void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) s->i_tex_bits += get_bits_diff(s); } -static int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) +static av_cold int speedhq_encode_init(AVCodecContext *avctx) { - return mb_height / 4 + (slice_num < (mb_height % 4)); -} + static AVOnce init_static_once = AV_ONCE_INIT; + MPVMainEncContext *const m = avctx->priv_data; + MPVEncContext *const s = &m->s; + int ret; -int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) -{ - int slice_num = 0; - while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { - mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); - slice_num++; + if (avctx->width > 65500 || avctx->height > 65500) { + av_log(avctx, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); + return AVERROR(EINVAL); } - *first_in_slice = (mb_y_order == 0); - return mb_y_order * 4 + slice_num; + + // border is not implemented correctly at the moment, see ticket #10078 + if (avctx->width % 16) { + av_log(avctx, AV_LOG_ERROR, "width must be a multiple of 16\n"); + return AVERROR_PATCHWELCOME; + } + + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + avctx->codec_tag = MKTAG('S','H','Q','0'); + break; + case AV_PIX_FMT_YUV422P: + avctx->codec_tag = MKTAG('S','H','Q','2'); + break; + case AV_PIX_FMT_YUV444P: + avctx->codec_tag = MKTAG('S','H','Q','4'); + break; + default: + av_unreachable("Already checked via CODEC_PIXFMTS"); + } + + m->encode_picture_header = speedhq_encode_picture_header; + s->encode_mb = speedhq_encode_mb; + + s->min_qcoeff = -2048; + s->max_qcoeff = 2047; + + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; + + s->c.y_dc_scale_table = + s->c.c_dc_scale_table = ff_mpeg12_dc_scale_table[3]; + + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; + + ff_thread_once(&init_static_once, speedhq_init_static_data); + + return 0; } const FFCodec ff_speedhq_encoder = { @@ -294,15 +296,12 @@ const FFCodec ff_speedhq_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_SPEEDHQ, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(SpeedHQEncContext), - .init = ff_mpv_encode_init, + .init = speedhq_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .color_ranges = AVCOL_RANGE_MPEG, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P), }; diff --git a/libavcodec/speedhqenc.h b/libavcodec/speedhqenc.h index 0c52e6a380..568f82c76e 100644 --- a/libavcodec/speedhqenc.h +++ b/libavcodec/speedhqenc.h @@ -29,17 +29,24 @@ #ifndef AVCODEC_SPEEDHQENC_H #define AVCODEC_SPEEDHQENC_H -#include +typedef struct MPVEncContext MPVEncContext; -#include "mpegvideo.h" +void ff_speedhq_end_slice(MPVEncContext *s); -int ff_speedhq_encode_init(MpegEncContext *s); -void ff_speedhq_encode_close(MpegEncContext *s); -void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]); +static inline int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) +{ + return mb_height / 4 + (slice_num < (mb_height % 4)); +} -void ff_speedhq_encode_picture_header(MpegEncContext *s); -void ff_speedhq_end_slice(MpegEncContext *s); - -int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice); +static inline int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) +{ + int slice_num = 0; + while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { + mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); + slice_num++; + } + *first_in_slice = (mb_y_order == 0); + return mb_y_order * 4 + slice_num; +} #endif /* AVCODEC_SPEEDHQENC_H */ diff --git a/libavcodec/speexdec.c b/libavcodec/speexdec.c index d25823ef6e..6caf0d96ad 100644 --- a/libavcodec/speexdec.c +++ b/libavcodec/speexdec.c @@ -54,6 +54,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/float_dsp.h" +#include "libavutil/intfloat.h" #include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -168,7 +169,7 @@ typedef struct SpeexSubmode { typedef struct SpeexMode { int modeID; /**< ID of the mode */ - int (*decode)(AVCodecContext *avctx, void *dec, GetBitContext *gb, float *out); + int (*decode)(AVCodecContext *avctx, void *dec, GetBitContext *gb, float *out, int packets_left); int frame_size; /**< Size of frames used for decoding */ int subframe_size; /**< Size of sub-frames used for decoding */ int lpc_size; /**< Order of LPC filter */ @@ -520,8 +521,8 @@ static const SpeexSubmode wb_submode4 = { split_cb_shape_sign_unquant, &split_cb_high, -1.f }; -static int nb_decode(AVCodecContext *, void *, GetBitContext *, float *); -static int sb_decode(AVCodecContext *, void *, GetBitContext *, float *); +static int nb_decode(AVCodecContext *, void *, GetBitContext *, float *, int packets_left); +static int sb_decode(AVCodecContext *, void *, GetBitContext *, float *, int packets_left); static const SpeexMode speex_modes[SPEEX_NB_MODES] = { { @@ -866,7 +867,7 @@ static void lsp_to_lpc(const float *freq, float *ak, int lpcrdr) } static int nb_decode(AVCodecContext *avctx, void *ptr_st, - GetBitContext *gb, float *out) + GetBitContext *gb, float *out, int packets_left) { DecoderState *st = ptr_st; float ol_gain = 0, ol_pitch_coef = 0, best_pitch_gain = 0, pitch_average = 0; @@ -1217,7 +1218,7 @@ static void qmf_synth(const float *x1, const float *x2, const float *a, float *y } static int sb_decode(AVCodecContext *avctx, void *ptr_st, - GetBitContext *gb, float *out) + GetBitContext *gb, float *out, int packets_left) { SpeexContext *s = avctx->priv_data; DecoderState *st = ptr_st; @@ -1233,9 +1234,11 @@ static int sb_decode(AVCodecContext *avctx, void *ptr_st, mode = st->mode; if (st->modeID > 0) { + if (packets_left * s->frame_size < 2*st->frame_size) + return AVERROR_INVALIDDATA; low_innov_alias = out + st->frame_size; s->st[st->modeID - 1].innov_save = low_innov_alias; - ret = speex_modes[st->modeID - 1].decode(avctx, &s->st[st->modeID - 1], gb, out); + ret = speex_modes[st->modeID - 1].decode(avctx, &s->st[st->modeID - 1], gb, out, packets_left); if (ret < 0) return ret; } @@ -1296,7 +1299,7 @@ static int sb_decode(AVCodecContext *avctx, void *ptr_st, lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpc_size, sub, st->nb_subframes, 0.05f); lsp_to_lpc(interp_qlsp, ak, st->lpc_size); - /* Calculate reponse ratio between the low and high filter in the middle + /* Calculate response ratio between the low and high filter in the middle of the band (4000 Hz) */ st->pi_gain[sub] = 1.f; rh = 1.f; @@ -1422,10 +1425,10 @@ static int parse_speex_extradata(AVCodecContext *avctx, return AVERROR_INVALIDDATA; s->bitrate = bytestream_get_le32(&buf); s->frame_size = bytestream_get_le32(&buf); - if (s->frame_size < NB_FRAME_SIZE << (s->mode > 0) || - s->frame_size > INT32_MAX >> (s->mode > 0)) + if (s->frame_size < NB_FRAME_SIZE << (s->mode > 1) || + s->frame_size > INT32_MAX >> (s->mode > 1)) return AVERROR_INVALIDDATA; - s->frame_size <<= (s->mode > 0); + s->frame_size = FFMIN(s->frame_size << (s->mode > 1), NB_FRAME_SIZE << s->mode); s->vbr = bytestream_get_le32(&buf); s->frames_per_packet = bytestream_get_le32(&buf); if (s->frames_per_packet <= 0 || @@ -1558,7 +1561,7 @@ static int speex_decode_frame(AVCodecContext *avctx, AVFrame *frame, dst = (float *)frame->extended_data[0]; for (int i = 0; i < frames_per_packet; i++) { - ret = speex_modes[s->mode].decode(avctx, &s->st[s->mode], &s->gb, dst + i * s->frame_size); + ret = speex_modes[s->mode].decode(avctx, &s->st[s->mode], &s->gb, dst + i * s->frame_size, frames_per_packet - i); if (ret < 0) return ret; if (avctx->ch_layout.nb_channels == 2) diff --git a/libavcodec/srtenc.c b/libavcodec/srtenc.c index a607beb990..de05a09254 100644 --- a/libavcodec/srtenc.c +++ b/libavcodec/srtenc.c @@ -145,7 +145,7 @@ static void srt_text_cb(void *priv, const char *text, int len) static void srt_new_line_cb(void *priv, int forced) { - srt_print(priv, "\r\n"); + srt_print(priv, "\n"); } static void srt_style_cb(void *priv, char style, int close) diff --git a/libavcodec/sunrast.c b/libavcodec/sunrast.c index 9e49c4f275..cc27838f5b 100644 --- a/libavcodec/sunrast.c +++ b/libavcodec/sunrast.c @@ -163,8 +163,10 @@ static int sunrast_decode_frame(AVCodecContext *avctx, AVFrame *p, x = 0; while (ptr != end && buf < buf_end) { run = 1; - if (buf_end - buf < 1) + if (buf_end - buf < 1) { + av_freep(&ptr2); return AVERROR_INVALIDDATA; + } if ((value = *buf++) == RLE_TRIGGER) { run = *buf++ + 1; diff --git a/libavcodec/sunrastenc.c b/libavcodec/sunrastenc.c index b2d57f7235..9922dbd061 100644 --- a/libavcodec/sunrastenc.c +++ b/libavcodec/sunrastenc.c @@ -218,9 +218,8 @@ const FFCodec ff_sunrast_encoder = { .init = sunrast_encode_init, FF_CODEC_ENCODE_CB(sunrast_encode_frame), .p.priv_class = &sunrast_class, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, + AV_PIX_FMT_PAL8, + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c index d969be25c1..ed3dca9025 100644 --- a/libavcodec/svq1enc.c +++ b/libavcodec/svq1enc.c @@ -58,11 +58,10 @@ typedef struct SVQ1EncContext { /* FIXME: Needed for motion estimation, should not be used for anything * else, the idea is to make the motion estimation eventually independent - * of MpegEncContext, so this will be removed then. */ - MpegEncContext m; + * of MPVEncContext, so this will be removed then. */ + MPVEncContext m; AVCodecContext *avctx; MECmpContext mecc; - HpelDSPContext hdsp; AVFrame *current_picture; AVFrame *last_picture; @@ -81,10 +80,6 @@ typedef struct SVQ1EncContext { int y_block_width; int y_block_height; - /* U & V plane (C planes) block dimensions */ - int c_block_width; - int c_block_height; - DECLARE_ALIGNED(16, int16_t, encoded_block_levels)[6][7][256]; uint16_t *mb_type; @@ -96,8 +91,6 @@ typedef struct SVQ1EncContext { uint8_t *scratchbuf; - int motion_est; - SVQ1EncDSPContext svq1encdsp; } SVQ1EncContext; @@ -291,13 +284,12 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref, return best_score; } -static void init_block_index(MpegEncContext *s){ +static void init_block_index(MpegEncContext *const s) +{ s->block_index[0]= s->b8_stride*(s->mb_y*2 ) + s->mb_x*2; s->block_index[1]= s->b8_stride*(s->mb_y*2 ) + 1 + s->mb_x*2; s->block_index[2]= s->b8_stride*(s->mb_y*2 + 1) + s->mb_x*2; s->block_index[3]= s->b8_stride*(s->mb_y*2 + 1) + 1 + s->mb_x*2; - s->block_index[4]= s->mb_stride*(s->mb_y + 1) + s->b8_stride*s->mb_height*2 + s->mb_x; - s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x; } static int svq1_encode_plane(SVQ1EncContext *s, int plane, @@ -307,6 +299,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, unsigned char *decoded_plane, int width, int height, int src_stride, int stride) { + MpegEncContext *const s2 = &s->m.c; int x, y; int i; int block_width, block_height; @@ -325,61 +318,48 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, block_height = (height + 15) / 16; if (s->pict_type == AV_PICTURE_TYPE_P) { - s->m.avctx = s->avctx; - s->m.last_pic.data[0] = ref_plane; - s->m.linesize = - s->m.last_pic.linesize[0] = + s2->last_pic.data[0] = ref_plane; + s2->linesize = + s2->last_pic.linesize[0] = s->m.new_pic->linesize[0] = - s->m.cur_pic.linesize[0] = stride; - s->m.width = width; - s->m.height = height; - s->m.mb_width = block_width; - s->m.mb_height = block_height; - s->m.mb_stride = s->m.mb_width + 1; - s->m.b8_stride = 2 * s->m.mb_width + 1; - s->m.f_code = 1; - s->m.pict_type = s->pict_type; - s->m.motion_est = s->motion_est; - s->m.me.scene_change_score = 0; - // s->m.out_format = FMT_H263; - // s->m.unrestricted_mv = 1; - s->m.lambda = s->quality; - s->m.qscale = s->m.lambda * 139 + + s2->cur_pic.linesize[0] = stride; + s2->width = width; + s2->height = height; + s2->mb_width = block_width; + s2->mb_height = block_height; + s2->mb_stride = s2->mb_width + 1; + s2->b8_stride = 2 * s2->mb_width + 1; + s->m.f_code = 1; + s2->pict_type = s->pict_type; + s->m.me.scene_change_score = 0; + // s2->out_format = FMT_H263; + // s->m.me.unrestricted_mv = 1; + s->m.lambda = s->quality; + s2->qscale = s->m.lambda * 139 + FF_LAMBDA_SCALE * 64 >> FF_LAMBDA_SHIFT + 7; - s->m.lambda2 = s->m.lambda * s->m.lambda + + s->m.lambda2 = s->m.lambda * s->m.lambda + FF_LAMBDA_SCALE / 2 >> FF_LAMBDA_SHIFT; - if (!s->motion_val8[plane]) { - s->motion_val8[plane] = av_mallocz((s->m.b8_stride * - block_height * 2 + 2) * - 2 * sizeof(int16_t)); - s->motion_val16[plane] = av_mallocz((s->m.mb_stride * - (block_height + 2) + 1) * - 2 * sizeof(int16_t)); - if (!s->motion_val8[plane] || !s->motion_val16[plane]) - return AVERROR(ENOMEM); - } - s->m.mb_type = s->mb_type; // dummies, to avoid segfaults s->m.mb_mean = (uint8_t *)s->dummy; s->m.mb_var = (uint16_t *)s->dummy; s->m.mc_mb_var = (uint16_t *)s->dummy; - s->m.cur_pic.mb_type = s->dummy; + s2->cur_pic.mb_type = s->dummy; - s->m.cur_pic.motion_val[0] = s->motion_val8[plane] + 2; - s->m.p_mv_table = s->motion_val16[plane] + - s->m.mb_stride + 1; + s2->cur_pic.motion_val[0] = s->motion_val8[plane] + 2; + s->m.p_mv_table = s->motion_val16[plane] + + s2->mb_stride + 1; ff_me_init_pic(&s->m); - s->m.me.dia_size = s->avctx->dia_size; - s->m.first_slice_line = 1; + s->m.me.dia_size = s->avctx->dia_size; + s2->first_slice_line = 1; for (y = 0; y < block_height; y++) { s->m.new_pic->data[0] = src - y * 16 * stride; // ugly - s->m.mb_y = y; + s2->mb_y = y; for (i = 0; i < 16 && i + 16 * y < height; i++) { memcpy(&src[i * stride], &src_plane[(i + 16 * y) * src_stride], @@ -392,12 +372,12 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, 16 * block_width); for (x = 0; x < block_width; x++) { - s->m.mb_x = x; - init_block_index(&s->m); + s2->mb_x = x; + init_block_index(s2); ff_estimate_p_frame_motion(&s->m, x, y); } - s->m.first_slice_line = 0; + s2->first_slice_line = 0; } ff_fix_long_p_mvs(&s->m, CANDIDATE_MB_TYPE_INTRA); @@ -405,7 +385,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, CANDIDATE_MB_TYPE_INTER, 0); } - s->m.first_slice_line = 1; + s2->first_slice_line = 1; for (y = 0; y < block_height; y++) { for (i = 0; i < 16 && i + 16 * y < height; i++) { memcpy(&src[i * stride], &src_plane[(i + 16 * y) * src_stride], @@ -416,7 +396,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, for (; i < 16 && i + 16 * y < 16 * block_height; i++) memcpy(&src[i * stride], &src[(i - 1) * stride], 16 * block_width); - s->m.mb_y = y; + s2->mb_y = y; for (x = 0; x < block_width; x++) { uint8_t reorder_buffer[2][6][7 * 32]; int count[2][6]; @@ -431,11 +411,11 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, return -1; } - s->m.mb_x = x; - init_block_index(&s->m); + s2->mb_x = x; + init_block_index(s2); if (s->pict_type == AV_PICTURE_TYPE_I || - (s->m.mb_type[x + y * s->m.mb_stride] & + (s->m.mb_type[x + y * s2->mb_stride] & CANDIDATE_MB_TYPE_INTRA)) { for (i = 0; i < 6; i++) init_put_bits(&s->reorder_pb[i], reorder_buffer[0][i], @@ -444,8 +424,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, put_bits(&s->reorder_pb[5], SVQ1_BLOCK_INTRA_LEN, SVQ1_BLOCK_INTRA_CODE); score[0] = SVQ1_BLOCK_INTRA_LEN * lambda; } - score[0] += encode_block(s, src + 16 * x, NULL, temp, stride, - 5, 64, lambda, 1); + score[0] += encode_block(s, src + 16 * x, src + 16 * x /* unused */, + temp, stride, 5, 64, lambda, 1); for (i = 0; i < 6; i++) { count[0][i] = put_bits_count(&s->reorder_pb[i]); flush_put_bits(&s->reorder_pb[i]); @@ -459,8 +439,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, int mx, my, pred_x, pred_y, dxy; int16_t *motion_ptr; - motion_ptr = ff_h263_pred_motion(&s->m, 0, 0, &pred_x, &pred_y); - if (s->m.mb_type[x + y * s->m.mb_stride] & + motion_ptr = ff_h263_pred_motion(s2, 0, 0, &pred_x, &pred_y); + if (s->m.mb_type[x + y * s2->mb_stride] & CANDIDATE_MB_TYPE_INTER) { for (i = 0; i < 6; i++) init_put_bits(&s->reorder_pb[i], reorder_buffer[1][i], @@ -480,10 +460,10 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, dxy = (mx & 1) + 2 * (my & 1); - s->hdsp.put_pixels_tab[0][dxy](temp + 16*stride, - ref + (mx >> 1) + - stride * (my >> 1), - stride, 16); + s2->hdsp.put_pixels_tab[0][dxy](temp + 16*stride, + ref + (mx >> 1) + + stride * (my >> 1), + stride, 16); score[1] += encode_block(s, src + 16 * x, temp + 16*stride, decoded, stride, 5, 64, lambda, 0); @@ -494,7 +474,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, score[2] += SVQ1_BLOCK_SKIP_LEN * lambda; if (score[2] < score[best] && mx == 0 && my == 0) { best = 2; - s->hdsp.put_pixels_tab[0][0](decoded, ref, stride, 16); + s2->hdsp.put_pixels_tab[0][0](decoded, ref, stride, 16); put_bits(pb, SVQ1_BLOCK_SKIP_LEN, SVQ1_BLOCK_SKIP_CODE); } } @@ -509,10 +489,10 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, motion_ptr[1] = motion_ptr[2] = motion_ptr[3] = - motion_ptr[0 + 2 * s->m.b8_stride] = - motion_ptr[1 + 2 * s->m.b8_stride] = - motion_ptr[2 + 2 * s->m.b8_stride] = - motion_ptr[3 + 2 * s->m.b8_stride] = 0; + motion_ptr[0 + 2 * s2->b8_stride] = + motion_ptr[1 + 2 * s2->b8_stride] = + motion_ptr[2 + 2 * s2->b8_stride] = + motion_ptr[3 + 2 * s2->b8_stride] = 0; } } @@ -523,9 +503,9 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, ff_copy_bits(pb, reorder_buffer[best][i], count[best][i]); if (best == 0) - s->hdsp.put_pixels_tab[0][0](decoded, temp, stride, 16); + s2->hdsp.put_pixels_tab[0][0](decoded, temp, stride, 16); } - s->m.first_slice_line = 0; + s2->first_slice_line = 0; } return 0; } @@ -541,14 +521,10 @@ static av_cold int svq1_encode_end(AVCodecContext *avctx) avctx->frame_num)); av_freep(&s->m.me.scratchpad); - av_freep(&s->m.me.map); av_freep(&s->mb_type); av_freep(&s->dummy); av_freep(&s->scratchbuf); - s->m.mb_type = NULL; - ff_mpv_common_end(&s->m); - for (i = 0; i < 3; i++) { av_freep(&s->motion_val8[i]); av_freep(&s->motion_val16[i]); @@ -584,7 +560,7 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ff_hpeldsp_init(&s->hdsp, avctx->flags); + ff_hpeldsp_init(&s->m.c.hdsp, avctx->flags); ff_me_cmp_init(&s->mecc, avctx); ret = ff_me_init(&s->m.me, avctx, &s->mecc, 0); if (ret < 0) @@ -596,6 +572,15 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) if (!s->current_picture || !s->last_picture) { return AVERROR(ENOMEM); } + ret = ff_encode_alloc_frame(avctx, s->current_picture); + if (ret < 0) + return ret; + ret = ff_encode_alloc_frame(avctx, s->last_picture); + if (ret < 0) + return ret; + s->scratchbuf = av_malloc_array(s->current_picture->linesize[0], 16 * 3); + if (!s->scratchbuf) + return AVERROR(ENOMEM); s->frame_width = avctx->width; s->frame_height = avctx->height; @@ -603,17 +588,23 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) s->y_block_width = (s->frame_width + 15) / 16; s->y_block_height = (s->frame_height + 15) / 16; - s->c_block_width = (s->frame_width / 4 + 15) / 16; - s->c_block_height = (s->frame_height / 4 + 15) / 16; - s->avctx = avctx; - s->m.avctx = avctx; + s->m.c.avctx = avctx; - if ((ret = ff_mpv_common_init(&s->m)) < 0) { - return ret; + for (size_t plane = 0; plane < FF_ARRAY_ELEMS(s->motion_val16); ++plane) { + const int shift = plane ? 2 : 0; + unsigned block_height = ((s->frame_height >> shift) + 15U) / 16; + unsigned block_width = ((s->frame_width >> shift) + 15U) / 16; + + s->motion_val8[plane] = av_calloc((2 * block_width + 1) * block_height * 2 + 2, + 2 * sizeof(int16_t)); + s->motion_val16[plane] = av_calloc((block_width + 1) * (block_height + 2) + 1, + 2 * sizeof(int16_t)); + if (!s->motion_val8[plane] || !s->motion_val16[plane]) + return AVERROR(ENOMEM); } - s->m.picture_structure = PICT_FRAME; + s->m.c.picture_structure = PICT_FRAME; s->m.me.temp = s->m.me.scratchpad = av_mallocz((avctx->width + 64) * 2 * 16 * 2 * sizeof(uint8_t)); @@ -621,17 +612,15 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) s->y_block_height * sizeof(int16_t)); s->dummy = av_mallocz((s->y_block_width + 1) * s->y_block_height * sizeof(int32_t)); - s->m.me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*s->m.me.map)); s->m.new_pic = av_frame_alloc(); - if (!s->m.me.scratchpad || !s->m.me.map || + if (!s->m.me.scratchpad || !s->mb_type || !s->dummy || !s->m.new_pic) return AVERROR(ENOMEM); - s->m.me.score_map = s->m.me.map + ME_MAP_SIZE; ff_svq1enc_init(&s->svq1encdsp); - ff_h263_encode_init(&s->m); // mv_penalty + s->m.me.mv_penalty = ff_h263_get_mv_penalty(); return write_ident(avctx, s->avctx->flags & AV_CODEC_FLAG_BITEXACT ? "Lavc" : LIBAVCODEC_IDENT); } @@ -648,27 +637,6 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (ret < 0) return ret; - if (avctx->pix_fmt != AV_PIX_FMT_YUV410P) { - av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n"); - return -1; - } - - if (!s->current_picture->data[0]) { - if ((ret = ff_encode_alloc_frame(avctx, s->current_picture)) < 0) { - return ret; - } - } - if (!s->last_picture->data[0]) { - ret = ff_encode_alloc_frame(avctx, s->last_picture); - if (ret < 0) - return ret; - } - if (!s->scratchbuf) { - s->scratchbuf = av_malloc_array(s->current_picture->linesize[0], 16 * 3); - if (!s->scratchbuf) - return AVERROR(ENOMEM); - } - FFSWAP(AVFrame*, s->current_picture, s->last_picture); if (avctx->gop_size && (avctx->frame_num % avctx->gop_size)) @@ -691,15 +659,8 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pict->linesize[i], s->current_picture->linesize[i]); emms_c(); - if (ret < 0) { - int j; - for (j = 0; j < i; j++) { - av_freep(&s->motion_val8[j]); - av_freep(&s->motion_val16[j]); - } - av_freep(&s->scratchbuf); - return -1; - } + if (ret < 0) + return ret; } // align_put_bits(&pb); @@ -719,7 +680,7 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(struct SVQ1EncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "motion-est", "Motion estimation algorithm", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, VE, .unit = "motion-est"}, + { "motion-est", "Motion estimation algorithm", OFFSET(m.me.motion_est), AV_OPT_TYPE_INT, { .i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, VE, .unit = "motion-est"}, { "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, { "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, { "xone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_XONE }, 0, 0, FF_MPV_OPT_FLAGS, .unit = "motion-est" }, @@ -745,8 +706,7 @@ const FFCodec ff_svq1_encoder = { .init = svq1_encode_init, FF_CODEC_ENCODE_CB(svq1_encode_frame), .close = svq1_encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV410P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV410P), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index f730358e2f..4c4f3018c5 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -71,13 +71,14 @@ * svq3 decoder. */ +#define NUM_PICS 3 + typedef struct SVQ3Frame { AVFrame *f; - int16_t (*motion_val_buf[2])[2]; int16_t (*motion_val[2])[2]; - uint32_t *mb_type_buf, *mb_type; + uint32_t *mb_type; } SVQ3Frame; typedef struct SVQ3Context { @@ -103,7 +104,6 @@ typedef struct SVQ3Context { int adaptive_quant; int h_edge_pos; int v_edge_pos; - int last_frame_output; int slice_num; int qscale; int cbp; @@ -142,7 +142,10 @@ typedef struct SVQ3Context { DECLARE_ALIGNED(8, uint8_t, non_zero_count_cache)[15 * 8]; uint32_t dequant4_coeff[QP_MAX_NUM + 1][16]; int block_offset[2 * (16 * 3)]; - SVQ3Frame frames[3]; + SVQ3Frame frames[NUM_PICS]; + + uint32_t *mb_type_buf; + int16_t (*motion_val_buf)[2]; } SVQ3Context; #define FULLPEL_MODE 1 @@ -1114,14 +1117,139 @@ static void init_dequant4_coeff_table(SVQ3Context *s) } } +static av_cold int svq3_decode_extradata(AVCodecContext *avctx, SVQ3Context *s, + int seqh_offset) +{ + const uint8_t *extradata = avctx->extradata + seqh_offset; + unsigned int size = AV_RB32(extradata + 4); + GetBitContext gb; + int ret; + + if (size > avctx->extradata_size - seqh_offset - 8) + return AVERROR_INVALIDDATA; + extradata += 8; + init_get_bits(&gb, extradata, size * 8); + + /* 'frame size code' and optional 'width, height' */ + int frame_size_code = get_bits(&gb, 3); + int w, h; + switch (frame_size_code) { + case 0: + w = 160; + h = 120; + break; + case 1: + w = 128; + h = 96; + break; + case 2: + w = 176; + h = 144; + break; + case 3: + w = 352; + h = 288; + break; + case 4: + w = 704; + h = 576; + break; + case 5: + w = 240; + h = 180; + break; + case 6: + w = 320; + h = 240; + break; + case 7: + w = get_bits(&gb, 12); + h = get_bits(&gb, 12); + break; + } + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + return ret; + + s->halfpel_flag = get_bits1(&gb); + s->thirdpel_flag = get_bits1(&gb); + + /* unknown fields */ + int unk0 = get_bits1(&gb); + int unk1 = get_bits1(&gb); + int unk2 = get_bits1(&gb); + int unk3 = get_bits1(&gb); + + s->low_delay = get_bits1(&gb); + avctx->has_b_frames = !s->low_delay; + + /* unknown field */ + int unk4 = get_bits1(&gb); + + av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n", + unk0, unk1, unk2, unk3, unk4); + + if (skip_1stop_8data_bits(&gb) < 0) + return AVERROR_INVALIDDATA; + + s->has_watermark = get_bits1(&gb); + + if (!s->has_watermark) + return 0; + +#if CONFIG_ZLIB + unsigned watermark_width = get_interleaved_ue_golomb(&gb); + unsigned watermark_height = get_interleaved_ue_golomb(&gb); + int u1 = get_interleaved_ue_golomb(&gb); + int u2 = get_bits(&gb, 8); + int u3 = get_bits(&gb, 2); + int u4 = get_interleaved_ue_golomb(&gb); + unsigned long buf_len = watermark_width * + watermark_height * 4; + int offset = get_bits_count(&gb) + 7 >> 3; + + if (watermark_height <= 0 || + get_bits_left(&gb) <= 0 || + (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height) + return AVERROR_INVALIDDATA; + + av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n", + watermark_width, watermark_height); + av_log(avctx, AV_LOG_DEBUG, + "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n", + u1, u2, u3, u4, offset); + + uint8_t *buf = av_malloc(buf_len); + if (!buf) + return AVERROR(ENOMEM); + + if (uncompress(buf, &buf_len, extradata + offset, + size - offset) != Z_OK) { + av_log(avctx, AV_LOG_ERROR, + "could not uncompress watermark logo\n"); + av_free(buf); + return AVERROR_EXTERNAL; + } + s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len)); + + s->watermark_key = s->watermark_key << 16 | s->watermark_key; + av_log(avctx, AV_LOG_DEBUG, + "watermark key %#"PRIx32"\n", s->watermark_key); + av_free(buf); + + return 0; +#else + av_log(avctx, AV_LOG_ERROR, + "this svq3 file contains watermark which need zlib support compiled in\n"); + return AVERROR(ENOSYS); +#endif +} + static av_cold int svq3_decode_init(AVCodecContext *avctx) { SVQ3Context *s = avctx->priv_data; int m, x, y; unsigned char *extradata; - unsigned char *extradata_end; - unsigned int size; - int marker_found = 0; int ret; s->cur_pic = &s->frames[0]; @@ -1154,138 +1282,19 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) /* prowl for the "SEQH" marker in the extradata */ extradata = (unsigned char *)avctx->extradata; - extradata_end = avctx->extradata + avctx->extradata_size; if (extradata) { for (m = 0; m + 8 < avctx->extradata_size; m++) { if (!memcmp(extradata, "SEQH", 4)) { - marker_found = 1; + /* if a match was found, parse the extra data */ + ret = svq3_decode_extradata(avctx, s, m); + if (ret < 0) + return ret; break; } extradata++; } } - /* if a match was found, parse the extra data */ - if (marker_found) { - GetBitContext gb; - int frame_size_code; - int unk0, unk1, unk2, unk3, unk4; - int w,h; - - size = AV_RB32(&extradata[4]); - if (size > extradata_end - extradata - 8) - return AVERROR_INVALIDDATA; - init_get_bits(&gb, extradata + 8, size * 8); - - /* 'frame size code' and optional 'width, height' */ - frame_size_code = get_bits(&gb, 3); - switch (frame_size_code) { - case 0: - w = 160; - h = 120; - break; - case 1: - w = 128; - h = 96; - break; - case 2: - w = 176; - h = 144; - break; - case 3: - w = 352; - h = 288; - break; - case 4: - w = 704; - h = 576; - break; - case 5: - w = 240; - h = 180; - break; - case 6: - w = 320; - h = 240; - break; - case 7: - w = get_bits(&gb, 12); - h = get_bits(&gb, 12); - break; - } - ret = ff_set_dimensions(avctx, w, h); - if (ret < 0) - return ret; - - s->halfpel_flag = get_bits1(&gb); - s->thirdpel_flag = get_bits1(&gb); - - /* unknown fields */ - unk0 = get_bits1(&gb); - unk1 = get_bits1(&gb); - unk2 = get_bits1(&gb); - unk3 = get_bits1(&gb); - - s->low_delay = get_bits1(&gb); - - /* unknown field */ - unk4 = get_bits1(&gb); - - av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n", - unk0, unk1, unk2, unk3, unk4); - - if (skip_1stop_8data_bits(&gb) < 0) - return AVERROR_INVALIDDATA; - - s->has_watermark = get_bits1(&gb); - avctx->has_b_frames = !s->low_delay; - if (s->has_watermark) { -#if CONFIG_ZLIB - unsigned watermark_width = get_interleaved_ue_golomb(&gb); - unsigned watermark_height = get_interleaved_ue_golomb(&gb); - int u1 = get_interleaved_ue_golomb(&gb); - int u2 = get_bits(&gb, 8); - int u3 = get_bits(&gb, 2); - int u4 = get_interleaved_ue_golomb(&gb); - unsigned long buf_len = watermark_width * - watermark_height * 4; - int offset = get_bits_count(&gb) + 7 >> 3; - uint8_t *buf; - - if (watermark_height <= 0 || - (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height) - return AVERROR_INVALIDDATA; - - buf = av_malloc(buf_len); - if (!buf) - return AVERROR(ENOMEM); - - av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n", - watermark_width, watermark_height); - av_log(avctx, AV_LOG_DEBUG, - "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n", - u1, u2, u3, u4, offset); - if (uncompress(buf, &buf_len, extradata + 8 + offset, - size - offset) != Z_OK) { - av_log(avctx, AV_LOG_ERROR, - "could not uncompress watermark logo\n"); - av_free(buf); - return -1; - } - s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len)); - - s->watermark_key = s->watermark_key << 16 | s->watermark_key; - av_log(avctx, AV_LOG_DEBUG, - "watermark key %#"PRIx32"\n", s->watermark_key); - av_free(buf); -#else - av_log(avctx, AV_LOG_ERROR, - "this svq3 file contains watermark which need zlib support compiled in\n"); - return AVERROR(ENOSYS); -#endif - } - } - s->mb_width = (avctx->width + 15) / 16; s->mb_height = (avctx->height + 15) / 16; s->mb_stride = s->mb_width + 1; @@ -1294,6 +1303,34 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) s->h_edge_pos = s->mb_width * 16; s->v_edge_pos = s->mb_height * 16; + const unsigned big_mb_num = s->mb_stride * (s->mb_height + 2) + 1; + + s->mb_type_buf = av_calloc(big_mb_num, NUM_PICS * sizeof(*s->mb_type_buf)); + if (!s->mb_type_buf) + return AVERROR(ENOMEM); + uint32_t *mb_type_buf = s->mb_type_buf + 2 * s->mb_stride + 1; + + const unsigned b4_stride = s->mb_width * 4 + 1; + const unsigned b4_array_size = b4_stride * s->mb_height * 4; + const unsigned motion_val_buf_size = b4_array_size + 4; + + s->motion_val_buf = av_calloc(motion_val_buf_size, + NUM_PICS * 2 * sizeof(*s->motion_val_buf)); + if (!s->motion_val_buf) + return AVERROR(ENOMEM); + int16_t (*motion_val_buf)[2] = s->motion_val_buf + 4; + + for (size_t i = 0; i < NUM_PICS; ++i) { + SVQ3Frame *const pic = &s->frames[i]; + + pic->mb_type = mb_type_buf; + mb_type_buf += big_mb_num; + for (size_t j = 0; j < FF_ARRAY_ELEMS(pic->motion_val); ++j) { + pic->motion_val[j] = motion_val_buf; + motion_val_buf += motion_val_buf_size; + } + } + s->intra4x4_pred_mode = av_mallocz(s->mb_stride * 2 * 8); if (!s->intra4x4_pred_mode) return AVERROR(ENOMEM); @@ -1315,49 +1352,14 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) return 0; } -static void free_picture(SVQ3Frame *pic) -{ - int i; - for (i = 0; i < 2; i++) { - av_freep(&pic->motion_val_buf[i]); - } - av_freep(&pic->mb_type_buf); - - av_frame_unref(pic->f); -} - static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic) { SVQ3Context *s = avctx->priv_data; - const int big_mb_num = s->mb_stride * (s->mb_height + 1) + 1; - const int b4_stride = s->mb_width * 4 + 1; - const int b4_array_size = b4_stride * s->mb_height * 4; - int ret; - - if (!pic->motion_val_buf[0]) { - int i; - - pic->mb_type_buf = av_calloc(big_mb_num + s->mb_stride, sizeof(uint32_t)); - if (!pic->mb_type_buf) - return AVERROR(ENOMEM); - pic->mb_type = pic->mb_type_buf + 2 * s->mb_stride + 1; - - for (i = 0; i < 2; i++) { - pic->motion_val_buf[i] = av_calloc(b4_array_size + 4, 2 * sizeof(int16_t)); - if (!pic->motion_val_buf[i]) { - ret = AVERROR(ENOMEM); - goto fail; - } - - pic->motion_val[i] = pic->motion_val_buf[i] + 4; - } - } - - ret = ff_get_buffer(avctx, pic->f, - (s->pict_type != AV_PICTURE_TYPE_B) ? - AV_GET_BUFFER_FLAG_REF : 0); + int ret = ff_get_buffer(avctx, pic->f, + (s->pict_type != AV_PICTURE_TYPE_B) ? + AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) - goto fail; + return ret; if (!s->edge_emu_buffer) { s->edge_emu_buffer = av_calloc(pic->f->linesize[0], 17); @@ -1366,9 +1368,23 @@ static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic) } return 0; -fail: - free_picture(pic); - return ret; +} + +static av_cold int alloc_dummy_frame(AVCodecContext *avctx, SVQ3Frame *pic) +{ + av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); + av_frame_unref(pic->f); + int ret = get_buffer(avctx, pic); + if (ret < 0) + return ret; + + memset(pic->f->data[0], 0, avctx->height * pic->f->linesize[0]); + memset(pic->f->data[1], 0x80, (avctx->height / 2) * + pic->f->linesize[1]); + memset(pic->f->data[2], 0x80, (avctx->height / 2) * + pic->f->linesize[2]); + + return 0; } static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, @@ -1381,11 +1397,8 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* special case for last picture */ if (buf_size == 0) { - if (s->next_pic->f->data[0] && !s->low_delay && !s->last_frame_output) { - ret = av_frame_ref(rframe, s->next_pic->f); - if (ret < 0) - return ret; - s->last_frame_output = 1; + if (s->next_pic->f->data[0] && !s->low_delay) { + av_frame_move_ref(rframe, s->next_pic->f); *got_frame = 1; } return 0; @@ -1397,8 +1410,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (ret < 0) return ret; - if (svq3_decode_slice_header(avctx)) - return -1; + ret = svq3_decode_slice_header(avctx); + if (ret < 0) + return ret; if (avpkt->size < s->mb_width * s->mb_height / 8) return AVERROR_INVALIDDATA; @@ -1434,29 +1448,15 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (s->pict_type != AV_PICTURE_TYPE_I) { if (!s->last_pic->f->data[0]) { - av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); - av_frame_unref(s->last_pic->f); - ret = get_buffer(avctx, s->last_pic); + ret = alloc_dummy_frame(avctx, s->last_pic); if (ret < 0) return ret; - memset(s->last_pic->f->data[0], 0, avctx->height * s->last_pic->f->linesize[0]); - memset(s->last_pic->f->data[1], 0x80, (avctx->height / 2) * - s->last_pic->f->linesize[1]); - memset(s->last_pic->f->data[2], 0x80, (avctx->height / 2) * - s->last_pic->f->linesize[2]); } if (s->pict_type == AV_PICTURE_TYPE_B && !s->next_pic->f->data[0]) { - av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); - av_frame_unref(s->next_pic->f); - ret = get_buffer(avctx, s->next_pic); + ret = alloc_dummy_frame(avctx, s->next_pic); if (ret < 0) return ret; - memset(s->next_pic->f->data[0], 0, avctx->height * s->next_pic->f->linesize[0]); - memset(s->next_pic->f->data[1], 0x80, (avctx->height / 2) * - s->next_pic->f->linesize[1]); - memset(s->next_pic->f->data[2], 0x80, (avctx->height / 2) * - s->next_pic->f->linesize[2]); } } @@ -1511,8 +1511,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (((get_bits_count(&s->gb_slice) & 7) == 0 || show_bits(&s->gb_slice, get_bits_left(&s->gb_slice) & 7) == 0)) { - if (svq3_decode_slice_header(avctx)) - return -1; + ret = svq3_decode_slice_header(avctx); + if (ret < 0) + return ret; } if (s->slice_type != s->pict_type) { avpriv_request_sample(avctx, "non constant slice type"); @@ -1582,10 +1583,10 @@ static av_cold int svq3_decode_end(AVCodecContext *avctx) { SVQ3Context *s = avctx->priv_data; - for (int i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) { - free_picture(&s->frames[i]); + for (int i = 0; i < NUM_PICS; i++) av_frame_free(&s->frames[i].f); - } + av_freep(&s->motion_val_buf); + av_freep(&s->mb_type_buf); av_freep(&s->slice_buf); av_freep(&s->intra4x4_pred_mode); av_freep(&s->edge_emu_buffer); diff --git a/libavcodec/tableprint_vlc.h b/libavcodec/tableprint_vlc.h index b97c1f9cfb..ab33e90090 100644 --- a/libavcodec/tableprint_vlc.h +++ b/libavcodec/tableprint_vlc.h @@ -26,6 +26,7 @@ #define AVUTIL_LOG_H #define av_log(a, ...) while(0) #define ff_dlog(a, ...) while(0) +#define ff_tlog(a, ...) while(0) #define AVUTIL_MEM_H #define av_malloc(s) NULL #define av_malloc_array(a, b) NULL diff --git a/libavcodec/takdec.c b/libavcodec/takdec.c index cfa69f4217..1e6e6caebd 100644 --- a/libavcodec/takdec.c +++ b/libavcodec/takdec.c @@ -434,6 +434,9 @@ static int decode_subframe(TAKDecContext *s, int32_t *decoded, return AVERROR_INVALIDDATA; } + if (get_bits_left(gb) < 2*10 + 2*size) + return AVERROR_INVALIDDATA; + s->predictors[0] = get_sbits(gb, 10); s->predictors[1] = get_sbits(gb, 10); s->predictors[2] = get_sbits(gb, size) * (1 << (10 - size)); @@ -950,8 +953,5 @@ const FFCodec ff_tak_decoder = { FF_CODEC_DECODE_CB(tak_decode_frame), UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), }; diff --git a/libavcodec/targa.c b/libavcodec/targa.c index 59fdc428d9..7e016ea4af 100644 --- a/libavcodec/targa.c +++ b/libavcodec/targa.c @@ -249,11 +249,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, } break; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - p->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } } diff --git a/libavcodec/targaenc.c b/libavcodec/targaenc.c index 8f496c62bd..04422013e5 100644 --- a/libavcodec/targaenc.c +++ b/libavcodec/targaenc.c @@ -215,8 +215,6 @@ const FFCodec ff_targa_encoder = { .p.priv_class = &targa_class, .init = targa_encode_init, FF_CODEC_ENCODE_CB(targa_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8), }; diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c index ab0a70859b..225ddf3701 100644 --- a/libavcodec/tdsc.c +++ b/libavcodec/tdsc.c @@ -36,6 +36,7 @@ #include #include +#include "libavutil/attributes_internal.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" @@ -95,7 +96,6 @@ static av_cold int tdsc_close(AVCodecContext *avctx) static av_cold int tdsc_init(AVCodecContext *avctx) { TDSCContext *ctx = avctx->priv_data; - const AVCodec *codec; int ret; avctx->pix_fmt = AV_PIX_FMT_BGR24; @@ -120,16 +120,14 @@ static av_cold int tdsc_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* Prepare everything needed for JPEG decoding */ - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - ctx->jpeg_avctx = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + ctx->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!ctx->jpeg_avctx) return AVERROR(ENOMEM); ctx->jpeg_avctx->flags = avctx->flags; ctx->jpeg_avctx->flags2 = avctx->flags2; ctx->jpeg_avctx->idct_algo = avctx->idct_algo; - ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL); + ret = avcodec_open2(ctx->jpeg_avctx, NULL, NULL); if (ret < 0) return ret; diff --git a/libavcodec/tests/.gitignore b/libavcodec/tests/.gitignore index 0df4ae10a0..6bd9b31b56 100644 --- a/libavcodec/tests/.gitignore +++ b/libavcodec/tests/.gitignore @@ -1,3 +1,4 @@ +/apv /av1_levels /avcodec /avpacket @@ -8,10 +9,10 @@ /codec_desc /dct /golomb +/hashtable /h264_levels /h265_levels /htmlsubtitles -/iirfilter /jpeg2000dwt /mathops /mjpegenc_huffman diff --git a/libavcodec/tests/apv.c b/libavcodec/tests/apv.c new file mode 100644 index 0000000000..365a395af1 --- /dev/null +++ b/libavcodec/tests/apv.c @@ -0,0 +1,449 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/lfg.h" +#include "libavutil/random_seed.h" + +#include "libavcodec/apv_decode.h" +#include "libavcodec/apv_dsp.h" +#include "libavcodec/put_bits.h" + + +// Whole file included here to get internal symbols. +#include "libavcodec/apv_entropy.c" + + +// As defined in 7.1.4, for testing. +// Adds a check to limit loop after reading 16 zero bits to avoid +// getting stuck reading a stream of zeroes forever (this matches +// the behaviour of the faster version). + +static unsigned int apv_read_vlc_spec(GetBitContext *gbc, int k_param) +{ + unsigned int symbol_value = 0; + int parse_exp_golomb = 1; + int k = k_param; + int stop_loop = 0; + + if(get_bits1(gbc) == 1) { + parse_exp_golomb = 0; + } else { + if (get_bits1(gbc) == 0) { + symbol_value += (1 << k); + parse_exp_golomb = 0; + } else { + symbol_value += (2 << k); + parse_exp_golomb = 1; + } + } + if (parse_exp_golomb) { + int read_limit = 0; + do { + if (get_bits1(gbc) == 1) { + stop_loop = 1; + } else { + if (++read_limit == 16) + break; + symbol_value += (1 << k); + k++; + } + } while (!stop_loop); + } + if (k > 0) + symbol_value += get_bits(gbc, k); + + return symbol_value; +} + +// As defined in 7.2.4, for testing. + +static void apv_write_vlc_spec(PutBitContext *pbc, + unsigned int symbol_val, int k_param) +{ + int prefix_vlc_table[3][2] = {{1, 0}, {0, 0}, {0, 1}}; + + unsigned int symbol_value = symbol_val; + int val_prefix_vlc = av_clip(symbol_val >> k_param, 0, 2); + int bit_count = 0; + int k = k_param; + + while (symbol_value >= (1 << k)) { + symbol_value -= (1 << k); + if (bit_count < 2) + put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]); + else + put_bits(pbc, 1, 0); + if (bit_count >= 2) + ++k; + ++bit_count; + } + + if(bit_count < 2) + put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]); + else + put_bits(pbc, 1, 1); + + if(k > 0) + put_bits(pbc, k, symbol_value); +} + +// Old version of ff_apv_entropy_decode_block, for test comparison. + +static int apv_entropy_decode_block(int16_t *restrict coeff, + GetBitContext *restrict gbc, + APVEntropyState *restrict state) +{ + const APVVLCLUT *lut = state->decode_lut; + + // DC coefficient. + { + int abs_dc_coeff_diff; + int sign_dc_coeff_diff; + int dc_coeff; + + abs_dc_coeff_diff = apv_read_vlc(gbc, state->prev_k_dc, lut); + + if (abs_dc_coeff_diff > 0) + sign_dc_coeff_diff = get_bits1(gbc); + else + sign_dc_coeff_diff = 0; + + if (sign_dc_coeff_diff) + dc_coeff = state->prev_dc - abs_dc_coeff_diff; + else + dc_coeff = state->prev_dc + abs_dc_coeff_diff; + + if (dc_coeff < APV_MIN_TRANS_COEFF || + dc_coeff > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range DC coefficient value: %d " + "(from prev_dc %d abs_dc_coeff_diff %d sign_dc_coeff_diff %d)\n", + dc_coeff, state->prev_dc, abs_dc_coeff_diff, sign_dc_coeff_diff); + return AVERROR_INVALIDDATA; + } + + coeff[0] = dc_coeff; + + state->prev_dc = dc_coeff; + state->prev_k_dc = FFMIN(abs_dc_coeff_diff >> 1, 5); + } + + // AC coefficients. + { + int scan_pos = 1; + int first_ac = 1; + int k_run = 0; + int k_level = state->prev_k_level; + + do { + int coeff_zero_run; + + coeff_zero_run = apv_read_vlc(gbc, k_run, lut); + + if (coeff_zero_run > APV_BLK_COEFFS - scan_pos) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range zero-run value: %d (at scan pos %d)\n", + coeff_zero_run, scan_pos); + return AVERROR_INVALIDDATA; + } + + for (int i = 0; i < coeff_zero_run; i++) { + coeff[ff_zigzag_direct[scan_pos]] = 0; + ++scan_pos; + } + k_run = FFMIN(coeff_zero_run >> 2, 2); + + if (scan_pos < APV_BLK_COEFFS) { + int abs_ac_coeff_minus1; + int sign_ac_coeff; + int abs_level, level; + + abs_ac_coeff_minus1 = apv_read_vlc(gbc, k_level, lut); + sign_ac_coeff = get_bits(gbc, 1); + + abs_level = abs_ac_coeff_minus1 + 1; + if (sign_ac_coeff) + level = -abs_level; + else + level = abs_level; + + if (level < APV_MIN_TRANS_COEFF || + level > APV_MAX_TRANS_COEFF) { + av_log(state->log_ctx, AV_LOG_ERROR, + "Out-of-range AC coefficient value: %d " + "(from k_param %d abs_ac_coeff_minus1 %d sign_ac_coeff %d)\n", + level, k_level, abs_ac_coeff_minus1, sign_ac_coeff); + } + + coeff[ff_zigzag_direct[scan_pos]] = level; + + k_level = FFMIN(abs_level >> 2, 4); + if (first_ac) { + state->prev_k_level = k_level; + first_ac = 0; + } + + ++scan_pos; + } + + } while (scan_pos < APV_BLK_COEFFS); + } + + return 0; +} + +static void binary(char *buf, uint32_t value, int bits) +{ + for (int i = 0; i < bits; i++) + buf[i] = (value >> (bits - i - 1) & 1) ? '1' : '0'; + buf[bits] = '\0'; +} + +static int test_apv_read_vlc(void) +{ + APVVLCLUT lut; + int err = 0; + + ff_apv_entropy_build_decode_lut(&lut); + + // Generate all possible 20 bit sequences (padded with zeroes), then + // verify that spec and improved parsing functions get the same result + // and consume the same number of bits for each possible k_param. + + for (int k = 0; k <= 5; k++) { + for (uint32_t b = 0; b < (1 << 20); b++) { + uint8_t buf[8] = { + b >> 12, + b >> 4, + b << 4, + 0, 0, 0, 0, 0 + }; + + GetBitContext gbc_test, gbc_spec; + unsigned int res_test, res_spec; + int con_test, con_spec; + + init_get_bits8(&gbc_test, buf, 8); + init_get_bits8(&gbc_spec, buf, 8); + + res_test = apv_read_vlc (&gbc_test, k, &lut); + res_spec = apv_read_vlc_spec(&gbc_spec, k); + + con_test = get_bits_count(&gbc_test); + con_spec = get_bits_count(&gbc_spec); + + if (res_test != res_spec || + con_test != con_spec) { + char str[21]; + binary(str, b, 20); + av_log(NULL, AV_LOG_ERROR, + "Mismatch reading %s (%d) with k=%d:\n", str, b, k); + av_log(NULL, AV_LOG_ERROR, + "Test function result %d consumed %d bits.\n", + res_test, con_test); + av_log(NULL, AV_LOG_ERROR, + "Spec function result %d consumed %d bits.\n", + res_spec, con_spec); + ++err; + if (err > 10) + return err; + } + } + } + + return err; +} + +static int random_coeff(AVLFG *lfg) +{ + // Geometric distribution of code lengths (1-14 bits), + // uniform distribution within codes of the length, + // equal probability of either sign. + int length = (av_lfg_get(lfg) / (UINT_MAX / 14 + 1)); + int random = av_lfg_get(lfg); + int value = (1 << length) + (random & (1 << length) - 1); + if (random & (1 << length)) + return value; + else + return -value; +} + +static int random_run(AVLFG *lfg) +{ + // Expoenential distribution of run lengths. + unsigned int random = av_lfg_get(lfg); + for (int len = 0;; len++) { + if (random & (1 << len)) + return len; + } + // You rolled zero on a 2^32 sided die; well done! + return 64; +} + +static int test_apv_entropy_decode_block(void) +{ + // Generate random entropy blocks, code them, then ensure they + // decode to the same block with both implementations. + + APVVLCLUT decode_lut; + AVLFG lfg; + unsigned int seed = av_get_random_seed(); + av_lfg_init(&lfg, seed); + + av_log(NULL, AV_LOG_INFO, "seed = %u\n", seed); + + ff_apv_entropy_build_decode_lut(&decode_lut); + + for (int t = 0; t < 100; t++) { + APVEntropyState state, save_state; + int16_t block[64]; + int16_t block_test1[64]; + int16_t block_test2[64]; + uint8_t buffer[1024]; + PutBitContext pbc; + GetBitContext gbc; + int bits_written; + int pos, run, coeff, level, err; + int k_dc, k_run, k_level; + + memset(block, 0, sizeof(block)); + memset(buffer, 0, sizeof(buffer)); + init_put_bits(&pbc, buffer, sizeof(buffer)); + + // Randomly-constructed state. + memset(&state, 0, sizeof(state)); + state.decode_lut = &decode_lut; + state.prev_dc = random_coeff(&lfg); + state.prev_k_dc = av_lfg_get(&lfg) % 5; + state.prev_k_level = av_lfg_get(&lfg) % 4; + save_state = state; + + k_dc = state.prev_k_dc; + k_run = 0; + k_level = state.prev_k_level; + + coeff = random_coeff(&lfg) / 2; + block[ff_zigzag_direct[0]] = state.prev_dc + coeff; + apv_write_vlc_spec(&pbc, FFABS(coeff), k_dc); + if (coeff != 0) + put_bits(&pbc, 1, coeff < 0); + + pos = 1; + while (pos < 64) { + run = random_run(&lfg); + if (pos + run > 64) + run = 64 - pos; + apv_write_vlc_spec(&pbc, run, k_run); + k_run = av_clip(run >> 2, 0, 2); + pos += run; + if (pos < 64) { + coeff = random_coeff(&lfg); + level = FFABS(coeff) - 1; + block[ff_zigzag_direct[pos]] = coeff; + apv_write_vlc_spec(&pbc, level, k_level); + put_bits(&pbc, 1, coeff < 0); + k_level = av_clip((level + 1) >> 2, 0, 4); + ++pos; + } + } + bits_written = put_bits_count(&pbc); + flush_put_bits(&pbc); + + // Fill output block with a distinctive error value. + for (int i = 0; i < 64; i++) + block_test1[i] = -9999; + init_get_bits8(&gbc, buffer, sizeof(buffer)); + + err = apv_entropy_decode_block(block_test1, &gbc, &state); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n"); + return 1; + } else { + int bits_read = get_bits_count(&gbc); + if (bits_written != bits_read) { + av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n", + bits_written, bits_read); + return 1; + } else { + err = 0; + for (int i = 0; i < 64; i++) { + if (block[i] != block_test1[i]) + ++err; + } + if (err > 0) { + av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err); + return err; + } + } + } + + init_get_bits8(&gbc, buffer, sizeof(buffer)); + memset(block_test2, 0, 64 * sizeof(int16_t)); + + err = ff_apv_entropy_decode_block(block_test2, &gbc, &save_state); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n"); + return 1; + } else { + int bits_read = get_bits_count(&gbc); + if (bits_written != bits_read) { + av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n", + bits_written, bits_read); + return 1; + } else { + err = 0; + for (int i = 0; i < 64; i++) { + if (block[i] != block_test2[i]) + ++err; + } + if (err > 0) { + av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err); + return err; + } + } + } + + if (state.prev_dc != save_state.prev_dc || + state.prev_k_dc != save_state.prev_k_dc || + state.prev_k_level != save_state.prev_k_level) { + av_log(NULL, AV_LOG_ERROR, "Entropy state mismatch.\n"); + return 1; + } + } + + return 0; +} + +int main(void) +{ + int err; + + err = test_apv_read_vlc(); + if (err) { + av_log(NULL, AV_LOG_ERROR, "Read VLC test failed.\n"); + return err; + } + + err = test_apv_entropy_decode_block(); + if (err) { + av_log(NULL, AV_LOG_ERROR, "Entropy decode block test failed.\n"); + return err; + } + + return 0; +} diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c index cd949f6385..dde8226384 100644 --- a/libavcodec/tests/avcodec.c +++ b/libavcodec/tests/avcodec.c @@ -77,17 +77,21 @@ int main(void){ ERR_EXT("Codec %s has unsupported type %s\n", get_type_string(codec->type)); if (codec->type != AVMEDIA_TYPE_AUDIO) { +FF_DISABLE_DEPRECATION_WARNINGS if (codec->ch_layouts || codec->sample_fmts || codec->supported_samplerates) ERR("Non-audio codec %s has audio-only fields set\n"); +FF_ENABLE_DEPRECATION_WARNINGS if (codec->capabilities & (AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) ERR("Non-audio codec %s has audio-only capabilities set\n"); } if (codec->type != AVMEDIA_TYPE_VIDEO) { +FF_DISABLE_DEPRECATION_WARNINGS if (codec->pix_fmts || codec->supported_framerates) ERR("Non-video codec %s has video-only fields set\n"); +FF_ENABLE_DEPRECATION_WARNINGS if (codec2->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING) ERR("Non-video codec %s exports cropping\n"); } @@ -136,10 +140,12 @@ int main(void){ if (codec2->update_thread_context || codec2->update_thread_context_for_user || codec2->bsfs) ERR("Encoder %s has decoder-only thread functions or bsf.\n"); if (codec->type == AVMEDIA_TYPE_AUDIO) { +FF_DISABLE_DEPRECATION_WARNINGS if (!codec->sample_fmts) { av_log(NULL, AV_LOG_FATAL, "Encoder %s is missing the sample_fmts field\n", codec->name); ret = 1; } +FF_ENABLE_DEPRECATION_WARNINGS } if (codec2->caps_internal & (FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_SETS_PKT_DTS | @@ -161,6 +167,9 @@ int main(void){ !(codec->capabilities & AV_CODEC_CAP_DELAY)) ERR("EOF_FLUSH encoder %s is not marked as having delay\n"); } else { + if ((codec2->update_thread_context || codec2->update_thread_context_for_user) && + !(codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)) + ERR("Non-frame-threaded decoder %s has update_thread_context set"); if ((codec->type == AVMEDIA_TYPE_SUBTITLE) != (codec2->cb_type == FF_CODEC_CB_TYPE_DECODE_SUB)) ERR("Subtitle decoder %s does not implement decode_sub callback\n"); if (codec->type == AVMEDIA_TYPE_SUBTITLE && codec2->bsfs) diff --git a/libavcodec/tests/avpacket.c b/libavcodec/tests/avpacket.c index fed700b4be..edb117952a 100644 --- a/libavcodec/tests/avpacket.c +++ b/libavcodec/tests/avpacket.c @@ -51,6 +51,7 @@ static int setup_side_data_entry(AVPacket* avpkt) ret = av_packet_add_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, extra_data, bytes); if(ret < 0){ + av_free(extra_data); fprintf(stderr, "Error occurred in av_packet_add_side_data: %s\n", av_err2str(ret)); @@ -87,7 +88,7 @@ int main(void) /* test av_packet_alloc */ avpkt = av_packet_alloc(); if(!avpkt) { - av_log(NULL, AV_LOG_ERROR, "av_packet_alloc failed to allcoate AVPacket\n"); + av_log(NULL, AV_LOG_ERROR, "av_packet_alloc failed to allocate AVPacket\n"); return 1; } @@ -101,11 +102,14 @@ int main(void) if(!avpkt_clone) { av_log(NULL, AV_LOG_ERROR,"av_packet_clone failed to clone AVPacket\n"); + av_packet_free(&avpkt); return 1; } /*test av_grow_packet*/ if(av_grow_packet(avpkt_clone, 20) < 0){ av_log(NULL, AV_LOG_ERROR, "av_grow_packet failed\n"); + av_packet_free(&avpkt_clone); + av_packet_free(&avpkt); return 1; } if(av_grow_packet(avpkt_clone, INT_MAX) == 0){ diff --git a/libavcodec/tests/celp_math.c b/libavcodec/tests/celp_math.c index 669ea70362..115817894f 100644 --- a/libavcodec/tests/celp_math.c +++ b/libavcodec/tests/celp_math.c @@ -16,8 +16,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/float_dsp.h" #include "libavutil/libm.h" -#include "libavcodec/celp_math.c" +#include "libavutil/macros.h" + +#include "libavcodec/celp_math.h" static inline void IsAlmostEqual(float A, float B, float epsilon) { @@ -36,7 +43,7 @@ int main(void) const int16_t i1[3] = {6, 7, 8}; const int16_t i2[3] = {9, 10, 11}; - float r = ff_dot_productf(f1, f2, FF_ARRAY_ELEMS(f1)); + float r = ff_scalarproduct_float_c(f1, f2, FF_ARRAY_ELEMS(f1)); int64_t d = ff_dot_product(i1, i2, FF_ARRAY_ELEMS(i1)); IsAlmostEqual(16.94f, r, 0.000001f); diff --git a/libavcodec/tests/dct.c b/libavcodec/tests/dct.c index 17a0814459..784b49276c 100644 --- a/libavcodec/tests/dct.c +++ b/libavcodec/tests/dct.c @@ -52,6 +52,9 @@ #include "libavcodec/faandct.h" #include "libavcodec/faanidct.h" #include "libavcodec/dctref.h" +#if CONFIG_PRORES_DECODER +#include "libavcodec/proresdsp.c" +#endif struct algo { const char *name; @@ -70,6 +73,7 @@ static const struct algo fdct_tab[] = { #endif /* CONFIG_FAANDCT */ }; +#if CONFIG_PRORES_DECODER static void ff_prores_idct_wrap(int16_t *dst){ LOCAL_ALIGNED(16, int16_t, qmat, [64]); int i; @@ -77,11 +81,12 @@ static void ff_prores_idct_wrap(int16_t *dst){ for(i=0; i<64; i++){ qmat[i]=4; } - ff_prores_idct_10(dst, qmat); + prores_idct_10(dst, qmat); for(i=0; i<64; i++) { dst[i] -= 512; } } +#endif static const struct algo idct_tab[] = { { "REF-DBL", ff_ref_idct, FF_IDCT_PERM_NONE }, @@ -89,7 +94,9 @@ static const struct algo idct_tab[] = { { "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 }, +#if CONFIG_PRORES_DECODER { "PR-C", ff_prores_idct_wrap, FF_IDCT_PERM_NONE, 0, 1 }, +#endif #if CONFIG_FAANIDCT { "FAANI", ff_faanidct, FF_IDCT_PERM_NONE }, #endif /* CONFIG_FAANIDCT */ diff --git a/libavcodec/tests/hashtable.c b/libavcodec/tests/hashtable.c new file mode 100644 index 0000000000..02c0ac8afa --- /dev/null +++ b/libavcodec/tests/hashtable.c @@ -0,0 +1,110 @@ +/* + * Generic hashtable tests + * Copyright (C) 2024 Emma Worley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "libavcodec/hashtable.h" + +int main(void) +{ + struct FFHashtableContext *ctx; + uint8_t k; + uint64_t v; + + // impossibly large allocation should fail gracefully + av_assert0(ff_hashtable_alloc(&ctx, -1, -1, -1) < 0); + + // hashtable can store up to 3 uint8_t->uint64_t entries + av_assert0(!ff_hashtable_alloc(&ctx, sizeof(k), sizeof(v), 3)); + + // unsuccessful deletes return 0 + k = 1; + av_assert0(!ff_hashtable_delete(ctx, &k)); + + // unsuccessful gets return 0 + k = 1; + av_assert0(!ff_hashtable_get(ctx, &k, &v)); + + // successful sets returns 1 + k = 1; + v = 1; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // get should now contain 1 + k = 1; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 1); + + // updating sets should return 1 + k = 1; + v = 2; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // get should now contain 2 + k = 1; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 2); + + // fill the table + k = 2; + v = 2; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + k = 3; + v = 3; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + + // inserting sets on a full table should return 0 + k = 4; + v = 4; + av_assert0(!ff_hashtable_set(ctx, &k, &v)); + + // updating sets on a full table should return 1 + k = 1; + v = 4; + av_assert0(ff_hashtable_set(ctx, &k, &v)); + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 4); + + // successful deletes should return 1 + k = 1; + av_assert0(ff_hashtable_delete(ctx, &k)); + + // get should now return 0 + av_assert0(!ff_hashtable_get(ctx, &k, &v)); + + // sanity check remaining keys + k = 2; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 2); + k = 3; + v = 0; + av_assert0(ff_hashtable_get(ctx, &k, &v)); + av_assert0(v == 3); + + ff_hashtable_freep(&ctx); + + return 0; +} diff --git a/libavcodec/tests/iirfilter.c b/libavcodec/tests/iirfilter.c deleted file mode 100644 index e03e842b85..0000000000 --- a/libavcodec/tests/iirfilter.c +++ /dev/null @@ -1,69 +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 -#include - -#include "libavutil/libm.h" - -#include "libavcodec/iirfilter.h" -#include "libavcodec/iirfilter.c" - -#define FILT_ORDER 4 -#define SIZE 1024 - -static void iir_filter_int16(const struct FFIIRFilterCoeffs *c, - struct FFIIRFilterState *s, int size, - const int16_t *src, ptrdiff_t sstep, - int16_t *dst, ptrdiff_t dstep) -{ - if (c->order == 2) { - FILTER_O2(int16_t, S16) - } else if (c->order == 4) { - FILTER_BW_O4(int16_t, S16) - } else { - FILTER_DIRECT_FORM_II(int16_t, S16) - } -} - -int main(void) -{ - struct FFIIRFilterCoeffs *fcoeffs = NULL; - struct FFIIRFilterState *fstate = NULL; - float cutoff_coeff = 0.4; - int16_t x[SIZE], y[SIZE]; - int i; - - fcoeffs = ff_iir_filter_init_coeffs(NULL, FF_FILTER_TYPE_BUTTERWORTH, - FF_FILTER_MODE_LOWPASS, FILT_ORDER, - cutoff_coeff, 0.0, 0.0); - fstate = ff_iir_filter_init_state(FILT_ORDER); - - for (i = 0; i < SIZE; i++) - x[i] = lrint(0.75 * INT16_MAX * sin(0.5 * M_PI * i * i / SIZE)); - - iir_filter_int16(fcoeffs, fstate, SIZE, x, 1, y, 1); - - for (i = 0; i < SIZE; i++) - printf("%6d %6d\n", x[i], y[i]); - - ff_iir_filter_free_coeffsp(&fcoeffs); - ff_iir_filter_free_statep(&fstate); - return 0; -} diff --git a/libavcodec/tests/jpeg2000dwt.c b/libavcodec/tests/jpeg2000dwt.c index 520ecc05a3..a6ba190a54 100644 --- a/libavcodec/tests/jpeg2000dwt.c +++ b/libavcodec/tests/jpeg2000dwt.c @@ -46,6 +46,11 @@ static int test_dwt(int *array, int *ref, int border[2][2], int decomp_levels, i fprintf(stderr, "ff_dwt_encode failed\n"); return 1; } + if (type == FF_DWT97_INT) { + // pre-scaling to simulate dequantization which places the binary point at 1 bit above from LSB + for (j = 0; j< s->linelen[decomp_levels-1][0] * s->linelen[decomp_levels-1][1]; j++) + array[j] = (uint32_t)array[j] << I_PRESHIFT; + } ret = ff_dwt_decode(s, array); if (ret < 0) { fprintf(stderr, "ff_dwt_encode failed\n"); @@ -53,7 +58,7 @@ static int test_dwt(int *array, int *ref, int border[2][2], int decomp_levels, i } for (j = 0; j max_diff) { - fprintf(stderr, "missmatch at %d (%d != %d) decomp:%d border %d %d %d %d\n", + fprintf(stderr, "mismatch at %d (%d != %d) decomp:%d border %d %d %d %d\n", j, array[j], ref[j],decomp_levels, border[0][0], border[0][1], border[1][0], border[1][1]); return 2; } @@ -92,7 +97,7 @@ static int test_dwtf(float *array, float *ref, int border[2][2], int decomp_leve } for (j = 0; j max_diff) { - fprintf(stderr, "missmatch at %d (%f != %f) decomp:%d border %d %d %d %d\n", + fprintf(stderr, "mismatch at %d (%f != %f) decomp:%d border %d %d %d %d\n", j, array[j], ref[j],decomp_levels, border[0][0], border[0][1], border[1][0], border[1][1]); return 2; } diff --git a/libavcodec/tests/mjpegenc_huffman.c b/libavcodec/tests/mjpegenc_huffman.c index 2ed92d07d5..9cc5d9b506 100644 --- a/libavcodec/tests/mjpegenc_huffman.c +++ b/libavcodec/tests/mjpegenc_huffman.c @@ -23,58 +23,80 @@ * Optimal Huffman Encoding tests. */ -#include "libavcodec/avcodec.h" -#include -#include "libavcodec/mjpegenc.h" -#include "libavcodec/mjpegenc_huffman.h" -#include "libavcodec/mjpegenc_common.h" -#include "libavcodec/mpegvideo.h" +#include + +#include "libavutil/avassert.h" +#include "libavutil/macros.h" + +#include "libavcodec/mjpegenc_huffman.c" // Validate the computed lengths satisfy the JPEG restrictions and is optimal. -static int check_lengths(int L, int expected_length, - const int *probs, int nprobs) +static int check_lengths(int L, const int *probs, int nprobs, + int expected_length, const uint8_t expected_len_counts[/* L + 1 */]) { - HuffTable lengths[256]; PTable val_counts[256]; - int actual_length = 0, i, j, k, prob, length; + uint8_t len_counts[17]; + int actual_length = 0, i; int ret = 0; - double cantor_measure = 0; av_assert0(nprobs <= 256); + av_assert0(L < FF_ARRAY_ELEMS(len_counts)); for (i = 0; i < nprobs; i++) { val_counts[i] = (PTable){.value = i, .prob = probs[i]}; } - ff_mjpegenc_huffman_compute_bits(val_counts, lengths, nprobs, L); + mjpegenc_huffman_compute_bits(val_counts, len_counts, nprobs, L); - for (i = 0; i < nprobs; i++) { - // Find the value's prob and length - for (j = 0; j < nprobs; j++) - if (val_counts[j].value == i) break; - for (k = 0; k < nprobs; k++) - if (lengths[k].code == i) break; - if (!(j < nprobs && k < nprobs)) return 1; - prob = val_counts[j].prob; - length = lengths[k].length; - - if (prob) { - actual_length += prob * length; - cantor_measure += 1. / (1 << length); - } - - if (length > L || length < 1) return 1; + // Test that the lengths can be made part of a complete, prefix-free tree: + unsigned code = 0, count = 0; + for (int i = 1; i <= L; ++i) { + count += len_counts[i]; + code <<= 1; + code += len_counts[i]; + } + if (code > 1U << L) { + fprintf(stderr, "Huffman tree overdetermined/invalid\n"); + ret = 1; + } + if (count != nprobs) { + fprintf(stderr, "Total count %u does not match expected value %d\n", + count, nprobs); + ret = 1; + } + // Test that the input values have been properly ordered. + for (unsigned i = 0; i < count; ++i) { + if (val_counts[i].prob != probs[val_counts[i].value]) { + fprintf(stderr, "PTable not properly reordered\n"); + ret = 1; + } + if (i && val_counts[i - 1].prob > val_counts[i].prob) { + fprintf(stderr, "PTable not order ascendingly: [%u] = %d > [%u] = %d\n", + i - 1, val_counts[i - 1].prob, i, val_counts[i].prob); + ret = 1; + } + unsigned j; + for (j = 0; j < count; ++j) + if (val_counts[j].value == i) + break; + if (j >= count) { + fprintf(stderr, "Element %u missing after sorting\n", i); + ret = 1; + } + } + for (int len = L, j = 0; len; --len) { + int prob = 0; + for (int end = j + len_counts[len]; j < end; ++j) + prob += val_counts[j].prob; + actual_length += prob * len; } - // Check that the codes can be prefix-free. - if (cantor_measure > 1) ret = 1; // Check that the total length is optimal if (actual_length != expected_length) ret = 1; if (ret == 1) { fprintf(stderr, - "Cantor measure: %f\n" "Actual length: %d\n" "Expected length: %d\n", - cantor_measure, actual_length, expected_length); + actual_length, expected_length); } return ret; @@ -83,6 +105,9 @@ static int check_lengths(int L, int expected_length, static const int probs_zeroes[] = { 6, 6, 0, 0, 0 }; +static const uint8_t len_counts_zeroes[] = { + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, +}; static const int probs_skewed[] = { 2, 0, 0, 0, 0, 1, 0, 0, 20, 0, 2, 0, 10, 5, 1, 1, 9, 1, 1, 6, 0, 5, 0, 1, 0, 7, 6, @@ -96,6 +121,9 @@ static const int probs_skewed[] = { 0, 3, 0, 0, 28, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 21, 1, 0, 3, 24, 2, 0, 0, 7, 0, 0, 1, 5, 1, 2, 0, 5 }; +static const uint8_t len_counts_skewed[] = { + 0, 1, 0, 0, 1, 2, 7, 11, 18, 31, 28, 40, 0, 1, 0, 0, 116, +}; static const int probs_sat[] = { 74, 8, 14, 7, 9345, 40, 0, 2014, 2, 1, 115, 0, 2, 1, 194, 388, 20, 0, 0, 2, 1, 121, @@ -110,12 +138,18 @@ static const int probs_sat[] = { 0, 1085, 0, 0, 0, 3, 489, 36, 1, 0, 1, 9420, 294, 28, 0, 57, 5, 0, 9, 2, 0, 1, 2, 2, 0, 0, 9, 2, 29, 2, 2, 7, 0, 5, 490, 0, 7, 5, 0, 1, 8, 0, 0, 23255, 0, 1 }; +static const uint8_t len_counts_sat[] = { + 0, 1, 0, 2, 1, 2, 2, 5, 5, 7, 7, 8, 17, 23, 16, 24, 136, +}; // Test the example given on @see // http://guru.multimedia.cx/small-tasks-for-ffmpeg/ int main(int argc, char **argv) { - int i, ret = 0; + enum { + MAX_LEN = 3, + }; + int ret = 0; // Probabilities of symbols 0..4 PTable val_counts[] = { {.value = 0, .prob = 1}, @@ -125,42 +159,45 @@ int main(int argc, char **argv) {.value = 4, .prob = 21}, }; // Expected code lengths for each symbol - static const HuffTable expected[] = { - {.code = 0, .length = 3}, - {.code = 1, .length = 3}, - {.code = 2, .length = 3}, - {.code = 3, .length = 3}, - {.code = 4, .length = 1}, + static const uint8_t expected[MAX_LEN + 1] = { + [1] = 1, [3] = 4, }; // Actual code lengths - HuffTable distincts[5]; + uint8_t len_counts[MAX_LEN + 1]; // Build optimal huffman tree using an internal function, to allow for // smaller-than-normal test cases. This mutates val_counts by sorting. - ff_mjpegenc_huffman_compute_bits(val_counts, distincts, - FF_ARRAY_ELEMS(distincts), 3); + mjpegenc_huffman_compute_bits(val_counts, len_counts, + FF_ARRAY_ELEMS(val_counts), MAX_LEN); - for (i = 0; i < FF_ARRAY_ELEMS(distincts); i++) { - if (distincts[i].code != expected[i].code || - distincts[i].length != expected[i].length) { + for (unsigned i = 1; i < FF_ARRAY_ELEMS(len_counts); i++) { + if (len_counts[i] != expected[i]) { fprintf(stderr, "Built huffman does not equal expectations. " - "Expected: code %d probability %d, " - "Actual: code %d probability %d\n", - expected[i].code, expected[i].length, - distincts[i].code, distincts[i].length); + "Expected: %d codes of length %u, " + "Actual: %d codes of length %u\n", + (int)expected[i], i, + (int)len_counts[i], i); + ret = 1; + } + } + for (unsigned i = 1; i < FF_ARRAY_ELEMS(val_counts); ++i) { + if (val_counts[i - 1].prob > val_counts[i].prob) { + fprintf(stderr, "Probability table not ordered ascendingly. " + "val_counts[%u] == %d, val_counts[%u] == %d\n", + i - 1, val_counts[i - 1].prob, i, val_counts[i].prob); ret = 1; } } // Check handling of zero probabilities - if (check_lengths(16, 18, probs_zeroes, FF_ARRAY_ELEMS(probs_zeroes))) + if (check_lengths(16, probs_zeroes, FF_ARRAY_ELEMS(probs_zeroes), 18, len_counts_zeroes)) ret = 1; // Check skewed distribution over 256 without saturated lengths - if (check_lengths(16, 41282, probs_skewed, FF_ARRAY_ELEMS(probs_skewed))) + if (check_lengths(16, probs_skewed, FF_ARRAY_ELEMS(probs_skewed), 41282, len_counts_skewed)) ret = 1; // Check skewed distribution over 256 with saturated lengths - if (check_lengths(16, 669904, probs_sat, FF_ARRAY_ELEMS(probs_sat))) + if (check_lengths(16, probs_sat, FF_ARRAY_ELEMS(probs_sat), 669904, len_counts_sat)) ret = 1; return ret; diff --git a/libavcodec/tests/motion.c b/libavcodec/tests/motion.c index c37fc551c3..719fba537d 100644 --- a/libavcodec/tests/motion.c +++ b/libavcodec/tests/motion.c @@ -129,6 +129,10 @@ int main(int argc, char **argv) printf("ffmpeg motion test\n"); ctx = avcodec_alloc_context3(NULL); + if (!ctx) { + return 1; + } + ctx->flags |= AV_CODEC_FLAG_BITEXACT; av_force_cpu_flags(0); ff_me_cmp_init(&cctx, ctx); diff --git a/libavcodec/tests/snowenc.c b/libavcodec/tests/snowenc.c index eb4e64f377..311374e5d4 100644 --- a/libavcodec/tests/snowenc.c +++ b/libavcodec/tests/snowenc.c @@ -45,7 +45,8 @@ int main(void){ if (!s.temp_dwt_buffer || !s.temp_idwt_buffer) { fprintf(stderr, "Failed to allocate memory\n"); - return 1; + ret = 1; + goto end; } av_lfg_init(&prng, 1); @@ -145,5 +146,9 @@ int main(void){ } } + +end: + av_free(s.temp_dwt_buffer); + av_free(s.temp_idwt_buffer); return ret; } diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c index b9aebff002..10a052e99b 100644 --- a/libavcodec/textdec.c +++ b/libavcodec/textdec.c @@ -95,7 +95,7 @@ const FFCodec ff_text_decoder = { #if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER || CONFIG_STL_DECODER -static int linebreak_init(AVCodecContext *avctx) +static av_cold int linebreak_init(AVCodecContext *avctx) { TextContext *text = avctx->priv_data; text->linebreaks = "|"; diff --git a/libavcodec/thread.h b/libavcodec/thread.h index 47c00a0ed2..7df5839ed0 100644 --- a/libavcodec/thread.h +++ b/libavcodec/thread.h @@ -56,10 +56,6 @@ int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags); int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, int (*action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr), int (*main_func)(AVCodecContext *c), void *arg, int *ret, int job_count); -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count); -int ff_slice_thread_init_progress(AVCodecContext *avctx); -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n); -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift); enum ThreadingStatus { FF_THREAD_IS_COPY, diff --git a/libavcodec/threadprogress.c b/libavcodec/threadprogress.c index 62c4fd898b..aa72ff80e7 100644 --- a/libavcodec/threadprogress.c +++ b/libavcodec/threadprogress.c @@ -55,9 +55,8 @@ void ff_thread_progress_report(ThreadProgress *pro, int n) if (atomic_load_explicit(&pro->progress, memory_order_relaxed) >= n) return; - atomic_store_explicit(&pro->progress, n, memory_order_release); - ff_mutex_lock(&pro->progress_mutex); + atomic_store_explicit(&pro->progress, n, memory_order_release); ff_cond_broadcast(&pro->progress_cond); ff_mutex_unlock(&pro->progress_mutex); } diff --git a/libavcodec/tiertexseqv.c b/libavcodec/tiertexseqv.c index cdc885558b..31acc9b438 100644 --- a/libavcodec/tiertexseqv.c +++ b/libavcodec/tiertexseqv.c @@ -182,11 +182,6 @@ static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int c[j] = (*data << 2) | (*data >> 4); palette[i] = 0xFFU << 24 | AV_RB24(c); } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - seq->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if (flags & 2) { diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 37b56e9757..e515845a83 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -36,6 +36,7 @@ #include #include "libavutil/attributes.h" +#include "libavutil/attributes_internal.h" #include "libavutil/avstring.h" #include "libavutil/error.h" #include "libavutil/intreadwrite.h" @@ -2409,7 +2410,6 @@ again: static av_cold int tiff_init(AVCodecContext *avctx) { TiffContext *s = avctx->priv_data; - const AVCodec *codec; int ret; s->width = 0; @@ -2429,17 +2429,15 @@ static av_cold int tiff_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* Prepare everything needed for JPEG decoding */ - codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if (!codec) - return AVERROR_BUG; - s->avctx_mjpeg = avcodec_alloc_context3(codec); + EXTERN const FFCodec ff_mjpeg_decoder; + s->avctx_mjpeg = avcodec_alloc_context3(&ff_mjpeg_decoder.p); if (!s->avctx_mjpeg) return AVERROR(ENOMEM); s->avctx_mjpeg->flags = avctx->flags; s->avctx_mjpeg->flags2 = avctx->flags2; s->avctx_mjpeg->idct_algo = avctx->idct_algo; s->avctx_mjpeg->max_pixels = avctx->max_pixels; - ret = avcodec_open2(s->avctx_mjpeg, codec, NULL); + ret = avcodec_open2(s->avctx_mjpeg, NULL, NULL); if (ret < 0) { return ret; } diff --git a/libavcodec/tiffenc.c b/libavcodec/tiffenc.c index 5e65979c79..66facb4174 100644 --- a/libavcodec/tiffenc.c +++ b/libavcodec/tiffenc.c @@ -580,15 +580,13 @@ const FFCodec ff_tiff_encoder = { .init = encode_init, .close = encode_close, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { + CODEC_PIXFMTS( AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_YA16LE, AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE - }, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &tiffenc_class, }; diff --git a/libavfilter/vulkan.h b/libavcodec/timecode_internal.c similarity index 86% rename from libavfilter/vulkan.h rename to libavcodec/timecode_internal.c index 928b2e21c3..8682bb1b2e 100644 --- a/libavfilter/vulkan.h +++ b/libavcodec/timecode_internal.c @@ -16,9 +16,4 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_VULKAN_H -#define AVFILTER_VULKAN_H - -#include "libavutil/vulkan.h" - -#endif /* AVFILTER_VULKAN_H */ +#include "libavutil/timecode_internal.c" diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c index 2ff1424bd8..0eedc258c3 100644 --- a/libavcodec/tmv.c +++ b/libavcodec/tmv.c @@ -40,6 +40,7 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt) { const uint8_t *src = avpkt->data; + const uint8_t *cga_font = avpriv_cga_font_get(); uint8_t *dst; unsigned char_cols = avctx->width >> 3; unsigned char_rows = avctx->height >> 3; @@ -58,11 +59,6 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, dst = frame->data[0]; -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], ff_cga_palette, 16 * 4); memset(frame->data[1] + 16 * 4, 0, AVPALETTE_SIZE - 16 * 4); @@ -72,7 +68,7 @@ FF_ENABLE_DEPRECATION_WARNINGS bg = *src >> 4; fg = *src++ & 0xF; ff_draw_pc_font(dst + x * 8, frame->linesize[0], - avpriv_cga_font, 8, c, fg, bg); + cga_font, 8, c, fg, bg); } dst += frame->linesize[0] * 8; } diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c index 575173698c..99bb0307b0 100644 --- a/libavcodec/tscc.c +++ b/libavcodec/tscc.c @@ -107,11 +107,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* make the palette available on the way out */ if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = palette_has_changed; -FF_ENABLE_DEPRECATION_WARNINGS -#endif memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); } diff --git a/libavcodec/ttaenc.c b/libavcodec/ttaenc.c index 1b9aeec8ff..16fa377536 100644 --- a/libavcodec/ttaenc.c +++ b/libavcodec/ttaenc.c @@ -211,8 +211,5 @@ const FFCodec ff_tta_encoder = { .init = tta_encode_init, .close = tta_encode_close, FF_CODEC_ENCODE_CB(tta_encode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), }; diff --git a/libavcodec/twinvqdec.c b/libavcodec/twinvqdec.c index 8b6b2196e7..983a47a65b 100644 --- a/libavcodec/twinvqdec.c +++ b/libavcodec/twinvqdec.c @@ -423,7 +423,6 @@ const FFCodec ff_twinvq_decoder = { .close = ff_twinvq_decode_close, FF_CODEC_DECODE_CB(ff_twinvq_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index d68e672e0a..cfa35d0e04 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -33,6 +33,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" +#include "libavutil/timecode_internal.h" #include "avcodec.h" #include "codec.h" #include "codec_desc.h" @@ -40,7 +41,7 @@ #include "codec_par.h" #include "decode.h" #include "hwconfig.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadframe.h" #include "internal.h" @@ -78,17 +79,13 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size) int av_codec_is_encoder(const AVCodec *avcodec) { const FFCodec *const codec = ffcodec(avcodec); - return codec && (codec->cb_type == FF_CODEC_CB_TYPE_ENCODE || - codec->cb_type == FF_CODEC_CB_TYPE_ENCODE_SUB || - codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_PACKET); + return codec && !codec->is_decoder; } int av_codec_is_decoder(const AVCodec *avcodec) { const FFCodec *const codec = ffcodec(avcodec); - return codec && (codec->cb_type == FF_CODEC_CB_TYPE_DECODE || - codec->cb_type == FF_CODEC_CB_TYPE_DECODE_SUB || - codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME); + return codec && codec->is_decoder; } int ff_set_dimensions(AVCodecContext *s, int width, int height) @@ -339,7 +336,7 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, // H.264 uses edge emulation for out of frame motion vectors, for this // it requires a temporary area large enough to hold a 21x21 block, - // increasing witdth ensure that the temporary area is large enough, + // increasing width ensure that the temporary area is large enough, // the next rounded up width is 32 *width = FFMAX(*width, 32); } @@ -553,11 +550,13 @@ int av_get_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_DFPWM: return 1; case AV_CODEC_ID_ADPCM_SBPRO_2: + case AV_CODEC_ID_G728: return 2; case AV_CODEC_ID_ADPCM_SBPRO_3: return 3; case AV_CODEC_ID_ADPCM_SBPRO_4: case AV_CODEC_ID_ADPCM_IMA_WAV: + case AV_CODEC_ID_ADPCM_IMA_XBOX: case AV_CODEC_ID_ADPCM_IMA_QT: case AV_CODEC_ID_ADPCM_SWF: case AV_CODEC_ID_ADPCM_MS: @@ -720,10 +719,15 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, int blocks = frame_bytes / ba; int64_t tmp = 0; switch (id) { + case AV_CODEC_ID_ADPCM_IMA_XBOX: + if (bps != 4) + return 0; + tmp = blocks * ((ba - 4 * ch) / (bps * ch) * 8); + break; case AV_CODEC_ID_ADPCM_IMA_WAV: if (bps < 2 || bps > 5) return 0; - tmp = blocks * (1LL + (ba - 4 * ch) / (bps * ch) * 8); + tmp = blocks * (1LL + (ba - 4 * ch) / (bps * ch) * 8LL); break; case AV_CODEC_ID_ADPCM_IMA_DK3: tmp = blocks * (((ba - 16LL) * 2 / 3 * 4) / ch); @@ -856,7 +860,7 @@ int ff_thread_ref_frame(ThreadFrame *dst, const ThreadFrame *src) av_assert0(!dst->progress); if (src->progress) - dst->progress = ff_refstruct_ref(src->progress); + dst->progress = av_refstruct_ref(src->progress); return 0; } @@ -872,7 +876,7 @@ int ff_thread_replace_frame(ThreadFrame *dst, const ThreadFrame *src) if (ret < 0) return ret; - ff_refstruct_replace(&dst->progress, src->progress); + av_refstruct_replace(&dst->progress, src->progress); return 0; } @@ -913,25 +917,6 @@ int ff_thread_can_start_frame(AVCodecContext *avctx) { return 1; } - -int ff_slice_thread_init_progress(AVCodecContext *avctx) -{ - return 0; -} - -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count) -{ - return 0; -} - -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) -{ -} - -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) -{ -} - #endif const uint8_t *avpriv_find_start_code(const uint8_t *restrict p, @@ -981,15 +966,6 @@ AVCPBProperties *av_cpb_properties_alloc(size_t *size) return props; } -static unsigned bcd2uint(uint8_t bcd) -{ - unsigned low = bcd & 0xf; - unsigned high = bcd >> 4; - if (low > 9 || high > 9) - return 0; - return low + 10*high; -} - int ff_alloc_timecode_sei(const AVFrame *frame, AVRational rate, size_t prefix_len, void **data, size_t *sei_size) { @@ -1019,23 +995,8 @@ int ff_alloc_timecode_sei(const AVFrame *frame, AVRational rate, size_t prefix_l put_bits(&pb, 2, m); // num_clock_ts for (int j = 1; j <= m; j++) { - uint32_t tcsmpte = tc[j]; - unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours - unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes - unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds - unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames - unsigned drop = tcsmpte & 1<<30 && !0; // 1-bit drop if not arbitrary bit - - /* Calculate frame number of HEVC by SMPTE ST 12-1:2014 Sec 12.2 if rate > 30FPS */ - if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) { - unsigned pc; - ff *= 2; - if (av_cmp_q(rate, (AVRational) {50, 1}) == 0) - pc = !!(tcsmpte & 1 << 7); - else - pc = !!(tcsmpte & 1 << 23); - ff = (ff + pc) & 0x7f; - } + unsigned hh, mm, ss, ff, drop; + ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, rate, tc[j], 0, 0); put_bits(&pb, 1, 1); // clock_timestamp_flag put_bits(&pb, 1, 1); // units_field_based_flag diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 4c0fa2ca67..bc02ac44d5 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -402,7 +402,7 @@ static void restore_median_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t str // second line - first element has top prediction, the rest uses median C = bsrc[-stride]; bsrc[0] += C; - A = bsrc[0]; + A = B = bsrc[0]; 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)); @@ -585,7 +585,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int buf_size = avpkt->size; UtvideoContext *c = avctx->priv_data; int i, j; - const uint8_t *plane_start[5]; + const uint8_t *plane_start[5] = {NULL}; int plane_size, max_slice_size = 0, slice_start, slice_end, slice_size; int ret; GetByteContext gb; diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index 54b1caa9e3..7cefca79bc 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -24,6 +24,7 @@ * Ut Video encoder */ +#include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" @@ -143,9 +144,7 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) original_format = UTVIDEO_444; break; default: - av_log(avctx, AV_LOG_ERROR, "Unknown pixel format: %d\n", - avctx->pix_fmt); - return AVERROR_INVALIDDATA; + av_unreachable("Already checked via CODEC_PIXFMTS"); } ff_bswapdsp_init(&c->bdsp); @@ -153,7 +152,7 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) if (c->frame_pred == PRED_GRADIENT) { av_log(avctx, AV_LOG_ERROR, "Gradient prediction is not supported.\n"); - return AVERROR_OPTION_NOT_FOUND; + return AVERROR_PATCHWELCOME; } /* @@ -646,7 +645,6 @@ static const AVOption options[] = { { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, { .i64 = PRED_LEFT }, PRED_NONE, PRED_MEDIAN, VE, .unit = "pred" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_NONE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_LEFT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, - { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_GRADIENT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_MEDIAN }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { NULL}, @@ -671,10 +669,8 @@ const FFCodec ff_utvideo_encoder = { .init = utvideo_encode_init, FF_CODEC_ENCODE_CB(utvideo_encode_frame), .close = utvideo_encode_close, - .p.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_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P), .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c index 2a30ed77da..2194e2128c 100644 --- a/libavcodec/v210enc.c +++ b/libavcodec/v210enc.c @@ -117,5 +117,5 @@ const FFCodec ff_v210_encoder = { .priv_data_size = sizeof(V210EncContext), .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P), }; diff --git a/libavcodec/v308dec.c b/libavcodec/v308dec.c index b591a79dd2..64876b7e5a 100644 --- a/libavcodec/v308dec.c +++ b/libavcodec/v308dec.c @@ -30,6 +30,8 @@ static av_cold int v308_decode_init(AVCodecContext *avctx) if (avctx->width & 1) av_log(avctx, AV_LOG_WARNING, "v308 requires width to be even.\n"); + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v308enc.c b/libavcodec/v308enc.c index 68f9c3310b..884932da44 100644 --- a/libavcodec/v308enc.c +++ b/libavcodec/v308enc.c @@ -33,6 +33,8 @@ static av_cold int v308_encode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + avctx->bits_per_coded_sample = 24; avctx->bit_rate = ff_guess_coded_bitrate(avctx); @@ -78,5 +80,5 @@ const FFCodec ff_v308_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v308_encode_init, FF_CODEC_ENCODE_CB(v308_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV444P), }; diff --git a/libavcodec/v408dec.c b/libavcodec/v408dec.c index 2433c6de14..4bce5c7b67 100644 --- a/libavcodec/v408dec.c +++ b/libavcodec/v408dec.c @@ -27,6 +27,8 @@ static av_cold int v408_decode_init(AVCodecContext *avctx) { avctx->pix_fmt = AV_PIX_FMT_YUVA444P; + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v408enc.c b/libavcodec/v408enc.c index c173f650ef..4b6717a1fb 100644 --- a/libavcodec/v408enc.c +++ b/libavcodec/v408enc.c @@ -30,6 +30,8 @@ static av_cold int v408_encode_init(AVCodecContext *avctx) avctx->bits_per_coded_sample = 32; avctx->bit_rate = ff_guess_coded_bitrate(avctx); + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + return 0; } @@ -77,5 +79,5 @@ const FFCodec ff_v408_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v408_encode_init, FF_CODEC_ENCODE_CB(v408_encode_frame), - .p.pix_fmts = pix_fmt, + CODEC_PIXFMTS_ARRAY(pix_fmt), }; diff --git a/libavcodec/v410dec.c b/libavcodec/v410dec.c index 04be830ad2..d3747c18e0 100644 --- a/libavcodec/v410dec.c +++ b/libavcodec/v410dec.c @@ -46,6 +46,8 @@ static av_cold int v410_decode_init(AVCodecContext *avctx) } } + av_log(avctx, AV_LOG_WARNING, "This decoder is deprecated and will be removed.\n"); + return 0; } diff --git a/libavcodec/v410enc.c b/libavcodec/v410enc.c index 89ee3a7278..1350acebba 100644 --- a/libavcodec/v410enc.c +++ b/libavcodec/v410enc.c @@ -37,6 +37,8 @@ static av_cold int v410_encode_init(AVCodecContext *avctx) avctx->bits_per_coded_sample = 32; avctx->bit_rate = ff_guess_coded_bitrate(avctx); + av_log(avctx, AV_LOG_WARNING, "This encoder is deprecated and will be removed.\n"); + return 0; } @@ -82,5 +84,5 @@ const FFCodec ff_v410_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = v410_encode_init, FF_CODEC_ENCODE_CB(v410_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV444P10), }; diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index 23474ee143..7f597a424a 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -29,7 +29,7 @@ #include #include "libavcodec/avcodec.h" #include "libavutil/pixdesc.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "v4l2_context.h" #include "v4l2_buffers.h" #include "v4l2_m2m.h" @@ -210,6 +210,23 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) return AVCOL_TRC_UNSPECIFIED; } +static void v4l2_get_interlacing(AVFrame *frame, V4L2Buffer *buf) +{ + enum v4l2_field field = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? + buf->context->format.fmt.pix_mp.field : + buf->context->format.fmt.pix.field; + + switch (field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + /* fallthrough */ + case V4L2_FIELD_INTERLACED_BT: + frame->flags |= AV_FRAME_FLAG_INTERLACED; + break; + } +} + static void v4l2_free_buffer(void *opaque, uint8_t *unused) { V4L2Buffer* avbuf = opaque; @@ -230,7 +247,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) ff_v4l2_buffer_enqueue(avbuf); } - ff_refstruct_unref(&avbuf->context_ref); + av_refstruct_unref(&avbuf->context_ref); } } @@ -241,7 +258,7 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in) if (in->context_ref) atomic_fetch_add(&in->context_refcount, 1); else { - in->context_ref = ff_refstruct_ref(s->self_ref); + in->context_ref = av_refstruct_ref(s->self_ref); in->context_refcount = 1; } @@ -434,6 +451,7 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) frame->color_trc = v4l2_get_color_trc(avbuf); frame->pts = v4l2_get_pts(avbuf); frame->pkt_dts = AV_NOPTS_VALUE; + v4l2_get_interlacing(frame, avbuf); /* these values are updated also during re-init in v4l2_process_driver_event */ frame->height = avbuf->context->height; diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h index 6f7460c89a..fdd5cf5284 100644 --- a/libavcodec/v4l2_context.h +++ b/libavcodec/v4l2_context.h @@ -124,7 +124,7 @@ int ff_v4l2_context_get_format(V4L2Context* ctx, int probe); * Releases a V4L2Context. * * @param[in] ctx A pointer to a V4L2Context. - * The caller is reponsible for freeing it. + * The caller is responsible for freeing it. * It must not be used after calling this function. */ void ff_v4l2_context_release(V4L2Context* ctx); diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c index 15415cfc4e..8f633e2aeb 100644 --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c @@ -32,7 +32,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "v4l2_context.h" #include "v4l2_fmt.h" #include "v4l2_m2m.h" @@ -248,7 +248,7 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s) return 0; } -static void v4l2_m2m_destroy_context(FFRefStructOpaque unused, void *context) +static void v4l2_m2m_destroy_context(AVRefStructOpaque unused, void *context) { V4L2m2mContext *s = context; @@ -282,7 +282,7 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) ff_v4l2_context_release(&s->output); s->self_ref = NULL; - ff_refstruct_unref(&priv->context); + av_refstruct_unref(&priv->context); return 0; } @@ -327,7 +327,7 @@ int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv) int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) { - *s = ff_refstruct_alloc_ext(sizeof(**s), 0, NULL, + *s = av_refstruct_alloc_ext(sizeof(**s), 0, NULL, &v4l2_m2m_destroy_context); if (!*s) return AVERROR(ENOMEM); @@ -344,7 +344,7 @@ int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) priv->context->frame = av_frame_alloc(); if (!priv->context->frame) { - ff_refstruct_unref(&priv->context); + av_refstruct_unref(&priv->context); *s = NULL; /* freed when unreferencing context */ return AVERROR(ENOMEM); } diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index aa2d759e1e..ba1fe769e0 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -164,7 +164,7 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) if (!s->draining) { ret = v4l2_try_start(avctx); if (ret) { - /* cant recover */ + /* can't recover */ if (ret != AVERROR(ENOMEM)) ret = 0; goto fail; diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index 5770e87ea1..93703ccc63 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -187,7 +187,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s) return ret; /** - * settingss + * settings */ if (avctx->framerate.num || avctx->framerate.den) v4l2_set_timeperframe(s, avctx->framerate.den, avctx->framerate.num); diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c index 5451b6055b..b8f5472c14 100644 --- a/libavcodec/vaapi_av1.c +++ b/libavcodec/vaapi_av1.c @@ -74,7 +74,7 @@ static int8_t vaapi_av1_get_bit_depth_idx(AVCodecContext *avctx) return bit_depth == 8 ? 0 : bit_depth == 10 ? 1 : 2; } -static int vaapi_av1_decode_init(AVCodecContext *avctx) +static av_cold int vaapi_av1_decode_init(AVCodecContext *avctx) { VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data; @@ -92,7 +92,7 @@ static int vaapi_av1_decode_init(AVCodecContext *avctx) return ff_vaapi_decode_init(avctx); } -static int vaapi_av1_decode_uninit(AVCodecContext *avctx) +static av_cold int vaapi_av1_decode_uninit(AVCodecContext *avctx) { VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data; @@ -108,6 +108,7 @@ static int vaapi_av1_decode_uninit(AVCodecContext *avctx) static int vaapi_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index a59194340f..4ac2df5b43 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -39,12 +39,24 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, { VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; VAStatus vas; - VABufferID buffer; - av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS); + av_assert0(pic->nb_param_buffers <= pic->nb_param_buffers_allocated); + if (pic->nb_param_buffers == pic->nb_param_buffers_allocated) { + VABufferID *tmp = + av_realloc_array(pic->param_buffers, + pic->nb_param_buffers_allocated + 16, + sizeof(*pic->param_buffers)); + if (!tmp) + return AVERROR(ENOMEM); + + pic->param_buffers = tmp; + pic->nb_param_buffers_allocated += 16; + } + av_assert0(pic->nb_param_buffers + 1 <= pic->nb_param_buffers_allocated); vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, - type, size, 1, (void*)data, &buffer); + type, size, 1, (void*)data, + &pic->param_buffers[pic->nb_param_buffers]); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter " "buffer (type %d): %d (%s).\n", @@ -52,14 +64,14 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, return AVERROR(EIO); } - pic->param_buffers[pic->nb_param_buffers++] = buffer; - av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) " - "is %#x.\n", type, size, buffer); + "is %#x.\n", type, size, pic->param_buffers[pic->nb_param_buffers]); + + ++pic->nb_param_buffers; + return 0; } - int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, const void *params_data, @@ -72,19 +84,19 @@ int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAStatus vas; int index; - av_assert0(pic->nb_slices <= pic->slices_allocated); - if (pic->nb_slices == pic->slices_allocated) { + av_assert0(pic->nb_slices <= pic->nb_slice_buffers_allocated); + if (pic->nb_slices == pic->nb_slice_buffers_allocated) { VABufferID *tmp = av_realloc_array(pic->slice_buffers, - pic->slices_allocated ? pic->slices_allocated * 2 : 64, + pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64, 2 * sizeof(*pic->slice_buffers)); if (!tmp) return AVERROR(ENOMEM); - pic->slice_buffers = tmp; - pic->slices_allocated = pic->slices_allocated ? pic->slices_allocated * 2 : 64; + pic->slice_buffers = tmp; + pic->nb_slice_buffers_allocated = pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64; } - av_assert0(pic->nb_slices + 1 <= pic->slices_allocated); + av_assert0(pic->nb_slices + 1 <= pic->nb_slice_buffers_allocated); index = 2 * pic->nb_slices; @@ -222,9 +234,11 @@ fail: ff_vaapi_decode_destroy_buffers(avctx, pic); fail_at_end: exit: - pic->nb_param_buffers = 0; - pic->nb_slices = 0; - pic->slices_allocated = 0; + pic->nb_param_buffers = 0; + pic->nb_param_buffers_allocated = 0; + av_freep(&pic->param_buffers); + pic->nb_slices = 0; + pic->nb_slice_buffers_allocated = 0; av_freep(&pic->slice_buffers); return err; @@ -235,9 +249,11 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx, { ff_vaapi_decode_destroy_buffers(avctx, pic); - pic->nb_param_buffers = 0; - pic->nb_slices = 0; - pic->slices_allocated = 0; + pic->nb_param_buffers = 0; + pic->nb_param_buffers_allocated = 0; + av_freep(&pic->param_buffers); + pic->nb_slices = 0; + pic->nb_slice_buffers_allocated = 0; av_freep(&pic->slice_buffers); return 0; @@ -448,6 +464,9 @@ static const struct { MAP(AV1, AV1_MAIN, AV1Profile0), MAP(AV1, AV1_HIGH, AV1Profile1), #endif +#if VA_CHECK_VERSION(1, 22, 0) + MAP(H266, VVC_MAIN_10, VVCMain10), +#endif #undef MAP }; @@ -613,6 +632,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, // Add per-codec number of surfaces used for storing reference frames. switch (avctx->codec_id) { case AV_CODEC_ID_H264: + case AV_CODEC_ID_H266: case AV_CODEC_ID_HEVC: case AV_CODEC_ID_AV1: frames->initial_pool_size += 16; diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h index 702171e108..7813473c98 100644 --- a/libavcodec/vaapi_decode.h +++ b/libavcodec/vaapi_decode.h @@ -32,19 +32,16 @@ static inline VASurfaceID ff_vaapi_get_surface_id(AVFrame *pic) return (uintptr_t)pic->data[3]; } -enum { - MAX_PARAM_BUFFERS = 16, -}; - typedef struct VAAPIDecodePicture { VASurfaceID output_surface; int nb_param_buffers; - VABufferID param_buffers[MAX_PARAM_BUFFERS]; + VABufferID *param_buffers; + int nb_param_buffers_allocated; int nb_slices; VABufferID *slice_buffers; - int slices_allocated; + int nb_slice_buffers_allocated; } VAAPIDecodePicture; typedef struct VAAPIDecodeContext { diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 16a9a364f0..8960e6b20a 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -31,7 +31,7 @@ #include "vaapi_encode.h" #include "encode.h" #include "avcodec.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI), @@ -316,7 +316,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->recon_surface = (VASurfaceID)(uintptr_t)base_pic->recon_image->data[3]; av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); - pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool); + pic->output_buffer_ref = av_refstruct_pool_get(ctx->output_buffer_pool); if (!pic->output_buffer_ref) { err = AVERROR(ENOMEM); goto fail; @@ -649,7 +649,7 @@ fail_at_end: av_freep(&pic->param_buffers); av_freep(&pic->slices); av_freep(&pic->roi); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return err; } @@ -759,8 +759,8 @@ static int vaapi_encode_get_coded_data(AVCodecContext *avctx, goto end; end: - ff_refstruct_unref(&ctx->coded_buffer_ref); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&ctx->coded_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return ret; @@ -781,7 +781,7 @@ static int vaapi_encode_output(AVCodecContext *avctx, if (pic->non_independent_frame) { av_assert0(!ctx->coded_buffer_ref); - ctx->coded_buffer_ref = ff_refstruct_ref(pic->output_buffer_ref); + ctx->coded_buffer_ref = av_refstruct_ref(pic->output_buffer_ref); if (pic->tail_size) { if (base_ctx->tail_pkt->size) { @@ -809,7 +809,7 @@ static int vaapi_encode_output(AVCodecContext *avctx, ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY); end: - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return err; } @@ -825,7 +825,7 @@ static int vaapi_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *ba "%"PRId64"/%"PRId64".\n", base_pic->display_order, base_pic->encode_order); - ff_refstruct_unref(&pic->output_buffer_ref); + av_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; } @@ -1133,6 +1133,68 @@ fail: return err; } +static av_cold int vaapi_encode_surface_alignment(av_unused AVCodecContext *avctx) +{ +#if VA_CHECK_VERSION(1, 21, 0) + VAAPIEncodeContext *ctx = avctx->priv_data; + VASurfaceAttrib *attr_list = NULL; + unsigned int attr_count = 0; + VAConfigID va_config; + VAStatus vas; + int err = 0; + + vas = vaCreateConfig(ctx->hwctx->display, + ctx->va_profile, ctx->va_entrypoint, + NULL, 0, &va_config); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create temp encode pipeline " + "configuration: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config, + 0, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; + goto fail; + } + + attr_list = av_malloc(attr_count * sizeof(*attr_list)); + if (!attr_list) { + err = AVERROR(ENOMEM); + goto fail; + } + + vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config, + attr_list, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; + goto fail; + } + + for (unsigned int i = 0; i < attr_count; i++) { + if (attr_list[i].type == VASurfaceAttribAlignmentSize) { + ctx->surface_alignment_width = + 1 << (attr_list[i].value.value.i & 0xf); + ctx->surface_alignment_height = + 1 << ((attr_list[i].value.value.i & 0xf0) >> 4); + break; + } + } + +fail: + av_freep(&attr_list); + vaDestroyConfig(ctx->hwctx->display, va_config); + return err; +#else + return 0; +#endif +} + static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = { // Bitrate Quality // | Maxrate | HRD/VBV @@ -1987,7 +2049,7 @@ static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx) return 0; } -static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque, +static void vaapi_encode_free_output_buffer(AVRefStructOpaque opaque, void *obj) { AVCodecContext *avctx = opaque.nc; @@ -2000,7 +2062,7 @@ static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque, av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id); } -static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj) +static int vaapi_encode_alloc_output_buffer(AVRefStructOpaque opaque, void *obj) { AVCodecContext *avctx = opaque.nc; FFHWBaseEncodeContext *base_ctx = avctx->priv_data; @@ -2111,6 +2173,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; + err = vaapi_encode_surface_alignment(avctx); + if (err < 0) + goto fail; + if (ctx->codec->get_encoder_caps) { err = ctx->codec->get_encoder_caps(avctx); if (err < 0) @@ -2187,7 +2253,7 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) } ctx->output_buffer_pool = - ff_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx, + av_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx, &vaapi_encode_alloc_output_buffer, NULL, vaapi_encode_free_output_buffer, NULL); if (!ctx->output_buffer_pool) { @@ -2288,7 +2354,7 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) vaapi_encode_free(avctx, pic); } - ff_refstruct_pool_uninit(&ctx->output_buffer_pool); + av_refstruct_pool_uninit(&ctx->output_buffer_pool); if (ctx->va_context != VA_INVALID_ID) { if (ctx->hwctx) diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index c4f85397a2..8e3eab9f27 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -202,7 +202,7 @@ typedef struct VAAPIEncodeContext { AVVAAPIDeviceContext *hwctx; // Pool of (reusable) bitstream output buffers. - struct FFRefStructPool *output_buffer_pool; + struct AVRefStructPool *output_buffer_pool; // Global parameters which will be applied at the start of the // sequence (includes rate control parameters below). @@ -260,6 +260,10 @@ typedef struct VAAPIEncodeContext { * This is a RefStruct reference. */ VABufferID *coded_buffer_ref; + + // Surface alignment required by driver. + int surface_alignment_width; + int surface_alignment_height; } VAAPIEncodeContext; typedef struct VAAPIEncodeType { diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c index 1b350cd936..9d837f5c6b 100644 --- a/libavcodec/vaapi_encode_av1.c +++ b/libavcodec/vaapi_encode_av1.c @@ -476,6 +476,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, AV1RawFrameHeader *fh = &fh_obu->obu.frame.header; VAEncPictureParameterBufferAV1 *vpic = vaapi_pic->codec_picture_params; CodedBitstreamFragment *obu = &priv->current_obu; + CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; FFHWBaseEncodePicture *ref; VAAPIEncodeAV1Picture *href; int slot, i; @@ -523,6 +524,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, fh->ref_frame_idx[3] = href->slot; fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN; + } else { + fh->ref_order_hint[!href->slot] = cbctx->ref[!href->slot].order_hint; } break; case FF_HW_PICTURE_TYPE_B: @@ -1024,6 +1027,7 @@ static const FFCodecDefault vaapi_encode_av1_defaults[] = { { "g", "120" }, { "qmin", "1" }, { "qmax", "255" }, + { "refs", "0" }, { NULL }, }; @@ -1049,10 +1053,7 @@ const FFCodec ff_av1_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_av1_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index fb87b68bec..27f6551719 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -406,6 +406,9 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) { FFHWBaseEncodeContext *base_ctx = avctx->priv_data; +#if !CONFIG_VAAPI_1 + VAAPIEncodeContext *ctx = avctx->priv_data; +#endif VAAPIEncodeH264Context *priv = avctx->priv_data; VAAPIEncodePicture *vaapi_pic = pic->priv; VAAPIEncodeH264Picture *hpic = pic->codec_priv; @@ -1150,6 +1153,7 @@ static const FFCodecDefault vaapi_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1175,10 +1179,7 @@ const FFCodec ff_h264_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_h264_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 2283bcc0b4..baf0d77c8a 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -526,7 +526,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, priv->sei_needed = 0; // Only look for the metadata on I/IDR frame on the output. We - // may force an IDR frame on the output where the medadata gets + // may force an IDR frame on the output where the metadata gets // changed on the input frame. if ((priv->sei & SEI_MASTERING_DISPLAY) && (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { @@ -951,8 +951,10 @@ static av_cold int vaapi_encode_h265_get_encoder_caps(AVCodecContext *avctx) "min CB size %dx%d.\n", priv->ctu_size, priv->ctu_size, priv->min_cb_size, priv->min_cb_size); - base_ctx->surface_width = FFALIGN(avctx->width, priv->min_cb_size); - base_ctx->surface_height = FFALIGN(avctx->height, priv->min_cb_size); + base_ctx->surface_width = FFALIGN(avctx->width, + FFMAX(priv->min_cb_size, priv->common.surface_alignment_width)); + base_ctx->surface_height = FFALIGN(avctx->height, + FFMAX(priv->min_cb_size, priv->common.surface_alignment_height)); base_ctx->slice_block_width = base_ctx->slice_block_height = priv->ctu_size; @@ -1182,6 +1184,7 @@ static const FFCodecDefault vaapi_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1207,10 +1210,7 @@ const FFCodec ff_hevc_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_h265_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 5f8266e98a..2eef5bf090 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -582,10 +582,7 @@ const FFCodec ff_mjpeg_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_mjpeg_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 5701e2e803..94cb3d4fb6 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -705,10 +705,7 @@ const FFCodec ff_mpeg2_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_mpeg2_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index ad88af63eb..69a56a17af 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -235,6 +235,7 @@ static const FFCodecDefault vaapi_encode_vp8_defaults[] = { { "g", "120" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -260,10 +261,7 @@ const FFCodec ff_vp8_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_vp8_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index ab925e24b5..ca8de541d9 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -292,6 +292,7 @@ static const FFCodecDefault vaapi_encode_vp9_defaults[] = { { "g", "250" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -318,10 +319,7 @@ const FFCodec ff_vp9_vaapi_encoder = { FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_vp9_defaults, .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VAAPI, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VAAPI), .hw_configs = ff_vaapi_encode_hw_configs, .p.wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 398e92568c..7f00da09fc 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -232,6 +232,7 @@ static void fill_vaapi_plain_pred_weight_table(const H264Context *h, /** Initialize and start decoding a frame with VA API. */ static int vaapi_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 0c5a829220..878f7965c4 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -122,6 +122,7 @@ static void fill_vaapi_reference_frames(const HEVCContext *h, const HEVCLayerCon } static int vaapi_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c index 9557cf5f9b..c8b59b8afa 100644 --- a/libavcodec/vaapi_mjpeg.c +++ b/libavcodec/vaapi_mjpeg.c @@ -24,6 +24,7 @@ #include "mjpegdec.h" static int vaapi_mjpeg_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c index d4304dfdd1..925f0db1ba 100644 --- a/libavcodec/vaapi_mpeg2.c +++ b/libavcodec/vaapi_mpeg2.c @@ -39,7 +39,10 @@ static inline int mpeg2_get_is_frame_start(const MpegEncContext *s) return s->first_field || s->picture_structure == PICT_FRAME; } -static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const MpegEncContext *s = avctx->priv_data; VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c index 2c9dfbe42f..d936a290cd 100644 --- a/libavcodec/vaapi_mpeg4.c +++ b/libavcodec/vaapi_mpeg4.c @@ -45,10 +45,13 @@ static int mpeg4_get_intra_dc_vlc_thr(Mpeg4DecContext *s) return 0; } -static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext *s = &ctx->m; + MPVContext *const s = &ctx->h.c; VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VAPictureParameterBufferMPEG4 pic_param; int i, err; @@ -67,9 +70,9 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ .obmc_disable = 1, .sprite_enable = ctx->vol_sprite_usage, .sprite_warping_accuracy = ctx->sprite_warping_accuracy, - .quant_type = s->mpeg_quant, + .quant_type = ctx->mpeg_quant, .quarter_sample = s->quarter_sample, - .data_partitioned = s->data_partitioning, + .data_partitioned = ctx->h.data_partitioning, .reversible_vlc = ctx->rvlc, .resync_marker_disable = !ctx->resync_marker, }, @@ -84,8 +87,8 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ .top_field_first = s->top_field_first, .alternate_vertical_scan_flag = s->alternate_scan, }, - .vop_fcode_forward = s->f_code, - .vop_fcode_backward = s->b_code, + .vop_fcode_forward = ctx->f_code, + .vop_fcode_backward = ctx->b_code, .vop_time_increment_resolution = avctx->framerate.num, .num_macroblocks_in_gob = s->mb_width * H263_GOB_HEIGHT(s->height), .num_gobs_in_vop = @@ -154,8 +157,8 @@ fail: static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { - MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; + H263DecContext *const h = avctx->priv_data; + VAAPIDecodePicture *pic = h->c.cur_pic.ptr->hwaccel_picture_private; VASliceParameterBufferMPEG4 slice_param; int err; @@ -163,9 +166,9 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, - .macroblock_offset = get_bits_count(&s->gb) % 8, + .macroblock_offset = get_bits_count(&h->gb) % 8, .macroblock_number = 0, - .quant_scale = s->qscale, + .quant_scale = h->c.qscale, }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 7d001882fd..a3dd3140e2 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -249,7 +249,10 @@ static inline void vc1_pack_bitplanes(uint8_t *bitplane, int n, const uint8_t *f bitplane[bitplane_index] = (bitplane[bitplane_index] << 4) | v; } -static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) +static int vaapi_vc1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; @@ -282,7 +285,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .broken_link = v->broken_link, .closed_entry = v->closed_entry, .panscan_flag = v->panscanflag, - .loopfilter = s->loop_filter, + .loopfilter = v->loop_filter, }, .conditional_overlap_flag = v->condover, .fast_uvmc_flag = v->fastuvmc, @@ -340,7 +343,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .mv_fields.bits = { .mv_mode = vc1_get_MVMODE(v), .mv_mode2 = vc1_get_MVMODE2(v), - .mv_table = (v->fcm == PROGRESSIVE ? s->mv_table_index : v->imvtab), + .mv_table = (v->fcm == PROGRESSIVE ? v->mv_table_index : v->imvtab), .two_mv_block_pattern_table = v->twomvbptab, .four_mv_switch = v->fourmvswitch, .four_mv_block_pattern_table = v->fourmvbptab, @@ -368,7 +371,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .frame_level_transform_type = vc1_get_TTFRM(v), .transform_ac_codingset_idx1 = v->c_ac_table_index, .transform_ac_codingset_idx2 = v->y_ac_table_index, - .intra_transform_dc_table = v->s.dc_table_index, + .intra_transform_dc_table = v->dc_table_index, }, }; @@ -487,7 +490,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, - .macroblock_offset = get_bits_count(&s->gb), + .macroblock_offset = get_bits_count(&v->gb), .slice_vertical_position = s->mb_y % mb_height, }; diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c index 66fdde1f39..b9b1f2aa51 100644 --- a/libavcodec/vaapi_vp8.c +++ b/libavcodec/vaapi_vp8.c @@ -32,6 +32,7 @@ static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf) } static int vaapi_vp8_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c index a28fc75a59..7d57f340e0 100644 --- a/libavcodec/vaapi_vp9.c +++ b/libavcodec/vaapi_vp9.c @@ -35,6 +35,7 @@ static VASurfaceID vaapi_vp9_surface_id(const VP9Frame *vf) } static int vaapi_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c new file mode 100644 index 0000000000..908db7bfab --- /dev/null +++ b/libavcodec/vaapi_vvc.c @@ -0,0 +1,658 @@ +/* + * VVC HW decode acceleration through VA API + * + * Copyright (c) 2024 Intel Corporation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "vvc/dec.h" +#include "vvc/refs.h" +#include "hwaccel_internal.h" +#include "vaapi_decode.h" + +typedef struct VAAPIDecodePictureVVC { + VAAPIDecodePicture pic; + VAPictureParameterBufferVVC pic_param; + VASliceParameterBufferVVC slice_param; + int decode_issued; +} VAAPIDecodePictureVVC; + +static void init_vaapi_pic(VAPictureVVC *va_pic) +{ + va_pic->picture_id = VA_INVALID_ID; + va_pic->flags = VA_PICTURE_VVC_INVALID; + va_pic->pic_order_cnt = 0; +} + +static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame *pic) +{ + va_pic->picture_id = ff_vaapi_get_surface_id(pic->frame); + va_pic->pic_order_cnt = pic->poc; + va_pic->flags = 0; + + if (pic->flags & VVC_FRAME_FLAG_LONG_REF) + va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE; +} + +static void fill_vaapi_reference_frames(const VVCFrameContext *h, VAPictureParameterBufferVVC *pp) +{ + const VVCFrame *current_picture = h->ref; + int i, j; + + for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) { + const VVCFrame *frame = NULL; + + while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) { + if ((&h->DPB[j] != current_picture ) && + (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF | VVC_FRAME_FLAG_SHORT_REF))) + frame = &h->DPB[j]; + j++; + } + + init_vaapi_pic(&pp->ReferenceFrames[i]); + + if (frame) { + VAAPIDecodePictureVVC *pic; + fill_vaapi_pic(&pp->ReferenceFrames[i], frame); + pic = frame->hwaccel_picture_private; + if (!pic->decode_issued) + pp->ReferenceFrames[i].flags |= VA_PICTURE_VVC_UNAVAILABLE_REFERENCE; + } + } +} + +static int vaapi_vvc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + const H266RawSPS *sps = fc->ps.sps->r; + const H266RawPPS *pps = fc->ps.pps->r; + const H266RawPictureHeader *ph = fc->ps.ph.r; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VAPictureParameterBufferVVC *pic_param = &pic->pic_param; + uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] = {0}; + int i, j, k, err; + + pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref->frame); + + *pic_param = (VAPictureParameterBufferVVC) { + .pps_pic_width_in_luma_samples = pps->pps_pic_width_in_luma_samples, + .pps_pic_height_in_luma_samples = pps->pps_pic_height_in_luma_samples, + .sps_num_subpics_minus1 = sps->sps_num_subpics_minus1, + .sps_chroma_format_idc = sps->sps_chroma_format_idc, + .sps_bitdepth_minus8 = sps->sps_bitdepth_minus8, + .sps_log2_ctu_size_minus5 = sps->sps_log2_ctu_size_minus5, + .sps_log2_min_luma_coding_block_size_minus2 = sps->sps_log2_min_luma_coding_block_size_minus2, + .sps_log2_transform_skip_max_size_minus2 = sps->sps_log2_transform_skip_max_size_minus2, + .sps_six_minus_max_num_merge_cand = sps->sps_six_minus_max_num_merge_cand, + .sps_five_minus_max_num_subblock_merge_cand = sps->sps_five_minus_max_num_subblock_merge_cand, + .sps_max_num_merge_cand_minus_max_num_gpm_cand = sps->sps_max_num_merge_cand_minus_max_num_gpm_cand, + .sps_log2_parallel_merge_level_minus2 = sps->sps_log2_parallel_merge_level_minus2, + .sps_min_qp_prime_ts = sps->sps_min_qp_prime_ts, + .sps_six_minus_max_num_ibc_merge_cand = sps->sps_six_minus_max_num_ibc_merge_cand, + .sps_num_ladf_intervals_minus2 = sps->sps_num_ladf_intervals_minus2, + .sps_ladf_lowest_interval_qp_offset = sps->sps_ladf_lowest_interval_qp_offset, + .sps_flags.bits = { + .sps_subpic_info_present_flag = sps->sps_subpic_info_present_flag, + .sps_independent_subpics_flag = sps->sps_independent_subpics_flag, + .sps_subpic_same_size_flag = sps->sps_subpic_same_size_flag, + .sps_entropy_coding_sync_enabled_flag = sps->sps_entropy_coding_sync_enabled_flag, + .sps_qtbtt_dual_tree_intra_flag = sps->sps_qtbtt_dual_tree_intra_flag, + .sps_max_luma_transform_size_64_flag = sps->sps_max_luma_transform_size_64_flag, + .sps_transform_skip_enabled_flag = sps->sps_transform_skip_enabled_flag, + .sps_bdpcm_enabled_flag = sps->sps_bdpcm_enabled_flag, + .sps_mts_enabled_flag = sps->sps_mts_enabled_flag, + .sps_explicit_mts_intra_enabled_flag = sps->sps_explicit_mts_intra_enabled_flag, + .sps_explicit_mts_inter_enabled_flag = sps->sps_explicit_mts_inter_enabled_flag, + .sps_lfnst_enabled_flag = sps->sps_lfnst_enabled_flag, + .sps_joint_cbcr_enabled_flag = sps->sps_joint_cbcr_enabled_flag, + .sps_same_qp_table_for_chroma_flag = sps->sps_same_qp_table_for_chroma_flag, + .sps_sao_enabled_flag = sps->sps_sao_enabled_flag, + .sps_alf_enabled_flag = sps->sps_alf_enabled_flag, + .sps_ccalf_enabled_flag = sps->sps_ccalf_enabled_flag, + .sps_lmcs_enabled_flag = sps->sps_lmcs_enabled_flag, + .sps_sbtmvp_enabled_flag = sps->sps_sbtmvp_enabled_flag, + .sps_amvr_enabled_flag = sps->sps_amvr_enabled_flag, + .sps_smvd_enabled_flag = sps->sps_smvd_enabled_flag, + .sps_mmvd_enabled_flag = sps->sps_mmvd_enabled_flag, + .sps_sbt_enabled_flag = sps->sps_sbt_enabled_flag, + .sps_affine_enabled_flag = sps->sps_affine_enabled_flag, + .sps_6param_affine_enabled_flag = sps->sps_6param_affine_enabled_flag, + .sps_affine_amvr_enabled_flag = sps->sps_affine_amvr_enabled_flag, + .sps_affine_prof_enabled_flag = sps->sps_affine_prof_enabled_flag, + .sps_bcw_enabled_flag = sps->sps_bcw_enabled_flag, + .sps_ciip_enabled_flag = sps->sps_ciip_enabled_flag, + .sps_gpm_enabled_flag = sps->sps_gpm_enabled_flag, + .sps_isp_enabled_flag = sps->sps_isp_enabled_flag, + .sps_mrl_enabled_flag = sps->sps_mrl_enabled_flag, + .sps_mip_enabled_flag = sps->sps_mip_enabled_flag, + .sps_cclm_enabled_flag = sps->sps_cclm_enabled_flag, + .sps_chroma_horizontal_collocated_flag = sps->sps_chroma_horizontal_collocated_flag, + .sps_chroma_vertical_collocated_flag = sps->sps_chroma_vertical_collocated_flag, + .sps_palette_enabled_flag = sps->sps_palette_enabled_flag, + .sps_act_enabled_flag = sps->sps_act_enabled_flag, + .sps_ibc_enabled_flag = sps->sps_ibc_enabled_flag, + .sps_ladf_enabled_flag = sps->sps_ladf_enabled_flag, + .sps_explicit_scaling_list_enabled_flag = sps->sps_explicit_scaling_list_enabled_flag, + .sps_scaling_matrix_for_lfnst_disabled_flag = sps->sps_scaling_matrix_for_lfnst_disabled_flag, + .sps_scaling_matrix_for_alternative_colour_space_disabled_flag = sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag, + .sps_scaling_matrix_designated_colour_space_flag = sps->sps_scaling_matrix_designated_colour_space_flag, + .sps_virtual_boundaries_enabled_flag = sps->sps_virtual_boundaries_enabled_flag, + .sps_virtual_boundaries_present_flag = sps->sps_virtual_boundaries_present_flag, + }, + .NumVerVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ? + sps->sps_num_ver_virtual_boundaries : + ph->ph_num_ver_virtual_boundaries, + .NumHorVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ? + sps->sps_num_hor_virtual_boundaries : + ph->ph_num_hor_virtual_boundaries, + .pps_scaling_win_left_offset = pps->pps_scaling_win_left_offset, + .pps_scaling_win_right_offset = pps->pps_scaling_win_right_offset, + .pps_scaling_win_top_offset = pps->pps_scaling_win_top_offset, + .pps_scaling_win_bottom_offset = pps->pps_scaling_win_bottom_offset, + .pps_num_exp_tile_columns_minus1 = pps->pps_num_exp_tile_columns_minus1, + .pps_num_exp_tile_rows_minus1 = pps->pps_num_exp_tile_rows_minus1, + .pps_num_slices_in_pic_minus1 = pps->pps_num_slices_in_pic_minus1, + .pps_pic_width_minus_wraparound_offset = pps->pps_pic_width_minus_wraparound_offset, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + .pps_joint_cbcr_qp_offset_value = pps->pps_joint_cbcr_qp_offset_value, + .pps_chroma_qp_offset_list_len_minus1 = pps->pps_chroma_qp_offset_list_len_minus1, + .pps_flags.bits = { + .pps_loop_filter_across_tiles_enabled_flag = pps->pps_loop_filter_across_tiles_enabled_flag, + .pps_rect_slice_flag = pps->pps_rect_slice_flag, + .pps_single_slice_per_subpic_flag = pps->pps_single_slice_per_subpic_flag, + .pps_loop_filter_across_slices_enabled_flag = pps->pps_loop_filter_across_slices_enabled_flag, + .pps_weighted_pred_flag = pps->pps_weighted_pred_flag, + .pps_weighted_bipred_flag = pps->pps_weighted_bipred_flag, + .pps_ref_wraparound_enabled_flag = pps->pps_ref_wraparound_enabled_flag, + .pps_cu_qp_delta_enabled_flag = pps->pps_cu_qp_delta_enabled_flag, + .pps_cu_chroma_qp_offset_list_enabled_flag = pps->pps_cu_chroma_qp_offset_list_enabled_flag, + .pps_deblocking_filter_override_enabled_flag = pps->pps_deblocking_filter_override_enabled_flag, + .pps_deblocking_filter_disabled_flag = pps->pps_deblocking_filter_disabled_flag, + .pps_dbf_info_in_ph_flag = pps->pps_dbf_info_in_ph_flag, + .pps_sao_info_in_ph_flag = pps->pps_sao_info_in_ph_flag, + .pps_alf_info_in_ph_flag = pps->pps_alf_info_in_ph_flag, + }, + .ph_lmcs_aps_id = ph->ph_lmcs_aps_id, + .ph_scaling_list_aps_id = ph->ph_scaling_list_aps_id, + .ph_log2_diff_min_qt_min_cb_intra_slice_luma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma, + .ph_max_mtt_hierarchy_depth_intra_slice_luma = ph->ph_max_mtt_hierarchy_depth_intra_slice_luma, + .ph_log2_diff_max_bt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma, + .ph_log2_diff_max_tt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma, + .ph_log2_diff_min_qt_min_cb_intra_slice_chroma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma, + .ph_max_mtt_hierarchy_depth_intra_slice_chroma = ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma, + .ph_log2_diff_max_bt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma, + .ph_log2_diff_max_tt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma, + .ph_cu_qp_delta_subdiv_intra_slice = ph->ph_cu_qp_delta_subdiv_intra_slice, + .ph_cu_chroma_qp_offset_subdiv_intra_slice = ph->ph_cu_chroma_qp_offset_subdiv_intra_slice, + .ph_log2_diff_min_qt_min_cb_inter_slice = ph->ph_log2_diff_min_qt_min_cb_inter_slice, + .ph_max_mtt_hierarchy_depth_inter_slice = ph->ph_max_mtt_hierarchy_depth_inter_slice, + .ph_log2_diff_max_bt_min_qt_inter_slice = ph->ph_log2_diff_max_bt_min_qt_inter_slice, + .ph_log2_diff_max_tt_min_qt_inter_slice = ph->ph_log2_diff_max_tt_min_qt_inter_slice, + .ph_cu_qp_delta_subdiv_inter_slice = ph->ph_cu_qp_delta_subdiv_inter_slice, + .ph_cu_chroma_qp_offset_subdiv_inter_slice = ph->ph_cu_chroma_qp_offset_subdiv_inter_slice, + .ph_flags.bits= { + .ph_non_ref_pic_flag = ph->ph_non_ref_pic_flag, + .ph_alf_enabled_flag = ph->ph_alf_enabled_flag, + .ph_alf_cb_enabled_flag = ph->ph_alf_cb_enabled_flag, + .ph_alf_cr_enabled_flag = ph->ph_alf_cr_enabled_flag, + .ph_alf_cc_cb_enabled_flag = ph->ph_alf_cc_cb_enabled_flag, + .ph_alf_cc_cr_enabled_flag = ph->ph_alf_cc_cr_enabled_flag, + .ph_lmcs_enabled_flag = ph->ph_lmcs_enabled_flag, + .ph_chroma_residual_scale_flag = ph->ph_chroma_residual_scale_flag, + .ph_explicit_scaling_list_enabled_flag = ph->ph_explicit_scaling_list_enabled_flag, + .ph_virtual_boundaries_present_flag = ph->ph_virtual_boundaries_present_flag, + .ph_temporal_mvp_enabled_flag = ph->ph_temporal_mvp_enabled_flag, + .ph_mmvd_fullpel_only_flag = ph->ph_mmvd_fullpel_only_flag, + .ph_mvd_l1_zero_flag = ph->ph_mvd_l1_zero_flag, + .ph_bdof_disabled_flag = ph->ph_bdof_disabled_flag, + .ph_dmvr_disabled_flag = ph->ph_dmvr_disabled_flag, + .ph_prof_disabled_flag = ph->ph_prof_disabled_flag, + .ph_joint_cbcr_sign_flag = ph->ph_joint_cbcr_sign_flag, + .ph_sao_luma_enabled_flag = ph->ph_sao_luma_enabled_flag, + .ph_sao_chroma_enabled_flag = ph->ph_sao_chroma_enabled_flag, + .ph_deblocking_filter_disabled_flag = ph->ph_deblocking_filter_disabled_flag, + }, + .PicMiscFlags.fields = { + .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag ? 0 : IS_IRAP(h) ? 1 : 0, + } + }; + + fill_vaapi_pic(&pic_param->CurrPic, fc->ref); + fill_vaapi_reference_frames(fc, pic_param); + + for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) + for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++) + pic_param->ChromaQpTable[i][j] = fc->ps.sps->chroma_qp_table[i][j]; + for (i = 0; i < 4; i++) { + pic_param->sps_ladf_qp_offset[i] = sps->sps_ladf_qp_offset[i]; + pic_param->sps_ladf_delta_threshold_minus1[i] = sps->sps_ladf_delta_threshold_minus1[i]; + } + + for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_ver_virtual_boundaries : ph->ph_num_ver_virtual_boundaries); i++) { + pic_param->VirtualBoundaryPosX[i] = (sps->sps_virtual_boundaries_present_flag ? + (sps->sps_virtual_boundary_pos_x_minus1[i] + 1) : + (ph->ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8; + } + + for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_hor_virtual_boundaries : ph->ph_num_hor_virtual_boundaries); i++) { + pic_param->VirtualBoundaryPosY[i] = (sps->sps_virtual_boundaries_present_flag ? + (sps->sps_virtual_boundary_pos_y_minus1[i] + 1) : + (ph->ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8; + } + + for (i = 0; i < 6; i++) { + pic_param->pps_cb_qp_offset_list[i] = pps->pps_cb_qp_offset_list[i]; + pic_param->pps_cr_qp_offset_list[i] = pps->pps_cr_qp_offset_list[i]; + pic_param->pps_joint_cbcr_qp_offset_list[i] = pps->pps_joint_cbcr_qp_offset_list[i]; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAPictureParameterBufferType, + &pic->pic_param, sizeof(VAPictureParameterBufferVVC)); + if (err < 0) + goto fail; + + for (i = 0; i <= sps->sps_num_subpics_minus1 && sps->sps_subpic_info_present_flag; i++) { + VASubPicVVC subpic_param = { + .sps_subpic_ctu_top_left_x = sps->sps_subpic_ctu_top_left_x[i], + .sps_subpic_ctu_top_left_y = sps->sps_subpic_ctu_top_left_y[i], + .sps_subpic_width_minus1 = sps->sps_subpic_width_minus1[i], + .sps_subpic_height_minus1 = sps->sps_subpic_height_minus1[i], + .SubpicIdVal = pps->sub_pic_id_val[i], + .subpic_flags.bits = { + .sps_subpic_treated_as_pic_flag = sps->sps_subpic_treated_as_pic_flag[i], + .sps_loop_filter_across_subpic_enabled_flag = sps->sps_loop_filter_across_subpic_enabled_flag[i], + } + }; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VASubPicBufferType, + &subpic_param, sizeof(VASubPicVVC)); + if (err < 0) + goto fail; + } + + for (i = 0; i < VVC_MAX_ALF_COUNT; i++) { + const VVCALF *alf_list = h->ps.alf_list[i]; + if (alf_list) { + const H266RawAPS *alf = alf_list->r; + VAAlfDataVVC alf_param = { + .aps_adaptation_parameter_set_id = i, + .alf_luma_num_filters_signalled_minus1 = alf->alf_luma_num_filters_signalled_minus1, + .alf_chroma_num_alt_filters_minus1 = alf->alf_chroma_num_alt_filters_minus1, + .alf_cc_cb_filters_signalled_minus1 = alf->alf_cc_cb_filters_signalled_minus1, + .alf_cc_cr_filters_signalled_minus1 = alf->alf_cc_cr_filters_signalled_minus1, + .alf_flags.bits = { + .alf_luma_filter_signal_flag = alf->alf_luma_filter_signal_flag, + .alf_chroma_filter_signal_flag = alf->alf_chroma_filter_signal_flag, + .alf_cc_cb_filter_signal_flag = alf->alf_cc_cb_filter_signal_flag, + .alf_cc_cr_filter_signal_flag = alf->alf_cc_cr_filter_signal_flag, + .alf_luma_clip_flag = alf->alf_luma_clip_flag, + .alf_chroma_clip_flag = alf->alf_chroma_clip_flag, + } + }; + + for (j = 0; j < 25; j++) + alf_param.alf_luma_coeff_delta_idx[j] = alf->alf_luma_coeff_delta_idx[j]; + + for (j = 0; j < 25; j++) { + for (k = 0; k < 12; k++) { + alf_param.filtCoeff[j][k] = alf->alf_luma_coeff_abs[j][k] * (1 - 2 * alf->alf_luma_coeff_sign[j][k]); + alf_param.alf_luma_clip_idx[j][k] = alf->alf_luma_clip_idx[j][k]; + } + } + + for (j = 0; j < 8; j++) { + for (k = 0; k < 6; k++) { + alf_param.AlfCoeffC[j][k] = alf->alf_chroma_coeff_abs[j][k] * (1 - 2 * alf->alf_chroma_coeff_sign[j][k]); + alf_param.alf_chroma_clip_idx[j][k] = alf->alf_chroma_clip_idx[j][k]; + } + } + + for (j = 0; j < 4; j++) { + for (k = 0; k < 7; k++) { + if (alf->alf_cc_cb_mapped_coeff_abs[j][k]) + alf_param.CcAlfApsCoeffCb[j][k] = (1 - 2 * alf->alf_cc_cb_coeff_sign[j][k]) * (1 << (alf->alf_cc_cb_mapped_coeff_abs[j][k] - 1)); + if (alf->alf_cc_cr_mapped_coeff_abs[j][k]) + alf_param.CcAlfApsCoeffCr[j][k] = (1 - 2 * alf->alf_cc_cr_coeff_sign[j][k]) * (1 << (alf->alf_cc_cr_mapped_coeff_abs[j][k] - 1)); + } + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAAlfBufferType, + &alf_param, sizeof(VAAlfDataVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) { + const H266RawAPS *lmcs = h->ps.lmcs_list[i]; + if (lmcs) { + VALmcsDataVVC lmcs_param = { + .aps_adaptation_parameter_set_id = i, + .lmcs_min_bin_idx = lmcs->lmcs_min_bin_idx, + .lmcs_delta_max_bin_idx = lmcs->lmcs_delta_max_bin_idx, + .lmcsDeltaCrs = (1 - 2 * lmcs->lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs, + }; + + for (j = lmcs->lmcs_min_bin_idx; j <= 15 - lmcs->lmcs_delta_max_bin_idx; j++) + lmcs_param.lmcsDeltaCW[j] = (1 - 2 * lmcs->lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j]; + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VALmcsBufferType, + &lmcs_param, sizeof(VALmcsDataVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i < VVC_MAX_SL_COUNT; i++) { + const VVCScalingList *sl = h->ps.scaling_list[i]; + if (sl) { + int l; + + VAScalingListVVC sl_param = { + .aps_adaptation_parameter_set_id = i, + }; + + for (j = 0; j < 14; j++) + sl_param.ScalingMatrixDCRec[j] = sl->scaling_matrix_dc_rec[j]; + + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + for (l = 0; l < 2; l++) + sl_param.ScalingMatrixRec2x2[j][k][l] = sl->scaling_matrix_rec[j][l * 2 + k]; + + for (j = 2; j < 8; j++) + for (k = 0; k < 4; k++) + for (l = 0; l < 4; l++) + sl_param.ScalingMatrixRec4x4[j - 2][k][l] = sl->scaling_matrix_rec[j][l * 4 + k]; + + for (j = 8; j < 28; j++) + for (k = 0; k < 8; k++) + for (l = 0; l < 8; l++) + sl_param.ScalingMatrixRec8x8[j - 8][k][l] = sl->scaling_matrix_rec[j][l * 8 + k]; + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VAIQMatrixBufferType, + &sl_param, sizeof(VAScalingListVVC)); + if (err < 0) + goto fail; + } + } + + for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) { + tile_dim = pps->pps_tile_column_width_minus1[i]; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VATileBufferType, + &tile_dim, sizeof(tile_dim)); + if (err < 0) + goto fail; + } + + for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) { + tile_dim = pps->pps_tile_row_height_minus1[i]; + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VATileBufferType, + &tile_dim, sizeof(tile_dim)); + if (err < 0) + goto fail; + } + + if (!pps->pps_no_pic_partition_flag && pps->pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) { + for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) { + for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) { + exp_slice_height_in_ctus[i + j] = pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1; + } + } + for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) { + VASliceStructVVC ss_param = { + .SliceTopLeftTileIdx = pps->slice_top_left_tile_idx[i], + .pps_slice_width_in_tiles_minus1 = pps->pps_slice_width_in_tiles_minus1[i], + .pps_slice_height_in_tiles_minus1 = pps->pps_slice_height_in_tiles_minus1[i], + }; + + if (pps->pps_slice_width_in_tiles_minus1[i] > 0 || pps->pps_slice_height_in_tiles_minus1[i] > 0) + ss_param.pps_exp_slice_height_in_ctus_minus1 = 0; + else { + if (pps->num_slices_in_tile[i] == 1) + ss_param.pps_exp_slice_height_in_ctus_minus1 = pps->row_height_val[pps->slice_top_left_tile_idx[i] / pps->num_tile_columns] - 1; + else if (exp_slice_height_in_ctus[i]) + ss_param.pps_exp_slice_height_in_ctus_minus1 = exp_slice_height_in_ctus[i] - 1; + else + continue; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic, + VASliceStructBufferType, + &ss_param, sizeof(VASliceStructVVC)); + if (err < 0) + goto fail; + } + } + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, &pic->pic); + return err; +} + +static uint8_t get_ref_pic_index(const VVCContext *h, const VVCFrame *frame) +{ + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC *)&pic->pic_param; + uint8_t i; + + if (!frame) + return 0xFF; + + for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) { + VASurfaceID pid = pp->ReferenceFrames[i].picture_id; + int poc = pp->ReferenceFrames[i].pic_order_cnt; + if (pid != VA_INVALID_ID && pid == ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc) + return i; + } + + return 0xFF; +} + +static int get_slice_data_byte_offset(const uint8_t *buffer, uint32_t size, const SliceContext* sc) +{ + const H266RawSlice *slice = sc->ref; + int num_identical_bytes = slice->data_size < 32 ? slice->data_size : 32; + + for (int i = 0; i < size; i++) { + int skip_bytes = 0; + if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] && !buffer[i - 2]) + continue; + + for (int j = 0; j < num_identical_bytes; j++) { + if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 && !buffer[i + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2]) + skip_bytes++; + + if (buffer[i + j + skip_bytes] != slice->data[j]) + break; + + if (j + 1 == num_identical_bytes) + return i; + } + } + + return 0; +} + +static int vaapi_vvc_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + const SliceContext *sc = fc->slices[fc->nb_slices]; + const H266RawPPS *pps = fc->ps.pps->r; + const H266RawPictureHeader *ph = fc->ps.ph.r; + const H266RawSliceHeader *sh = sc->sh.r; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + VASliceParameterBufferVVC *slice_param = &pic->slice_param; + int nb_list, i, err; + + *slice_param = (VASliceParameterBufferVVC) { + .slice_data_size = size, + .slice_data_offset = 0, + .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, + .slice_data_byte_offset = get_slice_data_byte_offset(buffer, size, sc), + .sh_subpic_id = sh->sh_subpic_id, + .sh_slice_address = sh->sh_slice_address, + .sh_num_tiles_in_slice_minus1 = sh->sh_num_tiles_in_slice_minus1, + .sh_slice_type = sh->sh_slice_type, + .sh_num_alf_aps_ids_luma = sh->sh_num_alf_aps_ids_luma, + .sh_alf_aps_id_chroma = sh->sh_alf_aps_id_chroma, + .sh_alf_cc_cb_aps_id = sh->sh_alf_cc_cb_aps_id, + .sh_alf_cc_cr_aps_id = sh->sh_alf_cc_cr_aps_id, + .NumRefIdxActive[0] = sh->num_ref_idx_active[0], + .NumRefIdxActive[1] = sh->num_ref_idx_active[1], + .sh_collocated_ref_idx = sh->sh_collocated_ref_idx, + .SliceQpY = pps->pps_qp_delta_info_in_ph_flag ? + 26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta : + 26 + pps->pps_init_qp_minus26 + sh->sh_qp_delta, + .sh_cb_qp_offset = sh->sh_cb_qp_offset, + .sh_cr_qp_offset = sh->sh_cr_qp_offset, + .sh_joint_cbcr_qp_offset = sh->sh_joint_cbcr_qp_offset, + .sh_luma_beta_offset_div2 = sh->sh_luma_beta_offset_div2, + .sh_luma_tc_offset_div2 = sh->sh_luma_tc_offset_div2, + .sh_cb_beta_offset_div2 = sh->sh_cb_beta_offset_div2, + .sh_cb_tc_offset_div2 = sh->sh_cb_tc_offset_div2, + .sh_cr_beta_offset_div2 = sh->sh_cr_beta_offset_div2, + .sh_cr_tc_offset_div2 = sh->sh_cr_tc_offset_div2, + .WPInfo = { + .luma_log2_weight_denom = sh->sh_pred_weight_table.luma_log2_weight_denom, + .delta_chroma_log2_weight_denom = sh->sh_pred_weight_table.delta_chroma_log2_weight_denom, + .num_l0_weights = sh->sh_pred_weight_table.num_l0_weights, + .num_l1_weights = sh->sh_pred_weight_table.num_l1_weights, + }, + .sh_flags.bits = { + .sh_alf_enabled_flag = sh->sh_alf_enabled_flag, + .sh_alf_cb_enabled_flag = sh->sh_alf_cb_enabled_flag, + .sh_alf_cr_enabled_flag = sh->sh_alf_cr_enabled_flag, + .sh_alf_cc_cb_enabled_flag = sh->sh_alf_cc_cb_enabled_flag, + .sh_alf_cc_cr_enabled_flag = sh->sh_alf_cc_cr_enabled_flag, + .sh_lmcs_used_flag = sh->sh_lmcs_used_flag, + .sh_explicit_scaling_list_used_flag = sh->sh_explicit_scaling_list_used_flag, + .sh_cabac_init_flag = sh->sh_cabac_init_flag, + .sh_collocated_from_l0_flag = sh->sh_collocated_from_l0_flag, + .sh_cu_chroma_qp_offset_enabled_flag = sh->sh_cu_chroma_qp_offset_enabled_flag, + .sh_sao_luma_used_flag = sh->sh_sao_luma_used_flag, + .sh_sao_chroma_used_flag = sh->sh_sao_chroma_used_flag, + .sh_deblocking_filter_disabled_flag = sh->sh_deblocking_filter_disabled_flag, + .sh_dep_quant_used_flag = sh->sh_dep_quant_used_flag, + .sh_sign_data_hiding_used_flag = sh->sh_sign_data_hiding_used_flag, + .sh_ts_residual_coding_disabled_flag = sh->sh_ts_residual_coding_disabled_flag, + }, + }; + + memset(&slice_param->RefPicList, 0xFF, sizeof(slice_param->RefPicList)); + + nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ? + 2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1); + for (int list_idx = 0; list_idx < nb_list; list_idx++) { + RefPicList *rpl = &sc->rpl[list_idx]; + + for (i = 0; i < rpl->nb_refs; i++) + slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h, rpl->refs[i].ref); + } + + for (i = 0; i < 7; i++) + slice_param->sh_alf_aps_id_luma[i] = sh->sh_alf_aps_id_luma[i]; + + for (i = 0; i < 15; i++) { + slice_param->WPInfo.luma_weight_l0_flag[i] = sh->sh_pred_weight_table.luma_weight_l0_flag[i]; + slice_param->WPInfo.chroma_weight_l0_flag[i] = sh->sh_pred_weight_table.chroma_weight_l0_flag[i]; + slice_param->WPInfo.delta_luma_weight_l0[i] = sh->sh_pred_weight_table.delta_luma_weight_l0[i]; + slice_param->WPInfo.luma_offset_l0[i] = sh->sh_pred_weight_table.luma_offset_l0[i]; + slice_param->WPInfo.luma_weight_l1_flag[i] = sh->sh_pred_weight_table.luma_weight_l1_flag[i]; + slice_param->WPInfo.chroma_weight_l1_flag[i] = sh->sh_pred_weight_table.chroma_weight_l1_flag[i]; + slice_param->WPInfo.delta_luma_weight_l1[i] = sh->sh_pred_weight_table.delta_luma_weight_l1[i]; + slice_param->WPInfo.luma_offset_l1[i] = sh->sh_pred_weight_table.luma_offset_l1[i]; + } + + for (i = 0; i < 15; i++) { + for (int j = 0; j < 2; j++) { + slice_param->WPInfo.delta_chroma_weight_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l0[i][j]; + slice_param->WPInfo.delta_chroma_offset_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l0[i][j]; + slice_param->WPInfo.delta_chroma_weight_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l1[i][j]; + slice_param->WPInfo.delta_chroma_offset_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l1[i][j]; + } + } + + err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic, + &pic->slice_param, 1, + sizeof(VASliceParameterBufferVVC), + buffer, size); + if (err) { + ff_vaapi_decode_cancel(avctx, &pic->pic); + return err; + } + + return 0; +} + +static int vaapi_vvc_end_frame(AVCodecContext *avctx) +{ + + const VVCContext *h = avctx->priv_data; + VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs]; + VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private; + int ret; + + ret = ff_vaapi_decode_issue(avctx, &pic->pic); + if (ret < 0) + goto fail; + + pic->decode_issued = 1; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, &pic->pic); + return ret; +} + +const FFHWAccel ff_vvc_vaapi_hwaccel = { + .p.name = "vvc_vaapi", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VVC, + .p.pix_fmt = AV_PIX_FMT_VAAPI, + .start_frame = &vaapi_vvc_start_frame, + .end_frame = &vaapi_vvc_end_frame, + .decode_slice = &vaapi_vvc_decode_slice, + .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC), + .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/vb.c b/libavcodec/vb.c index 0a9528a8d2..42d6f26f6c 100644 --- a/libavcodec/vb.c +++ b/libavcodec/vb.c @@ -231,11 +231,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = flags & VB_HAS_PALETTE; -FF_ENABLE_DEPRECATION_WARNINGS -#endif outptr = frame->data[0]; srcptr = c->frame; diff --git a/libavcodec/vbndec.c b/libavcodec/vbndec.c index a96843f212..b8acbce479 100644 --- a/libavcodec/vbndec.c +++ b/libavcodec/vbndec.c @@ -142,7 +142,7 @@ static int vbn_decode_frame(AVCodecContext *avctx, return image_len; if (image_len < linesize * avctx->coded_height) { - av_log(avctx, AV_LOG_ERROR, "Insufficent data\n"); + av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); ret = AVERROR_INVALIDDATA; goto out; } diff --git a/libavcodec/vbnenc.c b/libavcodec/vbnenc.c index 55e436b5e5..c653574980 100644 --- a/libavcodec/vbnenc.c +++ b/libavcodec/vbnenc.c @@ -161,8 +161,6 @@ const FFCodec ff_vbn_encoder = { .init = vbn_init, FF_CODEC_ENCODE_CB(vbn_encode), .priv_data_size = sizeof(VBNContext), - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index d263c70be7..e365aaec84 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -94,7 +94,7 @@ static void decode_colskip(uint8_t* plane, int width, int height, int stride, */ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int imode, x, y, code, offset; uint8_t invert, *planep = data; @@ -161,7 +161,7 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) planep += stride * 3; } if (width & 1) - decode_colskip(data, 1, height, stride, &v->s.gb); + decode_colskip(data, 1, height, stride, &v->gb); } else { // 3x2 planep += (height & 1) * stride; for (y = height & 1; y < height; y += 2) { @@ -182,16 +182,16 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) } x = width % 3; if (x) - decode_colskip(data, x, height, stride, &v->s.gb); + decode_colskip(data, x, height, stride, &v->gb); if (height & 1) - decode_rowskip(data + x, width - x, 1, stride, &v->s.gb); + decode_rowskip(data + x, width - x, 1, stride, &v->gb); } break; case IMODE_ROWSKIP: - decode_rowskip(data, width, height, stride, &v->s.gb); + decode_rowskip(data, width, height, stride, &v->gb); break; case IMODE_COLSKIP: - decode_colskip(data, width, height, stride, &v->s.gb); + decode_colskip(data, width, height, stride, &v->gb); break; default: break; @@ -227,7 +227,7 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v) */ static int vop_dquant_decoding(VC1Context *v) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int pqdiff; //variable size @@ -300,13 +300,13 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo v->frmrtq_postproc = get_bits(gb, 3); //common // (bitrate-32kbps)/64kbps v->bitrtq_postproc = get_bits(gb, 5); //common - v->s.loop_filter = get_bits1(gb); //common - if (v->s.loop_filter == 1 && v->profile == PROFILE_SIMPLE) { + v->loop_filter = get_bits1(gb); //common + if (v->loop_filter == 1 && v->profile == PROFILE_SIMPLE) { av_log(avctx, AV_LOG_ERROR, "LOOPFILTER shall not be enabled in Simple Profile\n"); } if (v->s.avctx->skip_loop_filter >= AVDISCARD_ALL) - v->s.loop_filter = 0; + v->loop_filter = 0; v->res_x8 = get_bits1(gb); //reserved v->multires = get_bits1(gb); @@ -343,7 +343,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo "RANGERED should be set to 0 in Simple Profile\n"); } - v->s.max_b_frames = avctx->max_b_frames = get_bits(gb, 3); //common + v->max_b_frames = avctx->max_b_frames = get_bits(gb, 3); //common v->quantizer_mode = get_bits(gb, 2); //common v->finterpflag = get_bits1(gb); //common @@ -376,7 +376,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo "Rangered=%i, VSTransform=%i, Overlap=%i, SyncMarker=%i\n" "DQuant=%i, Quantizer mode=%i, Max B-frames=%i\n", v->profile, v->frmrtq_postproc, v->bitrtq_postproc, - v->s.loop_filter, v->multires, v->fastuvmc, v->extended_mv, + v->loop_filter, v->multires, v->fastuvmc, v->extended_mv, v->rangered, v->vstransform, v->overlap, v->resync_marker, v->dquant, v->quantizer_mode, avctx->max_b_frames); return 0; @@ -415,23 +415,15 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb) "LoopFilter=%i, ChromaFormat=%i, Pulldown=%i, Interlace: %i\n" "TFCTRflag=%i, FINTERPflag=%i\n", v->level, v->frmrtq_postproc, v->bitrtq_postproc, - v->s.loop_filter, v->chromaformat, v->broadcast, v->interlace, + v->loop_filter, v->chromaformat, v->broadcast, v->interlace, v->tfcntrflag, v->finterpflag); -#if FF_API_TICKS_PER_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (v->broadcast) { // Pulldown may be present - v->s.avctx->ticks_per_frame = 2; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - v->psf = get_bits1(gb); if (v->psf) { //PsF, 6.1.13 av_log(v->s.avctx, AV_LOG_ERROR, "Progressive Segmented Frame mode: not supported (yet)\n"); return -1; } - v->s.max_b_frames = v->s.avctx->max_b_frames = 7; + v->max_b_frames = v->s.avctx->max_b_frames = 7; if (get_bits1(gb)) { //Display Info - decoding is not affected by it int w, h, ar = 0; av_log(v->s.avctx, AV_LOG_DEBUG, "Display extended info:\n"); @@ -509,9 +501,9 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex v->closed_entry = get_bits1(gb); v->panscanflag = get_bits1(gb); v->refdist_flag = get_bits1(gb); - v->s.loop_filter = get_bits1(gb); + v->loop_filter = get_bits1(gb); if (v->s.avctx->skip_loop_filter >= AVDISCARD_ALL) - v->s.loop_filter = 0; + v->loop_filter = 0; v->fastuvmc = get_bits1(gb); v->extended_mv = get_bits1(gb); v->dquant = get_bits(gb, 2); @@ -552,7 +544,7 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex "BrokenLink=%i, ClosedEntry=%i, PanscanFlag=%i\n" "RefDist=%i, Postproc=%i, FastUVMC=%i, ExtMV=%i\n" "DQuant=%i, VSTransform=%i, Overlap=%i, Qmode=%i\n", - v->broken_link, v->closed_entry, v->panscanflag, v->refdist_flag, v->s.loop_filter, + v->broken_link, v->closed_entry, v->panscanflag, v->refdist_flag, v->loop_filter, v->fastuvmc, v->extended_mv, v->dquant, v->vstransform, v->overlap, v->quantizer_mode); return 0; @@ -732,7 +724,6 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1); INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1); } - v->qs_last = v->s.quarter_sample; if (v->mv_mode == MV_PMODE_INTENSITY_COMP) { v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN); @@ -765,7 +756,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) return AVERROR_INVALIDDATA; /* Hopefully this is correct for P-frames */ - v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables + v->mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; @@ -789,7 +780,6 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) v->tt_index = (v->pq > 4) + (v->pq > 12); v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV); v->s.mspel = v->s.quarter_sample; @@ -804,7 +794,7 @@ int ff_vc1_parse_frame_header(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->mv_table_index = get_bits(gb, 2); v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; @@ -833,7 +823,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) v->y_ac_table_index = decode012(gb); } /* DC Syntax */ - v->s.dc_table_index = get_bits1(gb); + v->dc_table_index = get_bits1(gb); } if (v->s.pict_type == AV_PICTURE_TYPE_BI) { @@ -1127,7 +1117,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) } v->last_use_ic = 1; } - v->qs_last = v->s.quarter_sample; if (v->mv_mode == MV_PMODE_INTENSITY_COMP) { v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN); @@ -1158,11 +1147,10 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) "Imode: %i, Invert: %i\n", status>>1, status&1); /* Hopefully this is correct for P-frames */ - v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables + v->mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables 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 @@ -1226,7 +1214,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) mvmode = get_unary(gb, 1, 3); lowquant = (v->pq > 12) ? 0 : 1; v->mv_mode = ff_vc1_mv_pmode_table2[lowquant][mvmode]; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV || v->mv_mode == MV_PMODE_MIXED_MV); v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN); status = bitplane_decoding(v->forward_mb_plane, &v->fmb_is_raw, v); @@ -1256,7 +1243,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->intcomp = 0; v->mv_mode = MV_PMODE_1MV; v->fourmvswitch = 0; - v->qs_last = v->s.quarter_sample; v->s.quarter_sample = 1; v->s.mspel = 1; status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v); @@ -1282,7 +1268,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) 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; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV); v->s.mspel = v->s.quarter_sample; status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v); @@ -1295,7 +1280,7 @@ 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); - v->s.mv_table_index = get_bits(gb, 2); + v->mv_table_index = get_bits(gb, 2); v->cbptab = get_bits(gb, 2); v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab]; } @@ -1330,7 +1315,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) } /* DC Syntax */ - v->s.dc_table_index = get_bits1(gb); + v->dc_table_index = get_bits1(gb); if ((v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI) && v->dquant) { av_log(v->s.avctx, AV_LOG_DEBUG, "VOP DQuant info\n"); diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 185236662f..f2a52c19c1 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -24,12 +24,15 @@ #define AVCODEC_VC1_H #include "avcodec.h" +#include "get_bits.h" #include "h264chroma.h" #include "mpegvideo.h" #include "intrax8.h" #include "vc1_common.h" #include "vc1dsp.h" +#include "libavutil/mem_internal.h" + #define AC_VLC_BITS 9 /** Sequence quantizer mode */ @@ -172,6 +175,7 @@ enum Imode { */ typedef struct VC1Context{ MpegEncContext s; + GetBitContext gb; IntraX8Context x8; H264ChromaContext h264chroma; VC1DSPContext vc1dsp; @@ -216,12 +220,14 @@ typedef struct VC1Context{ int profile; ///< 2 bits, Profile int frmrtq_postproc; ///< 3 bits, int bitrtq_postproc; ///< 5 bits, quantized framerate-based postprocessing strength + int loop_filter; int max_coded_width, max_coded_height; int fastuvmc; ///< Rounding of qpel vector to hpel ? (not in Simple) int extended_mv; ///< Ext MV in P/B (not in Simple) int dquant; ///< How qscale varies with MBs, 2 bits (not in Simple) int vstransform; ///< variable-size [48]x[48] transform type + info int overlap; ///< overlapped transforms in use + int max_b_frames; ///< max number of B-frames int quantizer_mode; ///< 2 bits, quantizer mode used for sequence, see QUANT_* int finterpflag; ///< INTERPFRM present //@} @@ -245,6 +251,7 @@ typedef struct VC1Context{ uint8_t dqsbedge; uint8_t dqbilevel; //@} + int dc_table_index; /** AC coding set indexes * @see 8.1.1.10, p(1)10 */ @@ -252,6 +259,8 @@ typedef struct VC1Context{ int c_ac_table_index; ///< Chroma index from ACFRM element int y_ac_table_index; ///< Luma index from AC2FRM element //@} + int esc3_level_length; + int esc3_run_length; int ttfrm; ///< Transform type info present at frame level uint8_t ttmbf; ///< Transform type flag int *ttblk_base, *ttblk; ///< Transform type at the block level @@ -259,7 +268,7 @@ typedef struct VC1Context{ int codingset2; ///< index of current table set from 11.8 to use for chroma block decoding int pqindex; ///< raw pqindex used in coding set selection int a_avail, c_avail; - uint8_t *mb_type_base, *mb_type[3]; + uint8_t *mb_type_base, *mb_type; /** Luma compensation parameters */ @@ -281,6 +290,7 @@ typedef struct VC1Context{ uint8_t pquantizer; ///< Uniform (over sequence) quantizer in use const VLCElem *cbpcy_vlc; ///< CBPCY VLC table int tt_index; ///< Index for Transform Type tables (to decode TTMB) + int mv_table_index; uint8_t* mv_type_mb_plane; ///< bitplane for mv_type == (4MV) uint8_t* direct_mb_plane; ///< bitplane for "direct" MBs uint8_t* forward_mb_plane; ///< bitplane for "forward" MBs @@ -309,10 +319,6 @@ typedef struct VC1Context{ uint8_t numpanscanwin; uint8_t tfcntr; uint8_t rptfrm, tff, rff; - uint16_t topleftx; - uint16_t toplefty; - uint16_t bottomrightx; - uint16_t bottomrighty; uint8_t uvsamp; uint8_t postproc; int hrd_num_leaky_buckets; @@ -360,7 +366,6 @@ typedef struct VC1Context{ int cur_field_type; ///< 0: top, 1: bottom int ref_field_type[2]; ///< forward and backward reference field type (top or bottom) int blocks_off, mb_off; - int qs_last; ///< if qpel has been used in the previous (tr.) picture int bmvtype; int frfd, brfd; ///< reference frame distance (forward or backward) int first_pic_header_flag; @@ -397,6 +402,8 @@ typedef struct VC1Context{ int parse_only; ///< Context is used within parser int resync_marker; ///< could this stream contain resync markers + + DECLARE_ALIGNED_32(int16_t, blocks)[6][64]; } VC1Context; /** diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c index 1c422d902f..4fa03f287a 100644 --- a/libavcodec/vc1_block.c +++ b/libavcodec/vc1_block.c @@ -90,8 +90,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (!s->first_slice_line && v->fcm != ILACE_FRAME) { if (s->mb_x) { for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 1] : - v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i] - 2]) { + if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i] - 1] : + v->mb_type[s->block_index[i] - 2 * s->block_wrap[i] - 2]) { dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + ((i & 1) - 2) * 8; if (put_signed) s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]], @@ -106,8 +106,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) } if (s->mb_x == v->end_mb_x - 1) { for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i]] : - v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i]]) { + if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i]] : + v->mb_type[s->block_index[i] - 2 * s->block_wrap[i]]) { dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + (i & 1) * 8; if (put_signed) s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][block_map[i]], @@ -126,8 +126,8 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (v->fcm == ILACE_FRAME) fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x - 1]; for (i = 0; i < block_count; i++) { - if (i > 3 ? v->mb_type[0][s->block_index[i] - 1] : - v->mb_type[0][s->block_index[i] - 2]) { + if (i > 3 ? v->mb_type[s->block_index[i] - 1] : + v->mb_type[s->block_index[i] - 2]) { if (fieldtx) dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + ((i & 1) - 2) * 8; else @@ -147,7 +147,7 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) if (v->fcm == ILACE_FRAME) fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x]; for (i = 0; i < block_count; i++) { - if (v->mb_type[0][s->block_index[i]]) { + if (v->mb_type[s->block_index[i]]) { if (fieldtx) dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + (i & 1) * 8; else @@ -227,7 +227,7 @@ static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) * @param _dmv_y Vertical differential for decoded MV */ #define GET_MVDATA(_dmv_x, _dmv_y) \ - index = 1 + get_vlc2(gb, ff_vc1_mv_diff_vlc[s->mv_table_index], \ + index = 1 + get_vlc2(gb, ff_vc1_mv_diff_vlc[v->mv_table_index], \ VC1_MV_DIFF_VLC_BITS, 2); \ if (index > 36) { \ mb_has_coeffs = 1; \ @@ -269,7 +269,7 @@ static av_always_inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x, { int index, index1; int extend_x, extend_y; - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int bits, esc; int val, sign; @@ -354,11 +354,10 @@ static inline int vc1_i_pred_dc(MpegEncContext *s, int overlap, int pq, int n, }; /* find prediction - wmv3_dc_scale always used here in fact */ - if (n < 4) scale = s->y_dc_scale; - else scale = s->c_dc_scale; + scale = s->y_dc_scale; wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; + dc_val = s->dc_val + s->block_index[n]; /* B A * C X @@ -418,12 +417,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, /* scale predictors if needed */ q1 = FFABS(s->cur_pic.qscale_table[mb_pos]); - dqscale_index = s->y_dc_scale_table[q1] - 1; + dqscale_index = ff_wmv3_dc_scale_table[q1] - 1; if (dqscale_index < 0) return 0; wrap = s->block_wrap[n]; - dc_val = s->dc_val[0] + s->block_index[n]; + dc_val = s->dc_val + s->block_index[n]; /* B A * C X @@ -435,12 +434,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, if (c_avail && (n != 1 && n != 3)) { q2 = FFABS(s->cur_pic.qscale_table[mb_pos - 1]); if (q2 && q2 != q1) - c = (int)((unsigned)c * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + c = (int)((unsigned)c * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && (n != 2 && n != 3)) { q2 = FFABS(s->cur_pic.qscale_table[mb_pos - s->mb_stride]); if (q2 && q2 != q1) - a = (int)((unsigned)a * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + a = (int)((unsigned)a * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && c_avail && (n != 3)) { int off = mb_pos; @@ -450,7 +449,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, off -= s->mb_stride; q2 = FFABS(s->cur_pic.qscale_table[off]); if (q2 && q2 != q1) - b = (int)((unsigned)b * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + b = (int)((unsigned)b * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (c_avail && (!a_avail || abs(a - b) <= abs(b - c))) { @@ -516,7 +515,7 @@ static inline int vc1_coded_block_pred(MpegEncContext * s, int n, static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, int *value, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; int index, run, level, lst, sign; index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset], AC_VLC_BITS, 3); @@ -550,19 +549,19 @@ static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, sign = get_bits1(gb); } else { lst = get_bits1(gb); - if (v->s.esc3_level_length == 0) { + if (v->esc3_level_length == 0) { if (v->pq < 8 || v->dquantfrm) { // table 59 - v->s.esc3_level_length = get_bits(gb, 3); - if (!v->s.esc3_level_length) - v->s.esc3_level_length = get_bits(gb, 2) + 8; + v->esc3_level_length = get_bits(gb, 3); + if (!v->esc3_level_length) + v->esc3_level_length = get_bits(gb, 2) + 8; } else { // table 60 - v->s.esc3_level_length = get_unary(gb, 1, 6) + 2; + v->esc3_level_length = get_unary(gb, 1, 6) + 2; } - v->s.esc3_run_length = 3 + get_bits(gb, 2); + v->esc3_run_length = 3 + get_bits(gb, 2); } - run = get_bits(gb, v->s.esc3_run_length); + run = get_bits(gb, v->esc3_run_length); sign = get_bits1(gb); - level = get_bits(gb, v->s.esc3_level_length); + level = get_bits(gb, v->esc3_level_length); } } @@ -583,16 +582,15 @@ static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, int coded, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val; int16_t *ac_val, *ac_val2; int dcdiff, scale; /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (v->pq == 1 || v->pq == 2) ? 3 - v->pq : 0; @@ -611,13 +609,9 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - block[0] = dcdiff * scale; + block[0] = dcdiff * s->y_dc_scale; - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; if (dc_pred_dir) // left ac_val -= 16; @@ -627,7 +621,6 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, scale = v->pq * 2 + v->halfpq; //AC Decoding - i = !!coded; if (coded) { int last = 0, skip, value; @@ -642,14 +635,14 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, } else zz_table = v->zz_8x8[1]; - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; i += skip; if (i > 63) break; - block[zz_table[i++]] = value; + block[zz_table[i]] = value; } /* apply AC prediction if needed */ @@ -701,8 +694,6 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, } } } - if (s->ac_pred) i = 63; - s->block_last_index[n] = i; return 0; } @@ -718,10 +709,9 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, int coded, int codingset, int mquant) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val = NULL; int16_t *ac_val, *ac_val2; int dcdiff; @@ -733,7 +723,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, int quant = FFABS(mquant); /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; @@ -752,11 +742,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - block[0] = dcdiff * scale; + block[0] = dcdiff * s->y_dc_scale; /* check if AC is needed at all */ if (!a_avail && !c_avail) @@ -764,7 +750,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; if (dc_pred_dir) // left ac_val -= 16; @@ -787,7 +773,6 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } //AC Decoding - i = 1; if (coded) { int last = 0, skip, value; @@ -810,14 +795,14 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, zz_table = v->zzi_8x8; } - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; i += skip; if (i > 63) break; - block[zz_table[i++]] = value; + block[zz_table[i]] = value; } /* apply AC prediction if needed */ @@ -889,8 +874,6 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } } } - if (use_pred) i = 63; - s->block_last_index[n] = i; return 0; } @@ -906,10 +889,9 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int coded, int mquant, int codingset) { - GetBitContext *gb = &v->s.gb; + GetBitContext *const gb = &v->gb; MpegEncContext *s = &v->s; int dc_pred_dir = 0; /* Direction of the DC prediction used */ - int i; int16_t *dc_val = NULL; int16_t *ac_val, *ac_val2; int dcdiff; @@ -925,12 +907,11 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, /* XXX: Guard against dumb values of mquant */ quant = av_clip_uintp2(quant, 5); - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[quant]; - s->c_dc_scale = s->c_dc_scale_table[quant]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[quant]; /* Get DC differential */ - dcdiff = get_vlc2(&s->gb, ff_msmp4_dc_vlc[s->dc_table_index][n >= 4], + dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4], MSMP4_DC_VLC_BITS, 3); if (dcdiff) { const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; @@ -949,21 +930,15 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ - - if (n < 4) { - block[0] = dcdiff * s->y_dc_scale; - } else { - block[0] = dcdiff * s->c_dc_scale; - } + block[0] = dcdiff * s->y_dc_scale; //AC Decoding - i = 1; /* check if AC is needed at all and adjust direction if needed */ if (!a_avail) dc_pred_dir = 1; if (!c_avail) dc_pred_dir = 0; if (!a_avail && !c_avail) use_pred = 0; - ac_val = s->ac_val[0][s->block_index[n]]; + ac_val = s->ac_val[s->block_index[n]]; ac_val2 = ac_val; scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); @@ -988,7 +963,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int last = 0, skip, value; int k; - while (!last) { + for (int i = 1; !last; ++i) { int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); if (ret < 0) return ret; @@ -996,15 +971,15 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (i > 63) break; if (v->fcm == PROGRESSIVE) - block[v->zz_8x8[0][i++]] = value; + block[v->zz_8x8[0][i]] = value; else { if (use_pred && (v->fcm == ILACE_FRAME)) { if (!dc_pred_dir) // top - block[v->zz_8x8[2][i++]] = value; + block[v->zz_8x8[2][i]] = value; else // left - block[v->zz_8x8[3][i++]] = value; + block[v->zz_8x8[3][i]] = value; } else { - block[v->zzi_8x8[i++]] = value; + block[v->zzi_8x8[i]] = value; } } } @@ -1048,8 +1023,6 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (!v->pquantizer) block[k] += (block[k] < 0) ? -quant : quant; } - - if (use_pred) i = 63; } else { // no AC coeffs int k; @@ -1097,10 +1070,8 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -quant : quant; } } - i = 63; } } - s->block_last_index[n] = i; return 0; } @@ -1113,7 +1084,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, int *ttmb_out) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int subblkpat = 0; int scale, off, idx, last, skip, value; @@ -1282,7 +1253,7 @@ static const uint8_t size_table[6] = { 0, 2, 3, 4, 5, 8 }; static int vc1_decode_p_mb(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp; /* cbp decoding stuff */ @@ -1319,7 +1290,7 @@ static int vc1_decode_p_mb(VC1Context *v) s->cur_pic.motion_val[1][s->block_index[0]][1] = 0; } s->cur_pic.mb_type[mb_pos] = s->mb_intra ? MB_TYPE_INTRA : MB_TYPE_16x16; - ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, 0, 0); /* FIXME Set DC val for inter block ? */ if (s->mb_intra && !mb_has_coeffs) { @@ -1329,7 +1300,7 @@ static int vc1_decode_p_mb(VC1Context *v) } else if (mb_has_coeffs) { if (s->mb_intra) s->ac_pred = get_bits1(gb); - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); } else { mquant = v->pq; @@ -1343,18 +1314,18 @@ static int vc1_decode_p_mb(VC1Context *v) if (!s->mb_intra) ff_vc1_mc_1mv(v, 0); dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (s->mb_intra) { /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1383,12 +1354,12 @@ static int vc1_decode_p_mb(VC1Context *v) } else { // skipped s->mb_intra = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; - ff_vc1_pred_mv(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type, 0, 0); ff_vc1_mc_1mv(v, 0); } } else { // 4MV mode @@ -1396,10 +1367,10 @@ static int vc1_decode_p_mb(VC1Context *v) int intra_count = 0, coded_inter = 0; int is_intra[6], is_coded[6]; /* Get CBPCY */ - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); for (i = 0; i < 6; i++) { val = ((cbp >> (5 - i)) & 1); - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; s->mb_intra = 0; if (i < 4) { dmv_x = dmv_y = 0; @@ -1408,7 +1379,7 @@ static int vc1_decode_p_mb(VC1Context *v) if (val) { GET_MVDATA(dmv_x, dmv_y); } - ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, 0, 0); if (!s->mb_intra) ff_vc1_mc_4mv_luma(v, i, 0, 0); intra_count += s->mb_intra; @@ -1421,7 +1392,7 @@ static int vc1_decode_p_mb(VC1Context *v) } if (i == 4) ff_vc1_mc_4mv_chroma(v, 0); - v->mb_type[0][s->block_index[i]] = is_intra[i]; + v->mb_type[s->block_index[i]] = is_intra[i]; if (!coded_inter) coded_inter = !is_intra[i] & is_coded[i]; } @@ -1436,8 +1407,8 @@ static int vc1_decode_p_mb(VC1Context *v) int intrapred = 0; for (i = 0; i < 6; i++) if (is_intra[i]) { - if (((!s->first_slice_line || (i == 2 || i == 3)) && v->mb_type[0][s->block_index[i] - s->block_wrap[i]]) - || ((s->mb_x || (i == 1 || i == 3)) && v->mb_type[0][s->block_index[i] - 1])) { + if (((!s->first_slice_line || (i == 2 || i == 3)) && v->mb_type[s->block_index[i] - s->block_wrap[i]]) + || ((s->mb_x || (i == 1 || i == 3)) && v->mb_type[s->block_index[i] - 1])) { intrapred = 1; break; } @@ -1457,9 +1428,9 @@ static int vc1_decode_p_mb(VC1Context *v) /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, is_coded[i], mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1491,11 +1462,11 @@ static int vc1_decode_p_mb(VC1Context *v) s->mb_intra = 0; s->cur_pic.qscale_table[mb_pos] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } for (i = 0; i < 4; i++) { - ff_vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type, 0, 0); ff_vc1_mc_4mv_luma(v, i, 0, 0); } ff_vc1_mc_4mv_chroma(v, 0); @@ -1519,7 +1490,7 @@ end: static int vc1_decode_p_mb_intfr(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1589,24 +1560,23 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = get_bits1(gb); if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1621,7 +1591,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } else { // inter MB mb_has_coeffs = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][3]; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_2MV_FIELD) { v->twomvbp = get_vlc2(gb, v->twomvbp_vlc, VC1_2MV_BLOCK_PATTERN_VLC_BITS, 1); } else { @@ -1632,7 +1602,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } s->mb_intra = v->is_intra[s->mb_x] = 0; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][1]; /* for all motion vector read MVDATA and motion compensate each block */ dst_idx = 0; @@ -1678,7 +1648,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) if (!v->ttmbf && cbp) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (!fieldtx) @@ -1702,8 +1672,8 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } else { // skipped s->mb_intra = v->is_intra[s->mb_x] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; @@ -1728,7 +1698,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) static int vc1_decode_p_mb_intfi(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1756,24 +1726,23 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); @@ -1788,13 +1757,13 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) s->mb_intra = v->is_intra[s->mb_x] = 0; s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; if (idx_mbmode <= 5) { // 1-MV dmv_x = dmv_y = pred_flag = 0; if (idx_mbmode & 1) { get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag); } - ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0); + ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, pred_flag, 0); ff_vc1_mc_1mv(v, 0); mb_has_coeffs = !(idx_mbmode & 2); } else { // 4-MV @@ -1803,14 +1772,14 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) dmv_x = dmv_y = pred_flag = 0; if (v->fourmvbp & (8 >> i)) get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag); - ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0); + ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, pred_flag, 0); ff_vc1_mc_4mv_luma(v, i, 0, 0); } ff_vc1_mc_4mv_chroma(v, 0); mb_has_coeffs = idx_mbmode & 1; } if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (cbp) { GET_MQUANT(); } @@ -1820,7 +1789,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; @@ -1854,7 +1823,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) static int vc1_decode_b_mb(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -1884,8 +1853,8 @@ static int vc1_decode_b_mb(VC1Context *v) dmv_x[0] = dmv_x[1] = dmv_y[0] = dmv_y[1] = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.qscale_table[mb_pos] = 0; @@ -1911,7 +1880,7 @@ static int vc1_decode_b_mb(VC1Context *v) } } for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (skipped) { if (direct) @@ -1921,7 +1890,7 @@ static int vc1_decode_b_mb(VC1Context *v) return 0; } if (direct) { - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); s->mb_intra = 0; s->cur_pic.qscale_table[mb_pos] = mquant; @@ -1959,7 +1928,7 @@ static int vc1_decode_b_mb(VC1Context *v) } if (s->mb_intra) s->ac_pred = get_bits1(gb); - cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && !s->mb_intra && mb_has_coeffs) @@ -1968,35 +1937,35 @@ static int vc1_decode_b_mb(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - v->mb_type[0][s->block_index[i]] = s->mb_intra; + v->mb_type[s->block_index[i]] = s->mb_intra; if (s->mb_intra) { /* check if prediction blocks A and C are available */ v->a_avail = v->c_avail = 0; if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] *= 2; - s->idsp.put_signed_pixels_clamped(s->block[i], + v->blocks[i][j] *= 2; + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); } else if (val) { - int pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + int pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL); @@ -2015,7 +1984,7 @@ static int vc1_decode_b_mb(VC1Context *v) static int vc1_decode_b_mb_intfi(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -2044,37 +2013,36 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_ICBPCY_VLC_BITS, 2); dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] <<= 1; + v->blocks[i][j] <<= 1; off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - s->idsp.put_signed_pixels_clamped(s->block[i], + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize); @@ -2083,7 +2051,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) s->mb_intra = v->is_intra[s->mb_x] = 0; s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; if (v->fmb_is_raw) fwd = v->forward_mb_plane[mb_pos] = get_bits1(gb); else @@ -2146,7 +2114,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) mb_has_coeffs = idx_mbmode & 1; } if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (cbp) { GET_MQUANT(); } @@ -2156,12 +2124,12 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) } dst_idx = 0; for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); @@ -2185,7 +2153,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) static int vc1_decode_b_mb_intfr(VC1Context *v) { MpegEncContext *s = &v->s; - GetBitContext *gb = &s->gb; + GetBitContext *const gb = &v->gb; int i, j; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; int cbp = 0; /* cbp decoding stuff */ @@ -2241,32 +2209,31 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = get_bits1(gb); if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; - v->mb_type[0][s->block_index[i]] = 1; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 1; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (i == 2 || i == 3 || !s->first_slice_line) - v->a_avail = v->mb_type[0][s->block_index[i] - s->block_wrap[i]]; + v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]]; if (i == 1 || i == 3 || s->mb_x) - v->c_avail = v->mb_type[0][s->block_index[i] - 1]; + v->c_avail = v->mb_type[s->block_index[i] - 1]; - ret = vc1_decode_intra_block(v, s->block[i], i, val, mquant, + ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (ret < 0) return ret; if (CONFIG_GRAY && i > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]); if (i < 4) { stride_y = s->linesize << fieldtx; off = (fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize; @@ -2274,7 +2241,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) stride_y = s->uvlinesize; off = 0; } - s->idsp.put_signed_pixels_clamped(s->block[i], + s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, stride_y); } @@ -2338,7 +2305,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (!skipped) { // inter MB mb_has_coeffs = ff_vc1_mbmode_intfrp[0][idx_mbmode][3]; if (mb_has_coeffs) - cbp = 1 + get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); + cbp = 1 + get_vlc2(gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); if (!direct) { if (bmvtype == BMV_TYPE_INTERPOLATED && twomv) { v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc, VC1_4MV_BLOCK_PATTERN_VLC_BITS, 1); @@ -2348,7 +2315,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } for (i = 0; i < 6; i++) - v->mb_type[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[0][idx_mbmode][1]; /* for all motion vector read MVDATA and motion compensate each block */ dst_idx = 0; @@ -2455,7 +2422,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (!v->ttmbf && cbp) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); for (i = 0; i < 6; i++) { - s->dc_val[0][s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; dst_idx += i >> 2; val = ((cbp >> (5 - i)) & 1); if (!fieldtx) @@ -2463,7 +2430,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) else off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize)); if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : (s->linesize << fieldtx), CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); @@ -2479,8 +2446,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } else { // skipped dir = 0; for (i = 0; i < 6; i++) { - v->mb_type[0][s->block_index[i]] = 0; - s->dc_val[0][s->block_index[i]] = 0; + v->mb_type[s->block_index[i]] = 0; + s->dc_val[s->block_index[i]] = 0; } s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; s->cur_pic.qscale_table[mb_pos] = 0; @@ -2568,9 +2535,8 @@ static void vc1_decode_i_blocks(VC1Context *v) break; } - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[v->pq]; - s->c_dc_scale = s->c_dc_scale_table[v->pq]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[v->pq]; //do frame decode s->mb_x = s->mb_y = 0; @@ -2591,12 +2557,12 @@ static void vc1_decode_i_blocks(VC1Context *v) } // do actual MB decoding and displaying - cbp = get_vlc2(&v->s.gb, ff_msmp4_mb_i_vlc, + cbp = get_vlc2(&v->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); - v->s.ac_pred = get_bits1(&v->s.gb); + v->s.ac_pred = get_bits1(&v->gb); for (k = 0; k < 6; k++) { - v->mb_type[0][s->block_index[k]] = 1; + v->mb_type[s->block_index[k]] = 1; val = ((cbp >> (5 - k)) & 1); @@ -2629,13 +2595,13 @@ static void vc1_decode_i_blocks(VC1Context *v) vc1_put_blocks_clamped(v, 0); } - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); - if (get_bits_left(&s->gb) < 0) { + if (get_bits_left(&v->gb) < 0) { ff_er_add_slice(&s->er, 0, 0, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i\n", - get_bits_count(&s->gb), s->gb.size_in_bits); + get_bits_count(&v->gb), v->gb.size_in_bits); return; } @@ -2659,12 +2625,12 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) { int k; MpegEncContext *s = &v->s; + GetBitContext *const gb = &v->gb; int cbp, val; uint8_t *coded_val; int mb_pos; int mquant; int mqdiff; - GetBitContext *gb = &s->gb; if (get_bits_left(gb) <= 1) return AVERROR_INVALIDDATA; @@ -2719,31 +2685,30 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) // do actual MB decoding and displaying if (v->fieldtx_is_raw) - v->fieldtx_plane[mb_pos] = get_bits1(&v->s.gb); - if (get_bits_left(&v->s.gb) <= 1) { + v->fieldtx_plane[mb_pos] = get_bits1(gb); + if (get_bits_left(gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return 0; } - cbp = get_vlc2(&v->s.gb, ff_msmp4_mb_i_vlc, + cbp = get_vlc2(gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); if (v->acpred_is_raw) - v->s.ac_pred = get_bits1(&v->s.gb); + v->s.ac_pred = get_bits1(gb); else v->s.ac_pred = v->acpred_plane[mb_pos]; if (v->condover == CONDOVER_SELECT && v->overflg_is_raw) - v->over_flags_plane[mb_pos] = get_bits1(&v->s.gb); + v->over_flags_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); s->cur_pic.qscale_table[mb_pos] = mquant; - /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; - s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; + /* Set DC scale - y and c use the same so we only set y */ + s->y_dc_scale = ff_wmv3_dc_scale_table[FFABS(mquant)]; for (k = 0; k < 6; k++) { - v->mb_type[0][s->block_index[k]] = 1; + v->mb_type[s->block_index[k]] = 1; val = ((cbp >> (5 - k)) & 1); @@ -2768,14 +2733,14 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) if (v->overlap && (v->pq >= 9 || v->condover != CONDOVER_NONE)) ff_vc1_i_overlap_filter(v); vc1_put_blocks_clamped(v, 1); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); - if (get_bits_left(&s->gb) < 0) { + if (get_bits_left(gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i\n", - get_bits_count(&s->gb), s->gb.size_in_bits); + get_bits_count(gb), gb->size_in_bits); return 0; } inc_blk_idx(v->topleft_blk_idx); @@ -2822,7 +2787,7 @@ static void vc1_decode_p_blocks(VC1Context *v) break; } - apply_loop_filter = s->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY); + apply_loop_filter = v->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY); s->first_slice_line = 1; memset(v->cbp_base, 0, sizeof(v->cbp_base[0]) * 3 * s->mb_stride); for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { @@ -2832,7 +2797,7 @@ static void vc1_decode_p_blocks(VC1Context *v) update_block_index(s); if (v->fcm == ILACE_FIELD || (v->fcm == PROGRESSIVE && v->mv_type_is_raw) || v->skip_is_raw) - if (get_bits_left(&v->s.gb) <= 1) { + if (get_bits_left(&v->gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return; } @@ -2850,11 +2815,11 @@ static void vc1_decode_p_blocks(VC1Context *v) if (apply_loop_filter) ff_vc1_p_loop_filter(v); } - if (ret < 0 || get_bits_left(&s->gb) < 0 || get_bits_count(&s->gb) < 0) { + if (ret < 0 || get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Error or Bits overconsumption: %i > %i at %ix%i\n", - get_bits_count(&s->gb), s->gb.size_in_bits, s->mb_x, s->mb_y); + get_bits_count(&v->gb), v->gb.size_in_bits, s->mb_x, s->mb_y); return; } inc_blk_idx(v->topleft_blk_idx); @@ -2917,29 +2882,29 @@ static void vc1_decode_b_blocks(VC1Context *v) update_block_index(s); if (v->fcm == ILACE_FIELD || v->skip_is_raw || v->dmb_is_raw) - if (get_bits_left(&v->s.gb) <= 1) { + if (get_bits_left(&v->gb) <= 1) { ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); return; } if (v->fcm == ILACE_FIELD) { vc1_decode_b_mb_intfi(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_b_intfi_loop_filter(v); } else if (v->fcm == ILACE_FRAME) { vc1_decode_b_mb_intfr(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_p_intfr_loop_filter(v); } else { vc1_decode_b_mb(v); - if (v->s.loop_filter) + if (v->loop_filter) ff_vc1_i_loop_filter(v); } - if (get_bits_left(&s->gb) < 0 || get_bits_count(&s->gb) < 0) { + if (get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); av_log(s->avctx, AV_LOG_ERROR, "Bits overconsumption: %i > %i at %ix%i\n", - get_bits_count(&s->gb), s->gb.size_in_bits, s->mb_x, s->mb_y); + get_bits_count(&v->gb), v->gb.size_in_bits, s->mb_x, s->mb_y); return; } } @@ -2981,12 +2946,12 @@ static void vc1_decode_skip_blocks(VC1Context *v) void ff_vc1_decode_blocks(VC1Context *v) { - v->s.esc3_level_length = 0; + v->esc3_level_length = 0; if (v->x8_type) { ff_intrax8_decode_picture(&v->x8, v->s.cur_pic.ptr, - &v->s.gb, &v->s.mb_x, &v->s.mb_y, + &v->gb, &v->s.mb_x, &v->s.mb_y, 2 * v->pq + v->halfpq, v->pq * !v->pquantizer, - v->s.loop_filter, v->s.low_delay); + v->loop_filter, v->s.low_delay); ff_er_add_slice(&v->s.er, 0, 0, (v->s.mb_x >> 1) - 1, (v->s.mb_y >> 1) - 1, diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c index e788d1890e..1d71d9d5ca 100644 --- a/libavcodec/vc1_loopfilter.c +++ b/libavcodec/vc1_loopfilter.c @@ -175,7 +175,7 @@ void ff_vc1_p_overlap_filter(VC1Context *v) if (s->mb_x == 0 && (i & 5) != 1) continue; - if (v->mb_type[0][s->block_index[i]] && v->mb_type[0][s->block_index[i] - 1]) + if (v->mb_type[s->block_index[i]] && v->mb_type[s->block_index[i] - 1]) vc1_h_overlap_filter(v, s->mb_x ? left_blk : cur_blk, cur_blk, v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1], @@ -188,12 +188,12 @@ void ff_vc1_p_overlap_filter(VC1Context *v) if (s->first_slice_line && !(i & 2)) continue; - if (s->mb_x && v->mb_type[0][s->block_index[i] - 2 + (i > 3)] && - v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)]) + if (s->mb_x && v->mb_type[s->block_index[i] - 2 + (i > 3)] && + v->mb_type[s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)]) vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i); if (s->mb_x == s->mb_width - 1) - if (v->mb_type[0][s->block_index[i]] && - v->mb_type[0][s->block_index[i] - s->block_wrap[i]]) + if (v->mb_type[s->block_index[i]] && + v->mb_type[s->block_index[i] - s->block_wrap[i]]) vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i); } } diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c index 9adb71c7ad..db19d95ef9 100644 --- a/libavcodec/vc1_mc.c +++ b/libavcodec/vc1_mc.c @@ -140,10 +140,10 @@ static av_always_inline int get_luma_mv(VC1Context *v, int dir, int16_t *tx, int static av_always_inline int get_chroma_mv(VC1Context *v, int dir, int16_t *tx, int16_t *ty) { MpegEncContext *s = &v->s; - int idx = !v->mb_type[0][s->block_index[0]] | - (!v->mb_type[0][s->block_index[1]] << 1) | - (!v->mb_type[0][s->block_index[2]] << 2) | - (!v->mb_type[0][s->block_index[3]] << 3); + int idx = !v->mb_type[s->block_index[0]] | + (!v->mb_type[s->block_index[1]] << 1) | + (!v->mb_type[s->block_index[2]] << 2) | + (!v->mb_type[s->block_index[3]] << 3); static const uint8_t index2[16] = { 0, 0, 0, 0x01, 0, 0x02, 0x12, 0, 0, 0x03, 0x13, 0, 0x23, 0, 0, 0 }; int valid_count = popcount4[idx]; diff --git a/libavcodec/vc1_pred.c b/libavcodec/vc1_pred.c index 87d9b6d6dc..1ac8f6156b 100644 --- a/libavcodec/vc1_pred.c +++ b/libavcodec/vc1_pred.c @@ -420,7 +420,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, else sum = FFABS(px - field_predA[0]) + FFABS(py - field_predA[1]); if (sum > hybridmv_thresh) { - if (get_bits1(&s->gb)) { // read HYBRIDPRED bit + if (get_bits1(&v->gb)) { // read HYBRIDPRED bit px = field_predA[0]; py = field_predA[1]; } else { @@ -433,7 +433,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, else sum = FFABS(px - field_predC[0]) + FFABS(py - field_predC[1]); if (sum > hybridmv_thresh) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = field_predA[0]; py = field_predA[1]; } else { @@ -695,7 +695,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int px, py; int sum; int r_x, r_y; - const uint8_t *is_intra = v->mb_type[0]; + const uint8_t *is_intra = v->mb_type; av_assert0(!v->field_mode); @@ -782,7 +782,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - A[0]) + FFABS(py - A[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -795,7 +795,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - C[0]) + FFABS(py - C[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -852,7 +852,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - A[0]) + FFABS(py - A[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -865,7 +865,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], else sum = FFABS(px - C[0]) + FFABS(py - C[1]); if (sum > 32) { - if (get_bits1(&s->gb)) { + if (get_bits1(&v->gb)) { px = A[0]; py = A[1]; } else { @@ -927,19 +927,19 @@ void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, return; } if (v->bmvtype == BMV_TYPE_INTERPOLATED) { - ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type[0], pred_flag[0], 0); - ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type[0], pred_flag[1], 1); + ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0); + ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1); return; } if (dir) { // backward - ff_vc1_pred_mv(v, n, dmv_x[1], dmv_y[1], mv1, v->range_x, v->range_y, v->mb_type[0], pred_flag[1], 1); + ff_vc1_pred_mv(v, n, dmv_x[1], dmv_y[1], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1); if (n == 3 || mv1) { - ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type[0], 0, 0); + ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, 0, 0); } } else { // forward - ff_vc1_pred_mv(v, n, dmv_x[0], dmv_y[0], mv1, v->range_x, v->range_y, v->mb_type[0], pred_flag[0], 0); + ff_vc1_pred_mv(v, n, dmv_x[0], dmv_y[0], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0); if (n == 3 || mv1) { - ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type[0], 0, 1); + ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, 0, 1); } } } diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 5f1a5bd437..de6d9ef7a9 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -396,9 +396,7 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) v->mb_type_base = av_mallocz(s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); if (!v->mb_type_base) return AVERROR(ENOMEM); - v->mb_type[0] = v->mb_type_base + s->b8_stride + 1; - v->mb_type[1] = v->mb_type_base + s->b8_stride * (mb_height * 2 + 1) + s->mb_stride + 1; - v->mb_type[2] = v->mb_type[1] + s->mb_stride * (mb_height + 1); + v->mb_type = v->mb_type_base + s->b8_stride + 1; /* allocate memory to store block level MV info */ v->blk_mv_type_base = av_mallocz( s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); @@ -422,8 +420,7 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) return AVERROR(ENOMEM); } - ret = ff_intrax8_common_init(s->avctx, &v->x8, - s->block, s->block_last_index, + ret = ff_intrax8_common_init(s->avctx, &v->x8, v->blocks[0], s->mb_width, s->mb_height); if (ret < 0) return ret; @@ -471,13 +468,8 @@ av_cold int ff_vc1_decode_init(AVCodecContext *avctx) if (ret < 0) return ret; - s->y_dc_scale_table = ff_wmv3_dc_scale_table; - s->c_dc_scale_table = ff_wmv3_dc_scale_table; - - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, - ff_wmv1_scantable[0]); - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, - ff_wmv1_scantable[1]); + ff_permute_scantable(s->intra_scantable.permutated, ff_wmv1_scantable[1], + s->idsp.idct_permutation); ret = vc1_decode_init_alloc_tables(v); if (ret < 0) { @@ -788,6 +780,7 @@ static av_cold void vc1_decode_reset(AVCodecContext *avctx) for (i = 0; i < 4; i++) av_freep(&v->sr_rows[i >> 1][i & 1]); ff_mpv_common_end(&v->s); + memset(v->s.block_index, 0, sizeof(v->s.block_index)); av_freep(&v->mv_type_mb_plane); av_freep(&v->direct_mb_plane); av_freep(&v->forward_mb_plane); @@ -906,8 +899,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } case VC1_CODE_ENTRYPOINT: /* it should be before frame data */ buf_size2 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); - init_get_bits(&s->gb, buf2, buf_size2 * 8); - ff_vc1_decode_entry_point(avctx, v, &s->gb); + init_get_bits(&v->gb, buf2, buf_size2 * 8); + ff_vc1_decode_entry_point(avctx, v, &v->gb); break; case VC1_CODE_SLICE: { int buf_size3; @@ -971,16 +964,16 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } else { buf_size2 = v->vc1dsp.vc1_unescape_buffer(buf, buf_size, buf2); } - init_get_bits(&s->gb, buf2, buf_size2*8); + init_get_bits(&v->gb, buf2, buf_size2*8); } else{ - ret = init_get_bits8(&s->gb, buf, buf_size); + ret = init_get_bits8(&v->gb, buf, buf_size); if (ret < 0) return ret; } if (v->res_sprite) { - v->new_sprite = !get_bits1(&s->gb); - v->two_sprites = get_bits1(&s->gb); + v->new_sprite = !get_bits1(&v->gb); + v->two_sprites = get_bits1(&v->gb); /* res_sprite means a Windows Media Image stream, AV_CODEC_ID_*IMAGE means we're using the sprite compositor. These are intentionally kept separate so you can get the raw sprites by using the wmv3 decoder for WMVP or @@ -1023,11 +1016,11 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, v->pic_header_flag = 0; v->first_pic_header_flag = 1; if (v->profile < PROFILE_ADVANCED) { - if ((ret = ff_vc1_parse_frame_header(v, &s->gb)) < 0) { + if ((ret = ff_vc1_parse_frame_header(v, &v->gb)) < 0) { goto err; } } else { - if ((ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { goto err; } } @@ -1092,7 +1085,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if (v->field_mode && buf_start_second_field) { // decode first field s->picture_structure = PICT_BOTTOM_FIELD - v->tff; - ret = hwaccel->start_frame(avctx, buf_start, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start, buf_start_second_field - buf_start); if (ret < 0) goto err; @@ -1110,12 +1103,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; for (i = 0 ; i < n_slices1 + 1; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1135,19 +1128,19 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; // decode second field - s->gb = slices[n_slices1 + 1].gb; + v->gb = slices[n_slices1 + 1].gb; s->mb_y = slices[n_slices1 + 1].mby_start; s->picture_structure = PICT_TOP_FIELD + v->tff; v->second_field = 1; v->pic_header_flag = 0; - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(avctx, AV_LOG_ERROR, "parsing header for second field failed"); ret = AVERROR_INVALIDDATA; goto err; } v->s.cur_pic.ptr->f->pict_type = v->s.pict_type; - ret = hwaccel->start_frame(avctx, buf_start_second_field, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start_second_field, (buf + buf_size) - buf_start_second_field); if (ret < 0) goto err; @@ -1165,12 +1158,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; for (i = n_slices1 + 2; i < n_slices; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1190,7 +1183,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; } else { s->picture_structure = PICT_FRAME; - ret = hwaccel->start_frame(avctx, buf_start, + ret = hwaccel->start_frame(avctx, avpkt->buf, buf_start, (buf + buf_size) - buf_start); if (ret < 0) goto err; @@ -1210,12 +1203,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, // and process the slices as additional slices afterwards for (i = 0 ; i < n_slices; i++) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; s->mb_y = slices[i].mby_start; - v->pic_header_flag = get_bits1(&s->gb); + v->pic_header_flag = get_bits1(&v->gb); if (v->pic_header_flag) { - if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1270,16 +1263,16 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if (i) { v->pic_header_flag = 0; if (v->field_mode && i == n_slices1 + 2) { - if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((header_ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Field header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) goto err; continue; } - } else if (get_bits1(&s->gb)) { + } else if (get_bits1(&v->gb)) { v->pic_header_flag = 1; - if ((header_ret = ff_vc1_parse_frame_header_adv(v, &s->gb)) < 0) { + if ((header_ret = ff_vc1_parse_frame_header_adv(v, &v->gb)) < 0) { av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); ret = AVERROR_INVALIDDATA; if (avctx->err_recognition & AV_EF_EXPLODE) @@ -1312,7 +1305,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } ff_vc1_decode_blocks(v); if (i != n_slices) { - s->gb = slices[i].gb; + v->gb = slices[i].gb; } } if (v->field_mode) { @@ -1328,8 +1321,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } } ff_dlog(s->avctx, "Consumed %i/%i bits\n", - get_bits_count(&s->gb), s->gb.size_in_bits); -// if (get_bits_count(&s->gb) > buf_size * 8) + get_bits_count(&v->gb), v->gb.size_in_bits); +// if (get_bits_count(&v->gb) > buf_size * 8) // return -1; if(s->er.error_occurred && s->pict_type == AV_PICTURE_TYPE_B) { ret = AVERROR_INVALIDDATA; @@ -1355,7 +1348,7 @@ image: goto err; } #if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER - if ((ret = vc1_decode_sprites(v, &s->gb)) < 0) + if ((ret = vc1_decode_sprites(v, &v->gb)) < 0) goto err; #endif if ((ret = av_frame_ref(pict, v->sprite_output_frame)) < 0) @@ -1365,14 +1358,12 @@ image: if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) goto err; - if (!v->field_mode) - ff_print_debug_info(s, s->cur_pic.ptr, pict); + ff_print_debug_info(s, s->cur_pic.ptr, pict); *got_frame = 1; } else if (s->last_pic.ptr) { if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0) goto err; - if (!v->field_mode) - ff_print_debug_info(s, s->last_pic.ptr, pict); + ff_print_debug_info(s, s->last_pic.ptr, pict); *got_frame = 1; } } diff --git a/libavcodec/vc1dsp.h b/libavcodec/vc1dsp.h index e3b90d2b62..b018537af3 100644 --- a/libavcodec/vc1dsp.h +++ b/libavcodec/vc1dsp.h @@ -30,7 +30,9 @@ #include "hpeldsp.h" #include "h264chroma.h" -typedef void (*vc1op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, const uint8_t *pixels/*align 1*/, ptrdiff_t line_size, int h); +typedef void (*vc1op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, + const uint8_t *pixels/*align 1*/, + ptrdiff_t line_size, int round); typedef struct VC1DSPContext { /* vc1 functions */ diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c index b82370a753..2c155c01a1 100644 --- a/libavcodec/vc2enc.c +++ b/libavcodec/vc2enc.c @@ -22,6 +22,7 @@ #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "libavutil/version.h" #include "codec_internal.h" #include "dirac.h" @@ -186,51 +187,53 @@ typedef struct VC2EncContext { enum DiracParseCodes last_parse_code; } VC2EncContext; -static av_always_inline void put_vc2_ue_uint(PutBitContext *pb, uint32_t val) +/// x_k x_{k-1} ... x_0 -> 0 x_k 0 x_{k - 1} ... 0 x_0 +static uint16_t interleaved_ue_golomb_tab[256]; +/// 1 x_{k-1} ... x_0 -> 0 0 0 x_{k - 1} ... 0 x_0 +static uint16_t top_interleaved_ue_golomb_tab[256]; +/// 1 x_{k-1} ... x_0 -> 2 * k +static uint8_t golomb_len_tab[256]; +/// quant -> av_log2(ff_dirac_qscale_tab[quant]) + 32 +static uint8_t qscale_len_tab[FF_ARRAY_ELEMS(ff_dirac_qscale_tab)]; + +static av_cold void vc2_init_static_data(void) { - int i; - int bits = 0; - unsigned topbit = 1, maxval = 1; - uint64_t pbits = 0; - - if (!val++) { - put_bits(pb, 1, 1); - return; + interleaved_ue_golomb_tab[1] = 1; + for (unsigned i = 2; i < 256; ++i) { + golomb_len_tab[i] = golomb_len_tab[i >> 1] + 2; + interleaved_ue_golomb_tab[i] = (interleaved_ue_golomb_tab[i >> 1] << 2) | (i & 1); + top_interleaved_ue_golomb_tab[i] = interleaved_ue_golomb_tab[i] ^ (1 << golomb_len_tab[i]); } + for (size_t i = 0; i < FF_ARRAY_ELEMS(qscale_len_tab); ++i) + qscale_len_tab[i] = av_log2(ff_dirac_qscale_tab[i]) + 32; +} - while (val > maxval) { - topbit <<= 1; - maxval <<= 1; - maxval |= 1; +static av_always_inline void put_vc2_ue_uint_inline(PutBitContext *pb, uint32_t val) +{ + uint64_t pbits = 1; + int bits = 1; + + ++val; + + while (val >> 8) { + pbits |= (uint64_t)interleaved_ue_golomb_tab[val & 0xff] << bits; + val >>= 8; + bits += 16; } + pbits |= (uint64_t)top_interleaved_ue_golomb_tab[val] << bits; + bits += golomb_len_tab[val]; - bits = ff_log2(topbit); + put_bits63(pb, bits, pbits); +} - for (i = 0; i < bits; i++) { - topbit >>= 1; - av_assert2(pbits <= UINT64_MAX>>3); - pbits <<= 2; - if (val & topbit) - pbits |= 0x1; - } - - put_bits64(pb, bits*2 + 1, (pbits << 1) | 1); +static av_noinline void put_vc2_ue_uint(PutBitContext *pb, uint32_t val) +{ + put_vc2_ue_uint_inline(pb, val); } static av_always_inline int count_vc2_ue_uint(uint32_t val) { - int topbit = 1, maxval = 1; - - if (!val++) - return 1; - - while (val > maxval) { - topbit <<= 1; - maxval <<= 1; - maxval |= 1; - } - - return ff_log2(topbit)*2 + 1; + return 2 * av_log2(val + 1) + 1; } /* VC-2 10.4 - parse_info() */ @@ -546,12 +549,12 @@ static void encode_subband(const VC2EncContext *s, PutBitContext *pb, 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; + const int q_s = qscale_len_tab[quant]; for (y = top; y < bottom; y++) { for (x = left; x < right; x++) { uint32_t c_abs = QUANT(FFABS(coeff[x]), q_m, q_a, q_s); - put_vc2_ue_uint(pb, c_abs); + put_vc2_ue_uint_inline(pb, c_abs); if (c_abs) put_bits(pb, 1, coeff[x] < 0); } @@ -587,7 +590,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) const int q_idx = quants[level][orientation]; 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 q_s = qscale_len_tab[q_idx]; const int left = b->width * slice->x / s->num_x; const int right = b->width *(slice->x+1) / s->num_x; @@ -618,7 +621,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) return bits; } -/* Approaches the best possible quantizer asymptotically, its kinda exaustive +/* Approaches the best possible quantizer asymptotically, its kinda exhaustive * but we have a LUT to get the coefficient size in bits. Guaranteed to never * overshoot, which is apparently very important when streaming */ static int rate_control(AVCodecContext *avctx, void *arg) @@ -1027,6 +1030,7 @@ static av_cold int vc2_encode_end(AVCodecContext *avctx) static av_cold int vc2_encode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; Plane *p; SubBand *b; int i, level, o, shift; @@ -1080,13 +1084,13 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) if ((s->slice_width & (s->slice_width - 1)) || (s->slice_height & (s->slice_height - 1))) { av_log(avctx, AV_LOG_ERROR, "Slice size is not a power of two!\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } if ((s->slice_width > avctx->width) || (s->slice_height > avctx->height)) { av_log(avctx, AV_LOG_ERROR, "Slice size is bigger than the image!\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } if (s->base_vf <= 0) { @@ -1096,7 +1100,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } else { av_log(avctx, AV_LOG_WARNING, "Given format does not strictly comply with " "the specifications, decrease strictness to use it.\n"); - return AVERROR_UNKNOWN; + return AVERROR(EINVAL); } } else { av_log(avctx, AV_LOG_INFO, "Selected base video format = %i (%s)\n", @@ -1189,6 +1193,8 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } } + ff_thread_once(&init_static_once, vc2_init_static_data); + return 0; } @@ -1244,6 +1250,6 @@ const FFCodec ff_vc2_encoder = { FF_CODEC_ENCODE_CB(vc2_encode_frame), .p.priv_class = &vc2enc_class, .defaults = vc2enc_defaults, - .p.pix_fmts = allowed_pix_fmts, + CODEC_PIXFMTS_ARRAY(allowed_pix_fmts), .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 0dd5641603..e99ac5338d 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -28,7 +28,6 @@ #include "decode.h" #include "hwaccel_internal.h" #include "internal.h" -#include "mpegvideodec.h" #include "vdpau.h" #include "vdpau_internal.h" @@ -62,20 +61,6 @@ static int vdpau_error(VdpStatus status) } } -#if FF_API_VDPAU_ALLOC_GET_SET -AVVDPAUContext *av_alloc_vdpaucontext(void) -{ -FF_DISABLE_DEPRECATION_WARNINGS - return av_vdpau_alloc_context(); -FF_ENABLE_DEPRECATION_WARNINGS -} - -#define MAKE_ACCESSORS(str, name, type, field) \ - type av_##name##_get_##field(const str *s) { return s->field; } \ - void av_##name##_set_##field(str *s, type v) { s->field = v; } -MAKE_ACCESSORS(AVVDPAUContext, vdpau_hwaccel, AVVDPAU_Render2, render2) -#endif - int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, uint32_t *width, uint32_t *height) @@ -139,8 +124,8 @@ int ff_vdpau_common_frame_params(AVCodecContext *avctx, return 0; } -int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, - int level) +av_cold int ff_vdpau_common_init(AVCodecContext *avctx, + VdpDecoderProfile profile, int level) { VDPAUHWContext *hwctx = avctx->hwaccel_context; VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data; @@ -290,7 +275,7 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, return vdpau_error(status); } -int ff_vdpau_common_uninit(AVCodecContext *avctx) +av_cold int ff_vdpau_common_uninit(AVCodecContext *avctx) { VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data; VdpDecoderDestroy *destroy; @@ -367,6 +352,8 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, #if CONFIG_MPEG1_VDPAU_HWACCEL || \ CONFIG_MPEG2_VDPAU_HWACCEL || CONFIG_MPEG4_VDPAU_HWACCEL || \ CONFIG_VC1_VDPAU_HWACCEL || CONFIG_WMV3_VDPAU_HWACCEL +#include "mpegvideodec.h" + int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; @@ -402,13 +389,6 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx, return 0; } -#if FF_API_VDPAU_ALLOC_GET_SET -AVVDPAUContext *av_vdpau_alloc_context(void) -{ - return av_mallocz(sizeof(VDPAUHWContext)); -} -#endif - int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, VdpGetProcAddress *get_proc, unsigned flags) { diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h index 8021c25761..da77c5daed 100644 --- a/libavcodec/vdpau.h +++ b/libavcodec/vdpau.h @@ -93,28 +93,6 @@ typedef struct AVVDPAUContext { AVVDPAU_Render2 render2; } AVVDPAUContext; -#if FF_API_VDPAU_ALLOC_GET_SET -/** - * @brief allocation function for AVVDPAUContext - * - * Allows extending the struct without breaking API/ABI - * @deprecated use av_vdpau_bind_context() instead - */ -attribute_deprecated -AVVDPAUContext *av_alloc_vdpaucontext(void); - -/** - * @deprecated render2 is public and can be accessed directly - */ -attribute_deprecated -AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); -/** - * @deprecated render2 is public and can be accessed directly - */ -attribute_deprecated -void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); -#endif - /** * Associate a VDPAU device with a codec context for hardware acceleration. * This function is meant to be called from the get_format() codec callback, @@ -155,17 +133,6 @@ int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, uint32_t *width, uint32_t *height); -#if FF_API_VDPAU_ALLOC_GET_SET -/** - * Allocate an AVVDPAUContext. - * - * @return Newly-allocated AVVDPAUContext or NULL on failure. - * @deprecated use av_vdpau_bind_context() instead - */ -attribute_deprecated -AVVDPAUContext *av_vdpau_alloc_context(void); -#endif - /** @} */ #endif /* AVCODEC_VDPAU_H */ diff --git a/libavcodec/vdpau_av1.c b/libavcodec/vdpau_av1.c index a1aff79bb7..b7e7fa8b0c 100644 --- a/libavcodec/vdpau_av1.c +++ b/libavcodec/vdpau_av1.c @@ -41,7 +41,8 @@ static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq) } static int vdpau_av1_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { AV1DecContext *s = avctx->priv_data; const AV1RawSequenceHeader *seq = s->raw_seq; @@ -330,7 +331,7 @@ static int vdpau_av1_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_av1_init(AVCodecContext *avctx) +static av_cold int vdpau_av1_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c index 9c08e4048c..51c7e99900 100644 --- a/libavcodec/vdpau_h264.c +++ b/libavcodec/vdpau_h264.c @@ -118,6 +118,7 @@ static void vdpau_h264_set_reference_frames(AVCodecContext *avctx) } static int vdpau_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { H264Context * const h = avctx->priv_data; @@ -214,7 +215,7 @@ static int vdpau_h264_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_h264_init(AVCodecContext *avctx) +static av_cold int vdpau_h264_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index 0ddcafd897..1a92c32b27 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -32,6 +32,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { HEVCContext *h = avctx->priv_data; @@ -513,7 +514,7 @@ static int vdpau_hevc_parse_rext_profile(AVCodecContext *avctx, VdpDecoderProfil } -static int vdpau_hevc_init(AVCodecContext *avctx) +static av_cold int vdpau_hevc_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c index 1ce0bfaa07..4d16f18089 100644 --- a/libavcodec/vdpau_mpeg12.c +++ b/libavcodec/vdpau_mpeg12.c @@ -32,6 +32,7 @@ #include "vdpau_internal.h" static int vdpau_mpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { MpegEncContext * const s = avctx->priv_data; @@ -100,7 +101,7 @@ static int vdpau_mpeg_decode_slice(AVCodecContext *avctx, } #if CONFIG_MPEG1_VDPAU_HWACCEL -static int vdpau_mpeg1_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg1_init(AVCodecContext *avctx) { return ff_vdpau_common_init(avctx, VDP_DECODER_PROFILE_MPEG1, VDP_DECODER_LEVEL_MPEG1_NA); @@ -123,7 +124,7 @@ const FFHWAccel ff_mpeg1_vdpau_hwaccel = { #endif #if CONFIG_MPEG2_VDPAU_HWACCEL -static int vdpau_mpeg2_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg2_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c index 40af8655cc..668720a231 100644 --- a/libavcodec/vdpau_mpeg4.c +++ b/libavcodec/vdpau_mpeg4.c @@ -30,10 +30,11 @@ #include "vdpau_internal.h" static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { Mpeg4DecContext *ctx = avctx->priv_data; - MpegEncContext * const s = &ctx->m; + MPVContext *const s = &ctx->h.c; MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoMPEG4Part2 *info = &pic_ctx->info.mpeg4; @@ -63,11 +64,11 @@ static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, info->trd[1] = s->pp_field_time >> 1; info->trb[1] = s->pb_field_time >> 1; info->vop_time_increment_resolution = s->avctx->framerate.num; - info->vop_fcode_forward = s->f_code; - info->vop_fcode_backward = s->b_code; + info->vop_fcode_forward = ctx->f_code; + info->vop_fcode_backward = ctx->b_code; info->resync_marker_disable = !ctx->resync_marker; info->interlaced = !s->progressive_sequence; - info->quant_type = s->mpeg_quant; + info->quant_type = ctx->mpeg_quant; info->quarter_sample = s->quarter_sample; info->short_video_header = avctx->codec->id == AV_CODEC_ID_H263; info->rounding_control = s->no_rounding; @@ -90,7 +91,7 @@ static int vdpau_mpeg4_decode_slice(av_unused AVCodecContext *avctx, return 0; } -static int vdpau_mpeg4_init(AVCodecContext *avctx) +static av_cold int vdpau_mpeg4_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c index d02a454bb8..a5fd8156f4 100644 --- a/libavcodec/vdpau_vc1.c +++ b/libavcodec/vdpau_vc1.c @@ -32,6 +32,7 @@ #include "vdpau_internal.h" static int vdpau_vc1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { VC1Context * const v = avctx->priv_data; @@ -82,7 +83,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, info->extended_dmv = v->extended_dmv; info->overlap = v->overlap; info->vstransform = v->vstransform; - info->loopfilter = v->s.loop_filter; + info->loopfilter = v->loop_filter; info->fastuvmc = v->fastuvmc; info->range_mapy_flag = v->range_mapy_flag; info->range_mapy = v->range_mapy; @@ -92,7 +93,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, info->multires = v->multires; info->syncmarker = v->resync_marker; info->rangered = v->rangered | (v->rangeredfrm << 1); - info->maxbframes = v->s.max_b_frames; + info->maxbframes = v->max_b_frames; info->deblockEnable = v->postprocflag & 1; info->pquant = v->pq; @@ -116,7 +117,7 @@ static int vdpau_vc1_decode_slice(AVCodecContext *avctx, return 0; } -static int vdpau_vc1_init(AVCodecContext *avctx) +static av_cold int vdpau_vc1_init(AVCodecContext *avctx) { VdpDecoderProfile profile; diff --git a/libavcodec/vdpau_vp9.c b/libavcodec/vdpau_vp9.c index 424e2e60fb..7b3c1ff4d7 100644 --- a/libavcodec/vdpau_vp9.c +++ b/libavcodec/vdpau_vp9.c @@ -29,7 +29,8 @@ #include "vdpau_internal.h" static int vdpau_vp9_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, uint32_t size) { VP9Context *s = avctx->priv_data; VP9SharedContext *h = &(s->s); @@ -197,7 +198,7 @@ static int vdpau_vp9_end_frame(AVCodecContext *avctx) return 0; } -static int vdpau_vp9_init(AVCodecContext *avctx) +static av_cold int vdpau_vp9_init(AVCodecContext *avctx) { VdpDecoderProfile profile; uint32_t level = avctx->level; diff --git a/libavcodec/version.c b/libavcodec/version.c index 27f94323b8..8a0398f28f 100644 --- a/libavcodec/version.c +++ b/libavcodec/version.c @@ -31,12 +31,12 @@ const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avcodec_version(void) { - static_assert(AV_CODEC_ID_LEAD == 269 && + static_assert(AV_CODEC_ID_DNXUC == 270 && AV_CODEC_ID_PCM_SGA == 65572 && AV_CODEC_ID_ADPCM_XMD == 69683 && AV_CODEC_ID_CBD2_DPCM == 81928 && AV_CODEC_ID_QOA == 86121 && - AV_CODEC_ID_ARIB_CAPTION == 94233 && + AV_CODEC_ID_IVTV_VBI == 94234 && AV_CODEC_ID_SMPTE_2038 == 98315, "Don't insert new codec ids in the middle of a list"); static_assert(LIBAVCODEC_VERSION_MICRO >= 100, "micro version starts at 100"); diff --git a/libavcodec/version.h b/libavcodec/version.h index 4b7ec515fe..da2264a097 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 19 +#define LIBAVCODEC_VERSION_MINOR 12 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h index 63df40e9dd..97e4e12065 100644 --- a/libavcodec/version_major.h +++ b/libavcodec/version_major.h @@ -25,7 +25,7 @@ * Libavcodec version macros. */ -#define LIBAVCODEC_VERSION_MAJOR 61 +#define LIBAVCODEC_VERSION_MAJOR 62 /** * FF_API_* defines may be placed below to indicate public API that will be @@ -37,16 +37,19 @@ * at once through the bump. This improves the git bisect-ability of the change. */ -#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_SUBFRAMES (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_TICKS_PER_FRAME (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_DROPCHANGED (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 63) -#define FF_API_AVFFT (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_FF_PROFILE_LEVEL (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_AVCODEC_CLOSE (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_BUFFER_MIN_SIZE (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_VDPAU_ALLOC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_QUALITY_FACTOR (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_V408_CODECID (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_CODEC_PROPS (LIBAVCODEC_VERSION_MAJOR < 63) +#define FF_API_EXR_GAMMA (LIBAVCODEC_VERSION_MAJOR < 63) + +#define FF_API_NVDEC_OLD_PIX_FMTS (LIBAVCODEC_VERSION_MAJOR < 63) + +// reminder to remove the OMX encoder on next major bump +#define FF_CODEC_OMX (LIBAVCODEC_VERSION_MAJOR < 63) +// reminder to remove Sonic Lossy/Lossless encoders on next major bump +#define FF_CODEC_SONIC_ENC (LIBAVCODEC_VERSION_MAJOR < 63) +// reminder to remove Sonic decoder on next-next major bump +#define FF_CODEC_SONIC_DEC (LIBAVCODEC_VERSION_MAJOR < 63) #endif /* AVCODEC_VERSION_MAJOR_H */ diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index 505483ef66..ccba249140 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -56,6 +56,10 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' }; enum { kCMVideoCodecType_VP9 = 'vp09' }; #endif +#if !HAVE_KCMVIDEOCODECTYPE_AV1 +enum { kCMVideoCodecType_AV1 = 'av01' }; +#endif + #define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING 12 typedef struct VTHWFrame { @@ -79,8 +83,8 @@ int ff_videotoolbox_buffer_copy(VTContext *vtctx, void *tmp; tmp = av_fast_realloc(vtctx->bitstream, - &vtctx->allocated_size, - size); + &vtctx->allocated_size, + size); if (!tmp) return AVERROR(ENOMEM); @@ -92,6 +96,26 @@ int ff_videotoolbox_buffer_copy(VTContext *vtctx, return 0; } +int ff_videotoolbox_buffer_append(VTContext *vtctx, + const uint8_t *buffer, + uint32_t size) +{ + void *tmp; + + tmp = av_fast_realloc(vtctx->bitstream, + &vtctx->allocated_size, + vtctx->bitstream_size + size); + + if (!tmp) + return AVERROR(ENOMEM); + + vtctx->bitstream = tmp; + memcpy(vtctx->bitstream + vtctx->bitstream_size, buffer, size); + vtctx->bitstream_size += size; + + return 0; +} + static int videotoolbox_postproc_frame(void *avctx, AVFrame *frame) { int ret; @@ -143,7 +167,7 @@ int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) } frame->buf[0] = buf; - fdd = (FrameDecodeData*)frame->private_ref->data; + fdd = frame->private_ref; fdd->post_process = videotoolbox_postproc_frame; frame->width = avctx->width; @@ -391,6 +415,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) } int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -703,8 +728,13 @@ static void videotoolbox_decoder_callback(void *opaque, } if (!image_buffer) { + // kVTVideoDecoderReferenceMissingErr, defined since the macOS 12 SDKs + if (status != -17694) + vtctx->reconfig_needed = true; + av_log(vtctx->logctx, status ? AV_LOG_WARNING : AV_LOG_DEBUG, - "vt decoder cb: output image buffer is null: %i\n", status); + "vt decoder cb: output image buffer is null: %i, reconfig %d\n", + status, vtctx->reconfig_needed); return; } @@ -846,6 +876,13 @@ static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec if (data) CFDictionarySetValue(avc_info, CFSTR("vpcC"), data); break; +#endif +#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + case kCMVideoCodecType_AV1 : + data = ff_videotoolbox_av1c_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("av1C"), data); + break; #endif default: break; @@ -912,6 +949,9 @@ static int videotoolbox_start(AVCodecContext *avctx) case AV_CODEC_ID_VP9 : videotoolbox->cm_codec_type = kCMVideoCodecType_VP9; break; + case AV_CODEC_ID_AV1 : + videotoolbox->cm_codec_type = kCMVideoCodecType_AV1; + break; default : break; } @@ -1031,10 +1071,8 @@ int ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) return AVERROR_UNKNOWN; } - if (!vtctx->frame) { - vtctx->reconfig_needed = true; + if (!vtctx->frame) return AVERROR_UNKNOWN; - } return videotoolbox_buffer_create(avctx, frame); } @@ -1050,6 +1088,7 @@ static int videotoolbox_h264_end_frame(AVCodecContext *avctx) } static int videotoolbox_hevc_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -1093,6 +1132,7 @@ static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) } static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { @@ -1117,8 +1157,9 @@ static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) } static int videotoolbox_prores_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) + const AVBufferRef *buffer_ref, + const uint8_t *buffer, + uint32_t size) { return 0; } @@ -1146,11 +1187,10 @@ static enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) if (!descriptor) return AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + depth = descriptor->comp[0].depth; if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) - return AV_PIX_FMT_AYUV64; - - depth = descriptor->comp[0].depth; + return (depth > 8) ? AV_PIX_FMT_AYUV64 : AV_PIX_FMT_AYUV; #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE if (depth > 10) diff --git a/libavcodec/videotoolbox_av1.c b/libavcodec/videotoolbox_av1.c new file mode 100644 index 0000000000..e69ef8f028 --- /dev/null +++ b/libavcodec/videotoolbox_av1.c @@ -0,0 +1,106 @@ +/* + * Videotoolbox hardware acceleration for AV1 + * Copyright (c) 2023 Jan Ekström + * Copyright (c) 2024 Ruslan Chernenko + * Copyright (c) 2024 Martin Storsjö + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" + +#include "av1dec.h" +#include "hwaccel_internal.h" +#include "internal.h" +#include "vt_internal.h" + +CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx) +{ + AV1DecContext *s = avctx->priv_data; + uint8_t *buf; + CFDataRef data; + if (!s->raw_seq) + return NULL; + + buf = av_malloc(s->seq_data_ref->size + 4); + if (!buf) + return NULL; + buf[0] = 0x81; // version and marker (constant) + buf[1] = s->raw_seq->seq_profile << 5 | s->raw_seq->seq_level_idx[0]; + buf[2] = s->raw_seq->seq_tier[0] << 7 | + s->raw_seq->color_config.high_bitdepth << 6 | + s->raw_seq->color_config.twelve_bit << 5 | + s->raw_seq->color_config.mono_chrome << 4 | + s->raw_seq->color_config.subsampling_x << 3 | + s->raw_seq->color_config.subsampling_y << 2 | + s->raw_seq->color_config.chroma_sample_position; + + if (s->raw_seq->initial_display_delay_present_flag) + buf[3] = 0 << 5 | + s->raw_seq->initial_display_delay_present_flag << 4 | + s->raw_seq->initial_display_delay_minus_1[0]; + else + buf[3] = 0x00; + memcpy(buf + 4, s->seq_data_ref->data, s->seq_data_ref->size); + data = CFDataCreate(kCFAllocatorDefault, buf, s->seq_data_ref->size + 4); + av_free(buf); + return data; +}; + + +static int videotoolbox_av1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_av1_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_av1_end_frame(AVCodecContext *avctx) +{ + const AV1DecContext *s = avctx->priv_data; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + AVFrame *frame = s->cur_frame.f; + + vtctx->bitstream_size = 0; + for (int i = s->start_unit; i < s->nb_unit; i++) + ff_videotoolbox_buffer_append(vtctx, s->current_obu.units[i].data, + s->current_obu.units[i].data_size); + return ff_videotoolbox_common_end_frame(avctx, frame); +} + +const FFHWAccel ff_av1_videotoolbox_hwaccel = { + .p.name = "av1_videotoolbox", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_AV1, + .p.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX, + .alloc_frame = ff_videotoolbox_alloc_frame, + .start_frame = videotoolbox_av1_start_frame, + .decode_slice = videotoolbox_av1_decode_slice, + .end_frame = videotoolbox_av1_end_frame, + .frame_params = ff_videotoolbox_frame_params, + .init = ff_videotoolbox_common_init, + .uninit = ff_videotoolbox_uninit, + .priv_data_size = sizeof(VTContext), +}; diff --git a/libavcodec/videotoolbox_vp9.c b/libavcodec/videotoolbox_vp9.c index da94ff4e54..f2cb34fca4 100644 --- a/libavcodec/videotoolbox_vp9.c +++ b/libavcodec/videotoolbox_vp9.c @@ -71,12 +71,12 @@ CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx) uint8_t *vt_extradata; int subsampling = get_vpx_chroma_subsampling(avctx->sw_pix_fmt, avctx->chroma_sample_location); - vt_extradata_size = 1 + 3 + 6 + 2; - vt_extradata = av_malloc(vt_extradata_size); - if (subsampling < 0) return NULL; + vt_extradata_size = 1 + 3 + 6 + 2; + vt_extradata = av_malloc(vt_extradata_size); + if (!vt_extradata) return NULL; @@ -104,6 +104,7 @@ CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx) } static int videotoolbox_vp9_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size) { diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index da7b291b03..b748ecda61 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -54,6 +54,11 @@ enum { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange = 'xf20' }; enum { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange = 'x420' }; #endif +#if !HAVE_KVTQPMODULATIONLEVEL_DEFAULT +enum { kVTQPModulationLevel_Default = -1 }; +enum { kVTQPModulationLevel_Disable = 0 }; +#endif + #ifndef TARGET_CPU_ARM64 # define TARGET_CPU_ARM64 0 #endif @@ -115,12 +120,14 @@ static struct{ CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main42210_AutoLevel; CFStringRef kVTCompressionPropertyKey_RealTime; CFStringRef kVTCompressionPropertyKey_TargetQualityForAlpha; CFStringRef kVTCompressionPropertyKey_PrioritizeEncodingSpeedOverQuality; CFStringRef kVTCompressionPropertyKey_ConstantBitRate; CFStringRef kVTCompressionPropertyKey_EncoderID; + CFStringRef kVTCompressionPropertyKey_SpatialAdaptiveQPLevel; CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder; CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder; @@ -186,6 +193,7 @@ static void loadVTEncSymbols(void){ GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel"); GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main42210_AutoLevel, "HEVC_Main42210_AutoLevel"); GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); GET_SYM(kVTCompressionPropertyKey_TargetQualityForAlpha, @@ -208,6 +216,7 @@ static void loadVTEncSymbols(void){ "ReferenceBufferCount"); GET_SYM(kVTCompressionPropertyKey_MaxAllowedFrameQP, "MaxAllowedFrameQP"); GET_SYM(kVTCompressionPropertyKey_MinAllowedFrameQP, "MinAllowedFrameQP"); + GET_SYM(kVTCompressionPropertyKey_SpatialAdaptiveQPLevel, "SpatialAdaptiveQPLevel"); } #define H264_PROFILE_CONSTRAINED_HIGH (AV_PROFILE_H264_HIGH | AV_PROFILE_H264_CONSTRAINED) @@ -279,6 +288,7 @@ typedef struct VTEncContext { int max_slice_bytes; int power_efficient; int max_ref_frames; + int spatialaq; } VTEncContext; static void vtenc_free_buf_node(BufNode *info) @@ -971,6 +981,11 @@ static bool get_vt_hevc_profile_level(AVCodecContext *avctx, *profile_level_val = compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; break; + case AV_PROFILE_HEVC_REXT: + // only main42210 is supported, omit depth and chroma subsampling + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main42210_AutoLevel; + break; } if (!*profile_level_val) { @@ -1204,7 +1219,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } #if defined (MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13) - if (__builtin_available(macOS 10.13, *)) { + if (__builtin_available(macOS 10.13, iOS 11.0, *)) { if (vtctx->supported_props) { CFRelease(vtctx->supported_props); vtctx->supported_props = NULL; @@ -1327,8 +1342,10 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } } - if (vtctx->codec_id == AV_CODEC_ID_HEVC) { - if (avctx->pix_fmt == AV_PIX_FMT_BGRA && vtctx->alpha_quality > 0.0) { + if (vtctx->codec_id == AV_CODEC_ID_HEVC && vtctx->alpha_quality > 0.0) { + const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->pix_fmt); + + if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) { CFNumberRef alpha_quality_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &vtctx->alpha_quality); @@ -1599,6 +1616,13 @@ static int vtenc_create_encoder(AVCodecContext *avctx, } } + if (vtctx->spatialaq >= 0) { + set_encoder_int_property_or_log(avctx, + compat_keys.kVTCompressionPropertyKey_SpatialAdaptiveQPLevel, + "spatialaq", + vtctx->spatialaq ? kVTQPModulationLevel_Default : kVTQPModulationLevel_Disable); + } + status = VTCompressionSessionPrepareToEncodeFrames(vtctx->session); if (status) { av_log(avctx, AV_LOG_ERROR, "Error: cannot prepare encoder: %d\n", status); @@ -2838,7 +2862,9 @@ static const enum AVPixelFormat hevc_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, + AV_PIX_FMT_AYUV, AV_PIX_FMT_P010LE, + AV_PIX_FMT_P210, AV_PIX_FMT_NONE }; @@ -2891,6 +2917,8 @@ static const enum AVPixelFormat prores_pix_fmts[] = { { .i64 = -1 }, -1, 1, VE }, \ { "power_efficient", "Set to 1 to enable more power-efficient encoding if supported.", \ OFFSET(power_efficient), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ + { "spatial_aq", "Set to 1 to enable spatial AQ if supported.", \ + OFFSET(spatialaq), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "max_ref_frames", \ "Sets the maximum number of reference frames. This only has an effect when the value is less than the maximum allowed by the profile/level.", \ OFFSET(max_ref_frames), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, @@ -2957,7 +2985,7 @@ const FFCodec ff_h264_videotoolbox_encoder = { .p.id = AV_CODEC_ID_H264, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = avc_pix_fmts, + CODEC_PIXFMTS_ARRAY(avc_pix_fmts), .defaults = vt_defaults, .init = vtenc_init, FF_CODEC_ENCODE_CB(vtenc_frame), @@ -2971,6 +2999,8 @@ static const AVOption hevc_options[] = { { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, INT_MAX, VE, .unit = "profile" }, { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN }, INT_MIN, INT_MAX, VE, .unit = "profile" }, { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, VE, .unit = "profile" }, + { "main42210","Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" }, + { "rext", "Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" }, { "alpha_quality", "Compression quality for the alpha channel", OFFSET(alpha_quality), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0.0, 1.0, VE }, @@ -2995,7 +3025,7 @@ const FFCodec ff_hevc_videotoolbox_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = hevc_pix_fmts, + CODEC_PIXFMTS_ARRAY(hevc_pix_fmts), .defaults = vt_defaults, .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, @@ -3036,7 +3066,7 @@ const FFCodec ff_prores_videotoolbox_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .priv_data_size = sizeof(VTEncContext), - .p.pix_fmts = prores_pix_fmts, + CODEC_PIXFMTS_ARRAY(prores_pix_fmts), .defaults = vt_defaults, .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, diff --git a/libavcodec/vlc.c b/libavcodec/vlc.c index f46ecbb55e..260b2052be 100644 --- a/libavcodec/vlc.c +++ b/libavcodec/vlc.c @@ -42,6 +42,8 @@ { \ const uint8_t *ptr = (const uint8_t *)table + i * wrap; \ switch(size) { \ + default: \ + av_unreachable("Only uint8/16/32_t are used"); \ case 1: \ v = *(const uint8_t *)ptr; \ break; \ @@ -49,8 +51,6 @@ v = *(const uint16_t *)ptr; \ break; \ case 4: \ - default: \ - av_assert1(size == 4); \ v = *(const uint32_t *)ptr; \ break; \ } \ @@ -155,7 +155,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, int n = codes[i].bits; uint32_t code = codes[i].code; int symbol = codes[i].symbol; - ff_dlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); + ff_tlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); if (n <= table_nb_bits) { /* no need to add another table */ int j = code >> (32 - table_nb_bits); @@ -169,7 +169,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, for (int k = 0; k < nb; k++) { int bits = table[j].len; int oldsym = table[j].sym; - ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n); + ff_tlog(NULL, "%4x: code=%d n=%d\n", j, i, n); if ((bits || oldsym) && (bits != n || oldsym != symbol)) { av_log(NULL, AV_LOG_ERROR, "incorrect codes\n"); return AVERROR_INVALIDDATA; @@ -260,7 +260,7 @@ int ff_vlc_init_sparse(VLC *vlc, int nb_bits, int nb_codes, if (ret < 0) return ret; - av_assert0(symbols_size <= 2 || !symbols); + av_assert0(symbols_size <= 2U); j = 0; #define COPY(condition)\ for (int i = 0; i < nb_codes; i++) { \ @@ -491,7 +491,7 @@ static int vlc_multi_gen(VLC_MULTI_ELEM *table, const VLC *single, // We can only add a code that fits with the shortest other code into the table // We assume the table is sorted by bits and we skip subtables which from our // point of view are basically random corrupted entries - // If we have not a single useable vlc we end with max = nb_codes + // If we have not a single usable vlc we end with max = nb_codes if (buf[max - 1].bits+minbits > numbits) break; } diff --git a/libavcodec/vlc.h b/libavcodec/vlc.h index bf7b0e65b4..7eecd9651f 100644 --- a/libavcodec/vlc.h +++ b/libavcodec/vlc.h @@ -30,9 +30,23 @@ typedef int16_t VLCBaseType; typedef struct VLCElem { - VLCBaseType sym, len; + union { + /// The struct is for use as ordinary VLC (with get_vlc2()) + struct { + VLCBaseType sym; + VLCBaseType len; + }; + /// This struct is for use as run-length VLC (with GET_RL_VLC) + struct { + int16_t level; + int8_t len8; + uint8_t run; + }; + }; } VLCElem; +typedef VLCElem RL_VLC_ELEM; + typedef struct VLC { int bits; VLCElem *table; @@ -53,12 +67,6 @@ typedef struct VLC_MULTI { int table_size, table_allocated; } VLC_MULTI; -typedef struct RL_VLC_ELEM { - int16_t level; - int8_t len; - uint8_t run; -} RL_VLC_ELEM; - #define vlc_init(vlc, nb_bits, nb_codes, \ bits, bits_wrap, bits_size, \ codes, codes_wrap, codes_size, \ diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index 218e855f7a..60a83f394f 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -375,13 +375,13 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) } ff_dlog(NULL, " We expect %d numbers for building the codevectors. \n", codebook_lookup_values); - ff_dlog(NULL, " delta %f minmum %f \n", + ff_dlog(NULL, " delta %f minimum %f \n", codebook_delta_value, codebook_minimum_value); for (i = 0; i < codebook_lookup_values; ++i) { codebook_multiplicands[i] = get_bits(gb, codebook_value_bits); - ff_dlog(NULL, " multiplicands*delta+minmum : %e \n", + ff_dlog(NULL, " multiplicands*delta+minimum : %e \n", (float)codebook_multiplicands[i] * codebook_delta_value + codebook_minimum_value); ff_dlog(NULL, " multiplicand %u\n", codebook_multiplicands[i]); } @@ -1150,7 +1150,7 @@ static int vorbis_floor0_decode(vorbis_context *vc, ff_dlog(NULL, "floor0 dec: maximum depth: %d\n", codebook.maxdepth); /* read temp vector */ vec_off = get_vlc2(&vc->gb, codebook.vlc.table, - codebook.nb_bits, codebook.maxdepth); + codebook.nb_bits, 3); if (vec_off < 0) return AVERROR_INVALIDDATA; vec_off *= codebook.dimensions; @@ -1469,8 +1469,10 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, unsigned step = FASTDIV(vr->partition_size << 1, dim << 1); vorbis_codebook codebook = vc->codebooks[vqbook]; - if (get_bits_left(gb) <= 0) - return AVERROR_INVALIDDATA; + if (get_bits_left(gb) < 0) { + av_log(vc->avctx, AV_LOG_ERROR, "Overread %d bits\n", -get_bits_left(gb)); + return 0; + } if (vr_type == 0) { @@ -1894,7 +1896,6 @@ const FFCodec ff_vorbis_decoder = { .flush = vorbis_decode_flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_vorbis_ch_layouts, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_CH_LAYOUTS_ARRAY(ff_vorbis_ch_layouts), + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index 62684a7d8c..b4680a11ed 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -740,8 +740,10 @@ static int put_main_header(vorbis_enc_context *venc, uint8_t **out) len = hlens[0] + hlens[1] + hlens[2]; p = *out = av_mallocz(64 + len + len/255); - if (!p) + if (!p) { + av_freep(&buffer); return AVERROR(ENOMEM); + } *p++ = 2; p += av_xiphlacing(p, hlens[0]); @@ -1312,7 +1314,6 @@ const FFCodec ff_vorbis_encoder = { .init = vorbis_encode_init, FF_CODEC_ENCODE_CB(vorbis_encode_frame), .close = vorbis_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index d03a1c9dbc..8f18cdf4c6 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -50,7 +50,7 @@ #include "jpegquanttables.h" #include "mathops.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "videodsp.h" #include "vp3data.h" @@ -370,7 +370,7 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) /* release all frames */ vp3_decode_flush(avctx); - ff_refstruct_unref(&s->coeff_vlc); + av_refstruct_unref(&s->coeff_vlc); return 0; } @@ -2346,7 +2346,7 @@ static av_cold int allocate_tables(AVCodecContext *avctx) } -static av_cold void free_vlc_tables(FFRefStructOpaque unused, void *obj) +static av_cold void free_vlc_tables(AVRefStructOpaque unused, void *obj) { CoeffVLCs *vlcs = obj; @@ -2459,7 +2459,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) } if (!avctx->internal->is_copy) { - CoeffVLCs *vlcs = ff_refstruct_alloc_ext(sizeof(*s->coeff_vlc), 0, + CoeffVLCs *vlcs = av_refstruct_alloc_ext(sizeof(*s->coeff_vlc), 0, NULL, free_vlc_tables); if (!vlcs) return AVERROR(ENOMEM); @@ -2527,7 +2527,7 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * const Vp3DecodeContext *s1 = src->priv_data; int qps_changed = 0; - ff_refstruct_replace(&s->coeff_vlc, s1->coeff_vlc); + av_refstruct_replace(&s->coeff_vlc, s1->coeff_vlc); // copy previous frame data ref_frames(s, s1); @@ -2713,7 +2713,7 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, mb_height_mul = get_bits(&gb, 5); mb_height_div = get_bits(&gb, 3); if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1) - avpriv_request_sample(s->avctx, "unexpected macroblock dimension multipler/divider"); + avpriv_request_sample(s->avctx, "unexpected macroblock dimension multiplier/divider"); if (get_bits(&gb, 2)) avpriv_request_sample(s->avctx, "unknown bits"); diff --git a/libavcodec/vp5.c b/libavcodec/vp5.c index 78d4b38ce3..77b479471b 100644 --- a/libavcodec/vp5.c +++ b/libavcodec/vp5.c @@ -58,10 +58,7 @@ static int vp5_parse_header(VP56Context *s, const uint8_t *buf, int buf_size) if(vp56_rac_gets(c, 5) > 5) return AVERROR_INVALIDDATA; vp56_rac_gets(c, 2); - if (vpx_rac_get(c)) { - avpriv_report_missing_feature(s->avctx, "Interlacing"); - return AVERROR_PATCHWELCOME; - } + s->interlaced = vp56_rac_gets(c, 1); rows = vp56_rac_gets(c, 8); /* number of stored macroblock rows */ cols = vp56_rac_gets(c, 8); /* number of stored macroblock cols */ if (!rows || !cols) { diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index 1da47ca43f..4f2381f64a 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -338,7 +338,7 @@ static void vp56_deblock_filter(VP56Context *s, uint8_t *yuv, } static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, - ptrdiff_t stride, int x, int y) + ptrdiff_t stride, int x, int y, ptrdiff_t ref_stride) { uint8_t *dst = s->frames[VP56_FRAME_CURRENT]->data[plane] + s->block_offset[b]; uint8_t *src_block; @@ -364,7 +364,17 @@ static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, x += dx - 2; y += dy - 2; - if (x<0 || x+12>=s->plane_width[plane] || + if (s->interlaced && s->il_block) { + /* extract 12*(4+16+4) block from frame (containing both fields), then treat src_block as specific field */ + s->vdsp.emulated_edge_mc(s->edge_emu_buffer, + src + s->block_offset[b] + (dy-4)*ref_stride + (dx-2), + ref_stride, ref_stride, + 12, 24, x, y - 2, + s->plane_width[plane], + s->plane_height[plane]); + src_block = s->edge_emu_buffer; + src_offset = 2 + 4*ref_stride; + } else if (x<0 || x+12>=s->plane_width[plane] || y<0 || y+12>=s->plane_height[plane]) { s->vdsp.emulated_edge_mc(s->edge_emu_buffer, src + s->block_offset[b] + (dy-2)*stride + (dx-2), @@ -431,6 +441,7 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in int b, ab, b_max, plane, off; AVFrame *frame_current, *frame_ref; VP56Frame ref_frame = ff_vp56_reference_frame[mb_type]; + ptrdiff_t ref_stride[4]; vp56_add_predictors_dc(s, ref_frame); @@ -439,6 +450,13 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in if (mb_type != VP56_MB_INTRA && !frame_ref->data[0]) return; + memcpy(ref_stride, s->stride, sizeof(s->stride)); + if (s->interlaced && s->il_block) { + s->block_offset[2] -= s->stride[0] * 7; + s->block_offset[3] -= s->stride[0] * 7; + s->stride[0] *= 2; + } + ab = 6*is_alpha; b_max = 6 - 2*is_alpha; @@ -473,10 +491,10 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in case VP56_MB_INTER_V2_GF: for (b=0; binterlaced && s->il_block ? 1 : 8) : 0; plane = ff_vp56_b2p[b+ab]; vp56_mc(s, b, plane, frame_ref->data[plane], s->stride[plane], - 16*col+x_off, 16*row+y_off); + 16*col+x_off, 16*row+y_off, ref_stride[plane]); vp56_idct_add(s, frame_current->data[plane] + s->block_offset[b], s->stride[plane], s->block_coeff[b], s->idct_selector[b]); } @@ -487,6 +505,12 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in s->block_coeff[4][0] = 0; s->block_coeff[5][0] = 0; } + + if (s->interlaced && s->il_block) { + s->stride[0] /= 2; + s->block_offset[2] += s->stride[0] * 7; + s->block_offset[3] += s->stride[0] * 7; + } } static int vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha) @@ -494,6 +518,19 @@ static int vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha) VP56mb mb_type; int ret; + if (s->interlaced) { + int prob = s->il_prob; + + if (col > 0) { + if (s->il_block) + prob -= prob >> 1; + else + prob += (256 - prob) >> 1; /* can be simplified/combined */ + } + + s->il_block = vpx_rac_get_prob(&s->c, prob); + } + if (s->frames[VP56_FRAME_CURRENT]->flags & AV_FRAME_FLAG_KEY) mb_type = VP56_MB_INTRA; else @@ -552,12 +589,12 @@ static int vp56_size_changed(VP56Context *s) av_reallocp_array(&s->macroblocks, s->mb_width*s->mb_height, sizeof(*s->macroblocks)); av_free(s->edge_emu_buffer_alloc); - s->edge_emu_buffer_alloc = av_malloc(16*stride); + s->edge_emu_buffer_alloc = av_malloc(16*stride*2); s->edge_emu_buffer = s->edge_emu_buffer_alloc; if (!s->above_blocks || !s->macroblocks || !s->edge_emu_buffer_alloc) return AVERROR(ENOMEM); if (s->flip < 0) - s->edge_emu_buffer += 15 * stride; + s->edge_emu_buffer += 15 * stride * 2; if (s->alpha_context) return vp56_size_changed(s->alpha_context); @@ -686,6 +723,11 @@ static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *data, if (s->parse_coeff_models(s)) goto next; + if (s->interlaced) { + s->frames[VP56_FRAME_CURRENT]->flags |= AV_FRAME_FLAG_INTERLACED; + s->il_prob = vp56_rac_gets(&s->c, 8); + } + memset(s->prev_dc, 0, sizeof(s->prev_dc)); s->prev_dc[1][VP56_FRAME_CURRENT] = 128; s->prev_dc[2][VP56_FRAME_CURRENT] = 128; diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h index 9dc0b9c7ad..e922a13c5e 100644 --- a/libavcodec/vp56.h +++ b/libavcodec/vp56.h @@ -151,6 +151,7 @@ struct vp56_context { VP56Macroblock *macroblocks; DECLARE_ALIGNED(16, int16_t, block_coeff)[6][64]; int idct_selector[6]; + const uint8_t *def_coeff_reorder;/* used in vp6 only */ /* motion vectors */ VP56mv mv[6]; /* vectors for each block in MB */ @@ -171,6 +172,11 @@ struct vp56_context { int has_alpha; + /* interlacing params */ + int interlaced; + int il_prob; + int il_block; + /* upside-down flipping hints */ int flip; /* are we flipping ? */ int frbi; /* first row block index in MB */ @@ -197,7 +203,7 @@ struct vp56_context { GetBitContext gb; VLC dccv_vlc[2]; VLC runv_vlc[2]; - VLC ract_vlc[2][3][6]; + VLC ract_vlc[2][3][4]; unsigned int nb_null[2][2]; /* number of consecutive NULL DC/AC */ int have_undamaged_frame; diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index 97d63a5870..48ff9da818 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -41,6 +41,8 @@ #include "vpx_rac.h" #define VP6_MAX_HUFF_SIZE 12 +#define AC_DC_HUFF_BITS 10 +#define RUN_HUFF_BITS 8 static int vp6_parse_coeff(VP56Context *s); static int vp6_parse_coeff_huffman(VP56Context *s); @@ -68,10 +70,11 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size) if (sub_version > 8) return AVERROR_INVALIDDATA; s->filter_header = buf[1] & 0x06; - if (buf[1] & 1) { - avpriv_report_missing_feature(s->avctx, "Interlacing"); - return AVERROR_PATCHWELCOME; - } + s->interlaced = buf[1] & 1; + if (s->interlaced) + s->def_coeff_reorder = vp6_il_coeff_reorder; + else + s->def_coeff_reorder = vp6_def_coeff_reorder; if (separated_coeff || !s->filter_header) { coeff_offset = AV_RB16(buf+2) - 2; buf += 2; @@ -228,7 +231,7 @@ static void vp6_default_models_init(VP56Context *s) memcpy(model->vector_fdv, vp6_def_fdv_vector_model, sizeof(model->vector_fdv)); memcpy(model->vector_pdv, vp6_def_pdv_vector_model, sizeof(model->vector_pdv)); memcpy(model->coeff_runv, vp6_def_runv_coeff_model, sizeof(model->coeff_runv)); - memcpy(model->coeff_reorder, vp6_def_coeff_reorder, sizeof(model->coeff_reorder)); + memcpy(model->coeff_reorder, s->def_coeff_reorder, sizeof(model->coeff_reorder)); vp6_coeff_order_table_init(s); } @@ -265,7 +268,8 @@ static int vp6_huff_cmp(const void *va, const void *vb) } static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], - const uint8_t *map, unsigned size, VLC *vlc) + const uint8_t *map, unsigned size, + int nb_bits, VLC *vlc) { Node nodes[2*VP6_MAX_HUFF_SIZE], *tmp = &nodes[size]; int a, b, i; @@ -281,7 +285,7 @@ static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], ff_vlc_free(vlc); /* then build the huffman tree according to probabilities */ - return ff_huff_build_tree(s->avctx, vlc, size, FF_HUFFMAN_BITS, + return ff_huff_build_tree(s->avctx, vlc, size, nb_bits, nodes, vp6_huff_cmp, FF_HUFFMAN_FLAG_HNODE_FIRST); } @@ -294,6 +298,7 @@ static int vp6_parse_coeff_models(VP56Context *s) int node, cg, ctx, pos; int ct; /* code type */ int pt; /* plane type (0 for Y, 1 for U or V) */ + int ret; memset(def_prob, 0x80, sizeof(def_prob)); @@ -331,18 +336,25 @@ static int vp6_parse_coeff_models(VP56Context *s) if (s->use_huffman) { for (pt=0; pt<2; pt++) { - if (vp6_build_huff_tree(s, model->coeff_dccv[pt], - vp6_huff_coeff_map, 12, &s->dccv_vlc[pt])) - return -1; - if (vp6_build_huff_tree(s, model->coeff_runv[pt], - vp6_huff_run_map, 9, &s->runv_vlc[pt])) - return -1; + ret = vp6_build_huff_tree(s, model->coeff_dccv[pt], + vp6_huff_coeff_map, 12, AC_DC_HUFF_BITS, + &s->dccv_vlc[pt]); + if (ret < 0) + return ret; + ret = vp6_build_huff_tree(s, model->coeff_runv[pt], + vp6_huff_run_map, 9, RUN_HUFF_BITS, + &s->runv_vlc[pt]); + if (ret < 0) + return ret; for (ct=0; ct<3; ct++) - for (cg = 0; cg < 6; cg++) - if (vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg], - vp6_huff_coeff_map, 12, - &s->ract_vlc[pt][ct][cg])) - return -1; + for (int cg = 0; cg < 4; cg++) { + ret = vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg], + vp6_huff_coeff_map, 12, + AC_DC_HUFF_BITS, + &s->ract_vlc[pt][ct][cg]); + if (ret < 0) + return ret; + } } memset(s->nb_null, 0, sizeof(s->nb_null)); } else { @@ -414,7 +426,7 @@ static int vp6_parse_coeff_huffman(VP56Context *s) VP56Model *model = s->modelp; uint8_t *permute = s->idct_scantable; VLC *vlc_coeff; - int coeff, sign, coeff_idx; + int sign, coeff_idx; int b, cg, idx; int pt = 0; /* plane type (0 for Y, 1 for U or V) */ @@ -432,11 +444,11 @@ static int vp6_parse_coeff_huffman(VP56Context *s) } else { if (get_bits_left(&s->gb) <= 0) return AVERROR_INVALIDDATA; - coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 3); + int coeff = get_vlc2(&s->gb, vlc_coeff->table, AC_DC_HUFF_BITS, 2); if (coeff == 0) { if (coeff_idx) { int pt = (coeff_idx >= 6); - run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 3); + run += get_vlc2(&s->gb, s->runv_vlc[pt].table, RUN_HUFF_BITS, 1); if (run >= 9) run += get_bits(&s->gb, 6); } else @@ -703,15 +715,13 @@ static av_cold int vp6_decode_free(AVCodecContext *avctx) static av_cold void vp6_decode_free_context(VP56Context *s) { - int pt, ct, cg; - ff_vp56_free_context(s); - for (pt=0; pt<2; pt++) { + for (int pt = 0; pt < 2; ++pt) { ff_vlc_free(&s->dccv_vlc[pt]); ff_vlc_free(&s->runv_vlc[pt]); - for (ct=0; ct<3; ct++) - for (cg=0; cg<6; cg++) + for (int ct = 0; ct < 3; ++ct) + for (int cg = 0; cg < 4; ++cg) ff_vlc_free(&s->ract_vlc[pt][ct][cg]); } } diff --git a/libavcodec/vp6data.h b/libavcodec/vp6data.h index 539e19a627..be6e86919d 100644 --- a/libavcodec/vp6data.h +++ b/libavcodec/vp6data.h @@ -51,6 +51,17 @@ static const uint8_t vp6_def_coeff_reorder[] = { 14, 14, 15, 15, 15, 15, 15, 15, }; +static const uint8_t vp6_il_coeff_reorder[] = { + 0, 1, 0, 1, 1, 2, 5, 3, + 2, 2, 2, 2, 4, 7, 8, 10, + 9, 7, 5, 4, 2, 3, 5, 6, + 8, 9, 11, 12, 13, 12, 11, 10, + 9, 7, 5, 4, 6, 7, 9, 11, + 12, 12, 13, 13, 14, 12, 11, 9, + 7, 9, 11, 12, 14, 14, 14, 15, + 13, 11, 13, 15, 15, 15, 15, 15, +}; + static const uint8_t vp6_def_runv_coeff_model[2][14] = { { 198, 197, 196, 146, 198, 204, 169, 142, 130, 136, 149, 149, 191, 249 }, { 135, 201, 181, 154, 98, 117, 132, 126, 146, 169, 184, 240, 246, 254 }, diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index d6df018655..9010e19e6b 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -36,7 +36,7 @@ #include "hwconfig.h" #include "mathops.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "vp8.h" #include "vp89_rac.h" @@ -107,7 +107,7 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) ref ? AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) return ret; - f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height); + f->seg_map = av_refstruct_allocz(s->mb_width * s->mb_height); if (!f->seg_map) { ret = AVERROR(ENOMEM); goto fail; @@ -119,15 +119,15 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) return 0; fail: - ff_refstruct_unref(&f->seg_map); + av_refstruct_unref(&f->seg_map); ff_progress_frame_unref(&f->tf); return ret; } static void vp8_release_frame(VP8Frame *f) { - ff_refstruct_unref(&f->seg_map); - ff_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->seg_map); + av_refstruct_unref(&f->hwaccel_picture_private); ff_progress_frame_unref(&f->tf); } @@ -541,9 +541,12 @@ static int vp7_fade_frame(VP8Context *s, int alpha, int beta) /* preserve the golden frame, write a new previous frame */ if (s->framep[VP8_FRAME_GOLDEN] == s->framep[VP8_FRAME_PREVIOUS]) { - s->framep[VP8_FRAME_PREVIOUS] = vp8_find_free_buffer(s); - if ((ret = vp8_alloc_frame(s, s->framep[VP8_FRAME_PREVIOUS], 1)) < 0) + VP8Frame *prev_frame = vp8_find_free_buffer(s); + + ret = vp8_alloc_frame(s, prev_frame, 1); + if (ret < 0) return ret; + s->framep[VP8_FRAME_PREVIOUS] = prev_frame; dst = s->framep[VP8_FRAME_PREVIOUS]->tf.f; @@ -730,7 +733,7 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si int height = s->avctx->height; if (buf_size < 3) { - av_log(s->avctx, AV_LOG_ERROR, "Insufficent data (%d) for header\n", buf_size); + av_log(s->avctx, AV_LOG_ERROR, "Insufficient data (%d) for header\n", buf_size); return AVERROR_INVALIDDATA; } @@ -2413,7 +2416,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void mb = s->macroblocks_base + ((s->mb_width + 1) * (mb_y + 1) + 1); else { // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. + // if we reuse the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) ff_progress_frame_await(&prev_frame->tf, mb_y); @@ -2512,18 +2515,6 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void return 0; } -static int vp7_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 1); -} - -static int vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 0); -} - static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr, int is_vp7) { @@ -2531,7 +2522,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, VP8ThreadData *td = &s->thread_data[threadnr]; int mb_x, mb_y = atomic_load(&td->thread_mb_pos) >> 16, num_jobs = s->num_jobs; AVFrame *curframe = s->curframe->tf.f; - VP8Macroblock *mb; VP8ThreadData *prev_td, *next_td; uint8_t *dst[3] = { curframe->data[0] + 16 * mb_y * s->linesize, @@ -2539,11 +2529,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, curframe->data[2] + 8 * mb_y * s->uvlinesize }; - if (s->mb_layout == 1) - mb = s->macroblocks_base + ((s->mb_width + 1) * (mb_y + 1) + 1); - else - mb = s->macroblocks + (s->mb_height - mb_y - 1) * 2; - if (mb_y == 0) prev_td = td; else @@ -2553,7 +2538,7 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, else next_td = &s->thread_data[(jobnr + 1) % num_jobs]; - for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { const VP8FilterStrength *f = &td->filter_strength[mb_x]; if (prev_td != td) check_thread_pos(td, prev_td, @@ -2583,18 +2568,6 @@ static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata, } } -static void vp7_filter_mb_row(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - filter_mb_row(avctx, tdata, jobnr, threadnr, 1); -} - -static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata, - int jobnr, int threadnr) -{ - filter_mb_row(avctx, tdata, jobnr, threadnr, 0); -} - static av_always_inline int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr, int is_vp7) @@ -2699,8 +2672,6 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, &s->frames[i] != s->framep[VP8_FRAME_ALTREF]) vp8_release_frame(&s->frames[i]); - curframe = s->framep[VP8_FRAME_CURRENT] = vp8_find_free_buffer(s); - if (!s->colorspace) avctx->colorspace = AVCOL_SPC_BT470BG; if (s->fullrange) @@ -2721,8 +2692,10 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, goto err; } + curframe = vp8_find_free_buffer(s); if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0) goto err; + s->framep[VP8_FRAME_CURRENT] = curframe; if (s->keyframe) curframe->tf.f->flags |= AV_FRAME_FLAG_KEY; else @@ -2751,9 +2724,9 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, if (!is_vp7 && !s->actually_webp) ff_thread_finish_setup(avctx); - if (avctx->hwaccel) { + if (!is_vp7 && avctx->hwaccel) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, avpkt->data, avpkt->size); + ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size); if (ret < 0) goto err; @@ -2782,7 +2755,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, if (s->mb_layout == 1) { // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. + // if we reuse the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) ff_progress_frame_await(&prev_frame->tf, 1); @@ -2837,20 +2810,6 @@ err: return ret; } -int ff_vp8_decode_frame(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *avpkt) -{ - return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP8); -} - -#if CONFIG_VP7_DECODER -static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *avpkt) -{ - return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP7); -} -#endif /* CONFIG_VP7_DECODER */ - av_cold int ff_vp8_decode_free(AVCodecContext *avctx) { vp8_decode_flush_impl(avctx, 1); @@ -2858,8 +2817,7 @@ av_cold int ff_vp8_decode_free(AVCodecContext *avctx) return 0; } -static av_always_inline -int vp78_decode_init(AVCodecContext *avctx, int is_vp7) +static av_cold void vp78_decode_init(AVCodecContext *avctx) { VP8Context *s = avctx->priv_data; @@ -2870,43 +2828,49 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7) ff_videodsp_init(&s->vdsp, 8); ff_vp78dsp_init(&s->vp8dsp); - if (CONFIG_VP7_DECODER && is_vp7) { - ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP7, 8, 1); - ff_vp7dsp_init(&s->vp8dsp); - s->decode_mb_row_no_filter = vp7_decode_mb_row_no_filter; - s->filter_mb_row = vp7_filter_mb_row; - } else if (CONFIG_VP8_DECODER && !is_vp7) { - ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP8, 8, 1); - ff_vp8dsp_init(&s->vp8dsp); - s->decode_mb_row_no_filter = vp8_decode_mb_row_no_filter; - s->filter_mb_row = vp8_filter_mb_row; - } /* does not change for VP8 */ memcpy(s->prob[0].scan, ff_zigzag_scan, sizeof(s->prob[0].scan)); +} + +#if CONFIG_VP8_DECODER +static int vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 0); +} + +static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + filter_mb_row(avctx, tdata, jobnr, threadnr, 0); +} + +int ff_vp8_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *avpkt) +{ + return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP8); +} + +av_cold int ff_vp8_decode_init(AVCodecContext *avctx) +{ + VP8Context *s = avctx->priv_data; + + vp78_decode_init(avctx); + ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP8, 8, 1); + ff_vp8dsp_init(&s->vp8dsp); + s->decode_mb_row_no_filter = vp8_decode_mb_row_no_filter; + s->filter_mb_row = vp8_filter_mb_row; return 0; } -#if CONFIG_VP7_DECODER -static int vp7_decode_init(AVCodecContext *avctx) -{ - return vp78_decode_init(avctx, IS_VP7); -} -#endif /* CONFIG_VP7_DECODER */ - -av_cold int ff_vp8_decode_init(AVCodecContext *avctx) -{ - return vp78_decode_init(avctx, IS_VP8); -} - -#if CONFIG_VP8_DECODER #if HAVE_THREADS static void vp8_replace_frame(VP8Frame *dst, const VP8Frame *src) { ff_progress_frame_replace(&dst->tf, &src->tf); - ff_refstruct_replace(&dst->seg_map, src->seg_map); - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->seg_map, src->seg_map); + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); } @@ -2944,6 +2908,37 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, #endif /* CONFIG_VP8_DECODER */ #if CONFIG_VP7_DECODER +static int vp7_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + return decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 1); +} + +static void vp7_filter_mb_row(AVCodecContext *avctx, void *tdata, + int jobnr, int threadnr) +{ + filter_mb_row(avctx, tdata, jobnr, threadnr, 1); +} + +static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *avpkt) +{ + return vp78_decode_frame(avctx, frame, got_frame, avpkt, IS_VP7); +} + +av_cold static int vp7_decode_init(AVCodecContext *avctx) +{ + VP8Context *s = avctx->priv_data; + + vp78_decode_init(avctx); + ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP7, 8, 1); + ff_vp7dsp_init(&s->vp8dsp); + s->decode_mb_row_no_filter = vp7_decode_mb_row_no_filter; + s->filter_mb_row = vp7_filter_mb_row; + + return 0; +} + const FFCodec ff_vp7_decoder = { .p.name = "vp7", CODEC_LONG_NAME("On2 VP7"), @@ -2984,4 +2979,4 @@ const FFCodec ff_vp8_decoder = { NULL }, }; -#endif /* CONFIG_VP7_DECODER */ +#endif /* CONFIG_VP8_DECODER */ diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index 8ede2e2eb3..d0d0238c2c 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -31,7 +31,7 @@ #include "hwconfig.h" #include "profiles.h" #include "progressframe.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "pthread_internal.h" @@ -97,8 +97,9 @@ static void vp9_tile_data_free(VP9TileData *td) static void vp9_frame_unref(VP9Frame *f) { ff_progress_frame_unref(&f->tf); - ff_refstruct_unref(&f->extradata); - ff_refstruct_unref(&f->hwaccel_picture_private); + av_refstruct_unref(&f->header_ref); + av_refstruct_unref(&f->extradata); + av_refstruct_unref(&f->hwaccel_picture_private); f->segmentation_map = NULL; } @@ -113,9 +114,9 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f) sz = 64 * s->sb_cols * s->sb_rows; if (sz != s->frame_extradata_pool_size) { - ff_refstruct_pool_uninit(&s->frame_extradata_pool); - s->frame_extradata_pool = ff_refstruct_pool_alloc(sz * (1 + sizeof(VP9mvrefPair)), - FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + av_refstruct_pool_uninit(&s->frame_extradata_pool); + s->frame_extradata_pool = av_refstruct_pool_alloc(sz * (1 + sizeof(VP9mvrefPair)), + AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); if (!s->frame_extradata_pool) { s->frame_extradata_pool_size = 0; ret = AVERROR(ENOMEM); @@ -123,7 +124,7 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f) } s->frame_extradata_pool_size = sz; } - f->extradata = ff_refstruct_pool_get(s->frame_extradata_pool); + f->extradata = av_refstruct_pool_get(s->frame_extradata_pool); if (!f->extradata) { ret = AVERROR(ENOMEM); goto fail; @@ -145,15 +146,18 @@ fail: static void vp9_frame_replace(VP9Frame *dst, const VP9Frame *src) { + av_refstruct_replace(&dst->header_ref, src->header_ref); + dst->frame_header = src->frame_header; + ff_progress_frame_replace(&dst->tf, &src->tf); - ff_refstruct_replace(&dst->extradata, src->extradata); + av_refstruct_replace(&dst->extradata, src->extradata); dst->segmentation_map = src->segmentation_map; dst->mv = src->mv; dst->uses_2pass = src->uses_2pass; - ff_refstruct_replace(&dst->hwaccel_picture_private, + av_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); } @@ -165,7 +169,8 @@ static int update_size(AVCodecContext *avctx, int w, int h) CONFIG_VP9_NVDEC_HWACCEL + \ CONFIG_VP9_VAAPI_HWACCEL + \ CONFIG_VP9_VDPAU_HWACCEL + \ - CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) + CONFIG_VP9_VIDEOTOOLBOX_HWACCEL + \ + CONFIG_VP9_VULKAN_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; VP9Context *s = avctx->priv_data; uint8_t *p; @@ -202,6 +207,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_YUV420P12: @@ -213,6 +221,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_VDPAU_HWACCEL *fmtp++ = AV_PIX_FMT_VDPAU; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_YUV444P: @@ -220,6 +231,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) case AV_PIX_FMT_YUV444P12: #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; case AV_PIX_FMT_GBRP: @@ -227,6 +241,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) case AV_PIX_FMT_GBRP12: #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; #endif break; } @@ -682,8 +699,12 @@ static int decode_frame_header(AVCodecContext *avctx, s->s.h.uvac_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0; s->s.h.lossless = s->s.h.yac_qi == 0 && s->s.h.ydc_qdelta == 0 && s->s.h.uvdc_qdelta == 0 && s->s.h.uvac_qdelta == 0; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS if (s->s.h.lossless) avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif /* segmentation header info */ if ((s->s.h.segmentation.enabled = get_bits1(&s->gb))) { @@ -1136,7 +1157,8 @@ static void decode_sb(VP9TileData *td, int row, int col, VP9Filter *lflvl, uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1); break; default: - av_assert0(0); + av_unreachable("ff_vp9_partition_tree only has " + "the four PARTITION_* terminal codes"); } } else if (vpx_rac_get_prob_branchy(td->c, p[1])) { bp = PARTITION_SPLIT; @@ -1239,10 +1261,11 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx) for (int i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); - ff_refstruct_pool_uninit(&s->frame_extradata_pool); + av_refstruct_pool_uninit(&s->frame_extradata_pool); for (i = 0; i < 8; i++) { ff_progress_frame_unref(&s->s.refs[i]); ff_progress_frame_unref(&s->next_refs[i]); + vp9_frame_unref(&s->s.ref_frames[i]); } free_buffers(s); @@ -1250,6 +1273,11 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx) av_freep(&s->entries); ff_pthread_free(s, vp9_context_offsets); #endif + + av_refstruct_unref(&s->header_ref); + ff_cbs_fragment_free(&s->current_frag); + ff_cbs_close(&s->cbc); + av_freep(&s->td); return 0; } @@ -1552,11 +1580,27 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, int size = pkt->size; VP9Context *s = avctx->priv_data; int ret, i, j, ref; + CodedBitstreamUnit *unit; + VP9RawFrame *rf; + int retain_segmap_ref = s->s.frames[REF_FRAME_SEGMAP].segmentation_map && (!s->s.h.segmentation.enabled || !s->s.h.segmentation.update_map); const VP9Frame *src; AVFrame *f; + ret = ff_cbs_read_packet(s->cbc, &s->current_frag, pkt); + if (ret < 0) { + ff_cbs_fragment_reset(&s->current_frag); + av_log(avctx, AV_LOG_ERROR, "Failed to read frame header.\n"); + return ret; + } + + unit = &s->current_frag.units[0]; + rf = unit->content; + + av_refstruct_replace(&s->header_ref, unit->content_ref); + s->frame_header = &rf->header; + if ((ret = decode_frame_header(avctx, data, size, &ref)) < 0) { return ret; } else if (ret == 0) { @@ -1568,6 +1612,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, ff_progress_frame_replace(&s->next_refs[i], &s->s.refs[i]); ff_thread_finish_setup(avctx); ff_progress_frame_await(&s->s.refs[ref], INT_MAX); + ff_cbs_fragment_reset(&s->current_frag); if ((ret = av_frame_ref(frame, s->s.refs[ref].f)) < 0) return ret; @@ -1587,11 +1632,19 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, vp9_frame_unref(&s->s.frames[CUR_FRAME]); if ((ret = vp9_frame_alloc(avctx, &s->s.frames[CUR_FRAME])) < 0) return ret; + + s->s.frames[CUR_FRAME].header_ref = av_refstruct_ref(s->header_ref); + s->s.frames[CUR_FRAME].frame_header = s->frame_header; + f = s->s.frames[CUR_FRAME].tf.f; if (s->s.h.keyframe) f->flags |= AV_FRAME_FLAG_KEY; else f->flags &= ~AV_FRAME_FLAG_KEY; + if (s->s.h.lossless) + f->flags |= AV_FRAME_FLAG_LOSSLESS; + else + f->flags &= ~AV_FRAME_FLAG_LOSSLESS; f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; // Non-existent frames have the implicit dimension 0x0 != CUR_FRAME @@ -1610,7 +1663,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avctx->hwaccel) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); - ret = hwaccel->start_frame(avctx, NULL, 0); + ret = hwaccel->start_frame(avctx, pkt->buf, pkt->data, pkt->size); if (ret < 0) return ret; ret = hwaccel->decode_slice(avctx, pkt->data, pkt->size); @@ -1619,6 +1672,13 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, ret = hwaccel->end_frame(avctx); if (ret < 0) return ret; + + for (i = 0; i < 8; i++) { + vp9_frame_replace(&s->s.ref_frames[i], + s->s.h.refreshrefmask & (1 << i) ? + &s->s.frames[CUR_FRAME] : &s->s.ref_frames[i]); + } + goto finish; } @@ -1743,6 +1803,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, } finish: + ff_cbs_fragment_reset(&s->current_frag); + ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, INT_MAX); // ref frame setup for (int i = 0; i < 8; i++) @@ -1767,8 +1829,14 @@ static void vp9_decode_flush(AVCodecContext *avctx) for (i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); - for (i = 0; i < 8; i++) + + for (i = 0; i < 8; i++) { ff_progress_frame_unref(&s->s.refs[i]); + vp9_frame_unref(&s->s.ref_frames[i]); + } + + ff_cbs_fragment_reset(&s->current_frag); + ff_cbs_flush(s->cbc); if (FF_HW_HAS_CB(avctx, flush)) FF_HW_SIMPLE_CALL(avctx, flush); @@ -1782,6 +1850,10 @@ static av_cold int vp9_decode_init(AVCodecContext *avctx) s->last_bpp = 0; s->s.h.filter.sharpness = -1; + ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_VP9, avctx); + if (ret < 0) + return ret; + #if HAVE_THREADS if (avctx->active_thread_type & FF_THREAD_SLICE) { ret = ff_pthread_init(s, vp9_context_offsets); @@ -1802,9 +1874,16 @@ static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo vp9_frame_replace(&s->s.frames[i], &ssrc->s.frames[i]); for (int i = 0; i < 8; i++) ff_progress_frame_replace(&s->s.refs[i], &ssrc->next_refs[i]); - ff_refstruct_replace(&s->frame_extradata_pool, ssrc->frame_extradata_pool); + av_refstruct_replace(&s->frame_extradata_pool, ssrc->frame_extradata_pool); s->frame_extradata_pool_size = ssrc->frame_extradata_pool_size; + av_refstruct_replace(&s->header_ref, ssrc->header_ref); + for (int i = 0; i < 8; i++) + vp9_frame_replace(&s->s.ref_frames[i], &ssrc->s.ref_frames[i]); + + s->frame_header = ssrc->frame_header; + memcpy(s->cbc->priv_data, ssrc->cbc->priv_data, sizeof(CodedBitstreamVP9Context)); + s->s.h.invisible = ssrc->s.h.invisible; s->s.h.keyframe = ssrc->s.h.keyframe; s->s.h.intraonly = ssrc->s.h.intraonly; @@ -1870,6 +1949,9 @@ const FFCodec ff_vp9_decoder = { #endif #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL HWACCEL_VIDEOTOOLBOX(vp9), +#endif +#if CONFIG_VP9_VULKAN_HWACCEL + HWACCEL_VULKAN(vp9), #endif NULL }, diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h index 81dc801052..c3ad2bbcdb 100644 --- a/libavcodec/vp9dec.h +++ b/libavcodec/vp9dec.h @@ -38,6 +38,7 @@ #include "vp9dsp.h" #include "vp9shared.h" #include "vpx_rac.h" +#include "cbs_vp9.h" #define REF_INVALID_SCALE 0xFFFF @@ -97,6 +98,11 @@ typedef struct VP9Context { VP9SharedContext s; VP9TileData *td; + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_frag; + VP9RawFrame *header_ref; ///< RefStruct reference backing frame_header + VP9RawFrameHeader *frame_header; + VP9DSPContext dsp; VideoDSPContext vdsp; GetBitContext gb; @@ -160,7 +166,7 @@ typedef struct VP9Context { uint8_t mvstep[3][2]; // frame specific buffer pools - struct FFRefStructPool *frame_extradata_pool; + struct AVRefStructPool *frame_extradata_pool; int frame_extradata_pool_size; } VP9Context; @@ -220,8 +226,8 @@ struct VP9TileData { DECLARE_ALIGNED(8, uint8_t, left_ref_ctx)[8]; DECLARE_ALIGNED(8, uint8_t, left_filter_ctx)[8]; // block reconstruction intermediates - DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64 * 2]; - DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][64 * 64 * 2]; + DECLARE_ALIGNED(64, uint8_t, tmp_y)[64 * 64 * 2]; + DECLARE_ALIGNED(64, uint8_t, tmp_uv)[2][64 * 64 * 2]; struct { int x, y; } min_mv, max_mv; int16_t *block_base, *block, *uvblock_base[2], *uvblock[2]; uint8_t *eob_base, *uveob_base[2], *eob, *uveob[2]; diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h index 772848e349..0e93224e17 100644 --- a/libavcodec/vp9dsp.h +++ b/libavcodec/vp9dsp.h @@ -121,7 +121,7 @@ typedef struct VP9DSPContext { vp9_scaled_mc_func smc[5][N_FILTERS][2]; } VP9DSPContext; -extern const int16_t attribute_visibility_hidden ff_vp9_subpel_filters[3][16][8]; +EXTERN const int16_t ff_vp9_subpel_filters[3][16][8]; void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp, int bitexact); diff --git a/libavcodec/vp9recon.c b/libavcodec/vp9recon.c index ef08ed17c8..ccc49d7716 100644 --- a/libavcodec/vp9recon.c +++ b/libavcodec/vp9recon.c @@ -319,7 +319,11 @@ static av_always_inline void mc_luma_unscaled(VP9TileData *td, const vp9_mc_func // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (!!my * 5) than horizontally (!!mx * 4). + // The arm/aarch64 _h filters read one more pixel than what actually is + // needed, so switch to emulated edge if that would read beyond the bottom + // right block. if (x < !!mx * 3 || y < !!my * 3 || + ((ARCH_AARCH64 || ARCH_ARM) && (x + !!mx * 5 > w - bw) && (y + !!my * 5 + 1 > h - bh)) || x + !!mx * 4 > w - bw || y + !!my * 5 > h - bh) { s->vdsp.emulated_edge_mc(td->edge_emu_buffer, ref - !!my * 3 * ref_stride - !!mx * 3 * bytesperpixel, @@ -358,7 +362,11 @@ static av_always_inline void mc_chroma_unscaled(VP9TileData *td, const vp9_mc_fu // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (!!my * 5) than horizontally (!!mx * 4). + // The arm/aarch64 _h filters read one more pixel than what actually is + // needed, so switch to emulated edge if that would read beyond the bottom + // right block. if (x < !!mx * 3 || y < !!my * 3 || + ((ARCH_AARCH64 || ARCH_ARM) && (x + !!mx * 5 > w - bw) && (y + !!my * 5 + 1 > h - bh)) || x + !!mx * 4 > w - bw || y + !!my * 5 > h - bh) { s->vdsp.emulated_edge_mc(td->edge_emu_buffer, ref_u - !!my * 3 * src_stride_u - !!mx * 3 * bytesperpixel, diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h index 8a450c26a6..098372f8a4 100644 --- a/libavcodec/vp9shared.h +++ b/libavcodec/vp9shared.h @@ -30,6 +30,7 @@ #include "libavutil/mem_internal.h" #include "progressframe.h" +#include "cbs_vp9.h" #include "vp9.h" enum BlockPartition { @@ -63,6 +64,9 @@ typedef struct VP9mvrefPair { } VP9mvrefPair; typedef struct VP9Frame { + VP9RawFrame *header_ref; ///< RefStruct reference backing frame_header + VP9RawFrameHeader *frame_header; + ProgressFrame tf; void *extradata; ///< RefStruct reference uint8_t *segmentation_map; @@ -170,6 +174,7 @@ typedef struct VP9SharedContext { #define REF_FRAME_SEGMAP 2 #define BLANK_FRAME 3 VP9Frame frames[4]; + VP9Frame ref_frames[8]; } VP9SharedContext; #endif /* AVCODEC_VP9SHARED_H */ diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c index 4fd1861d25..99c86a4610 100644 --- a/libavcodec/vqavideo.c +++ b/libavcodec/vqavideo.c @@ -571,8 +571,9 @@ static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame) } /* accumulate partial codebook */ - bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], - chunk_size); + if (chunk_size != bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], + chunk_size)) + return AVERROR_INVALIDDATA; s->next_codebook_buffer_index += chunk_size; s->partial_countdown--; @@ -600,8 +601,9 @@ static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame) } /* accumulate partial codebook */ - bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], - chunk_size); + if (chunk_size != bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], + chunk_size)) + return AVERROR_INVALIDDATA; s->next_codebook_buffer_index += chunk_size; s->partial_countdown--; @@ -810,11 +812,6 @@ static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe, /* make the palette available on the way out */ memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4); -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - s->frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0) return res; diff --git a/libavcodec/vt_internal.h b/libavcodec/vt_internal.h index 9502d7c7dc..b1eb07310a 100644 --- a/libavcodec/vt_internal.h +++ b/libavcodec/vt_internal.h @@ -56,14 +56,19 @@ int ff_videotoolbox_frame_params(AVCodecContext *avctx, int ff_videotoolbox_buffer_copy(VTContext *vtctx, const uint8_t *buffer, uint32_t size); +int ff_videotoolbox_buffer_append(VTContext *vtctx, + const uint8_t *buffer, + uint32_t size); int ff_videotoolbox_uninit(AVCodecContext *avctx); int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, const uint8_t *buffer, uint32_t size); int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size); int ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame); +CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx); diff --git a/libavcodec/vulkan/Makefile b/libavcodec/vulkan/Makefile new file mode 100644 index 0000000000..d8e1471fa6 --- /dev/null +++ b/libavcodec/vulkan/Makefile @@ -0,0 +1,24 @@ +GEN_CLEANSUFFIXES = *.o *.c *.d + +clean:: + $(RM) $(GEN_CLEANSUFFIXES:%=libavcodec/vulkan/%) + +OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/common.o \ + vulkan/rangecoder.o vulkan/ffv1_vlc.o \ + vulkan/ffv1_common.o vulkan/ffv1_reset.o \ + vulkan/ffv1_enc_rct.o vulkan/ffv1_enc_setup.o \ + vulkan/ffv1_rct_search.o vulkan/ffv1_enc.o + +OBJS-$(CONFIG_FFV1_VULKAN_HWACCEL) += vulkan/common.o \ + vulkan/rangecoder.o vulkan/ffv1_vlc.o \ + vulkan/ffv1_common.o vulkan/ffv1_reset.o \ + vulkan/ffv1_dec_setup.o vulkan/ffv1_dec.o + +OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/common.o \ + vulkan/prores_raw.o + +VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavcodec/vulkan/*.comp)) +.SECONDARY: $(VULKAN:.comp=.c) +libavcodec/vulkan/%.c: TAG = VULKAN +libavcodec/vulkan/%.c: $(SRC_PATH)/libavcodec/vulkan/%.comp + $(M)$(SRC_PATH)/tools/source2c $< $@ diff --git a/libavcodec/vulkan/common.comp b/libavcodec/vulkan/common.comp new file mode 100644 index 0000000000..6825693fa3 --- /dev/null +++ b/libavcodec/vulkan/common.comp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +layout(buffer_reference, buffer_reference_align = 1) buffer u8buf { + uint8_t v; +}; + +layout(buffer_reference, buffer_reference_align = 1) buffer u8vec2buf { + u8vec2 v; +}; + +layout(buffer_reference, buffer_reference_align = 1) buffer u8vec4buf { + u8vec4 v; +}; + +layout(buffer_reference, buffer_reference_align = 2) buffer u16buf { + uint16_t v; +}; + +layout(buffer_reference, buffer_reference_align = 4) buffer u32buf { + uint32_t v; +}; + +layout(buffer_reference, buffer_reference_align = 4) buffer u32vec2buf { + u32vec2 v; +}; + +layout(buffer_reference, buffer_reference_align = 8) buffer u64buf { + uint64_t v; +}; + +#define OFFBUF(type, b, l) \ + type(uint64_t(b) + uint64_t(l)) + +#define zero_extend(a, p) \ + ((a) & ((1 << (p)) - 1)) + +#define sign_extend(val, bits) \ + bitfieldExtract(val, 0, bits) + +#define fold(diff, bits) \ + sign_extend(diff, bits) + +#define mid_pred(a, b, c) \ + max(min((a), (b)), min(max((a), (b)), (c))) + +/* TODO: optimize */ +uint align(uint src, uint a) +{ + uint res = src % a; + if (res == 0) + return src; + return src + a - res; +} + +/* TODO: optimize */ +uint64_t align64(uint64_t src, uint64_t a) +{ + uint64_t res = src % a; + if (res == 0) + return src; + return src + a - res; +} + +#define reverse4(src) \ + (pack32(unpack8(uint32_t(src)).wzyx)) + +u32vec2 reverse8(uint64_t src) +{ + u32vec2 tmp = unpack32(src); + tmp.x = reverse4(tmp.x); + tmp.y = reverse4(tmp.y); + return tmp.yx; +} + +#ifdef PB_32 +#define BIT_BUF_TYPE uint32_t +#define BUF_TYPE u32buf +#define BUF_REVERSE(src) reverse4(src) +#define BUF_BITS uint8_t(32) +#define BUF_BYTES uint8_t(4) +#define BYTE_EXTRACT(src, byte_off) \ + (uint8_t(bitfieldExtract((src), ((byte_off) << 3), 8))) +#else +#define BIT_BUF_TYPE uint64_t +#define BUF_TYPE u32vec2buf +#define BUF_REVERSE(src) reverse8(src) +#define BUF_BITS uint8_t(64) +#define BUF_BYTES uint8_t(8) +#define BYTE_EXTRACT(src, byte_off) \ + (uint8_t(((src) >> ((byte_off) << 3)) & 0xFF)) +#endif + +struct PutBitContext { + uint64_t buf_start; + uint64_t buf; + + BIT_BUF_TYPE bit_buf; + uint8_t bit_left; +}; + +void put_bits(inout PutBitContext pb, const uint32_t n, uint32_t value) +{ + if (n < pb.bit_left) { + pb.bit_buf = (pb.bit_buf << n) | value; + pb.bit_left -= uint8_t(n); + } else { + pb.bit_buf <<= pb.bit_left; + pb.bit_buf |= (value >> (n - pb.bit_left)); + +#ifdef PB_UNALIGNED + u8buf bs = u8buf(pb.buf); + [[unroll]] + for (uint8_t i = uint8_t(0); i < BUF_BYTES; i++) + bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i); +#else +#ifdef DEBUG + if ((pb.buf % BUF_BYTES) != 0) + debugPrintfEXT("put_bits buffer is not aligned!"); +#endif + + BUF_TYPE bs = BUF_TYPE(pb.buf); + bs.v = BUF_REVERSE(pb.bit_buf); +#endif + pb.buf = uint64_t(bs) + BUF_BYTES; + + pb.bit_left += BUF_BITS - uint8_t(n); + pb.bit_buf = value; + } +} + +uint32_t flush_put_bits(inout PutBitContext pb) +{ + /* Align bits to MSBs */ + if (pb.bit_left < BUF_BITS) + pb.bit_buf <<= pb.bit_left; + + if (pb.bit_left < BUF_BITS) { + uint to_write = ((BUF_BITS - pb.bit_left - 1) >> 3) + 1; + + u8buf bs = u8buf(pb.buf); + for (int i = 0; i < to_write; i++) + bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i); + pb.buf = uint64_t(bs) + to_write; + } + + pb.bit_left = BUF_BITS; + pb.bit_buf = 0x0; + + return uint32_t(pb.buf - pb.buf_start); +} + +void init_put_bits(out PutBitContext pb, u8buf data, uint64_t len) +{ + pb.buf_start = uint64_t(data); + pb.buf = uint64_t(data); + + pb.bit_buf = 0; + pb.bit_left = BUF_BITS; +} + +uint64_t put_bits_count(in PutBitContext pb) +{ + return (pb.buf - pb.buf_start)*8 + BUF_BITS - pb.bit_left; +} + +uint32_t put_bytes_count(in PutBitContext pb) +{ + uint64_t num_bytes = (pb.buf - pb.buf_start) + ((BUF_BITS - pb.bit_left) >> 3); + return uint32_t(num_bytes); +} + +struct GetBitContext { + uint64_t buf_start; + uint64_t buf; + uint64_t buf_end; + + uint64_t bits; + int bits_valid; + int size_in_bits; +}; + +#define LOAD64() \ + { \ + u8vec4buf ptr = u8vec4buf(gb.buf); \ + uint32_t rf1 = pack32((ptr[0].v).wzyx); \ + uint32_t rf2 = pack32((ptr[1].v).wzyx); \ + gb.buf += 8; \ + gb.bits = uint64_t(rf1) << 32 | uint64_t(rf2); \ + gb.bits_valid = 64; \ + } + +#define RELOAD32() \ + { \ + u8vec4buf ptr = u8vec4buf(gb.buf); \ + uint32_t rf = pack32((ptr[0].v).wzyx); \ + gb.buf += 4; \ + gb.bits = uint64_t(rf) << (32 - gb.bits_valid) | gb.bits; \ + gb.bits_valid += 32; \ + } + +void init_get_bits(inout GetBitContext gb, u8buf data, int len) +{ + gb.buf = gb.buf_start = uint64_t(data); + gb.buf_end = uint64_t(data) + len; + gb.size_in_bits = len * 8; + + /* Preload */ + LOAD64() +} + +bool get_bit(inout GetBitContext gb) +{ + if (gb.bits_valid == 0) + LOAD64() + + bool val = bool(gb.bits >> (64 - 1)); + gb.bits <<= 1; + gb.bits_valid--; + return val; +} + +uint get_bits(inout GetBitContext gb, int n) +{ + if (n == 0) + return 0; + + if (n > gb.bits_valid) + RELOAD32() + + uint val = uint(gb.bits >> (64 - n)); + gb.bits <<= n; + gb.bits_valid -= n; + return val; +} + +uint show_bits(inout GetBitContext gb, int n) +{ + if (n > gb.bits_valid) + RELOAD32() + + return uint(gb.bits >> (64 - n)); +} + +void skip_bits(inout GetBitContext gb, int n) +{ + if (n > gb.bits_valid) + RELOAD32() + + gb.bits <<= n; + gb.bits_valid -= n; +} + +int tell_bits(in GetBitContext gb) +{ + return int(gb.buf - gb.buf_start) * 8 - gb.bits_valid; +} + +int left_bits(in GetBitContext gb) +{ + return gb.size_in_bits - int(gb.buf - gb.buf_start) * 8 + gb.bits_valid; +} diff --git a/libavcodec/vulkan/ffv1_common.comp b/libavcodec/vulkan/ffv1_common.comp new file mode 100644 index 0000000000..3d40592739 --- /dev/null +++ b/libavcodec/vulkan/ffv1_common.comp @@ -0,0 +1,181 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +struct SliceContext { + RangeCoder c; + +#if !defined(DECODE) + PutBitContext pb; /* 8*8 bytes */ +#else + GetBitContext gb; +#endif + + ivec2 slice_dim; + ivec2 slice_pos; + ivec2 slice_rct_coef; + u8vec3 quant_table_idx; + + uint hdr_len; // only used for golomb + + uint slice_coding_mode; + bool slice_reset_contexts; +}; + +/* -1, { -1, 0 } */ +int predict(int L, ivec2 top) +{ + return mid_pred(L, L + top[1] - top[0], top[1]); +} + +/* { -2, -1 }, { -1, 0, 1 }, 0 */ +int get_context(VTYPE2 cur_l, VTYPE3 top_l, TYPE top2, uint8_t quant_table_idx) +{ + const int LT = top_l[0]; /* -1 */ + const int T = top_l[1]; /* 0 */ + const int RT = top_l[2]; /* 1 */ + const int L = cur_l[1]; /* -1 */ + + int base = quant_table[quant_table_idx][0][(L - LT) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][1][(LT - T) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][2][(T - RT) & MAX_QUANT_TABLE_MASK]; + + if ((quant_table[quant_table_idx][3][127] == 0) && + (quant_table[quant_table_idx][4][127] == 0)) + return base; + + const int TT = top2; /* -2 */ + const int LL = cur_l[0]; /* -2 */ + return base + + quant_table[quant_table_idx][3][(LL - L) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][4][(TT - T) & MAX_QUANT_TABLE_MASK]; +} + +const uint32_t log2_run[41] = { + 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, +}; + +uint slice_coord(uint width, uint sx, uint num_h_slices, uint chroma_shift) +{ + uint mpw = 1 << chroma_shift; + uint awidth = align(width, mpw); + + if ((version < 4) || ((version == 4) && (micro_version < 3))) + return width * sx / num_h_slices; + + sx = (2 * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw; + if (sx == awidth) + sx = width; + + return sx; +} + +#ifdef RGB +#define RGB_LBUF (RGB_LINECACHE - 1) +#define LADDR(p) (ivec2((p).x, ((p).y & RGB_LBUF))) + +ivec2 get_pred(readonly uimage2D pred, ivec2 sp, ivec2 off, + int comp, int sw, uint8_t quant_table_idx, bool extend_lookup) +{ + const ivec2 yoff_border1 = expectEXT(off.x == 0, false) ? off + ivec2(1, -1) : off; + + /* Thanks to the same coincidence as below, we can skip checking if off == 0, 1 */ + VTYPE3 top = VTYPE3(TYPE(imageLoad(pred, sp + LADDR(yoff_border1 + ivec2(-1, -1)))[comp]), + TYPE(imageLoad(pred, sp + LADDR(off + ivec2(0, -1)))[comp]), + TYPE(imageLoad(pred, sp + LADDR(off + ivec2(min(1, sw - off.x - 1), -1)))[comp])); + + /* Normally, we'd need to check if off != ivec2(0, 0) here, since otherwise, we must + * return zero. However, ivec2(-1, 0) + ivec2(1, -1) == ivec2(0, -1), e.g. previous + * row, 0 offset, same slice, which is zero since we zero out the buffer for RGB */ + TYPE cur = TYPE(imageLoad(pred, sp + LADDR(yoff_border1 + ivec2(-1, 0)))[comp]); + + int base = quant_table[quant_table_idx][0][(cur - top[0]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][1][(top[0] - top[1]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][2][(top[1] - top[2]) & MAX_QUANT_TABLE_MASK]; + + if (expectEXT(extend_lookup, false)) { + TYPE cur2 = TYPE(0); + if (expectEXT(off.x > 0, true)) { + const ivec2 yoff_border2 = expectEXT(off.x == 1, false) ? ivec2(-1, -1) : ivec2(-2, 0); + cur2 = TYPE(imageLoad(pred, sp + LADDR(off + yoff_border2))[comp]); + } + base += quant_table[quant_table_idx][3][(cur2 - cur) & MAX_QUANT_TABLE_MASK]; + + /* top-2 became current upon swap */ + TYPE top2 = TYPE(imageLoad(pred, sp + LADDR(off))[comp]); + base += quant_table[quant_table_idx][4][(top2 - top[1]) & MAX_QUANT_TABLE_MASK]; + } + + /* context, prediction */ + return ivec2(base, predict(cur, VTYPE2(top))); +} + +#else /* RGB */ + +#define LADDR(p) (p) + +ivec2 get_pred(readonly uimage2D pred, ivec2 sp, ivec2 off, + int comp, int sw, uint8_t quant_table_idx, bool extend_lookup) +{ + const ivec2 yoff_border1 = off.x == 0 ? ivec2(1, -1) : ivec2(0, 0); + sp += off; + + VTYPE3 top = VTYPE3(TYPE(0), + TYPE(0), + TYPE(0)); + if (off.y > 0 && off != ivec2(0, 1)) + top[0] = TYPE(imageLoad(pred, sp + ivec2(-1, -1) + yoff_border1)[comp]); + if (off.y > 0) { + top[1] = TYPE(imageLoad(pred, sp + ivec2(0, -1))[comp]); + top[2] = TYPE(imageLoad(pred, sp + ivec2(min(1, sw - off.x - 1), -1))[comp]); + } + + TYPE cur = TYPE(0); + if (off != ivec2(0, 0)) + cur = TYPE(imageLoad(pred, sp + ivec2(-1, 0) + yoff_border1)[comp]); + + int base = quant_table[quant_table_idx][0][(cur - top[0]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][1][(top[0] - top[1]) & MAX_QUANT_TABLE_MASK] + + quant_table[quant_table_idx][2][(top[1] - top[2]) & MAX_QUANT_TABLE_MASK]; + + if (expectEXT(extend_lookup, false)) { + TYPE cur2 = TYPE(0); + if (off.x > 0 && off != ivec2(1, 0)) { + const ivec2 yoff_border2 = off.x == 1 ? ivec2(1, -1) : ivec2(0, 0); + cur2 = TYPE(imageLoad(pred, sp + ivec2(-2, 0) + yoff_border2)[comp]); + } + base += quant_table[quant_table_idx][3][(cur2 - cur) & MAX_QUANT_TABLE_MASK]; + + TYPE top2 = TYPE(0); + if (off.y > 1) + top2 = TYPE(imageLoad(pred, sp + ivec2(0, -2))[comp]); + base += quant_table[quant_table_idx][4][(top2 - top[1]) & MAX_QUANT_TABLE_MASK]; + } + + /* context, prediction */ + return ivec2(base, predict(cur, VTYPE2(top))); +} +#endif diff --git a/libavcodec/vulkan/ffv1_dec.comp b/libavcodec/vulkan/ffv1_dec.comp new file mode 100644 index 0000000000..eb795dcba4 --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec.comp @@ -0,0 +1,302 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GOLOMB +#ifdef CACHED_SYMBOL_READER +shared uint8_t state[CONTEXT_SIZE]; +#define READ(c, off) get_rac_direct(c, state[off]) +#else +#define READ(c, off) get_rac(c, uint64_t(slice_state) + (state_off + off)) +#endif + +int get_isymbol(inout RangeCoder c, uint state_off) +{ + if (READ(c, 0)) + return 0; + + uint e = 1; + for (; e < 33; e++) + if (!READ(c, min(e, 10))) + break; + + if (expectEXT(e == 1, false)) { + return READ(c, 11) ? -1 : 1; + } else if (expectEXT(e == 33, false)) { + corrupt = true; + return 0; + } + + int a = 1; + for (uint i = e + 20; i >= 22; i--) { + a <<= 1; + a |= int(READ(c, min(i, 31))); + } + + return READ(c, min(e + 10, 21)) ? -a : a; +} + +void decode_line_pcm(inout SliceContext sc, ivec2 sp, int w, int y, int p, int bits) +{ +#ifdef CACHED_SYMBOL_READER + if (gl_LocalInvocationID.x > 0) + return; +#endif + +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + uint v = 0; + for (int i = (bits - 1); i >= 0; i--) + v |= uint(get_rac_equi(sc.c)) << i; + + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + } +} + +void decode_line(inout SliceContext sc, ivec2 sp, int w, + int y, int p, int bits, uint state_off, + uint8_t quant_table_idx, const int run_index) +{ +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + ivec2 pr = get_pred(dec[p], sp, ivec2(x, y), 0, w, + quant_table_idx, extend_lookup[quant_table_idx] > 0); + + uint context_off = state_off + CONTEXT_SIZE*abs(pr[0]); +#ifdef CACHED_SYMBOL_READER + u8buf sb = u8buf(uint64_t(slice_state) + context_off + gl_LocalInvocationID.x); + state[gl_LocalInvocationID.x] = sb.v; + barrier(); + if (gl_LocalInvocationID.x == 0) { + +#endif + + int diff = get_isymbol(sc.c, context_off); + if (pr[0] < 0) + diff = -diff; + + uint v = zero_extend(pr[1] + diff, bits); + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + +#ifdef CACHED_SYMBOL_READER + } + + barrier(); + sb.v = state[gl_LocalInvocationID.x]; +#endif + } +} + +#else /* GOLOMB */ + +void decode_line(inout SliceContext sc, ivec2 sp, int w, + int y, int p, int bits, uint state_off, + uint8_t quant_table_idx, inout int run_index) +{ +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + int run_count = 0; + int run_mode = 0; + + for (int x = 0; x < w; x++) { + ivec2 pos = sp + ivec2(x, y); + int diff; + ivec2 pr = get_pred(dec[p], sp, ivec2(x, y), 0, w, + quant_table_idx, extend_lookup[quant_table_idx] > 0); + + uint context_off = state_off + VLC_STATE_SIZE*abs(pr[0]); + VlcState sb = VlcState(uint64_t(slice_state) + context_off); + + if (pr[0] == 0 && run_mode == 0) + run_mode = 1; + + if (run_mode != 0) { + if (run_count == 0 && run_mode == 1) { + int tmp_idx = int(log2_run[run_index]); + if (get_bit(sc.gb)) { + run_count = 1 << tmp_idx; + if (x + run_count <= w) + run_index++; + } else { + if (tmp_idx != 0) { + run_count = int(get_bits(sc.gb, tmp_idx)); + } else + run_count = 0; + + if (run_index != 0) + run_index--; + run_mode = 2; + } + } + + run_count--; + if (run_count < 0) { + run_mode = 0; + run_count = 0; + diff = read_vlc_symbol(sc.gb, sb, bits); + if (diff >= 0) + diff++; + } else { + diff = 0; + } + } else { + diff = read_vlc_symbol(sc.gb, sb, bits); + } + + if (pr[0] < 0) + diff = -diff; + + uint v = zero_extend(pr[1] + diff, bits); + imageStore(dec[p], sp + LADDR(ivec2(x, y)), uvec4(v)); + } +} +#endif + +#ifdef RGB +ivec4 transform_sample(ivec4 pix, ivec2 rct_coef) +{ + pix.b -= rct_offset; + pix.r -= rct_offset; + pix.g -= (pix.b*rct_coef.y + pix.r*rct_coef.x) >> 2; + pix.b += pix.g; + pix.r += pix.g; + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void writeout_rgb(in SliceContext sc, ivec2 sp, int w, int y, bool apply_rct) +{ + for (uint x = gl_LocalInvocationID.x; x < w; x += gl_WorkGroupSize.x) { + ivec2 lpos = sp + LADDR(ivec2(x, y)); + ivec2 pos = sc.slice_pos + ivec2(x, y); + + ivec4 pix; + pix.r = int(imageLoad(dec[2], lpos)[0]); + pix.g = int(imageLoad(dec[0], lpos)[0]); + pix.b = int(imageLoad(dec[1], lpos)[0]); + if (transparency != 0) + pix.a = int(imageLoad(dec[3], lpos)[0]); + + if (expectEXT(apply_rct, true)) + pix = transform_sample(pix, sc.slice_rct_coef); + + imageStore(dst[0], pos, pix); + if (planar_rgb != 0) { + for (int i = 1; i < color_planes; i++) + imageStore(dst[i], pos, ivec4(pix[i])); + } + } +} +#endif + +void decode_slice(inout SliceContext sc, const uint slice_idx) +{ + int w = sc.slice_dim.x; + ivec2 sp = sc.slice_pos; + +#ifndef RGB + int bits = bits_per_raw_sample; +#else + int bits = 9; + if (bits != 8 || sc.slice_coding_mode != 0) + bits = bits_per_raw_sample + int(sc.slice_coding_mode != 1); + + sp.y = int(gl_WorkGroupID.y)*RGB_LINECACHE; +#endif + + /* PCM coding */ +#ifndef GOLOMB + if (sc.slice_coding_mode == 1) { +#ifndef RGB + for (int p = 0; p < planes; p++) { + int h = sc.slice_dim.y; + if (p > 0 && p < 3) + h >>= chroma_shift.y; + + for (int y = 0; y < h; y++) + decode_line_pcm(sc, sp, w, y, p, bits); + } +#else + for (int y = 0; y < sc.slice_dim.y; y++) { + for (int p = 0; p < color_planes; p++) + decode_line_pcm(sc, sp, w, y, p, bits); + + writeout_rgb(sc, sp, w, y, false); + } +#endif + } else + + /* Arithmetic coding */ +#endif + { + u8vec4 quant_table_idx = sc.quant_table_idx.xyyz; + u32vec4 slice_state_off = (slice_idx*codec_planes + uvec4(0, 1, 1, 2))*plane_state_size; + +#ifndef RGB + for (int p = 0; p < planes; p++) { + int h = sc.slice_dim.y; + if (p > 0 && p < 3) + h >>= chroma_shift.y; + + int run_index = 0; + for (int y = 0; y < h; y++) + decode_line(sc, sp, w, y, p, bits, + slice_state_off[p], quant_table_idx[p], run_index); + } +#else + int run_index = 0; + for (int y = 0; y < sc.slice_dim.y; y++) { + for (int p = 0; p < color_planes; p++) + decode_line(sc, sp, w, y, p, bits, + slice_state_off[p], quant_table_idx[p], run_index); + + writeout_rgb(sc, sp, w, y, true); + } +#endif + } +} + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + decode_slice(slice_ctx[slice_idx], slice_idx); + + uint32_t status = corrupt ? uint32_t(corrupt) : overread; + if (status != 0) + slice_status[2*slice_idx + 1] = status; +} diff --git a/libavcodec/vulkan/ffv1_dec_setup.comp b/libavcodec/vulkan/ffv1_dec_setup.comp new file mode 100644 index 0000000000..5da09df21c --- /dev/null +++ b/libavcodec/vulkan/ffv1_dec_setup.comp @@ -0,0 +1,140 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +uint8_t setup_state[CONTEXT_SIZE]; + +uint get_usymbol(inout RangeCoder c) +{ + if (get_rac_direct(c, setup_state[0])) + return 0; + + int e = 0; + while (get_rac_direct(c, setup_state[1 + min(e, 9)])) { // 1..10 + e++; + if (e > 31) { + corrupt = true; + return 0; + } + } + + uint a = 1; + for (int i = e - 1; i >= 0; i--) { + a <<= 1; + a |= uint(get_rac_direct(c, setup_state[22 + min(i, 9)])); // 22..31 + } + + return a; +} + +bool decode_slice_header(inout SliceContext sc) +{ + [[unroll]] + for (int i = 0; i < CONTEXT_SIZE; i++) + setup_state[i] = uint8_t(128); + + uint sx = get_usymbol(sc.c); + uint sy = get_usymbol(sc.c); + uint sw = get_usymbol(sc.c) + 1; + uint sh = get_usymbol(sc.c) + 1; + + if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0 || + sx > (gl_NumWorkGroups.x - sw) || sy > (gl_NumWorkGroups.y - sh) || + corrupt) { + return true; + } + + /* Set coordinates */ + uint sxs = slice_coord(img_size.x, sx , gl_NumWorkGroups.x, chroma_shift.x); + uint sxe = slice_coord(img_size.x, sx + sw, gl_NumWorkGroups.x, chroma_shift.x); + uint sys = slice_coord(img_size.y, sy , gl_NumWorkGroups.y, chroma_shift.y); + uint sye = slice_coord(img_size.y, sy + sh, gl_NumWorkGroups.y, chroma_shift.y); + + sc.slice_pos = ivec2(sxs, sys); + sc.slice_dim = ivec2(sxe - sxs, sye - sys); + sc.slice_rct_coef = ivec2(1, 1); + sc.slice_coding_mode = int(0); + + for (uint i = 0; i < codec_planes; i++) { + uint idx = get_usymbol(sc.c); + if (idx >= quant_table_count) + return true; + sc.quant_table_idx[i] = uint8_t(idx); + } + + get_usymbol(sc.c); + get_usymbol(sc.c); + get_usymbol(sc.c); + + if (version >= 4) { + sc.slice_reset_contexts = get_rac_direct(sc.c, setup_state[0]); + sc.slice_coding_mode = get_usymbol(sc.c); + if (sc.slice_coding_mode != 1 && colorspace == 1) { + sc.slice_rct_coef.x = int(get_usymbol(sc.c)); + sc.slice_rct_coef.y = int(get_usymbol(sc.c)); + if (sc.slice_rct_coef.x + sc.slice_rct_coef.y > 4) + return true; + } + } + + return false; +} + +void golomb_init(inout SliceContext sc) +{ + if (version == 3 && micro_version > 1 || version > 3) { + setup_state[0] = uint8_t(129); + get_rac_direct(sc.c, setup_state[0]); + } + + uint64_t ac_byte_count = sc.c.bytestream - sc.c.bytestream_start - 1; + init_get_bits(sc.gb, u8buf(sc.c.bytestream_start + ac_byte_count), + int(sc.c.bytestream_end - sc.c.bytestream_start - ac_byte_count)); +} + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + u8buf bs = u8buf(slice_data + slice_offsets[2*slice_idx + 0]); + uint32_t slice_size = slice_offsets[2*slice_idx + 1]; + + rac_init_dec(slice_ctx[slice_idx].c, + bs, slice_size); + + if (slice_idx == (gl_NumWorkGroups.x*gl_NumWorkGroups.y - 1)) + get_rac_equi(slice_ctx[slice_idx].c); + + decode_slice_header(slice_ctx[slice_idx]); + + if (golomb == 1) + golomb_init(slice_ctx[slice_idx]); + + if (ec != 0 && check_crc != 0) { + uint32_t crc = crcref; + for (int i = 0; i < slice_size; i++) + crc = crc_ieee[(crc & 0xFF) ^ uint32_t(bs[i].v)] ^ (crc >> 8); + + slice_status[2*slice_idx + 0] = crc; + } + + slice_status[2*slice_idx + 1] = corrupt ? uint32_t(corrupt) : overread; +} diff --git a/libavcodec/vulkan/ffv1_enc.comp b/libavcodec/vulkan/ffv1_enc.comp new file mode 100644 index 0000000000..78372f5b3a --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc.comp @@ -0,0 +1,358 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GOLOMB +#ifdef CACHED_SYMBOL_READER +shared uint8_t state[CONTEXT_SIZE]; +#define WRITE(c, off, val) put_rac_direct(c, state[off], val) +#else +#define WRITE(c, off, val) put_rac(c, uint64_t(slice_state) + (state_off + off), val) +#endif + +/* Note - only handles signed values */ +void put_symbol(inout RangeCoder c, uint state_off, int v) +{ + bool is_nil = (v == 0); + WRITE(c, 0, is_nil); + if (is_nil) + return; + + const int a = abs(v); + const int e = findMSB(a); + + for (int i = 0; i < e; i++) + WRITE(c, 1 + min(i, 9), true); + WRITE(c, 1 + min(e, 9), false); + + for (int i = e - 1; i >= 0; i--) + WRITE(c, 22 + min(i, 9), bool(bitfieldExtract(a, i, 1))); + + WRITE(c, 22 - 11 + min(e, 10), v < 0); +} + +void encode_line_pcm(inout SliceContext sc, readonly uimage2D img, + ivec2 sp, int y, int p, int comp, int bits) +{ + int w = sc.slice_dim.x; + +#ifdef CACHED_SYMBOL_READER + if (gl_LocalInvocationID.x > 0) + return; +#endif + +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + uint v = imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]; + for (int i = (bits - 1); i >= 0; i--) + put_rac_equi(sc.c, bool(bitfieldExtract(v, i, 1))); + } +} + +void encode_line(inout SliceContext sc, readonly uimage2D img, uint state_off, + ivec2 sp, int y, int p, int comp, int bits, + uint8_t quant_table_idx, const int run_index) +{ + int w = sc.slice_dim.x; + +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + for (int x = 0; x < w; x++) { + ivec2 d = get_pred(img, sp, ivec2(x, y), comp, w, + quant_table_idx, extend_lookup[quant_table_idx] > 0); + d[1] = int(imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]) - d[1]; + + if (d[0] < 0) + d = -d; + + d[1] = fold(d[1], bits); + + uint context_off = state_off + CONTEXT_SIZE*d[0]; +#ifdef CACHED_SYMBOL_READER + u8buf sb = u8buf(uint64_t(slice_state) + context_off + gl_LocalInvocationID.x); + state[gl_LocalInvocationID.x] = sb.v; + barrier(); + if (gl_LocalInvocationID.x == 0) +#endif + + put_symbol(sc.c, context_off, d[1]); + +#ifdef CACHED_SYMBOL_READER + barrier(); + sb.v = state[gl_LocalInvocationID.x]; +#endif + } +} + +#else /* GOLOMB */ + +void encode_line(inout SliceContext sc, readonly uimage2D img, uint state_off, + ivec2 sp, int y, int p, int comp, int bits, + uint8_t quant_table_idx, inout int run_index) +{ + int w = sc.slice_dim.x; + +#ifndef RGB + if (p > 0 && p < 3) { + w >>= chroma_shift.x; + sp >>= chroma_shift; + } +#endif + + int run_count = 0; + bool run_mode = false; + + for (int x = 0; x < w; x++) { + ivec2 d = get_pred(img, sp, ivec2(x, y), comp, w, + quant_table_idx, extend_lookup[quant_table_idx] > 0); + d[1] = int(imageLoad(img, sp + LADDR(ivec2(x, y)))[comp]) - d[1]; + + if (d[0] < 0) + d = -d; + + d[1] = fold(d[1], bits); + + if (d[0] == 0) + run_mode = true; + + if (run_mode) { + if (d[1] != 0) { + /* A very unlikely loop */ + while (run_count >= 1 << log2_run[run_index]) { + run_count -= 1 << log2_run[run_index]; + run_index++; + put_bits(sc.pb, 1, 1); + } + + put_bits(sc.pb, 1 + log2_run[run_index], run_count); + if (run_index != 0) + run_index--; + run_count = 0; + run_mode = false; + if (d[1] > 0) + d[1]--; + } else { + run_count++; + } + } + + if (!run_mode) { + VlcState sb = VlcState(uint64_t(slice_state) + state_off + VLC_STATE_SIZE*d[0]); + Symbol sym = get_vlc_symbol(sb, d[1], bits); + put_bits(sc.pb, sym.bits, sym.val); + } + } + + if (run_mode) { + while (run_count >= (1 << log2_run[run_index])) { + run_count -= 1 << log2_run[run_index]; + run_index++; + put_bits(sc.pb, 1, 1); + } + + if (run_count > 0) + put_bits(sc.pb, 1, 1); + } +} +#endif + +#ifdef RGB +ivec4 load_components(ivec2 pos) +{ + ivec4 pix = ivec4(imageLoad(src[0], pos)); + if (planar_rgb != 0) { + for (int i = 1; i < (3 + transparency); i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + } + + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void transform_sample(inout ivec4 pix, ivec2 rct_coef) +{ + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2; + pix.b += rct_offset; + pix.r += rct_offset; +} + +void preload_rgb(in SliceContext sc, ivec2 sp, int w, int y, bool apply_rct) +{ + for (uint x = gl_LocalInvocationID.x; x < w; x += gl_WorkGroupSize.x) { + ivec2 lpos = sp + LADDR(ivec2(x, y)); + ivec2 pos = sc.slice_pos + ivec2(x, y); + + ivec4 pix = load_components(pos); + + if (expectEXT(apply_rct, true)) + transform_sample(pix, sc.slice_rct_coef); + + imageStore(tmp, lpos, pix); + } +} +#endif + +void encode_slice(inout SliceContext sc, const uint slice_idx) +{ + ivec2 sp = sc.slice_pos; + +#ifndef RGB + int bits = bits_per_raw_sample; +#else + int bits = 9; + if (bits != 8 || sc.slice_coding_mode != 0) + bits = bits_per_raw_sample + int(sc.slice_coding_mode != 1); + + sp.y = int(gl_WorkGroupID.y)*RGB_LINECACHE; +#endif + +#ifndef GOLOMB + if (sc.slice_coding_mode == 1) { +#ifndef RGB + for (int c = 0; c < components; c++) { + + int h = sc.slice_dim.y; + if (c > 0 && c < 3) + h >>= chroma_shift.y; + + /* Takes into account dual-plane YUV formats */ + int p = min(c, planes - 1); + int comp = c - p; + + for (int y = 0; y < h; y++) + encode_line_pcm(sc, src[p], sp, y, p, comp, bits); + } +#else + for (int y = 0; y < sc.slice_dim.y; y++) { + preload_rgb(sc, sp, sc.slice_dim.x, y, false); + + encode_line_pcm(sc, tmp, sp, y, 0, 1, bits); + encode_line_pcm(sc, tmp, sp, y, 0, 2, bits); + encode_line_pcm(sc, tmp, sp, y, 0, 0, bits); + if (transparency == 1) + encode_line_pcm(sc, tmp, sp, y, 0, 3, bits); + } +#endif + } else +#endif + { + u8vec4 quant_table_idx = sc.quant_table_idx.xyyz; + u32vec4 slice_state_off = (slice_idx*codec_planes + uvec4(0, 1, 1, 2))*plane_state_size; + +#ifndef RGB + for (int c = 0; c < components; c++) { + int run_index = 0; + + int h = sc.slice_dim.y; + if (c > 0 && c < 3) + h >>= chroma_shift.y; + + int p = min(c, planes - 1); + int comp = c - p; + + for (int y = 0; y < h; y++) + encode_line(sc, src[p], slice_state_off[c], sp, y, p, + comp, bits, quant_table_idx[c], run_index); + } +#else + int run_index = 0; + for (int y = 0; y < sc.slice_dim.y; y++) { + preload_rgb(sc, sp, sc.slice_dim.x, y, true); + + encode_line(sc, tmp, slice_state_off[0], + sp, y, 0, 1, bits, quant_table_idx[0], run_index); + encode_line(sc, tmp, slice_state_off[1], + sp, y, 0, 2, bits, quant_table_idx[1], run_index); + encode_line(sc, tmp, slice_state_off[2], + sp, y, 0, 0, bits, quant_table_idx[2], run_index); + if (transparency == 1) + encode_line(sc, tmp, slice_state_off[3], + sp, y, 0, 3, bits, quant_table_idx[3], run_index); + } +#endif + } +} + +void finalize_slice(inout SliceContext sc, const uint slice_idx) +{ +#ifdef CACHED_SYMBOL_READER + if (gl_LocalInvocationID.x > 0) + return; +#endif + +#ifdef GOLOMB + uint32_t enc_len = sc.hdr_len + flush_put_bits(sc.pb); +#else + uint32_t enc_len = rac_terminate(sc.c); +#endif + + u8buf bs = u8buf(sc.c.bytestream_start); + + /* Append slice length */ + u8vec4 enc_len_p = unpack8(enc_len); + bs[enc_len + 0].v = enc_len_p.z; + bs[enc_len + 1].v = enc_len_p.y; + bs[enc_len + 2].v = enc_len_p.x; + enc_len += 3; + + /* Calculate and write CRC */ + if (ec != 0) { + bs[enc_len].v = uint8_t(0); + enc_len++; + + uint32_t crc = crcref; + for (int i = 0; i < enc_len; i++) + crc = crc_ieee[(crc & 0xFF) ^ uint32_t(bs[i].v)] ^ (crc >> 8); + + if (crcref != 0x00000000) + crc ^= 0x8CD88196; + + u8vec4 crc_p = unpack8(crc); + bs[enc_len + 0].v = crc_p.x; + bs[enc_len + 1].v = crc_p.y; + bs[enc_len + 2].v = crc_p.z; + bs[enc_len + 3].v = crc_p.w; + enc_len += 4; + } + + slice_results[slice_idx*2 + 0] = enc_len; + slice_results[slice_idx*2 + 1] = uint64_t(bs) - uint64_t(out_data); +} + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + encode_slice(slice_ctx[slice_idx], slice_idx); + finalize_slice(slice_ctx[slice_idx], slice_idx); +} diff --git a/libavcodec/vulkan/ffv1_enc_rct.comp b/libavcodec/vulkan/ffv1_enc_rct.comp new file mode 100644 index 0000000000..b611f4be98 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_rct.comp @@ -0,0 +1,79 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +ivec4 load_components(ivec2 pos) +{ + ivec4 pix = ivec4(imageLoad(src[0], pos)); + if (planar_rgb != 0) { + for (int i = 1; i < (3 + transparency); i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + } + + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void bypass_sample(ivec2 pos) +{ + imageStore(dst[0], pos, load_components(pos)); +} + +void bypass_block(in SliceContext sc) +{ + ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos; + ivec2 end = sc.slice_pos + sc.slice_dim; + for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y) + for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x) + bypass_sample(ivec2(x, y)); +} + +void transform_sample(ivec2 pos, ivec2 rct_coef) +{ + ivec4 pix = load_components(pos); + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2; + pix.b += offset; + pix.r += offset; + imageStore(dst[0], pos, pix); +} + +void transform_block(in SliceContext sc) +{ + const ivec2 rct_coef = sc.slice_rct_coef; + const ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos; + const ivec2 end = sc.slice_pos + sc.slice_dim; + + for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y) + for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x) + transform_sample(ivec2(x, y), rct_coef); +} + +void main() +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (slice_ctx[slice_idx].slice_coding_mode == 1) + bypass_block(slice_ctx[slice_idx]); + else + transform_block(slice_ctx[slice_idx]); +} diff --git a/libavcodec/vulkan/ffv1_enc_setup.comp b/libavcodec/vulkan/ffv1_enc_setup.comp new file mode 100644 index 0000000000..5f8e6704b0 --- /dev/null +++ b/libavcodec/vulkan/ffv1_enc_setup.comp @@ -0,0 +1,126 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +uint8_t state[CONTEXT_SIZE]; + +void init_slice(inout SliceContext sc, const uint slice_idx) +{ + /* Set coordinates */ + uvec2 img_size = imageSize(src[0]); + uint sxs = slice_coord(img_size.x, gl_WorkGroupID.x + 0, + gl_NumWorkGroups.x, chroma_shift.x); + uint sxe = slice_coord(img_size.x, gl_WorkGroupID.x + 1, + gl_NumWorkGroups.x, chroma_shift.x); + uint sys = slice_coord(img_size.y, gl_WorkGroupID.y + 0, + gl_NumWorkGroups.y, chroma_shift.y); + uint sye = slice_coord(img_size.y, gl_WorkGroupID.y + 1, + gl_NumWorkGroups.y, chroma_shift.y); + + sc.slice_pos = ivec2(sxs, sys); + sc.slice_dim = ivec2(sxe - sxs, sye - sys); + sc.slice_coding_mode = int(force_pcm == 1); + sc.slice_reset_contexts = sc.slice_coding_mode == 1; + sc.quant_table_idx = u8vec3(context_model); + + if ((rct_search == 0) || (sc.slice_coding_mode == 1)) + sc.slice_rct_coef = ivec2(1, 1); + + rac_init(sc.c, + OFFBUF(u8buf, out_data, slice_idx * slice_size_max), + slice_size_max); +} + +void put_usymbol(inout RangeCoder c, uint v) +{ + bool is_nil = (v == 0); + put_rac_direct(c, state[0], is_nil); + if (is_nil) + return; + + const int e = findMSB(v); + + for (int i = 0; i < e; i++) + put_rac_direct(c, state[1 + min(i, 9)], true); + put_rac_direct(c, state[1 + min(e, 9)], false); + + for (int i = e - 1; i >= 0; i--) + put_rac_direct(c, state[22 + min(i, 9)], bool(bitfieldExtract(v, i, 1))); +} + +void write_slice_header(inout SliceContext sc) +{ + [[unroll]] + for (int i = 0; i < CONTEXT_SIZE; i++) + state[i] = uint8_t(128); + + put_usymbol(sc.c, gl_WorkGroupID.x); + put_usymbol(sc.c, gl_WorkGroupID.y); + put_usymbol(sc.c, 0); + put_usymbol(sc.c, 0); + + for (int i = 0; i < codec_planes; i++) + put_usymbol(sc.c, sc.quant_table_idx[i]); + + put_usymbol(sc.c, pic_mode); + put_usymbol(sc.c, sar.x); + put_usymbol(sc.c, sar.y); + + if (version >= 4) { + put_rac_direct(sc.c, state[0], sc.slice_reset_contexts); + put_usymbol(sc.c, sc.slice_coding_mode); + if (sc.slice_coding_mode != 1 && colorspace == 1) { + put_usymbol(sc.c, sc.slice_rct_coef.y); + put_usymbol(sc.c, sc.slice_rct_coef.x); + } + } +} + +void write_frame_header(inout SliceContext sc) +{ + put_rac_equi(sc.c, bool(key_frame)); +} + +#ifdef GOLOMB +void init_golomb(inout SliceContext sc) +{ + sc.hdr_len = rac_terminate(sc.c); + init_put_bits(sc.pb, + OFFBUF(u8buf, sc.c.bytestream_start, sc.hdr_len), + slice_size_max - sc.hdr_len); +} +#endif + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + init_slice(slice_ctx[slice_idx], slice_idx); + + if (slice_idx == 0) + write_frame_header(slice_ctx[slice_idx]); + + write_slice_header(slice_ctx[slice_idx]); + +#ifdef GOLOMB + init_golomb(slice_ctx[slice_idx]); +#endif +} diff --git a/libavcodec/vulkan/ffv1_rct.comp b/libavcodec/vulkan/ffv1_rct.comp new file mode 100644 index 0000000000..b10bb47132 --- /dev/null +++ b/libavcodec/vulkan/ffv1_rct.comp @@ -0,0 +1,90 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +ivec4 load_components(ivec2 pos) +{ + ivec4 pix = ivec4(imageLoad(src[0], pos)); + if (planar_rgb != 0) { + for (int i = 1; i < (3 + transparency); i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + } + + return ivec4(pix[fmt_lut[0]], pix[fmt_lut[1]], + pix[fmt_lut[2]], pix[fmt_lut[3]]); +} + +void bypass_sample(ivec2 pos) +{ + imageStore(dst[0], pos, load_components(pos)); +} + +void bypass_block(in SliceContext sc) +{ + ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos; + ivec2 end = sc.slice_pos + sc.slice_dim; + for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y) + for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x) + bypass_sample(ivec2(x, y)); +} + +void transform_sample(ivec2 pos, ivec2 rct_coef) +{ + ivec4 pix = load_components(pos); + pix.b -= offset; + pix.r -= offset; + pix.g -= (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2; + pix.b += pix.g; + pix.r += pix.g; + imageStore(dst[0], pos, pix); +} + +void transform_sample(ivec2 pos, ivec2 rct_coef) +{ + ivec4 pix = load_components(pos); + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2; + pix.b += offset; + pix.r += offset; + imageStore(dst[0], pos, pix); +} + +void transform_block(in SliceContext sc) +{ + const ivec2 rct_coef = sc.slice_rct_coef; + const ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos; + const ivec2 end = sc.slice_pos + sc.slice_dim; + + for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y) + for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x) + transform_sample(ivec2(x, y), rct_coef); +} + +void main() +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (slice_ctx[slice_idx].slice_coding_mode == 1) + bypass_block(slice_ctx[slice_idx]); + else + transform_block(slice_ctx[slice_idx]); +} diff --git a/libavcodec/vulkan/ffv1_rct_search.comp b/libavcodec/vulkan/ffv1_rct_search.comp new file mode 100644 index 0000000000..055bde46c4 --- /dev/null +++ b/libavcodec/vulkan/ffv1_rct_search.comp @@ -0,0 +1,139 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +ivec3 load_components(ivec2 pos) +{ + ivec3 pix = ivec3(imageLoad(src[0], pos)); + if (planar_rgb != 0) { + for (int i = 1; i < 3; i++) + pix[i] = int(imageLoad(src[i], pos)[0]); + } + + return ivec3(pix[fmt_lut[0]], pix[fmt_lut[1]], pix[fmt_lut[2]]); +} + +#define NUM_CHECKS 15 +const ivec2 rct_y_coeff[NUM_CHECKS] = { + ivec2(0, 0), // 4G + + ivec2(0, 1), // 3G + B + ivec2(1, 0), // R + 3G + ivec2(1, 1), // R + 2G + B + + ivec2(0, 2), // 2G + 2B + ivec2(2, 0), // 2R + 2G + ivec2(2, 2), // 2R + 2B + + ivec2(0, 3), // 1G + 3B + ivec2(3, 0), // 3R + 1G + + ivec2(0, 4), // 4B + ivec2(4, 0), // 4R + + ivec2(1, 2), // R + G + 2B + ivec2(2, 1), // 2R + G + B + + ivec2(3, 1), // 3R + B + ivec2(1, 3), // R + 3B +}; + +shared ivec3 pix_buf[gl_WorkGroupSize.x + 1][gl_WorkGroupSize.y + 1] = { }; + +ivec3 transform_sample(ivec3 pix, ivec2 rct_coef) +{ + pix.b -= pix.g; + pix.r -= pix.g; + pix.g += (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2; + pix.b += rct_offset; + pix.r += rct_offset; + return pix; +} + +uint get_dist(ivec3 cur) +{ + ivec3 LL = pix_buf[gl_LocalInvocationID.x + 0][gl_LocalInvocationID.y + 1]; + ivec3 TL = pix_buf[gl_LocalInvocationID.x + 0][gl_LocalInvocationID.y + 0]; + ivec3 TT = pix_buf[gl_LocalInvocationID.x + 1][gl_LocalInvocationID.y + 0]; + + ivec3 pred = ivec3(predict(LL.r, ivec2(TL.r, TT.r)), + predict(LL.g, ivec2(TL.g, TT.g)), + predict(LL.b, ivec2(TL.b, TT.b))); + + uvec3 c = abs(pred - cur); + return mid_pred(c.r, c.g, c.b); +} + +shared uint score_cols[gl_WorkGroupSize.y] = { }; +shared uint score_mode[16] = { }; + +void process(ivec2 pos) +{ + ivec3 pix = load_components(pos); + + for (int i = 0; i < NUM_CHECKS; i++) { + ivec3 tx_pix = transform_sample(pix, rct_y_coeff[i]); + pix_buf[gl_LocalInvocationID.x + 1][gl_LocalInvocationID.y + 1] = tx_pix; + memoryBarrierShared(); + + uint dist = get_dist(tx_pix); + atomicAdd(score_mode[i], dist); + } +} + +void coeff_search(inout SliceContext sc) +{ + uvec2 img_size = imageSize(src[0]); + uint sxs = slice_coord(img_size.x, gl_WorkGroupID.x + 0, + gl_NumWorkGroups.x, 0); + uint sxe = slice_coord(img_size.x, gl_WorkGroupID.x + 1, + gl_NumWorkGroups.x, 0); + uint sys = slice_coord(img_size.y, gl_WorkGroupID.y + 0, + gl_NumWorkGroups.y, 0); + uint sye = slice_coord(img_size.y, gl_WorkGroupID.y + 1, + gl_NumWorkGroups.y, 0); + + for (uint y = sys + gl_LocalInvocationID.y; y < sye; y += gl_WorkGroupSize.y) { + for (uint x = sxs + gl_LocalInvocationID.x; x < sxe; x += gl_WorkGroupSize.x) { + process(ivec2(x, y)); + } + } + + if (gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0) { + uint min_score = 0xFFFFFFFF; + uint min_idx = 3; + for (int i = 0; i < NUM_CHECKS; i++) { + if (score_mode[i] < min_score) { + min_score = score_mode[i]; + min_idx = i; + } + } + sc.slice_rct_coef = rct_y_coeff[min_idx]; + } +} + +void main(void) +{ + if (force_pcm == 1) + return; + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + coeff_search(slice_ctx[slice_idx]); +} diff --git a/libavcodec/vulkan/ffv1_reset.comp b/libavcodec/vulkan/ffv1_reset.comp new file mode 100644 index 0000000000..cfb7dcc444 --- /dev/null +++ b/libavcodec/vulkan/ffv1_reset.comp @@ -0,0 +1,57 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +void main(void) +{ + const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + + if (key_frame == 0 && + slice_ctx[slice_idx].slice_reset_contexts == false) + return; + + const uint8_t qidx = slice_ctx[slice_idx].quant_table_idx[gl_WorkGroupID.z]; + uint contexts = context_count[qidx]; + uint64_t slice_state_off = uint64_t(slice_state) + + slice_idx*plane_state_size*codec_planes; + +#ifdef GOLOMB + uint64_t start = slice_state_off + + (gl_WorkGroupID.z*(plane_state_size/VLC_STATE_SIZE) + gl_LocalInvocationID.x)*VLC_STATE_SIZE; + for (uint x = gl_LocalInvocationID.x; x < contexts; x += gl_WorkGroupSize.x) { + VlcState sb = VlcState(start); + sb.drift = int16_t(0); + sb.error_sum = uint16_t(4); + sb.bias = int8_t(0); + sb.count = uint8_t(1); + start += gl_WorkGroupSize.x*VLC_STATE_SIZE; + } +#else + uint64_t start = slice_state_off + + gl_WorkGroupID.z*plane_state_size + + (gl_LocalInvocationID.x << 2 /* dwords */); /* Bytes */ + uint count_total = contexts*(CONTEXT_SIZE /* bytes */ >> 2 /* dwords */); + for (uint x = gl_LocalInvocationID.x; x < count_total; x += gl_WorkGroupSize.x) { + u32buf(start).v = 0x80808080; + start += gl_WorkGroupSize.x*(CONTEXT_SIZE >> 3 /* 1/8th of context */); + } +#endif +} diff --git a/libavcodec/vulkan/ffv1_vlc.comp b/libavcodec/vulkan/ffv1_vlc.comp new file mode 100644 index 0000000000..32a6ca9f37 --- /dev/null +++ b/libavcodec/vulkan/ffv1_vlc.comp @@ -0,0 +1,159 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 VLC_STATE_SIZE 8 +layout(buffer_reference, buffer_reference_align = VLC_STATE_SIZE) buffer VlcState { + uint32_t error_sum; + int16_t drift; + int8_t bias; + uint8_t count; +}; + +void update_vlc_state(inout VlcState state, const int v) +{ + int drift = state.drift; + int count = state.count; + int bias = state.bias; + state.error_sum += uint16_t(abs(v)); + drift += v; + + if (count == 128) { // FIXME: variable + count >>= 1; + drift >>= 1; + state.error_sum >>= 1; + } + count++; + + if (drift <= -count) { + bias = max(bias - 1, -128); + drift = max(drift + count, -count + 1); + } else if (drift > 0) { + bias = min(bias + 1, 127); + drift = min(drift - count, 0); + } + + state.bias = int8_t(bias); + state.drift = int16_t(drift); + state.count = uint8_t(count); +} + +struct Symbol { + uint32_t bits; + uint32_t val; +}; + +Symbol set_ur_golomb(int i, int k, int limit, int esc_len) +{ + int e; + Symbol sym; + +#ifdef DEBUG + if (i < 0) + debugPrintfEXT("Error: i is zero!"); +#endif + + e = i >> k; + if (e < limit) { + sym.bits = e + k + 1; + sym.val = (1 << k) + zero_extend(i, k); + } else { + sym.bits = limit + esc_len; + sym.val = i - limit + 1; + } + + return sym; +} + +/** + * write signed golomb rice code (ffv1). + */ +Symbol set_sr_golomb(int i, int k, int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + return set_ur_golomb(v, k, limit, esc_len); +} + +Symbol get_vlc_symbol(inout VlcState state, int v, int bits) +{ + int i, k, code; + Symbol sym; + v = fold(v - int(state.bias), bits); + + i = state.count; + k = 0; + while (i < state.error_sum) { // FIXME: optimize + k++; + i += i; + } + +#ifdef DEBUG + if (k > 16) + debugPrintfEXT("Error: k > 16!"); +#endif + + code = v ^ ((2 * state.drift + state.count) >> 31); + + update_vlc_state(state, v); + + return set_sr_golomb(code, k, 12, bits); +} + +uint get_ur_golomb(inout GetBitContext gb, int k, int limit, int esc_len) +{ + for (uint i = 0; i < 12; i++) + if (get_bit(gb)) + return get_bits(gb, k) + (i << k); + + return get_bits(gb, esc_len) + 11; +} + +int get_sr_golomb(inout GetBitContext gb, int k, int limit, int esc_len) +{ + int v = int(get_ur_golomb(gb, k, limit, esc_len)); + return (v >> 1) ^ -(v & 1); +} + +int read_vlc_symbol(inout GetBitContext gb, inout VlcState state, int bits) +{ + int k, i, v, ret; + + i = state.count; + k = 0; + while (i < state.error_sum) { // FIXME: optimize + k++; + i += i; + } + + v = get_sr_golomb(gb, k, 12, bits); + + v ^= ((2 * state.drift + state.count) >> 31); + + ret = fold(v + state.bias, bits); + + update_vlc_state(state, v); + + return ret; +} diff --git a/libavcodec/vulkan/prores_raw.comp b/libavcodec/vulkan/prores_raw.comp new file mode 100644 index 0000000000..89eece3c7e --- /dev/null +++ b/libavcodec/vulkan/prores_raw.comp @@ -0,0 +1,347 @@ +/* + * ProRes RAW decoder + * + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 I16(x) (int16_t(x)) + +#define COMP_ID (gl_LocalInvocationID.z) +#define BLOCK_ID (gl_LocalInvocationID.y) +#define ROW_ID (gl_LocalInvocationID.x) + +GetBitContext gb; +shared float btemp[gl_WorkGroupSize.z][16][64] = { }; +shared float block[gl_WorkGroupSize.z][16][64]; + +void idct8_horiz(const uint row_id) +{ + float t0, t1, t2, t3, t4, t5, t6, t7, u8; + float u0, u1, u2, u3, u4, u5, u6, u7; + + /* Input */ + t0 = block[COMP_ID][BLOCK_ID][8*row_id + 0]; + u4 = block[COMP_ID][BLOCK_ID][8*row_id + 1]; + t2 = block[COMP_ID][BLOCK_ID][8*row_id + 2]; + u6 = block[COMP_ID][BLOCK_ID][8*row_id + 3]; + t1 = block[COMP_ID][BLOCK_ID][8*row_id + 4]; + u5 = block[COMP_ID][BLOCK_ID][8*row_id + 5]; + t3 = block[COMP_ID][BLOCK_ID][8*row_id + 6]; + u7 = block[COMP_ID][BLOCK_ID][8*row_id + 7]; + + /* Embedded scaled inverse 4-point Type-II DCT */ + u0 = t0 + t1; + u1 = t0 - t1; + u3 = t2 + t3; + u2 = (t2 - t3)*(1.4142135623730950488016887242097f) - u3; + t0 = u0 + u3; + t3 = u0 - u3; + t1 = u1 + u2; + t2 = u1 - u2; + + /* Embedded scaled inverse 4-point Type-IV DST */ + t5 = u5 + u6; + t6 = u5 - u6; + t7 = u4 + u7; + t4 = u4 - u7; + u7 = t7 + t5; + u5 = (t7 - t5)*(1.4142135623730950488016887242097f); + u8 = (t4 + t6)*(1.8477590650225735122563663787936f); + u4 = u8 - t4*(1.0823922002923939687994464107328f); + u6 = u8 - t6*(2.6131259297527530557132863468544f); + t7 = u7; + t6 = t7 - u6; + t5 = t6 + u5; + t4 = t5 - u4; + + /* Butterflies */ + u0 = t0 + t7; + u7 = t0 - t7; + u6 = t1 + t6; + u1 = t1 - t6; + u2 = t2 + t5; + u5 = t2 - t5; + u4 = t3 + t4; + u3 = t3 - t4; + + /* Output */ + btemp[COMP_ID][BLOCK_ID][0*8 + row_id] = u0; + btemp[COMP_ID][BLOCK_ID][1*8 + row_id] = u1; + btemp[COMP_ID][BLOCK_ID][2*8 + row_id] = u2; + btemp[COMP_ID][BLOCK_ID][3*8 + row_id] = u3; + btemp[COMP_ID][BLOCK_ID][4*8 + row_id] = u4; + btemp[COMP_ID][BLOCK_ID][5*8 + row_id] = u5; + btemp[COMP_ID][BLOCK_ID][6*8 + row_id] = u6; + btemp[COMP_ID][BLOCK_ID][7*8 + row_id] = u7; +} + +void idct8_vert(const uint row_id) +{ + float t0, t1, t2, t3, t4, t5, t6, t7, u8; + float u0, u1, u2, u3, u4, u5, u6, u7; + + /* Input */ + t0 = btemp[COMP_ID][BLOCK_ID][8*row_id + 0] + 0.5f; // NOTE + u4 = btemp[COMP_ID][BLOCK_ID][8*row_id + 1]; + t2 = btemp[COMP_ID][BLOCK_ID][8*row_id + 2]; + u6 = btemp[COMP_ID][BLOCK_ID][8*row_id + 3]; + t1 = btemp[COMP_ID][BLOCK_ID][8*row_id + 4]; + u5 = btemp[COMP_ID][BLOCK_ID][8*row_id + 5]; + t3 = btemp[COMP_ID][BLOCK_ID][8*row_id + 6]; + u7 = btemp[COMP_ID][BLOCK_ID][8*row_id + 7]; + + /* Embedded scaled inverse 4-point Type-II DCT */ + u0 = t0 + t1; + u1 = t0 - t1; + u3 = t2 + t3; + u2 = (t2 - t3)*(1.4142135623730950488016887242097f) - u3; + t0 = u0 + u3; + t3 = u0 - u3; + t1 = u1 + u2; + t2 = u1 - u2; + + /* Embedded scaled inverse 4-point Type-IV DST */ + t5 = u5 + u6; + t6 = u5 - u6; + t7 = u4 + u7; + t4 = u4 - u7; + u7 = t7 + t5; + u5 = (t7 - t5)*(1.4142135623730950488016887242097f); + u8 = (t4 + t6)*(1.8477590650225735122563663787936f); + u4 = u8 - t4*(1.0823922002923939687994464107328f); + u6 = u8 - t6*(2.6131259297527530557132863468544f); + t7 = u7; + t6 = t7 - u6; + t5 = t6 + u5; + t4 = t5 - u4; + + /* Butterflies */ + u0 = t0 + t7; + u7 = t0 - t7; + u6 = t1 + t6; + u1 = t1 - t6; + u2 = t2 + t5; + u5 = t2 - t5; + u4 = t3 + t4; + u3 = t3 - t4; + + /* Output */ + block[COMP_ID][BLOCK_ID][0*8 + row_id] = u0; + block[COMP_ID][BLOCK_ID][1*8 + row_id] = u1; + block[COMP_ID][BLOCK_ID][2*8 + row_id] = u2; + block[COMP_ID][BLOCK_ID][3*8 + row_id] = u3; + block[COMP_ID][BLOCK_ID][4*8 + row_id] = u4; + block[COMP_ID][BLOCK_ID][5*8 + row_id] = u5; + block[COMP_ID][BLOCK_ID][6*8 + row_id] = u6; + block[COMP_ID][BLOCK_ID][7*8 + row_id] = u7; +} + +int16_t get_value(int16_t codebook) +{ + const int16_t switch_bits = codebook >> 8; + const int16_t rice_order = codebook & I16(0xf); + const int16_t exp_order = (codebook >> 4) & I16(0xf); + + uint32_t b = show_bits(gb, 32); + if (expectEXT(b == 0, false)) + return I16(0); + int16_t q = I16(31) - I16(findMSB(b)); + + if ((b & 0x80000000) != 0) { + skip_bits(gb, 1 + rice_order); + return I16((b & 0x7FFFFFFF) >> (31 - rice_order)); + } + + if (q <= switch_bits) { + skip_bits(gb, q + rice_order + 1); + return I16((q << rice_order) + + (((b << (q + 1)) >> 1) >> (31 - rice_order))); + } + + int16_t bits = exp_order + (q << 1) - switch_bits; + skip_bits(gb, bits); + return I16((b >> (32 - bits)) + + ((switch_bits + 1) << rice_order) - + (1 << exp_order)); +} + +#define TODCCODEBOOK(x) ((x + 1) >> 1) + +void read_dc_vals(const uint nb_blocks) +{ + int16_t dc, dc_add; + int16_t prev_dc = I16(0), sign = I16(0); + + /* Special handling for first block */ + dc = get_value(I16(700)); + prev_dc = (dc >> 1) ^ -(dc & I16(1)); + btemp[COMP_ID][0][0] = prev_dc; + + for (uint n = 1; n < nb_blocks; n++) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + uint8_t dc_codebook; + if ((n & 15) == 1) + dc_codebook = uint8_t(100); + else + dc_codebook = dc_cb[min(TODCCODEBOOK(dc), 13 - 1)]; + + dc = get_value(dc_codebook); + + sign = sign ^ dc & int16_t(1); + dc_add = (-sign ^ I16(TODCCODEBOOK(dc))) + sign; + sign = I16(dc_add < 0); + prev_dc += dc_add; + + btemp[COMP_ID][n][0] = prev_dc; + } +} + +void read_ac_vals(const uint nb_blocks) +{ + const uint nb_codes = nb_blocks << 6; + const uint log2_nb_blocks = findMSB(nb_blocks); + const uint block_mask = (1 << log2_nb_blocks) - 1; + + int16_t ac, rn, ln; + int16_t ac_codebook = I16(49); + int16_t rn_codebook = I16( 0); + int16_t ln_codebook = I16(66); + int16_t sign; + int16_t val; + + for (uint n = nb_blocks; n <= nb_codes;) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + ln = get_value(ln_codebook); + for (uint i = 0; i < ln; i++) { + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + if (expectEXT(n >= nb_codes, false)) + break; + + ac = get_value(ac_codebook); + ac_codebook = ac_cb[min(ac, 95 - 1)]; + sign = -int16_t(get_bit(gb)); + + val = ((ac + I16(1)) ^ sign) - sign; + btemp[COMP_ID][n & block_mask][n >> log2_nb_blocks] = val; + + n++; + } + + if (expectEXT(n >= nb_codes, false)) + break; + + rn = get_value(rn_codebook); + rn_codebook = rn_cb[min(rn, 28 - 1)]; + + n += rn + 1; + if (expectEXT(n >= nb_codes, false)) + break; + + if (expectEXT(left_bits(gb) <= 0, false)) + break; + + ac = get_value(ac_codebook); + sign = -int16_t(get_bit(gb)); + + val = ((ac + I16(1)) ^ sign) - sign; + btemp[COMP_ID][n & block_mask][n >> log2_nb_blocks] = val; + + ac_codebook = ac_cb[min(ac, 95 - 1)]; + ln_codebook = ln_cb[min(ac, 15 - 1)]; + + n++; + } +} + +void main(void) +{ + const uint tile_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; + TileData td = tile_data[tile_idx]; + + if (expectEXT(td.pos.x >= frame_size.x, false)) + return; + + uint64_t pkt_offset = uint64_t(pkt_data) + td.offset; + u8vec2buf hdr_data = u8vec2buf(pkt_offset); + float qscale = float(pack16(hdr_data[0].v.yx)) / 2.0f; + + ivec4 size = ivec4(td.size, + pack16(hdr_data[2].v.yx), + pack16(hdr_data[1].v.yx), + pack16(hdr_data[3].v.yx)); + size[0] = size[0] - size[1] - size[2] - size[3] - 8; + if (expectEXT(size[0] < 0, false)) + return; + + const ivec2 offs = td.pos + ivec2(COMP_ID & 1, COMP_ID >> 1); + const uint w = min(tile_size.x, frame_size.x - td.pos.x) / 2; + const uint nb_blocks = w / 8; + + const ivec4 comp_offset = ivec4(size[2] + size[1] + size[3], + size[2], + 0, + size[2] + size[1]); + + if (BLOCK_ID == 0 && ROW_ID == 0) { + init_get_bits(gb, u8buf(pkt_offset + 8 + comp_offset[COMP_ID]), + size[COMP_ID]); + read_dc_vals(nb_blocks); + read_ac_vals(nb_blocks); + } + + barrier(); + + [[unroll]] + for (uint i = gl_LocalInvocationID.x; i < 64; i += gl_WorkGroupSize.x) + block[COMP_ID][BLOCK_ID][i] = (btemp[COMP_ID][BLOCK_ID][scan[i]] / 16384.0) * + (float(qmat[i]) / 295.0) * + idct_8x8_scales[i] * qscale; + + barrier(); + +#ifdef PARALLEL_ROWS + idct8_horiz(ROW_ID); + + barrier(); + + idct8_vert(ROW_ID); +#else + for (uint j = 0; j < 8; j++) + idct8_horiz(j); + + barrier(); + + for (uint j = 0; j < 8; j++) + idct8_vert(j); +#endif + + barrier(); + + [[unroll]] + for (uint i = gl_LocalInvocationID.x; i < 64; i += gl_WorkGroupSize.x) + imageStore(dst, + offs + 2*ivec2(BLOCK_ID*8 + (i & 7), i >> 3), + vec4(block[COMP_ID][BLOCK_ID][i])); +} diff --git a/libavcodec/vulkan/rangecoder.comp b/libavcodec/vulkan/rangecoder.comp new file mode 100644 index 0000000000..b6b6c0490f --- /dev/null +++ b/libavcodec/vulkan/rangecoder.comp @@ -0,0 +1,241 @@ +/* + * FFv1 codec + * + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +struct RangeCoder { + uint64_t bytestream_start; + uint64_t bytestream; + uint64_t bytestream_end; + + int low; + int range; + uint16_t outstanding_count; + uint8_t outstanding_byte; +}; + +#ifdef FULL_RENORM +/* Full renorm version that can handle outstanding_byte == 0xFF */ +void renorm_encoder(inout RangeCoder c) +{ + int bs_cnt = 0; + u8buf bytestream = u8buf(c.bytestream); + + if (c.outstanding_byte == 0xFF) { + c.outstanding_byte = uint8_t(c.low >> 8); + } else if (c.low <= 0xFF00) { + bytestream[bs_cnt++].v = c.outstanding_byte; + uint16_t cnt = c.outstanding_count; + for (; cnt > 0; cnt--) + bytestream[bs_cnt++].v = uint8_t(0xFF); + c.outstanding_count = uint16_t(0); + c.outstanding_byte = uint8_t(c.low >> 8); + } else if (c.low >= 0x10000) { + bytestream[bs_cnt++].v = c.outstanding_byte + uint8_t(1); + uint16_t cnt = c.outstanding_count; + for (; cnt > 0; cnt--) + bytestream[bs_cnt++].v = uint8_t(0x00); + c.outstanding_count = uint16_t(0); + c.outstanding_byte = uint8_t(bitfieldExtract(c.low, 8, 8)); + } else { + c.outstanding_count++; + } + + c.bytestream += bs_cnt; + c.range <<= 8; + c.low = bitfieldInsert(0, c.low, 8, 8); +} + +#else + +/* Cannot deal with outstanding_byte == -1 in the name of speed */ +void renorm_encoder(inout RangeCoder c) +{ + uint16_t oc = c.outstanding_count + uint16_t(1); + int low = c.low; + + c.range <<= 8; + c.low = bitfieldInsert(0, low, 8, 8); + + if (low > 0xFF00 && low < 0x10000) { + c.outstanding_count = oc; + return; + } + + u8buf bs = u8buf(c.bytestream); + uint8_t outstanding_byte = c.outstanding_byte; + + c.bytestream = uint64_t(bs) + oc; + c.outstanding_count = uint16_t(0); + c.outstanding_byte = uint8_t(low >> 8); + + uint8_t obs = uint8_t(low > 0xFF00); + uint8_t fill = obs - uint8_t(1); /* unsigned underflow */ + + bs[0].v = outstanding_byte + obs; + for (int i = 1; i < oc; i++) + bs[i].v = fill; +} +#endif + +void put_rac_internal(inout RangeCoder c, const int range1, bool bit) +{ +#ifdef DEBUG + if (range1 >= c.range) + debugPrintfEXT("Error: range1 >= c.range"); + if (range1 <= 0) + debugPrintfEXT("Error: range1 <= 0"); +#endif + + int ranged = c.range - range1; + c.low += bit ? ranged : 0; + c.range = bit ? range1 : ranged; + + if (expectEXT(c.range < 0x100, false)) + renorm_encoder(c); +} + +void put_rac_direct(inout RangeCoder c, inout uint8_t state, bool bit) +{ + put_rac_internal(c, (c.range * state) >> 8, bit); + state = zero_one_state[(uint(bit) << 8) + state]; +} + +void put_rac(inout RangeCoder c, uint64_t state, bool bit) +{ + put_rac_direct(c, u8buf(state).v, bit); +} + +/* Equiprobable bit */ +void put_rac_equi(inout RangeCoder c, bool bit) +{ + put_rac_internal(c, c.range >> 1, bit); +} + +void put_rac_terminate(inout RangeCoder c) +{ + int range1 = (c.range * 129) >> 8; + +#ifdef DEBUG + if (range1 >= c.range) + debugPrintfEXT("Error: range1 >= c.range"); + if (range1 <= 0) + debugPrintfEXT("Error: range1 <= 0"); +#endif + + c.range -= range1; + if (expectEXT(c.range < 0x100, false)) + renorm_encoder(c); +} + +/* Return the number of bytes written. */ +uint32_t rac_terminate(inout RangeCoder c) +{ + put_rac_terminate(c); + c.range = uint16_t(0xFF); + c.low += 0xFF; + renorm_encoder(c); + c.range = uint16_t(0xFF); + renorm_encoder(c); + +#ifdef DEBUG + if (c.low != 0) + debugPrintfEXT("Error: c.low != 0"); + if (c.range < 0x100) + debugPrintfEXT("Error: range < 0x100"); +#endif + + return uint32_t(uint64_t(c.bytestream) - uint64_t(c.bytestream_start)); +} + +void rac_init(out RangeCoder r, u8buf data, uint buf_size) +{ + r.bytestream_start = uint64_t(data); + r.bytestream = uint64_t(data); + r.bytestream_end = uint64_t(data) + buf_size; + r.low = 0; + r.range = 0xFF00; + r.outstanding_count = uint16_t(0); + r.outstanding_byte = uint8_t(0xFF); +} + +/* Decoder */ +uint overread = 0; +bool corrupt = false; + +void rac_init_dec(out RangeCoder r, u8buf data, uint buf_size) +{ + overread = 0; + corrupt = false; + + /* Skip priming bytes */ + rac_init(r, OFFBUF(u8buf, data, 2), buf_size - 2); + + u8vec2 prime = u8vec2buf(data).v; + /* Switch endianness of the priming bytes */ + r.low = pack16(prime.yx); + + if (r.low >= 0xFF00) { + r.low = 0xFF00; + r.bytestream_end = uint64_t(data) + 2; + } +} + +void refill(inout RangeCoder c) +{ + c.range <<= 8; + c.low <<= 8; + if (expectEXT(c.bytestream < c.bytestream_end, false)) { + c.low |= u8buf(c.bytestream).v; + c.bytestream++; + } else { + overread++; + } +} + +bool get_rac_internal(inout RangeCoder c, const int range1) +{ + int ranged = c.range - range1; + bool bit = c.low >= ranged; + c.low -= bit ? ranged : 0; + c.range = (bit ? 0 : ranged) + (bit ? range1 : 0); + + if (expectEXT(c.range < 0x100, false)) + refill(c); + + return bit; +} + +bool get_rac_direct(inout RangeCoder c, inout uint8_t state) +{ + bool bit = get_rac_internal(c, c.range * state >> 8); + state = zero_one_state[state + (bit ? 256 : 0)]; + return bit; +} + +bool get_rac(inout RangeCoder c, uint64_t state) +{ + return get_rac_direct(c, u8buf(state).v); +} + +bool get_rac_equi(inout RangeCoder c) +{ + return get_rac_internal(c, c.range >> 1); +} diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c index a0befb9c4e..788e3cca78 100644 --- a/libavcodec/vulkan_av1.c +++ b/libavcodec/vulkan_av1.c @@ -26,6 +26,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_av1_desc = { .codec_id = AV_CODEC_ID_AV1, .decode_extension = FF_VK_EXT_VIDEO_DECODE_AV1, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME, @@ -122,7 +123,7 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ((has_grain || dec->dedicated_dpb) && ctx->common.layered_dpb) ? hp->frame_id : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -138,23 +139,15 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, return 0; } -static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) +static void vk_av1_params_fill(AVCodecContext *avctx, + StdVideoAV1TimingInfo *av1_timing_info, + StdVideoAV1ColorConfig *av1_color_config, + StdVideoAV1SequenceHeader *av1_sequence_header) { const AV1DecContext *s = avctx->priv_data; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx = dec->shared_ctx; - const AV1RawSequenceHeader *seq = s->raw_seq; - StdVideoAV1SequenceHeader av1_sequence_header; - StdVideoAV1TimingInfo av1_timing_info; - StdVideoAV1ColorConfig av1_color_config; - VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params; - VkVideoSessionParametersCreateInfoKHR session_params_create; - - int err; - - av1_timing_info = (StdVideoAV1TimingInfo) { + *av1_timing_info = (StdVideoAV1TimingInfo) { .flags = (StdVideoAV1TimingInfoFlags) { .equal_picture_interval = seq->timing_info.equal_picture_interval, }, @@ -163,7 +156,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .num_ticks_per_picture_minus_1 = seq->timing_info.num_ticks_per_picture_minus_1, }; - av1_color_config = (StdVideoAV1ColorConfig) { + *av1_color_config = (StdVideoAV1ColorConfig) { .flags = (StdVideoAV1ColorConfigFlags) { .mono_chrome = seq->color_config.mono_chrome, .color_range = seq->color_config.color_range, @@ -178,7 +171,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .matrix_coefficients = seq->color_config.matrix_coefficients, }; - av1_sequence_header = (StdVideoAV1SequenceHeader) { + *av1_sequence_header = (StdVideoAV1SequenceHeader) { .flags = (StdVideoAV1SequenceHeaderFlags) { .still_picture = seq->still_picture, .reduced_still_picture_header = seq->reduced_still_picture_header, @@ -210,9 +203,26 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1, .seq_force_integer_mv = seq->seq_force_integer_mv, .seq_force_screen_content_tools = seq->seq_force_screen_content_tools, - .pTimingInfo = &av1_timing_info, - .pColorConfig = &av1_color_config, + .pTimingInfo = av1_timing_info, + .pColorConfig = av1_color_config, }; +} + +static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf, + AV1VulkanDecodePicture *ap) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + + StdVideoAV1SequenceHeader av1_sequence_header; + StdVideoAV1TimingInfo av1_timing_info; + StdVideoAV1ColorConfig av1_color_config; + VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params; + VkVideoSessionParametersCreateInfoKHR session_params_create; + + vk_av1_params_fill(avctx, &av1_timing_info, &av1_color_config, + &av1_sequence_header); av1_params = (VkVideoDecodeAV1SessionParametersCreateInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, @@ -235,6 +245,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_av1_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { @@ -243,6 +254,8 @@ static int vk_av1_start_frame(AVCodecContext *avctx, AV1DecContext *s = avctx->priv_data; const AV1Frame *pic = &s->cur_frame; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + uint32_t frame_id_alloc_mask = 0; + AV1VulkanDecodePicture *ap = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &ap->vp; @@ -256,23 +269,24 @@ static int vk_av1_start_frame(AVCodecContext *avctx, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ }; - if (!dec->session_params) { - err = vk_av1_create_params(avctx, &dec->session_params); - if (err < 0) - return err; + /* Use the current frame_ids in ref[] to decide occupied frame_ids */ + for (int i = 0; i < STD_VIDEO_AV1_NUM_REF_FRAMES; i++) { + const AV1VulkanDecodePicture* rp = s->ref[i].hwaccel_picture_private; + if (rp) + frame_id_alloc_mask |= 1 << rp->frame_id; } if (!ap->frame_id_set) { unsigned slot_idx = 0; for (unsigned i = 0; i < 32; i++) { - if (!(dec->frame_id_alloc_mask & (1 << i))) { + if (!(frame_id_alloc_mask & (1 << i))) { slot_idx = i; break; } } ap->frame_id = slot_idx; ap->frame_id_set = 1; - dec->frame_id_alloc_mask |= (1 << slot_idx); + frame_id_alloc_mask |= (1 << slot_idx); } ap->ref_frame_sign_bias_mask = 0x0; @@ -345,7 +359,7 @@ static int vk_av1_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -577,17 +591,37 @@ static int vk_av1_end_frame(AVCodecContext *avctx) { const AV1DecContext *s = avctx->priv_data; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + const AV1Frame *pic = &s->cur_frame; AV1VulkanDecodePicture *ap = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &ap->vp; FFVulkanDecodePicture *rvp[AV1_NUM_REF_FRAMES] = { 0 }; AVFrame *rav[AV1_NUM_REF_FRAMES] = { 0 }; +#ifdef VK_KHR_video_maintenance2 + StdVideoAV1SequenceHeader av1_sequence_header; + StdVideoAV1TimingInfo av1_timing_info; + StdVideoAV1ColorConfig av1_color_config; + VkVideoDecodeAV1InlineSessionParametersInfoKHR av1_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + vk_av1_params_fill(avctx, &av1_timing_info, &av1_color_config, + &av1_sequence_header); + av1_params = (VkVideoDecodeAV1InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSequenceHeader = &av1_sequence_header, + }; + ap->av1_pic_info.pNext = &av1_params; + } +#endif + if (!ap->av1_pic_info.tileCount) return 0; - if (!dec->session_params) { - int err = vk_av1_create_params(avctx, &dec->session_params); + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { + int err = vk_av1_create_params(avctx, &dec->session_params, ap); if (err < 0) return err; } @@ -600,21 +634,17 @@ static int vk_av1_end_frame(AVCodecContext *avctx) rav[i] = ap->ref_src[i]->f; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i tiles\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i tiles\n", vp->slices_size, ap->av1_pic_info.tileCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_av1_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_av1_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; AV1VulkanDecodePicture *ap = data; - /* Workaround for a spec issue. */ - if (ap->frame_id_set) - ap->dec->frame_id_alloc_mask &= ~(1 << ap->frame_id); - /* Free frame resources, this also destroys the session parameters. */ ff_vk_decode_free_frame(hwctx, &ap->vp); } @@ -636,15 +666,5 @@ const FFHWAccel ff_av1_vulkan_hwaccel = { .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - - /* NOTE: Threading is intentionally disabled here. Due to the design of Vulkan, - * where frames are opaque to users, and mostly opaque for driver developers, - * there's an issue with current hardware accelerator implementations of AV1, - * where they require an internal index. With regular hwaccel APIs, this index - * is given to users as an opaque handle directly. With Vulkan, due to increased - * flexibility, this index cannot be present anywhere. - * The current implementation tracks the index for the driver and submits it - * as necessary information. Due to needing to modify the decoding context, - * which is not thread-safe, on frame free, threading is disabled. */ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c index a8b906a9dd..b038d456dd 100644 --- a/libavcodec/vulkan_decode.c +++ b/libavcodec/vulkan_decode.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "vulkan_video.h" #include "vulkan_decode.h" #include "config_components.h" @@ -24,15 +24,28 @@ #include "libavutil/mem.h" #include "libavutil/vulkan_loader.h" +#define DECODER_IS_SDR(codec_id) \ + (((codec_id) == AV_CODEC_ID_FFV1) || \ + ((codec_id) == AV_CODEC_ID_PRORES_RAW)) + #if CONFIG_H264_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc; #endif #if CONFIG_HEVC_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_hevc_desc; #endif +#if CONFIG_VP9_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_vp9_desc; +#endif #if CONFIG_AV1_VULKAN_HWACCEL extern const FFVulkanDecodeDescriptor ff_vk_dec_av1_desc; #endif +#if CONFIG_FFV1_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_ffv1_desc; +#endif +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL +extern const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc; +#endif static const FFVulkanDecodeDescriptor *dec_descs[] = { #if CONFIG_H264_VULKAN_HWACCEL @@ -41,11 +54,33 @@ static const FFVulkanDecodeDescriptor *dec_descs[] = { #if CONFIG_HEVC_VULKAN_HWACCEL &ff_vk_dec_hevc_desc, #endif +#if CONFIG_VP9_VULKAN_HWACCEL + &ff_vk_dec_vp9_desc, +#endif #if CONFIG_AV1_VULKAN_HWACCEL &ff_vk_dec_av1_desc, #endif +#if CONFIG_FFV1_VULKAN_HWACCEL + &ff_vk_dec_ffv1_desc, +#endif +#if CONFIG_PRORES_RAW_VULKAN_HWACCEL + &ff_vk_dec_prores_raw_desc, +#endif }; +typedef struct FFVulkanDecodeProfileData { + VkVideoDecodeH264ProfileInfoKHR h264_profile; + VkVideoDecodeH265ProfileInfoKHR h265_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9ProfileInfoKHR vp9_profile; +#endif + VkVideoDecodeAV1ProfileInfoKHR av1_profile; + + VkVideoDecodeUsageInfoKHR usage; + VkVideoProfileInfoKHR profile; + VkVideoProfileListInfoKHR profile_list; +} FFVulkanDecodeProfileData; + static const FFVulkanDecodeDescriptor *get_codecdesc(enum AVCodecID codec_id) { for (size_t i = 0; i < FF_ARRAY_ELEMS(dec_descs); i++) @@ -62,8 +97,13 @@ static const VkVideoProfileInfoKHR *get_video_profile(FFVulkanDecodeShared *ctx, VkStructureType profile_struct_type = codec_id == AV_CODEC_ID_H264 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR : codec_id == AV_CODEC_ID_HEVC ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR : +#if CONFIG_VP9_VULKAN_HWACCEL + codec_id == AV_CODEC_ID_VP9 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR : +#endif codec_id == AV_CODEC_ID_AV1 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR : - 0; + VK_STRUCTURE_TYPE_MAX_ENUM; + if (profile_struct_type == VK_STRUCTURE_TYPE_MAX_ENUM) + return NULL; profile_list = ff_vk_find_struct(ctx->s.hwfc->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR); @@ -83,36 +123,14 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) FFVulkanDecodeContext *src_ctx = src->internal->hwaccel_priv_data; FFVulkanDecodeContext *dst_ctx = dst->internal->hwaccel_priv_data; - if (!dst_ctx->exec_pool.cmd_bufs) { - FFVulkanDecodeShared *ctx = src_ctx->shared_ctx; + av_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx); - const VkVideoProfileInfoKHR *profile = get_video_profile(ctx, dst->codec_id); - if (!profile) { - av_log(dst, AV_LOG_ERROR, "Video profile missing from frames context!\n"); - return AVERROR(EINVAL); - } - - err = ff_vk_exec_pool_init(&ctx->s, &ctx->qf, - &dst_ctx->exec_pool, - src_ctx->exec_pool.pool_size, - src_ctx->exec_pool.nb_queries, - VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0, - profile); - if (err < 0) - return err; - } - - ff_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx); - - if (src_ctx->session_params) { - err = av_buffer_replace(&dst_ctx->session_params, src_ctx->session_params); - if (err < 0) - return err; - } + err = av_buffer_replace(&dst_ctx->session_params, src_ctx->session_params); + if (err < 0) + return err; dst_ctx->dedicated_dpb = src_ctx->dedicated_dpb; dst_ctx->external_fg = src_ctx->external_fg; - dst_ctx->frame_id_alloc_mask = src_ctx->frame_id_alloc_mask; return 0; } @@ -138,32 +156,42 @@ static AVFrame *vk_get_dpb_pool(FFVulkanDecodeShared *ctx) return avf; } +static void init_frame(FFVulkanDecodeContext *dec, FFVulkanDecodePicture *vkpic) +{ + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + vkpic->dpb_frame = NULL; + for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) { + vkpic->view.ref[i] = VK_NULL_HANDLE; + vkpic->view.out[i] = VK_NULL_HANDLE; + vkpic->view.dst[i] = VK_NULL_HANDLE; + } + + vkpic->destroy_image_view = vk->DestroyImageView; + vkpic->wait_semaphores = vk->WaitSemaphores; + vkpic->invalidate_memory_ranges = vk->InvalidateMappedMemoryRanges; +} + int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, FFVulkanDecodePicture *vkpic, int is_current, int alloc_dpb) { int err; FFVulkanDecodeShared *ctx = dec->shared_ctx; - FFVulkanFunctions *vk = &ctx->s.vkfn; vkpic->slices_size = 0; /* If the decoder made a blank frame to make up for a missing ref, or the * frame is the current frame so it's missing one, create a re-representation */ - if (vkpic->img_view_ref) + if (vkpic->view.ref[0]) return 0; - vkpic->dpb_frame = NULL; - vkpic->img_view_ref = VK_NULL_HANDLE; - vkpic->img_view_out = VK_NULL_HANDLE; - vkpic->img_view_dest = VK_NULL_HANDLE; - - vkpic->destroy_image_view = vk->DestroyImageView; - vkpic->wait_semaphores = vk->WaitSemaphores; + init_frame(dec, vkpic); if (ctx->common.layered_dpb && alloc_dpb) { - vkpic->img_view_ref = ctx->common.layered_view; - vkpic->img_aspect_ref = ctx->common.layered_aspect; + vkpic->view.ref[0] = ctx->common.layered_view; + vkpic->view.aspect_ref[0] = ctx->common.layered_aspect; } else if (alloc_dpb) { AVHWFramesContext *dpb_frames = (AVHWFramesContext *)ctx->common.dpb_hwfc_ref->data; AVVulkanFramesContext *dpb_hwfc = dpb_frames->hwctx; @@ -173,13 +201,13 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, return AVERROR(ENOMEM); err = ff_vk_create_view(&ctx->s, &ctx->common, - &vkpic->img_view_ref, &vkpic->img_aspect_ref, + &vkpic->view.ref[0], &vkpic->view.aspect_ref[0], (AVVkFrame *)vkpic->dpb_frame->data[0], dpb_hwfc->format[0], !is_current); if (err < 0) return err; - vkpic->img_view_dest = vkpic->img_view_ref; + vkpic->view.dst[0] = vkpic->view.ref[0]; } if (!alloc_dpb || is_current) { @@ -187,15 +215,62 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, AVVulkanFramesContext *hwfc = frames->hwctx; err = ff_vk_create_view(&ctx->s, &ctx->common, - &vkpic->img_view_out, &vkpic->img_aspect, + &vkpic->view.out[0], &vkpic->view.aspect[0], (AVVkFrame *)pic->data[0], hwfc->format[0], !is_current); if (err < 0) return err; if (!alloc_dpb) { - vkpic->img_view_ref = vkpic->img_view_out; - vkpic->img_aspect_ref = vkpic->img_aspect; + vkpic->view.ref[0] = vkpic->view.out[0]; + vkpic->view.aspect_ref[0] = vkpic->view.aspect[0]; + } + } + + return 0; +} + +int ff_vk_decode_prepare_frame_sdr(FFVulkanDecodeContext *dec, AVFrame *pic, + FFVulkanDecodePicture *vkpic, int is_current, + enum FFVkShaderRepFormat rep_fmt, int alloc_dpb) +{ + int err; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + AVHWFramesContext *frames = (AVHWFramesContext *)pic->hw_frames_ctx->data; + + vkpic->slices_size = 0; + + if (vkpic->view.ref[0]) + return 0; + + init_frame(dec, vkpic); + + for (int i = 0; i < av_pix_fmt_count_planes(frames->sw_format); i++) { + if (alloc_dpb) { + vkpic->dpb_frame = vk_get_dpb_pool(ctx); + if (!vkpic->dpb_frame) + return AVERROR(ENOMEM); + + err = ff_vk_create_imageview(&ctx->s, + &vkpic->view.ref[i], &vkpic->view.aspect_ref[i], + vkpic->dpb_frame, i, rep_fmt); + if (err < 0) + return err; + + vkpic->view.dst[i] = vkpic->view.ref[i]; + } + + if (!alloc_dpb || is_current) { + err = ff_vk_create_imageview(&ctx->s, + &vkpic->view.out[i], &vkpic->view.aspect[i], + pic, i, rep_fmt); + if (err < 0) + return err; + + if (!alloc_dpb) { + vkpic->view.ref[i] = vkpic->view.out[i]; + vkpic->view.aspect_ref[i] = vkpic->view.aspect[i]; + } } } @@ -211,7 +286,7 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, static const uint8_t startcode_prefix[3] = { 0x0, 0x0, 0x1 }; const size_t startcode_len = add_startcode ? sizeof(startcode_prefix) : 0; - const int nb = *nb_slices; + const int nb = nb_slices ? *nb_slices : 0; uint8_t *slices; uint32_t *slice_off; FFVkBuffer *vkbuf; @@ -220,13 +295,16 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, ctx->caps.minBitstreamBufferSizeAlignment; new_size = FFALIGN(new_size, ctx->caps.minBitstreamBufferSizeAlignment); - slice_off = av_fast_realloc(dec->slice_off, &dec->slice_off_max, - (nb + 1)*sizeof(slice_off)); - if (!slice_off) - return AVERROR(ENOMEM); + if (offsets) { + slice_off = av_fast_realloc(dec->slice_off, &dec->slice_off_max, + (nb + 1)*sizeof(slice_off)); + if (!slice_off) + return AVERROR(ENOMEM); - *offsets = dec->slice_off = slice_off; - slice_off[nb] = vp->slices_size; + *offsets = dec->slice_off = slice_off; + + slice_off[nb] = vp->slices_size; + } vkbuf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; if (!vkbuf || vkbuf->size < new_size) { @@ -242,9 +320,14 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, buf_size = 2 << av_log2(buf_size); err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref, + DECODER_IS_SDR(avctx->codec_id) ? + (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) : VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, ctx->s.hwfc->create_pnext, buf_size, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + (DECODER_IS_SDR(avctx->codec_id) ? + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0)); if (err < 0) return err; @@ -267,7 +350,9 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, /* Slice data */ memcpy(slices + vp->slices_size + startcode_len, data, size); - *nb_slices = nb + 1; + if (nb_slices) + *nb_slices = nb + 1; + vp->slices_size += startcode_len + size; return 0; @@ -293,8 +378,13 @@ void ff_vk_decode_flush(AVCodecContext *avctx) }; VkCommandBuffer cmd_buf; - FFVkExecContext *exec = ff_vk_exec_get(&dec->exec_pool); - int had_submission = exec->had_submission; + FFVkExecContext *exec; + + /* Non-video queues do not need to be reset */ + if (!(get_codecdesc(avctx->codec_id)->decode_op)) + return; + + exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); ff_vk_exec_start(&ctx->s, exec); cmd_buf = exec->buf; @@ -302,11 +392,6 @@ void ff_vk_decode_flush(AVCodecContext *avctx) vk->CmdControlVideoCodingKHR(cmd_buf, &decode_ctrl); vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end); ff_vk_exec_submit(&ctx->s, exec); - - /* If this is the very first time this context is used, then remove the - * had_submission flag to indicate that no query result is available, - * as no decode command was issued. */ - exec->had_submission = had_submission; } int ff_vk_decode_frame(AVCodecContext *avctx, @@ -328,11 +413,12 @@ int ff_vk_decode_frame(AVCodecContext *avctx, /* Quirks */ const int layered_dpb = ctx->common.layered_dpb; - VkVideoSessionParametersKHR *par = (VkVideoSessionParametersKHR *)dec->session_params->data; VkVideoBeginCodingInfoKHR decode_start = { .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR, .videoSession = ctx->common.session, - .videoSessionParameters = *par, + .videoSessionParameters = dec->session_params ? + *((VkVideoSessionParametersKHR *)dec->session_params->data) : + VK_NULL_HANDLE, .referenceSlotCount = vp->decode_info.referenceSlotCount, .pReferenceSlots = vp->decode_info.pReferenceSlots, }; @@ -345,7 +431,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, size_t data_size = FFALIGN(vp->slices_size, ctx->caps.minBitstreamBufferSizeAlignment); - FFVkExecContext *exec = ff_vk_exec_get(&dec->exec_pool); + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); /* The current decoding reference has to be bound as an inactive reference */ VkVideoReferenceSlotInfoKHR *cur_vk_ref; @@ -354,22 +440,6 @@ int ff_vk_decode_frame(AVCodecContext *avctx, cur_vk_ref[0].slotIndex = -1; decode_start.referenceSlotCount++; - if (dec->exec_pool.nb_queries && exec->had_submission) { - uint32_t *result; - ret = ff_vk_exec_get_query(&ctx->s, exec, (void **)&result, - VK_QUERY_RESULT_WAIT_BIT); - if (ret != VK_NOT_READY && ret != VK_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Unable to perform query: %s!\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; - } - - av_log(avctx, - result[0] != VK_QUERY_RESULT_STATUS_COMPLETE_KHR ? - AV_LOG_ERROR : AV_LOG_DEBUG, - "Result of previous frame decoding: %u\n", result[0]); - } - sd_buf = (FFVkBuffer *)vp->slices_buf->data; /* Flush if needed */ @@ -438,7 +508,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = vkf->img[0], .subresourceRange = (VkImageSubresourceRange) { - .aspectMask = vp->img_aspect, + .aspectMask = vp->view.aspect[0], .layerCount = 1, .levelCount = 1, }, @@ -494,7 +564,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = rvkf->img[0], .subresourceRange = (VkImageSubresourceRange) { - .aspectMask = rvp->img_aspect_ref, + .aspectMask = rvp->view.aspect_ref[0], .layerCount = 1, .levelCount = 1, }, @@ -504,7 +574,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, } } } else if (vp->decode_info.referenceSlotCount || - vp->img_view_out != vp->img_view_ref) { + vp->view.out[0] != vp->view.ref[0]) { /* Single barrier for a single layered ref */ err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ctx->common.layered_frame, VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, @@ -523,17 +593,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, /* Start, use parameters, decode and end decoding */ vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start); - - /* Start status query */ - if (dec->exec_pool.nb_queries) - vk->CmdBeginQuery(cmd_buf, dec->exec_pool.query_pool, exec->query_idx + 0, 0); - vk->CmdDecodeVideoKHR(cmd_buf, &vp->decode_info); - - /* End status query */ - if (dec->exec_pool.nb_queries) - vk->CmdEndQuery(cmd_buf, dec->exec_pool.query_pool, exec->query_idx + 0); - vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end); /* End recording and submit for execution */ @@ -561,22 +621,27 @@ void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, FFVulkanDecodePicture * av_buffer_unref(&vp->slices_buf); /* Destroy image view (out) */ - if (vp->img_view_out && vp->img_view_out != vp->img_view_dest) - vp->destroy_image_view(hwctx->act_dev, vp->img_view_out, hwctx->alloc); + for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) { + if (vp->view.out[i] && vp->view.out[i] != vp->view.dst[i]) + vp->destroy_image_view(hwctx->act_dev, vp->view.out[i], hwctx->alloc); - /* Destroy image view (ref, unlayered) */ - if (vp->img_view_dest) - vp->destroy_image_view(hwctx->act_dev, vp->img_view_dest, hwctx->alloc); + /* Destroy image view (ref, unlayered) */ + if (vp->view.dst[i]) + vp->destroy_image_view(hwctx->act_dev, vp->view.dst[i], hwctx->alloc); + } av_frame_free(&vp->dpb_frame); } -static void free_common(FFRefStructOpaque unused, void *obj) +static void free_common(AVRefStructOpaque unused, void *obj) { FFVulkanDecodeShared *ctx = obj; FFVulkanContext *s = &ctx->s; FFVulkanFunctions *vk = &ctx->s.vkfn; + /* Wait on and free execution pool */ + ff_vk_exec_pool_free(&ctx->s, &ctx->exec_pool); + /* This also frees all references from this pool */ av_frame_free(&ctx->common.layered_frame); @@ -590,6 +655,9 @@ static void free_common(FFRefStructOpaque unused, void *obj) ff_vk_video_common_uninit(s, &ctx->common); + if (ctx->sd_ctx_free) + ctx->sd_ctx_free(ctx); + ff_vk_uninit(s); } @@ -597,6 +665,7 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re { int err; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + const FFVulkanDecodeDescriptor *vk_desc = get_codecdesc(avctx->codec_id); AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; AVHWDeviceContext *device = (AVHWDeviceContext *)frames->device_ref->data; AVVulkanDeviceContext *hwctx = device->hwctx; @@ -605,7 +674,7 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re if (dec->shared_ctx) return 0; - dec->shared_ctx = ff_refstruct_alloc_ext(sizeof(*ctx), 0, NULL, + dec->shared_ctx = av_refstruct_alloc_ext(sizeof(*ctx), 0, NULL, free_common); if (!dec->shared_ctx) return AVERROR(ENOMEM); @@ -615,16 +684,18 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re ctx->s.extensions = ff_vk_extensions_to_mask(hwctx->enabled_dev_extensions, hwctx->nb_enabled_dev_extensions); - if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) { - av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", - VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME); - ff_refstruct_unref(&dec->shared_ctx); - return AVERROR(ENOSYS); + if (vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) { + if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) { + av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", + VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME); + av_refstruct_unref(&dec->shared_ctx); + return AVERROR(ENOSYS); + } } err = ff_vk_load_functions(device, &ctx->s.vkfn, ctx->s.extensions, 1, 1); if (err < 0) { - ff_refstruct_unref(&dec->shared_ctx); + av_refstruct_unref(&dec->shared_ctx); return err; } @@ -638,6 +709,9 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, const FFVulkanDecodeDescriptor *vk_desc, VkVideoDecodeH264CapabilitiesKHR *h264_caps, VkVideoDecodeH265CapabilitiesKHR *h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9CapabilitiesKHR *vp9_caps, +#endif VkVideoDecodeAV1CapabilitiesKHR *av1_caps, VkVideoCapabilitiesKHR *caps, VkVideoDecodeCapabilitiesKHR *dec_caps, @@ -649,6 +723,9 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, VkVideoDecodeH264ProfileInfoKHR *h264_profile = &prof->h264_profile; VkVideoDecodeH265ProfileInfoKHR *h265_profile = &prof->h265_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9ProfileInfoKHR *vp9_profile = &prof->vp9_profile; +#endif VkVideoDecodeAV1ProfileInfoKHR *av1_profile = &prof->av1_profile; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); @@ -674,6 +751,13 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx, usage->pNext = h265_profile; h265_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR; h265_profile->stdProfileIdc = cur_profile; +#if CONFIG_VP9_VULKAN_HWACCEL + } else if (avctx->codec_id == AV_CODEC_ID_VP9) { + dec_caps->pNext = vp9_caps; + usage->pNext = vp9_profile; + vp9_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR; + vp9_profile->stdProfile = cur_profile; +#endif } else if (avctx->codec_id == AV_CODEC_ID_AV1) { dec_caps->pNext = av1_caps; usage->pNext = av1_profile; @@ -734,6 +818,11 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ VkVideoDecodeH265CapabilitiesKHR h265_caps = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR, }; +#if CONFIG_VP9_VULKAN_HWACCEL + VkVideoDecodeVP9CapabilitiesKHR vp9_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_CAPABILITIES_KHR, + }; +#endif VkVideoDecodeAV1CapabilitiesKHR av1_caps = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR, }; @@ -754,12 +843,18 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ cur_profile = avctx->profile; base_profile = avctx->codec_id == AV_CODEC_ID_H264 ? AV_PROFILE_H264_CONSTRAINED_BASELINE : avctx->codec_id == AV_CODEC_ID_H265 ? AV_PROFILE_HEVC_MAIN : +#if CONFIG_VP9_VULKAN_HWACCEL + avctx->codec_id == AV_CODEC_ID_VP9 ? STD_VIDEO_VP9_PROFILE_0 : +#endif avctx->codec_id == AV_CODEC_ID_AV1 ? STD_VIDEO_AV1_PROFILE_MAIN : 0; ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, &h264_caps, &h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + &vp9_caps, +#endif &av1_caps, caps, dec_caps, @@ -776,6 +871,9 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, &h264_caps, &h265_caps, +#if CONFIG_VP9_VULKAN_HWACCEL + &vp9_caps, +#endif &av1_caps, caps, dec_caps, @@ -802,6 +900,9 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ max_level = avctx->codec_id == AV_CODEC_ID_H264 ? ff_vk_h264_level_to_av(h264_caps.maxLevelIdc) : avctx->codec_id == AV_CODEC_ID_H265 ? ff_vk_h265_level_to_av(h265_caps.maxLevelIdc) : +#if CONFIG_VP9_VULKAN_HWACCEL + avctx->codec_id == AV_CODEC_ID_VP9 ? vp9_caps.maxLevel : +#endif avctx->codec_id == AV_CODEC_ID_AV1 ? av1_caps.maxLevel : 0; @@ -973,53 +1074,77 @@ static void free_profile_data(AVHWFramesContext *hwfc) int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { - VkFormat vkfmt; + VkFormat vkfmt = VK_FORMAT_UNDEFINED; int err, dedicated_dpb; AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; AVVulkanFramesContext *hwfc = frames_ctx->hwctx; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeProfileData *prof; - FFVulkanDecodeShared *ctx; - - frames_ctx->sw_format = AV_PIX_FMT_NONE; + FFVulkanDecodeProfileData *prof = NULL; err = vulkan_decode_bootstrap(avctx, hw_frames_ctx); if (err < 0) return err; - prof = av_mallocz(sizeof(FFVulkanDecodeProfileData)); - if (!prof) - return AVERROR(ENOMEM); + frames_ctx->sw_format = avctx->sw_pix_fmt; - err = vulkan_decode_get_profile(avctx, hw_frames_ctx, - &frames_ctx->sw_format, &vkfmt, - prof, &dedicated_dpb); - if (err < 0) { - av_free(prof); - return err; + if (!DECODER_IS_SDR(avctx->codec_id)) { + prof = av_mallocz(sizeof(FFVulkanDecodeProfileData)); + if (!prof) + return AVERROR(ENOMEM); + + err = vulkan_decode_get_profile(avctx, hw_frames_ctx, + &frames_ctx->sw_format, &vkfmt, + prof, &dedicated_dpb); + if (err < 0) { + av_free(prof); + return err; + } + + frames_ctx->user_opaque = prof; + frames_ctx->free = free_profile_data; + + hwfc->create_pnext = &prof->profile_list; + } else { + switch (frames_ctx->sw_format) { + case AV_PIX_FMT_GBRAP16: + /* This should be more efficient for downloading and using */ + frames_ctx->sw_format = AV_PIX_FMT_RGBA64; + break; + case AV_PIX_FMT_GBRP10: + /* This saves memory bandwidth when downloading */ + frames_ctx->sw_format = AV_PIX_FMT_X2BGR10; + break; + case AV_PIX_FMT_BGR0: + /* mpv has issues with bgr0 mapping, so just remap it */ + frames_ctx->sw_format = AV_PIX_FMT_RGB0; + break; + default: + break; + } } - frames_ctx->user_opaque = prof; - frames_ctx->free = free_profile_data; - frames_ctx->width = avctx->coded_width; frames_ctx->height = avctx->coded_height; frames_ctx->format = AV_PIX_FMT_VULKAN; hwfc->format[0] = vkfmt; - hwfc->create_pnext = &prof->profile_list; hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; - hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR; + hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; - if (!dec->dedicated_dpb) - hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + if (prof) { + FFVulkanDecodeShared *ctx; - ctx = dec->shared_ctx; - if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | - FF_VK_EXT_VIDEO_MAINTENANCE_1)) - hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR; + if (!dec->dedicated_dpb) + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + + ctx = dec->shared_ctx; + if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | + FF_VK_EXT_VIDEO_MAINTENANCE_1)) + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + } return err; } @@ -1066,29 +1191,20 @@ int ff_vk_decode_create_params(AVBufferRef **par_ref, void *logctx, FFVulkanDeco int ff_vk_decode_uninit(AVCodecContext *avctx) { FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx = dec->shared_ctx; - - /* Wait on and free execution pool */ - ff_vk_exec_pool_free(&ctx->s, &dec->exec_pool); av_freep(&dec->hevc_headers); av_buffer_unref(&dec->session_params); - ff_refstruct_unref(&dec->shared_ctx); + av_refstruct_unref(&dec->shared_ctx); av_freep(&dec->slice_off); return 0; } -int ff_vk_decode_init(AVCodecContext *avctx) +static int create_empty_session_parameters(AVCodecContext *avctx, + FFVulkanDecodeShared *ctx) { - int err, nb_q = 0; VkResult ret; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - FFVulkanDecodeShared *ctx; - FFVulkanContext *s; - FFVulkanFunctions *vk; - const VkVideoProfileInfoKHR *profile; - const FFVulkanDecodeDescriptor *vk_desc; - const VkPhysicalDeviceDriverProperties *driver_props; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &s->vkfn; VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, @@ -1107,7 +1223,34 @@ int ff_vk_decode_init(AVCodecContext *avctx) avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params : avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params : NULL, + .videoSession = ctx->common.session, }; + + if (avctx->codec_id == AV_CODEC_ID_VP9) + return 0; + + ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create, + s->hwctx->alloc, &ctx->empty_session_params); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video session parameters: %s!\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +int ff_vk_decode_init(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx; + FFVulkanContext *s; + int async_depth; + const VkVideoProfileInfoKHR *profile; + const FFVulkanDecodeDescriptor *vk_desc; + const VkPhysicalDeviceDriverProperties *driver_props; + VkVideoSessionCreateInfoKHR session_create = { .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR, }; @@ -1119,35 +1262,29 @@ int ff_vk_decode_init(AVCodecContext *avctx) /* Initialize contexts */ ctx = dec->shared_ctx; s = &ctx->s; - vk = &ctx->s.vkfn; err = ff_vk_init(s, avctx, NULL, avctx->hw_frames_ctx); if (err < 0) return err; + vk_desc = get_codecdesc(avctx->codec_id); + profile = get_video_profile(ctx, avctx->codec_id); - if (!profile) { + if ((vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) && !profile) { av_log(avctx, AV_LOG_ERROR, "Video profile missing from frames context!"); return AVERROR(EINVAL); } /* Create queue context */ vk_desc = get_codecdesc(avctx->codec_id); - err = ff_vk_video_qf_init(s, &ctx->qf, - VK_QUEUE_VIDEO_DECODE_BIT_KHR, - vk_desc->decode_op); - if (err < 0) { + ctx->qf = ff_vk_qf_find(s, vk_desc->queue_flags, vk_desc->decode_op); + if (!ctx->qf) { av_log(avctx, AV_LOG_ERROR, "Decoding of %s is not supported by this device\n", avcodec_get_name(avctx->codec_id)); return err; } - /* Enable queries if supported */ - if (s->query_props[ctx->qf.queue_family].queryResultStatusSupport) - nb_q = 1; - - session_create.flags = 0x0; - session_create.queueFamilyIndex = ctx->qf.queue_family; + session_create.queueFamilyIndex = ctx->qf->idx; session_create.maxCodedExtent = ctx->caps.maxCodedExtent; session_create.maxDpbSlots = ctx->caps.maxDpbSlots; session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; @@ -1155,19 +1292,30 @@ int ff_vk_decode_init(AVCodecContext *avctx) session_create.referencePictureFormat = session_create.pictureFormat; session_create.pStdHeaderVersion = &vk_desc->ext_props; session_create.pVideoProfile = profile; +#ifdef VK_KHR_video_maintenance2 + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) + session_create.flags = VK_VIDEO_SESSION_CREATE_INLINE_SESSION_PARAMETERS_BIT_KHR; +#endif /* Create decode exec context for this specific main thread. * 2 async contexts per thread was experimentally determined to be optimal * for a majority of streams. */ - err = ff_vk_exec_pool_init(s, &ctx->qf, &dec->exec_pool, 2, - nb_q, VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR, 0, - profile); + async_depth = 2*ctx->qf->num; + /* We don't need more than 2 per thread context */ + async_depth = FFMIN(async_depth, 2*avctx->thread_count); + /* Make sure there are enough async contexts for each thread */ + async_depth = FFMAX(async_depth, avctx->thread_count); + + err = ff_vk_exec_pool_init(s, ctx->qf, &ctx->exec_pool, + async_depth, 0, 0, 0, profile); if (err < 0) goto fail; - err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create); - if (err < 0) - goto fail; + if (!DECODER_IS_SDR(avctx->codec_id)) { + err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create); + if (err < 0) + goto fail; + } /* If doing an out-of-place decoding, create a DPB pool */ if (dec->dedicated_dpb || avctx->codec_id == AV_CODEC_ID_AV1) { @@ -1218,13 +1366,16 @@ int ff_vk_decode_init(AVCodecContext *avctx) } } - session_params_create.videoSession = ctx->common.session; - ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create, - s->hwctx->alloc, &ctx->empty_session_params); - if (ret != VK_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video session parameters: %s!\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; + if (!DECODER_IS_SDR(avctx->codec_id)) { + if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { + err = create_empty_session_parameters(avctx, ctx); + if (err < 0) + return err; + } + } else { + /* For SDR decoders, this alignment value will be 0. Since this will make + * add_slice() malfunction, set it to a sane default value. */ + ctx->caps.minBitstreamBufferSizeAlignment = AV_INPUT_BUFFER_PADDING_SIZE; } driver_props = &dec->shared_ctx->s.driver_props; @@ -1237,7 +1388,7 @@ int ff_vk_decode_init(AVCodecContext *avctx) ff_vk_decode_flush(avctx); - av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization sucessful\n"); + av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization successful\n"); return 0; diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h index 76e60836b5..e32468f317 100644 --- a/libavcodec/vulkan_decode.h +++ b/libavcodec/vulkan_decode.h @@ -29,24 +29,17 @@ typedef struct FFVulkanDecodeDescriptor { enum AVCodecID codec_id; FFVulkanExtensions decode_extension; + VkQueueFlagBits queue_flags; VkVideoCodecOperationFlagBitsKHR decode_op; VkExtensionProperties ext_props; } FFVulkanDecodeDescriptor; -typedef struct FFVulkanDecodeProfileData { - VkVideoDecodeH264ProfileInfoKHR h264_profile; - VkVideoDecodeH265ProfileInfoKHR h265_profile; - VkVideoDecodeAV1ProfileInfoKHR av1_profile; - VkVideoDecodeUsageInfoKHR usage; - VkVideoProfileInfoKHR profile; - VkVideoProfileListInfoKHR profile_list; -} FFVulkanDecodeProfileData; - typedef struct FFVulkanDecodeShared { FFVulkanContext s; FFVkVideoCommon common; - FFVkQueueFamilyCtx qf; + AVVulkanDeviceQueueFamily *qf; + FFVkExecPool exec_pool; AVBufferPool *buf_pool; @@ -54,16 +47,18 @@ typedef struct FFVulkanDecodeShared { VkVideoDecodeCapabilitiesKHR dec_caps; VkVideoSessionParametersKHR empty_session_params; + + /* Software-defined decoder context */ + void *sd_ctx; + void (*sd_ctx_free)(struct FFVulkanDecodeShared *ctx); } FFVulkanDecodeShared; typedef struct FFVulkanDecodeContext { FFVulkanDecodeShared *shared_ctx; AVBufferRef *session_params; - FFVkExecPool exec_pool; int dedicated_dpb; /* Oddity #1 - separate DPB images */ int external_fg; /* Oddity #2 - hardware can't apply film grain */ - uint32_t frame_id_alloc_mask; /* For AV1 only */ /* Workaround for NVIDIA drivers tested with CTS version 1.3.8 for AV1. * The tests were incorrect as the OrderHints were offset by 1. */ @@ -80,11 +75,13 @@ typedef struct FFVulkanDecodeContext { typedef struct FFVulkanDecodePicture { AVFrame *dpb_frame; /* Only used for out-of-place decoding. */ - VkImageView img_view_ref; /* Image representation view (reference) */ - VkImageView img_view_out; /* Image representation view (output-only) */ - VkImageView img_view_dest; /* Set to img_view_out if no layered refs are used */ - VkImageAspectFlags img_aspect; /* Image plane mask bits */ - VkImageAspectFlags img_aspect_ref; /* Only used for out-of-place decoding */ + struct { + VkImageView ref[AV_NUM_DATA_POINTERS]; /* Image representation view (reference) */ + VkImageView out[AV_NUM_DATA_POINTERS]; /* Image representation view (output-only) */ + VkImageView dst[AV_NUM_DATA_POINTERS]; /* Set to img_view_out if no layered refs are used */ + VkImageAspectFlags aspect[AV_NUM_DATA_POINTERS]; /* Image plane mask bits */ + VkImageAspectFlags aspect_ref[AV_NUM_DATA_POINTERS]; /* Only used for out-of-place decoding */ + } view; VkSemaphore sem; uint64_t sem_value; @@ -107,6 +104,7 @@ typedef struct FFVulkanDecodePicture { /* Vulkan functions needed for destruction, as no other context is guaranteed to exist */ PFN_vkWaitSemaphores wait_semaphores; PFN_vkDestroyImageView destroy_image_view; + PFN_vkInvalidateMappedMemoryRanges invalidate_memory_ranges; } FFVulkanDecodePicture; /** @@ -140,6 +138,13 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, FFVulkanDecodePicture *vkpic, int is_current, int alloc_dpb); +/** + * Software-defined decoder version of ff_vk_decode_prepare_frame. + */ +int ff_vk_decode_prepare_frame_sdr(FFVulkanDecodeContext *dec, AVFrame *pic, + FFVulkanDecodePicture *vkpic, int is_current, + enum FFVkShaderRepFormat rep_fmt, int alloc_dpb); + /** * Add slice data to frame. */ diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c index d187b7cdd3..e5c0496f1c 100644 --- a/libavcodec/vulkan_encode.c +++ b/libavcodec/vulkan_encode.c @@ -220,8 +220,7 @@ static int vulkan_encode_issue(AVCodecContext *avctx, .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .pNext = NULL, .codedOffset = { 0 }, - .codedExtent = (VkExtent2D){ ctx->base.surface_width, - ctx->base.surface_height }, + .codedExtent = (VkExtent2D){ avctx->width, avctx->height }, .baseArrayLayer = ctx->common.layered_dpb ? slot_index : 0, .imageViewBinding = vp->dpb.view, }; @@ -339,7 +338,7 @@ static int vulkan_encode_issue(AVCodecContext *avctx, size_align); /* Start command buffer recording */ - exec = vp->exec = ff_vk_exec_get(&ctx->enc_pool); + exec = vp->exec = ff_vk_exec_get(&ctx->s, &ctx->enc_pool); ff_vk_exec_start(&ctx->s, exec); cmd_buf = exec->buf; @@ -565,14 +564,13 @@ static int vulkan_encode_create_dpb(AVCodecContext *avctx, FFVulkanEncodeContext base_ctx->recon_frames->format = AV_PIX_FMT_VULKAN; base_ctx->recon_frames->sw_format = dpb_format; - base_ctx->recon_frames->width = base_ctx->surface_width; - base_ctx->recon_frames->height = base_ctx->surface_height; + base_ctx->recon_frames->width = avctx->width; + base_ctx->recon_frames->height = avctx->height; hwfc->format[0] = ctx->pic_format; hwfc->create_pnext = &ctx->profile_list; hwfc->tiling = VK_IMAGE_TILING_OPTIMAL; - hwfc->usage = VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; + hwfc->usage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; if (ctx->common.layered_dpb) hwfc->nb_layers = ctx->caps.maxDpbSlots; @@ -770,10 +768,8 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * return err; /* Create queue context */ - err = ff_vk_video_qf_init(s, &ctx->qf_enc, - VK_QUEUE_VIDEO_ENCODE_BIT_KHR, - vk_desc->encode_op); - if (err < 0) { + ctx->qf_enc = ff_vk_qf_find(s, VK_QUEUE_VIDEO_ENCODE_BIT_KHR, vk_desc->encode_op); + if (!ctx->qf_enc) { av_log(avctx, AV_LOG_ERROR, "Encoding of %s is not supported by this device\n", avcodec_get_name(avctx->codec_id)); return err; @@ -847,7 +843,7 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * .encodeFeedbackFlags = ctx->enc_caps.supportedEncodeFeedbackFlags & (~VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR), }; - err = ff_vk_exec_pool_init(s, &ctx->qf_enc, &ctx->enc_pool, base_ctx->async_depth, + err = ff_vk_exec_pool_init(s, ctx->qf_enc, &ctx->enc_pool, base_ctx->async_depth, 1, VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR, 0, &query_create); if (err < 0) @@ -915,9 +911,9 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * /* Setup width/height alignment */ base_ctx->surface_width = avctx->coded_width = - FFALIGN(avctx->width, ctx->caps.pictureAccessGranularity.width); + FFALIGN(avctx->width, ctx->enc_caps.encodeInputPictureGranularity.width); base_ctx->surface_height = avctx->coded_height = - FFALIGN(avctx->height, ctx->caps.pictureAccessGranularity.height); + FFALIGN(avctx->height, ctx->enc_caps.encodeInputPictureGranularity.height); /* Setup slice width/height */ base_ctx->slice_block_width = ctx->enc_caps.encodeInputPictureGranularity.width; @@ -934,8 +930,7 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * return AVERROR(EINVAL); } - fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR | - VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR; + fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR; ctx->common.layered_dpb = !(ctx->caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); @@ -995,7 +990,7 @@ av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext * /* Create session */ session_create.pVideoProfile = &ctx->profile; session_create.flags = 0x0; - session_create.queueFamilyIndex = ctx->qf_enc.queue_family; + session_create.queueFamilyIndex = ctx->qf_enc->idx; session_create.maxCodedExtent = ctx->caps.maxCodedExtent; session_create.maxDpbSlots = ctx->caps.maxDpbSlots; session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; diff --git a/libavcodec/vulkan_encode.h b/libavcodec/vulkan_encode.h index a7a02d5fd0..3df06e11d0 100644 --- a/libavcodec/vulkan_encode.h +++ b/libavcodec/vulkan_encode.h @@ -188,7 +188,7 @@ typedef struct FFVulkanEncodeContext { VkVideoEncodeCapabilitiesKHR enc_caps; VkVideoEncodeUsageInfoKHR usage_info; - FFVkQueueFamilyCtx qf_enc; + AVVulkanDeviceQueueFamily *qf_enc; FFVkExecPool enc_pool; FFHWBaseEncodePicture *slots[32]; diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c new file mode 100644 index 0000000000..08ffbfa393 --- /dev/null +++ b/libavcodec/vulkan_encode_av1.c @@ -0,0 +1,1401 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/mem.h" + +#include "cbs.h" +#include "cbs_av1.h" +#include "av1_levels.h" +#include "libavutil/mastering_display_metadata.h" + +#include "codec_internal.h" +#include "vulkan_encode.h" + +#include "libavutil/avassert.h" + +const FFVulkanEncodeDescriptor ff_vk_enc_av1_desc = { + .codec_id = AV_CODEC_ID_AV1, + .encode_extension = FF_VK_EXT_VIDEO_ENCODE_AV1, + .encode_op = VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION, + }, +}; + +enum UnitElems { + UNIT_MASTERING_DISPLAY = 1 << 0, + UNIT_CONTENT_LIGHT_LEVEL = 1 << 1, +}; + +typedef struct VulkanEncodeAV1Picture { + int slot; + int64_t last_idr_frame; + + enum UnitElems units_needed; + + StdVideoAV1TileInfo tile_info; + StdVideoAV1Quantization quantization; + StdVideoAV1Segmentation segmentation; + StdVideoAV1LoopFilter loop_filter; + StdVideoAV1CDEF cdef; + StdVideoAV1LoopRestoration loop_restoration; + StdVideoAV1GlobalMotion global_motion; + + StdVideoEncodeAV1PictureInfo av1pic_info; + VkVideoEncodeAV1PictureInfoKHR vkav1pic_info; + + StdVideoEncodeAV1ExtensionHeader ext_header; + StdVideoEncodeAV1ReferenceInfo av1dpb_info; + VkVideoEncodeAV1DpbSlotInfoKHR vkav1dpb_info; + + VkVideoEncodeAV1RateControlInfoKHR vkrc_info; + VkVideoEncodeAV1RateControlLayerInfoKHR vkrc_layer_info; + VkVideoEncodeAV1GopRemainingFrameInfoKHR vkrc_remaining; +} VulkanEncodeAV1Picture; + +typedef struct VulkanEncodeAV1Context { + FFVulkanEncodeContext common; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment current_access_unit; + + enum UnitElems unit_elems; + AV1RawOBU seq_hdr_obu; + AV1RawOBU meta_cll_obu; + AV1RawOBU meta_mastering_obu; + + VkVideoEncodeAV1ProfileInfoKHR profile; + + VkVideoEncodeAV1CapabilitiesKHR caps; + VkVideoEncodeAV1QualityLevelPropertiesKHR quality_props; + + uint64_t hrd_buffer_size; + uint64_t initial_buffer_fullness; + + int uniform_tile; + int tile_cols; + int tile_rows; + + int seq_tier; + int seq_level_idx; + + int q_idx_idr; + int q_idx_p; + int q_idx_b; + + uint8_t *padding_payload; +} VulkanEncodeAV1Context; + +static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + VulkanEncodeAV1Picture *ap = pic->codec_priv; + + /* This can be easy to calculate */ + ap->vkrc_remaining = (VkVideoEncodeAV1GopRemainingFrameInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_GOP_REMAINING_FRAME_INFO_KHR, + .useGopRemainingFrames = 0, + .gopRemainingIntra = 0, + .gopRemainingPredictive = 0, + .gopRemainingBipredictive = 0, + }; + + ap->vkrc_info = (VkVideoEncodeAV1RateControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_INFO_KHR, + .flags = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR | + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR, + .gopFrameCount = ctx->base.gop_size, + .keyFramePeriod = ctx->base.gop_size, + .consecutiveBipredictiveFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), + .temporalLayerCount = 0, + }; + rc_info->pNext = &ap->vkrc_info; + + if (rc_info->rateControlMode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + rc_info->virtualBufferSizeInMs = (enc->hrd_buffer_size * 1000LL) / avctx->bit_rate; + rc_info->initialVirtualBufferSizeInMs = (enc->initial_buffer_fullness * 1000LL) / avctx->bit_rate; + + ap->vkrc_layer_info = (VkVideoEncodeAV1RateControlLayerInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_LAYER_INFO_KHR, + + .useMinQIndex = avctx->qmin > 0, + .minQIndex.intraQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + .minQIndex.predictiveQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + .minQIndex.bipredictiveQIndex = avctx->qmin > 0 ? avctx->qmin : 0, + + .useMaxQIndex = avctx->qmax > 0, + .maxQIndex.intraQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQIndex.predictiveQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQIndex.bipredictiveQIndex = avctx->qmax > 0 ? avctx->qmax : 0, + + .useMaxFrameSize = 0, + }; + rc_layer->pNext = &ap->vkrc_layer_info; + ap->vkrc_info.temporalLayerCount = 1; + } + + return 0; +} + +static void set_name_slot(int slot, int *slot_indices, uint32_t allowed_idx, int group) +{ + int from = group ? AV1_REF_FRAME_GOLDEN : 0; + int to = group ? AV1_REFS_PER_FRAME : AV1_REF_FRAME_GOLDEN; + + for (int i = from; i < to; i++) { + if ((slot_indices[i] == -1) && (allowed_idx & (1 << i))) { + slot_indices[i] = slot; + return; + } + } + + av_assert0(0); +} + + +static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + VulkanEncodeAV1Picture *ap = pic->codec_priv; + FFHWBaseEncodePicture *ref; + VulkanEncodeAV1Picture *ap_ref; + VkVideoReferenceSlotInfoKHR *ref_slot; + + uint32_t ref_name_mask = 0x0; + int name_slots[STD_VIDEO_AV1_REFS_PER_FRAME]; + + StdVideoAV1Segmentation *segmentation = &ap->segmentation; + StdVideoAV1LoopFilter *loop_filter = &ap->loop_filter; + StdVideoAV1Quantization *quantization = &ap->quantization; + StdVideoAV1CDEF *cdef = &ap->cdef; + StdVideoAV1LoopRestoration *loop_restoration = &ap->loop_restoration; + StdVideoAV1GlobalMotion *global_motion = &ap->global_motion; + StdVideoAV1TileInfo *tile_info = &ap->tile_info; + static const int8_t default_loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME] = + { 1, 0, 0, 0, -1, 0, -1, -1 }; + + VkVideoEncodeAV1PredictionModeKHR pred_mode; + VkVideoEncodeAV1RateControlGroupKHR rc_group; + int lr_unit_shift = 0; + int lr_uv_shift = 0; + + ap->ext_header = (StdVideoEncodeAV1ExtensionHeader) { + .temporal_id = 0, + .spatial_id = 0, + }; + + *tile_info = (StdVideoAV1TileInfo) { + .flags = (StdVideoAV1TileInfoFlags) { + .uniform_tile_spacing_flag = enc->uniform_tile, + }, + .TileCols = enc->tile_cols, + .TileRows = enc->tile_rows, + .context_update_tile_id = 0, + .tile_size_bytes_minus_1 = 0, + }; + + for (int i = 0; i < STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME; i++) { + global_motion->GmType[i] = 0; + for (int j = 0; j < STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS; j++) { + global_motion->gm_params[i][j] = 0; + } + } + + for (int i = 0; i < STD_VIDEO_AV1_REFS_PER_FRAME; i++) + name_slots[i] = -1; + + *loop_restoration = (StdVideoAV1LoopRestoration) { + .FrameRestorationType[0] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .FrameRestorationType[1] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .FrameRestorationType[2] = STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE, + .LoopRestorationSize[0] = 1 + lr_unit_shift, + .LoopRestorationSize[1] = 1 + lr_unit_shift - lr_uv_shift, + .LoopRestorationSize[2] = 1 + lr_unit_shift - lr_uv_shift, + }; + + *cdef = (StdVideoAV1CDEF) { + .cdef_damping_minus_3 = 0, + .cdef_bits = 0, + }; + + for (int i = 0; i < STD_VIDEO_AV1_MAX_SEGMENTS; i++) { + segmentation->FeatureEnabled[i] = 0x0; + for (int j = 0; j < STD_VIDEO_AV1_SEG_LVL_MAX; j++) { + segmentation->FeatureEnabled[i] |= 0x0; + segmentation->FeatureData[i][j] = 0; + } + } + + *loop_filter = (StdVideoAV1LoopFilter) { + .flags = (StdVideoAV1LoopFilterFlags) { + .loop_filter_delta_enabled = 0, + .loop_filter_delta_update = 0, + }, + .loop_filter_level = { 0 }, + .loop_filter_sharpness = 0, + .update_ref_delta = 0, + .loop_filter_ref_deltas = { 0 }, + .update_mode_delta = 0, + .loop_filter_mode_deltas = { 0 }, + }; + loop_filter->update_mode_delta = 1; + memcpy(loop_filter->loop_filter_ref_deltas, default_loop_filter_ref_deltas, + STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); + + *quantization = (StdVideoAV1Quantization) { + .flags = (StdVideoAV1QuantizationFlags) { + .using_qmatrix = 0, + .diff_uv_delta = 0, + /* Reserved */ + }, + .base_q_idx = 0, /* Set later */ + .DeltaQYDc = 0, + .DeltaQUDc = 0, + .DeltaQUAc = 0, + .DeltaQVDc = 0, + .DeltaQVAc = 0, + .qm_y = 0, + .qm_u = 0, + .qm_v = 0, + }; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ap->av1pic_info = (StdVideoEncodeAV1PictureInfo) { + .flags = (StdVideoEncodeAV1PictureInfoFlags) { + .error_resilient_mode = (pic->type == FF_HW_PICTURE_TYPE_I || + pic->type == FF_HW_PICTURE_TYPE_IDR) && + (pic->display_order <= pic->encode_order), + .disable_cdf_update = 0, + .use_superres = 0, + .render_and_frame_size_different = 0, + .allow_screen_content_tools = 0, + .is_filter_switchable = 0, + .force_integer_mv = 0, + .frame_size_override_flag = 0, + .buffer_removal_time_present_flag = 0, + .allow_intrabc = 0, + .frame_refs_short_signaling = 0, + .allow_high_precision_mv = 0, + .is_motion_mode_switchable = 0, + .use_ref_frame_mvs = 0, + .disable_frame_end_update_cdf = 0, + .allow_warped_motion = 0, + .reduced_tx_set = 0, + .skip_mode_present = 0, + .delta_q_present = 0, + .delta_lf_present = 0, + .delta_lf_multi = 0, + .segmentation_enabled = 0, + .segmentation_update_map = 0, + .segmentation_temporal_update = 0, + .segmentation_update_data = 0, + .UsesLr = 0, + .usesChromaLr = 0, + .show_frame = pic->display_order <= pic->encode_order, + .showable_frame = 0, + /* Reserved */ + }, + .frame_type = 0, // set later + .frame_presentation_time = 0, + .current_frame_id = ref_slot->slotIndex, + .order_hint = 0, // set later + .primary_ref_frame = 0, // set later + .refresh_frame_flags = 0x0, // set later + .coded_denom = 0, + .render_width_minus_1 = base_ctx->surface_width - 1, + .render_height_minus_1 = base_ctx->surface_height - 1, + .interpolation_filter = 0, + .TxMode = STD_VIDEO_AV1_TX_MODE_SELECT, + .delta_q_res = 0, + .delta_lf_res = 0, + .ref_order_hint = { 0 }, // set later + .ref_frame_idx = { 0 }, // set later + /* Reserved */ + .delta_frame_id_minus_1 = { 0 }, + +// .pTileInfo = tile_info, TODO FIX + .pQuantization = quantization, + .pSegmentation = segmentation, + .pLoopFilter = loop_filter, + .pCDEF = cdef, + .pLoopRestoration = loop_restoration, + .pGlobalMotion = global_motion, + .pExtensionHeader = &ap->ext_header, + .pBufferRemovalTimes = NULL, + }; + + switch (pic->type) { + case FF_HW_PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_IDR: + av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]); + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_KEY; + ap->av1pic_info.refresh_frame_flags = 0xFF; + quantization->base_q_idx = enc->q_idx_idr; + ap->slot = 0; + ap->last_idr_frame = pic->display_order; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_INTRA_ONLY_KHR; + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_INTRA_KHR; + break; + case FF_HW_PICTURE_TYPE_P: + ref = pic->refs[0][pic->nb_refs[0] - 1]; + ap_ref = ref->codec_priv; + + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTER; + quantization->base_q_idx = enc->q_idx_p; + + ap->last_idr_frame = ap_ref->last_idr_frame; + ap->slot = !ap_ref->slot; + + ap->av1pic_info.refresh_frame_flags = 1 << ap->slot; + + /** set the nearest frame in L0 as all reference frame. */ + for (int i = 0; i < AV1_REFS_PER_FRAME; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + + ap->av1pic_info.primary_ref_frame = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_PREDICTIVE_KHR; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR; + ref_name_mask = enc->caps.singleReferenceNameMask; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + +// vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; + + /** set the 2nd nearest frame in L0 as Golden frame. */ + if ((pic->nb_refs[0] > 1) && + ((enc->caps.maxSingleReferenceCount > 1) || + (enc->caps.maxUnidirectionalCompoundReferenceCount > 0))) { + if (enc->caps.maxUnidirectionalCompoundReferenceCount) { + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR; + ref_name_mask = enc->caps.unidirectionalCompoundReferenceNameMask; + } + ref = pic->refs[0][pic->nb_refs[0] - 2]; + ap_ref = ref->codec_priv; + ap->av1pic_info.ref_frame_idx[3] = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; +// vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + } + break; + case FF_HW_PICTURE_TYPE_B: + ap->av1pic_info.frame_type = STD_VIDEO_AV1_FRAME_TYPE_INTER; + quantization->base_q_idx = enc->q_idx_b; + ap->av1pic_info.refresh_frame_flags = 0x0; + + rc_group = VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_BIPREDICTIVE_KHR; + pred_mode = VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR; + ref_name_mask = enc->caps.bidirectionalCompoundReferenceNameMask; + +// fh->reference_select = 1; + /** B frame will not be referenced, disable its recon frame. */ +// vpic->picture_flags.bits.disable_frame_recon = 1; + + /** Use LAST_FRAME and BWDREF_FRAME for reference. */ +// vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; +// vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF; + + ref = pic->refs[0][pic->nb_refs[0] - 1]; + ap_ref = ref->codec_priv; + ap->last_idr_frame = ap_ref->last_idr_frame; + ap->av1pic_info.primary_ref_frame = ap_ref->slot; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + for (int i = 0; i < AV1_REF_FRAME_GOLDEN; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 0); + + ref = pic->refs[1][pic->nb_refs[1] - 1]; + ap_ref = ref->codec_priv; + ap->av1pic_info.ref_order_hint[ap_ref->slot] = ref->display_order - ap_ref->last_idr_frame; + for (int i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) + ap->av1pic_info.ref_frame_idx[i] = ap_ref->slot; + set_name_slot(ap_ref->av1pic_info.current_frame_id, name_slots, ref_name_mask, 1); + break; + } + + ap->av1pic_info.flags.showable_frame = ap->av1pic_info.frame_type != STD_VIDEO_AV1_FRAME_TYPE_KEY; + ap->av1pic_info.order_hint = pic->display_order - ap->last_idr_frame; + + ap->vkav1pic_info = (VkVideoEncodeAV1PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PICTURE_INFO_KHR, + .pNext = NULL, + .predictionMode = pred_mode, + .rateControlGroup = rc_group, + .constantQIndex = quantization->base_q_idx, + .pStdPictureInfo = &ap->av1pic_info, + // .referenceNameSlotIndices is set below + .primaryReferenceCdfOnly = 0, + .generateObuExtensionHeader = 0, + }; + encode_info->pNext = &ap->vkav1pic_info; + + for (int i = 0; i < FF_ARRAY_ELEMS(ap->vkav1pic_info.referenceNameSlotIndices); i++) + ap->vkav1pic_info.referenceNameSlotIndices[i] = name_slots[i]; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ref_slot->pNext = &ap->vkav1dpb_info; + + ap->av1dpb_info = (StdVideoEncodeAV1ReferenceInfo) { + .flags = (StdVideoEncodeAV1ReferenceInfoFlags) { + .disable_frame_end_update_cdf = 0, + .segmentation_enabled = 0, + /* Reserved */ + }, + .RefFrameId = ref_slot->slotIndex, + .frame_type = ap->av1pic_info.frame_type, + .OrderHint = pic->display_order - ap->last_idr_frame, + /* Reserved */ + .pExtensionHeader = &ap->ext_header, + }; + + ap->vkav1dpb_info = (VkVideoEncodeAV1DpbSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_DPB_SLOT_INFO_KHR, + .pStdReferenceInfo = &ap->av1dpb_info, + }; + + ap->units_needed = 0; + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + AVFrameSideData *sd = NULL; + if (enc->unit_elems & UNIT_MASTERING_DISPLAY) + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (sd) { + AVMasteringDisplayMetadata *mdm = + (AVMasteringDisplayMetadata *)sd->data; + if (mdm->has_primaries && mdm->has_luminance) { + AV1RawOBU *obu = &enc->meta_mastering_obu; + AV1RawMetadata *md = &obu->obu.metadata; + AV1RawMetadataHDRMDCV *mdcv = &md->metadata.hdr_mdcv; + const int chroma_den = 1 << 16; + const int max_luma_den = 1 << 8; + const int min_luma_den = 1 << 14; + + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_METADATA; + md->metadata_type = AV1_METADATA_TYPE_HDR_MDCV; + + for (int i = 0; i < 3; i++) { + mdcv->primary_chromaticity_x[i] = + av_rescale(mdm->display_primaries[i][0].num, chroma_den, + mdm->display_primaries[i][0].den); + mdcv->primary_chromaticity_y[i] = + av_rescale(mdm->display_primaries[i][1].num, chroma_den, + mdm->display_primaries[i][1].den); + } + + mdcv->white_point_chromaticity_x = + av_rescale(mdm->white_point[0].num, chroma_den, + mdm->white_point[0].den); + mdcv->white_point_chromaticity_y = + av_rescale(mdm->white_point[1].num, chroma_den, + mdm->white_point[1].den); + + mdcv->luminance_max = + av_rescale(mdm->max_luminance.num, max_luma_den, + mdm->max_luminance.den); + mdcv->luminance_min = + av_rescale(mdm->min_luminance.num, min_luma_den, + mdm->min_luminance.den); + ap->units_needed |= UNIT_MASTERING_DISPLAY; + } + } + + if (enc->unit_elems & UNIT_CONTENT_LIGHT_LEVEL) + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + if (sd) { + AVContentLightMetadata *cllm = (AVContentLightMetadata *)sd->data; + AV1RawOBU *obu = &enc->meta_cll_obu; + AV1RawMetadata *md = &obu->obu.metadata; + AV1RawMetadataHDRCLL *cll = &md->metadata.hdr_cll; + + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_METADATA; + md->metadata_type = AV1_METADATA_TYPE_HDR_CLL; + cll->max_cll = cllm->MaxCLL; + cll->max_fall = cllm->MaxFALL; + + ap->units_needed |= UNIT_CONTENT_LIGHT_LEVEL; + } + } + + return 0; +} + +static int init_profile(AVCodecContext *avctx, + VkVideoProfileInfoKHR *profile, void *pnext) +{ + VkResult ret; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + VkVideoEncodeAV1CapabilitiesKHR av1_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, + }; + VkVideoEncodeCapabilitiesKHR enc_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR, + .pNext = &av1_caps, + }; + VkVideoCapabilitiesKHR caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR, + .pNext = &enc_caps, + }; + + /* In order of preference */ + int last_supported = AV_PROFILE_UNKNOWN; + static const int known_profiles[] = { + AV_PROFILE_AV1_MAIN, + AV_PROFILE_AV1_HIGH, + AV_PROFILE_AV1_PROFESSIONAL, + }; + int nb_profiles = FF_ARRAY_ELEMS(known_profiles); + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->frames->sw_format); + if (!desc) + return AVERROR(EINVAL); + + if (s->frames->sw_format == AV_PIX_FMT_NV12 || + s->frames->sw_format == AV_PIX_FMT_P010) + nb_profiles = 1; + + enc->profile = (VkVideoEncodeAV1ProfileInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PROFILE_INFO_KHR, + .pNext = pnext, + .stdProfile = ff_vk_av1_profile_to_vk(avctx->profile), + }; + profile->pNext = &enc->profile; + + /* Set level */ + if (avctx->level == AV_LEVEL_UNKNOWN) { + const AV1LevelDescriptor *level; + float framerate = 0.0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = av_q2d(avctx->framerate); + + level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier, + base_ctx->surface_width, base_ctx->surface_height, + enc->tile_rows * enc->tile_cols, + enc->tile_cols, framerate); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + enc->seq_level_idx = ff_vk_av1_level_to_vk(level->level_idx); + } else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level, using level 7.3 by default.\n"); + enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3; + enc->seq_tier = 1; + } + } else { + enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level); + } + + /* User has explicitly specified a profile. */ + if (avctx->profile != AV_PROFILE_UNKNOWN) + return 0; + + av_log(avctx, AV_LOG_DEBUG, "Supported profiles:\n"); + for (int i = 0; i < nb_profiles; i++) { + enc->profile.stdProfile = ff_vk_av1_profile_to_vk(known_profiles[i]); + ret = vk->GetPhysicalDeviceVideoCapabilitiesKHR(s->hwctx->phys_dev, + profile, + &caps); + if (ret == VK_SUCCESS) { + av_log(avctx, AV_LOG_DEBUG, " %s\n", + avcodec_profile_name(avctx->codec_id, known_profiles[i])); + last_supported = known_profiles[i]; + } + } + + if (last_supported == AV_PROFILE_UNKNOWN) { + av_log(avctx, AV_LOG_ERROR, "No supported profiles for given format\n"); + return AVERROR(ENOTSUP); + } + + enc->profile.stdProfile = ff_vk_av1_profile_to_vk(last_supported); + av_log(avctx, AV_LOG_VERBOSE, "Using profile %s\n", + avcodec_profile_name(avctx->codec_id, last_supported)); + avctx->profile = last_supported; + + return 0; +} + +static int init_enc_options(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + + if (avctx->rc_buffer_size) + enc->hrd_buffer_size = avctx->rc_buffer_size; + else if (avctx->rc_max_rate > 0) + enc->hrd_buffer_size = avctx->rc_max_rate; + else + enc->hrd_buffer_size = avctx->bit_rate; + + if (avctx->rc_initial_buffer_occupancy) { + if (avctx->rc_initial_buffer_occupancy > enc->hrd_buffer_size) { + av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: " + "must have initial buffer size (%d) <= " + "buffer size (%"PRId64").\n", + avctx->rc_initial_buffer_occupancy, enc->hrd_buffer_size); + return AVERROR(EINVAL); + } + enc->initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + } else { + enc->initial_buffer_fullness = enc->hrd_buffer_size * 3 / 4; + } + + if (enc->common.opts.rc_mode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + enc->q_idx_p = av_clip(enc->common.opts.qp, + enc->caps.minQIndex, enc->caps.maxQIndex); + if (fabs(avctx->i_quant_factor) > 0.0) + enc->q_idx_idr = + av_clip((fabs(avctx->i_quant_factor) * enc->q_idx_p + + avctx->i_quant_offset) + 0.5, + 0, 255); + else + enc->q_idx_idr = enc->q_idx_p; + + if (fabs(avctx->b_quant_factor) > 0.0) + enc->q_idx_b = + av_clip((fabs(avctx->b_quant_factor) * enc->q_idx_p + + avctx->b_quant_offset) + 0.5, + 0, 255); + else + enc->q_idx_b = enc->q_idx_p; + } else { + /** Arbitrary value */ + enc->q_idx_idr = enc->q_idx_p = enc->q_idx_b = 128; + } + + return 0; +} + +static av_cold int init_sequence_headers(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->frames->sw_format); + if (!desc) + return AVERROR(EINVAL); + + seq_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; + *seq = (AV1RawSequenceHeader) { + .seq_profile = avctx->profile, + .seq_force_integer_mv = seq->seq_force_screen_content_tools ? + AV1_SELECT_SCREEN_CONTENT_TOOLS : + AV1_SELECT_INTEGER_MV, + .frame_width_bits_minus_1 = av_log2(base_ctx->surface_width), + .frame_height_bits_minus_1 = av_log2(base_ctx->surface_height), + .max_frame_width_minus_1 = base_ctx->surface_width - 1, + .max_frame_height_minus_1 = base_ctx->surface_height - 1, + .enable_order_hint = 1, + .order_hint_bits_minus_1 = av_clip_intp2(av_log2(ctx->base.gop_size), 3), + .use_128x128_superblock = !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR), + .color_config = (AV1RawColorConfig) { + .high_bitdepth = desc->comp[0].depth > 8, + .color_primaries = avctx->color_primaries, + .transfer_characteristics = avctx->color_trc, + .matrix_coefficients = avctx->colorspace, + .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED), + .subsampling_x = desc->log2_chroma_w, + .subsampling_y = desc->log2_chroma_h, + .chroma_sample_position = avctx->chroma_sample_location == AVCHROMA_LOC_LEFT ? + AV1_CSP_VERTICAL : + avctx->chroma_sample_location == AVCHROMA_LOC_TOPLEFT ? + AV1_CSP_COLOCATED : + AV1_CSP_UNKNOWN, + }, + + /* Operating point */ + .seq_tier = { enc->seq_tier }, + .seq_level_idx = { enc->seq_level_idx }, + .decoder_buffer_delay = { base_ctx->decode_delay }, + .encoder_buffer_delay = { base_ctx->output_delay }, + .operating_points_cnt_minus_1 = 1 - 1, + }; + + return 0; +} + +typedef struct VulkanAV1Units { + StdVideoAV1SequenceHeader seq_hdr; + StdVideoAV1TimingInfo timing_info; + StdVideoAV1ColorConfig color_config; + + StdVideoEncodeAV1DecoderModelInfo decoder_model; + StdVideoEncodeAV1OperatingPointInfo operating_points[AV1_MAX_OPERATING_POINTS]; + int nb_operating_points; +} VulkanAV1Units; + +static av_cold int base_unit_to_vk(AVCodecContext *avctx, VulkanAV1Units *vk_units) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + StdVideoAV1SequenceHeader *seq_hdr = &vk_units->seq_hdr; + StdVideoAV1TimingInfo *timing_info = &vk_units->timing_info; + StdVideoAV1ColorConfig *color_config = &vk_units->color_config; + + StdVideoEncodeAV1OperatingPointInfo *operating_points = vk_units->operating_points; + + *timing_info = (StdVideoAV1TimingInfo) { + .flags = (StdVideoAV1TimingInfoFlags) { + .equal_picture_interval = seq->timing_info.equal_picture_interval, + }, + .num_units_in_display_tick = seq->timing_info.num_units_in_display_tick, + .time_scale = seq->timing_info.time_scale, + .num_ticks_per_picture_minus_1 = seq->timing_info.num_ticks_per_picture_minus_1, + }; + + *color_config = (StdVideoAV1ColorConfig) { + .flags = (StdVideoAV1ColorConfigFlags) { + .mono_chrome = seq->color_config.mono_chrome, + .color_range = seq->color_config.color_range, + .separate_uv_delta_q = seq->color_config.separate_uv_delta_q, + }, + .BitDepth = seq->color_config.twelve_bit ? 12 : + seq->color_config.high_bitdepth ? 10 : 8, + .subsampling_x = seq->color_config.subsampling_x, + .subsampling_y = seq->color_config.subsampling_y, + .color_primaries = seq->color_config.color_primaries, + .transfer_characteristics = seq->color_config.transfer_characteristics, + .matrix_coefficients = seq->color_config.matrix_coefficients, + }; + + *seq_hdr = (StdVideoAV1SequenceHeader) { + .flags = (StdVideoAV1SequenceHeaderFlags) { + .still_picture = seq->still_picture, + .reduced_still_picture_header = seq->reduced_still_picture_header, + .use_128x128_superblock = seq->use_128x128_superblock, + .enable_filter_intra = seq->enable_filter_intra, + .enable_intra_edge_filter = seq->enable_intra_edge_filter, + .enable_interintra_compound = seq->enable_interintra_compound, + .enable_masked_compound = seq->enable_masked_compound, + .enable_warped_motion = seq->enable_warped_motion, + .enable_dual_filter = seq->enable_dual_filter, + .enable_order_hint = seq->enable_order_hint, + .enable_jnt_comp = seq->enable_jnt_comp, + .enable_ref_frame_mvs = seq->enable_ref_frame_mvs, + .frame_id_numbers_present_flag = seq->frame_id_numbers_present_flag, + .enable_superres = seq->enable_superres, + .enable_cdef = seq->enable_cdef, + .enable_restoration = seq->enable_restoration, + .film_grain_params_present = seq->film_grain_params_present, + .timing_info_present_flag = seq->timing_info_present_flag, + .initial_display_delay_present_flag = seq->initial_display_delay_present_flag, + }, + .seq_profile = seq->seq_profile, + .frame_width_bits_minus_1 = seq->frame_width_bits_minus_1, + .frame_height_bits_minus_1 = seq->frame_height_bits_minus_1, + .max_frame_width_minus_1 = seq->max_frame_width_minus_1, + .max_frame_height_minus_1 = seq->max_frame_height_minus_1, + .delta_frame_id_length_minus_2 = seq->delta_frame_id_length_minus_2, + .additional_frame_id_length_minus_1 = seq->additional_frame_id_length_minus_1, + .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1, + .seq_force_integer_mv = seq->seq_force_integer_mv, + .seq_force_screen_content_tools = seq->seq_force_screen_content_tools, + .pTimingInfo = timing_info, + .pColorConfig = color_config, + }; + + for (int i = 0; i <= seq->operating_points_cnt_minus_1; i++) { + operating_points[i] = (StdVideoEncodeAV1OperatingPointInfo) { + .flags = (StdVideoEncodeAV1OperatingPointInfoFlags) { + .decoder_model_present_for_this_op = seq->decoder_model_present_for_this_op[i], + .low_delay_mode_flag = seq->low_delay_mode_flag[i], + .initial_display_delay_present_for_this_op = seq->initial_display_delay_present_for_this_op[i], + /* Reserved */ + }, + .operating_point_idc = seq->operating_point_idc[i], + .seq_level_idx = seq->seq_level_idx[i], + .seq_tier = seq->seq_tier[i], + .decoder_buffer_delay = seq->decoder_buffer_delay[i], + .encoder_buffer_delay = seq->encoder_buffer_delay[i], + .initial_display_delay_minus_1 = seq->initial_display_delay_minus_1[i], + }; + } + vk_units->nb_operating_points = seq->operating_points_cnt_minus_1 + 1; + + return 0; +} + +static int create_session_params(AVCodecContext *avctx) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VulkanAV1Units vk_units = { 0 }; + + VkVideoEncodeAV1SessionParametersCreateInfoKHR av1_params; + + /* Convert it to Vulkan */ + err = base_unit_to_vk(avctx, &vk_units); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to convert sequence header to Vulkan: %s\n", + av_err2str(err)); + return err; + } + + /* Destroy the session params */ + if (ctx->session_params) + vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev, + ctx->session_params, + s->hwctx->alloc); + + av1_params = (VkVideoEncodeAV1SessionParametersCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR, + .pStdSequenceHeader = &vk_units.seq_hdr, + .pStdDecoderModelInfo = &vk_units.decoder_model, + .pStdOperatingPoints = vk_units.operating_points, + .stdOperatingPointCount = vk_units.nb_operating_points, + }; + + return ff_vulkan_encode_create_session_params(avctx, ctx, &av1_params); +} + +static int parse_feedback_units(AVCodecContext *avctx, + const uint8_t *data, size_t size) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + AV1RawOBU *seq_obu = &enc->seq_hdr_obu; + AV1RawSequenceHeader *seq = &seq_obu->obu.sequence_header; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment obu = { 0 }; + + err = ff_cbs_init(&cbs, AV_CODEC_ID_AV1, avctx); + if (err < 0) + return err; + + err = ff_cbs_read(cbs, &obu, NULL, data, size); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", + av_err2str(err)); + return err; + } + + /* If PPS has an override, just copy it entirely. */ + for (int i = 0; i < obu.nb_units; i++) { + if (obu.units[i].type == AV1_OBU_SEQUENCE_HEADER) { + AV1RawOBU *f_seq_obu = obu.units[i].content; + AV1RawSequenceHeader *f_seq = &f_seq_obu->obu.sequence_header; + seq->frame_width_bits_minus_1 = f_seq->frame_width_bits_minus_1; + seq->frame_height_bits_minus_1 = f_seq->frame_height_bits_minus_1; + seq->max_frame_width_minus_1 = f_seq->max_frame_width_minus_1; + seq->max_frame_height_minus_1 = f_seq->max_frame_height_minus_1; + seq->seq_choose_screen_content_tools = f_seq->seq_choose_screen_content_tools; + seq->seq_force_screen_content_tools = f_seq->seq_force_screen_content_tools; + seq->seq_choose_integer_mv = f_seq->seq_choose_integer_mv; + seq->seq_force_integer_mv = f_seq->seq_force_integer_mv; + } + } + + ff_cbs_fragment_free(&obu); + ff_cbs_close(&cbs); + + return 0; +} + +static int init_base_units(AVCodecContext *avctx) +{ + int err; + VkResult ret; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VkVideoEncodeSessionParametersGetInfoKHR params_info; + VkVideoEncodeSessionParametersFeedbackInfoKHR params_feedback; + + void *data = NULL; + size_t data_size = 0; + + /* Generate SPS/PPS unit info */ + err = init_sequence_headers(avctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize sequence header: %s\n", + av_err2str(err)); + return err; + } + + /* Create session parameters from them */ + err = create_session_params(avctx); + if (err < 0) + return err; + + params_info = (VkVideoEncodeSessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR, + .videoSessionParameters = ctx->session_params, + }; + params_feedback = (VkVideoEncodeSessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + }; + + ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info, + ¶ms_feedback, + &data_size, data); + if (ret == VK_INCOMPLETE || + (ret == VK_SUCCESS) && (data_size > 0)) { + data = av_mallocz(data_size); + if (!data) + return AVERROR(ENOMEM); + } else { + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for AV1 sequence header = %"SIZE_SPECIFIER"\n", + data_size); + return err; + } + + ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info, + ¶ms_feedback, + &data_size, data); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error writing feedback units\n"); + return err; + } + + av_log(avctx, AV_LOG_VERBOSE, "Feedback units written, overrides: %i\n", + params_feedback.hasOverrides); + + params_feedback.hasOverrides = 1; + + /* No need to sync any overrides */ + if (!params_feedback.hasOverrides) + return 0; + + /* Parse back tne units and override */ + err = parse_feedback_units(avctx, data, data_size); + if (err < 0) + return err; + + /* Create final session parameters */ + err = create_session_params(avctx); + if (err < 0) + return err; + + return 0; +} + +static int vulkan_encode_av1_add_obu(AVCodecContext *avctx, + CodedBitstreamFragment *au, + uint8_t type, void *obu_unit) +{ + int err; + + err = ff_cbs_insert_unit_content(au, -1, + type, obu_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: " + "type = %d.\n", type); + return err; + } + + return err; +} + +static int vulkan_encode_av1_write_obu(AVCodecContext *avctx, + uint8_t *data, size_t *data_len, + CodedBitstreamFragment *obu) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + int ret; + + ret = ff_cbs_write_fragment_data(enc->cbs, obu); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return ret; + } + + memcpy(data, obu->data, obu->data_size); + *data_len = obu->data_size; + + return 0; +} + +static int write_sequence_header(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_SEQUENCE_HEADER, &enc->seq_hdr_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int write_extra_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + VulkanEncodeAV1Picture *ap = base_pic->codec_priv; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + if (ap->units_needed & AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) { + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_METADATA, + &enc->meta_mastering_obu); + if (err < 0) + goto fail; + } + + if (ap->units_needed & UNIT_CONTENT_LIGHT_LEVEL) { + err = vulkan_encode_av1_add_obu(avctx, obu, + AV1_OBU_METADATA, + &enc->meta_cll_obu); + if (err < 0) + goto fail; + } + + if (ap->units_needed) { + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); + if (err < 0) + goto fail; + } else { + err = 0; + *data_len = 0; + } + +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static int write_padding(AVCodecContext *avctx, uint32_t padding, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + CodedBitstreamFragment *obu = &enc->current_access_unit; + + AV1RawOBU padding_obu = { 0 }; + AV1RawPadding *raw_padding = &padding_obu.obu.padding; + + if (!padding) + padding = 16; + + /* 2 byte header + 1 byte trailing bits */ + padding_obu.header.obu_type = AV1_OBU_PADDING; + *raw_padding = (AV1RawPadding) { + .payload = enc->padding_payload, + .payload_size = padding, + }; + + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_PADDING, &padding_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, data, data_len, obu); +fail: + ff_cbs_fragment_reset(obu); + return err; +} + +static const FFVulkanCodec enc_cb = { + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + VK_ENC_FLAG_NO_DELAY | + FF_HW_FLAG_SLICE_CONTROL, + .picture_priv_data_size = sizeof(VulkanEncodeAV1Picture), + .filler_header_size = 4, + .init_profile = init_profile, + .init_pic_rc = init_pic_rc, + .init_pic_params = init_pic_params, + .write_sequence_headers = write_sequence_header, + .write_extra_headers = write_extra_headers, + .write_filler = write_padding, +}; + +static av_cold int vulkan_encode_av1_init(AVCodecContext *avctx) +{ + int err; + VulkanEncodeAV1Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + int flags; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = enc->common.opts.profile; + + enc->caps = (VkVideoEncodeAV1CapabilitiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, + }; + + enc->quality_props = (VkVideoEncodeAV1QualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUALITY_LEVEL_PROPERTIES_KHR, + }; + + err = ff_vulkan_encode_init(avctx, &enc->common, + &ff_vk_enc_av1_desc, &enc_cb, + &enc->caps, &enc->quality_props); + if (err < 0) + return err; + + av_log(avctx, AV_LOG_VERBOSE, "AV1 encoder capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " Standard capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " per_rate_control_group_min_max_q_index: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PER_RATE_CONTROL_GROUP_MIN_MAX_Q_INDEX_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " generate_obu_extension_header: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_GENERATE_OBU_EXTENSION_HEADER_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " primary_reference_cdf_only: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " frame_size_override: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_FRAME_SIZE_OVERRIDE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " motion_vector_scaling: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_AV1_CAPABILITY_MOTION_VECTOR_SCALING_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " Capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " 64x64 superblocks: %i\n", + !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " 128x128 superblocks: %i\n", + !!(enc->caps.superblockSizes & VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " maxSingleReferenceCount: %i\n", + enc->caps.maxSingleReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " singleReferenceNameMask: 0x%x\n", + enc->caps.singleReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxUnidirectionalCompoundReferenceCount: %i\n", + enc->caps.maxUnidirectionalCompoundReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxUnidirectionalCompoundGroup1ReferenceCount: %i\n", + enc->caps.maxUnidirectionalCompoundGroup1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " unidirectionalCompoundReferenceNameMask: 0x%x\n", + enc->caps.unidirectionalCompoundReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundGroup1ReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundGroup1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxBidirectionalCompoundGroup2ReferenceCount: %i\n", + enc->caps.maxBidirectionalCompoundGroup2ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " bidirectionalCompoundReferenceNameMask: 0x%x\n", + enc->caps.bidirectionalCompoundReferenceNameMask); + av_log(avctx, AV_LOG_VERBOSE, " maxTemporalLayerCount: %i\n", + enc->caps.maxTemporalLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " maxSpatialLayerCount: %i\n", + enc->caps.maxSpatialLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " maxOperatingPoints: %i\n", + enc->caps.maxOperatingPoints); + av_log(avctx, AV_LOG_VERBOSE, " min/max Qindex: [%i, %i]\n", + enc->caps.minQIndex, enc->caps.maxQIndex); + av_log(avctx, AV_LOG_VERBOSE, " prefersGopRemainingFrames: %i\n", + enc->caps.prefersGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " requiresGopRemainingFrames: %i\n", + enc->caps.requiresGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " maxLevel: %i\n", + enc->caps.maxLevel); + av_log(avctx, AV_LOG_VERBOSE, " codedPictureAlignment: %ix%i\n", + enc->caps.codedPictureAlignment.width, enc->caps.codedPictureAlignment.height); + av_log(avctx, AV_LOG_VERBOSE, " maxTiles: %ix%i\n", + enc->caps.maxTiles.width, enc->caps.maxTiles.height); + av_log(avctx, AV_LOG_VERBOSE, " Tile size: %ix%i to %ix%i\n", + enc->caps.minTileSize.width, enc->caps.minTileSize.height, + enc->caps.maxTileSize.width, enc->caps.maxTileSize.height); + + err = init_enc_options(avctx); + if (err < 0) + return err; + + flags = ctx->codec->flags; + err = ff_hw_base_init_gop_structure(base_ctx, avctx, + ctx->caps.maxDpbSlots, + enc->caps.maxBidirectionalCompoundReferenceCount, + flags, 0); + if (err < 0) + return err; + + base_ctx->output_delay = base_ctx->b_per_p; + base_ctx->decode_delay = base_ctx->max_b_depth; + + /* Create units and session parameters */ + err = init_base_units(avctx); + if (err < 0) + return err; + + /* Init CBS */ + err = ff_cbs_init(&enc->cbs, AV_CODEC_ID_AV1, avctx); + if (err < 0) + return err; + + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + uint8_t data[4096]; + size_t data_len = sizeof(data); + + err = write_sequence_header(avctx, NULL, data, &data_len); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write sequence header " + "for extradata: %d.\n", err); + return err; + } else { + avctx->extradata_size = data_len; + avctx->extradata = av_mallocz(avctx->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + err = AVERROR(ENOMEM); + return err; + } + memcpy(avctx->extradata, data, avctx->extradata_size); + } + } + + enc->padding_payload = av_mallocz(2*ctx->caps.minBitstreamBufferOffsetAlignment); + if (!enc->padding_payload) + return AVERROR(ENOMEM); + + memset(enc->padding_payload, 0xaa, 2*ctx->caps.minBitstreamBufferOffsetAlignment); + + return 0; +} + +static av_cold int vulkan_encode_av1_close(AVCodecContext *avctx) +{ + VulkanEncodeAV1Context *enc = avctx->priv_data; + av_free(enc->padding_payload); + ff_vulkan_encode_uninit(&enc->common); + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeAV1Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vulkan_encode_av1_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + VULKAN_ENCODE_COMMON_OPTIONS, + + { "profile", "Set profile", + OFFSET(common.opts.profile), AV_OPT_TYPE_INT, + { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xffff, FLAGS, .unit = "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, .unit = "profile" + { PROFILE("main", AV_PROFILE_AV1_MAIN) }, + { PROFILE("high", AV_PROFILE_AV1_HIGH) }, + { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) }, +#undef PROFILE + + { "tier", "Set tier (seq_tier)", + OFFSET(common.opts.tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, .unit = "tier" }, + { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, .unit = "tier" }, + { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "tier" }, + + { "level", "Set level (level_idc)", + OFFSET(common.opts.level), AV_OPT_TYPE_INT, + { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, .unit = "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, .unit = "level" + { LEVEL("20", 0) }, + { LEVEL("21", 1) }, + { LEVEL("22", 2) }, + { LEVEL("23", 3) }, + { LEVEL("30", 4) }, + { LEVEL("31", 5) }, + { LEVEL("32", 6) }, + { LEVEL("33", 7) }, + { LEVEL("40", 8) }, + { LEVEL("41", 9) }, + { LEVEL("42", 10) }, + { LEVEL("43", 11) }, + { LEVEL("50", 12) }, + { LEVEL("51", 13) }, + { LEVEL("52", 14) }, + { LEVEL("53", 15) }, + { LEVEL("60", 16) }, + { LEVEL("61", 17) }, + { LEVEL("62", 18) }, + { LEVEL("63", 19) }, + { LEVEL("70", 20) }, + { LEVEL("71", 21) }, + { LEVEL("72", 22) }, + { LEVEL("73", 23) }, +#undef LEVEL + + { "units", "Set units to include", OFFSET(unit_elems), AV_OPT_TYPE_FLAGS, { .i64 = UNIT_MASTERING_DISPLAY | UNIT_CONTENT_LIGHT_LEVEL }, 0, INT_MAX, FLAGS, "units" }, + { "hdr", "Include HDR metadata for mastering display colour volume and content light level information", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_MASTERING_DISPLAY | UNIT_CONTENT_LIGHT_LEVEL }, INT_MIN, INT_MAX, FLAGS, "units" }, + + { NULL }, +}; + +static const FFCodecDefault vulkan_encode_av1_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "300" }, + { "qmin", "1" }, + { "qmax", "255" }, + { "refs", "0" }, + { NULL }, +}; + +static const AVClass vulkan_encode_av1_class = { + .class_name = "av1_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_av1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_av1_vulkan_encoder = { + .p.name = "av1_vulkan", + CODEC_LONG_NAME("AV1 (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(VulkanEncodeAV1Context), + .init = &vulkan_encode_av1_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_vulkan_encode_receive_packet), + .close = &vulkan_encode_av1_close, + .p.priv_class = &vulkan_encode_av1_class, + .p.capabilities = AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1 | + AV_CODEC_CAP_ENCODER_FLUSH | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .defaults = vulkan_encode_av1_defaults, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), + .hw_configs = ff_vulkan_encode_hw_configs, + .p.wrapper_name = "vulkan", +}; diff --git a/libavcodec/vulkan_encode_h264.c b/libavcodec/vulkan_encode_h264.c index 9964ba5b8b..942e911fb7 100644 --- a/libavcodec/vulkan_encode_h264.c +++ b/libavcodec/vulkan_encode_h264.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mem.h" @@ -130,12 +131,12 @@ static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, .consecutiveBFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), .temporalLayerCount = 0, }; - rc_info->pNext = &hp->vkrc_info; - rc_info->virtualBufferSizeInMs = enc->unit_opts.hrd_buffer_size; - rc_info->initialVirtualBufferSizeInMs = enc->unit_opts.initial_buffer_fullness; if (rc_info->rateControlMode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + rc_info->virtualBufferSizeInMs = (enc->unit_opts.hrd_buffer_size * 1000LL) / avctx->bit_rate; + rc_info->initialVirtualBufferSizeInMs = (enc->unit_opts.initial_buffer_fullness * 1000LL) / avctx->bit_rate; + hp->vkrc_layer_info = (VkVideoEncodeH264RateControlLayerInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR, @@ -1060,11 +1061,11 @@ static int parse_feedback_units(AVCodecContext *avctx, if (err < 0) return err; - err = ff_cbs_read(cbs, &au, data, size); + err = ff_cbs_read(cbs, &au, NULL, data, size); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", av_err2str(err)); - return err; + goto fail; } /* If PPS has an override, just copy it entirely. */ @@ -1078,10 +1079,12 @@ static int parse_feedback_units(AVCodecContext *avctx, } } + err = 0; +fail: ff_cbs_fragment_free(&au); ff_cbs_close(&cbs); - return 0; + return err; } static int init_base_units(AVCodecContext *avctx) @@ -1144,7 +1147,7 @@ static int init_base_units(AVCodecContext *avctx) if (!data) return AVERROR(ENOMEM); } else { - av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.264 units = %lu\n", data_size); + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.264 units = %"SIZE_SPECIFIER"\n", data_size); return err; } @@ -1310,6 +1313,7 @@ static int write_extra_headers(AVCodecContext *avctx, if (err < 0) goto fail; } else { + err = 0; *data_len = 0; } @@ -1630,6 +1634,7 @@ static const FFCodecDefault vulkan_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1657,10 +1662,7 @@ const FFCodec ff_h264_vulkan_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .defaults = vulkan_encode_h264_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VULKAN, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), .hw_configs = ff_vulkan_encode_hw_configs, .p.wrapper_name = "vulkan", }; diff --git a/libavcodec/vulkan_encode_h265.c b/libavcodec/vulkan_encode_h265.c index 54bf071d78..c30b7e8f93 100644 --- a/libavcodec/vulkan_encode_h265.c +++ b/libavcodec/vulkan_encode_h265.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/mem.h" @@ -124,12 +125,12 @@ static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, .consecutiveBFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), .subLayerCount = 0, }; - rc_info->pNext = &hp->vkrc_info; - rc_info->virtualBufferSizeInMs = 1000; - rc_info->initialVirtualBufferSizeInMs = 500; if (rc_info->rateControlMode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + rc_info->virtualBufferSizeInMs = (enc->hrd_buffer_size * 1000LL) / avctx->bit_rate; + rc_info->initialVirtualBufferSizeInMs = (enc->initial_buffer_fullness * 1000LL) / avctx->bit_rate; + hp->vkrc_layer_info = (VkVideoEncodeH265RateControlLayerInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR, @@ -206,7 +207,7 @@ static int vk_enc_h265_update_pic_info(AVCodecContext *avctx, } // Only look for the metadata on I/IDR frame on the output. We - // may force an IDR frame on the output where the medadata gets + // may force an IDR frame on the output where the metadata gets // changed on the input frame. if ((enc->unit_elems & UNIT_SEI_MASTERING_DISPLAY) && (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { @@ -1213,11 +1214,11 @@ static int parse_feedback_units(AVCodecContext *avctx, if (err < 0) return err; - err = ff_cbs_read(cbs, &au, data, size); + err = ff_cbs_read(cbs, &au, NULL, data, size); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Unable to parse feedback units, bad drivers: %s\n", av_err2str(err)); - return err; + goto fail; } if (sps_override) { @@ -1245,10 +1246,12 @@ static int parse_feedback_units(AVCodecContext *avctx, } } + err = 0; +fail: ff_cbs_fragment_free(&au); ff_cbs_close(&cbs); - return 0; + return err; } static int init_base_units(AVCodecContext *avctx) @@ -1313,7 +1316,7 @@ static int init_base_units(AVCodecContext *avctx) if (!data) return AVERROR(ENOMEM); } else { - av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.265 units = %lu\n", data_size); + av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.265 units = %"SIZE_SPECIFIER"\n", data_size); return err; } @@ -1470,6 +1473,7 @@ static int write_extra_headers(AVCodecContext *avctx, if (err < 0) goto fail; } else { + err = 0; *data_len = 0; } @@ -1757,6 +1761,7 @@ static const FFCodecDefault vulkan_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; @@ -1784,10 +1789,7 @@ const FFCodec ff_hevc_vulkan_encoder = { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .defaults = vulkan_encode_h265_defaults, - .p.pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_VULKAN, - AV_PIX_FMT_NONE, - }, + CODEC_PIXFMTS(AV_PIX_FMT_VULKAN), .hw_configs = ff_vulkan_encode_hw_configs, .p.wrapper_name = "vulkan", }; diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c new file mode 100644 index 0000000000..b02bc71683 --- /dev/null +++ b/libavcodec/vulkan_ffv1.c @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 2024 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "vulkan_decode.h" +#include "hwaccel_internal.h" + +#include "ffv1.h" +#include "ffv1_vulkan.h" +#include "libavutil/vulkan_spirv.h" +#include "libavutil/mem.h" + +#define RGB_LINECACHE 2 + +extern const char *ff_source_common_comp; +extern const char *ff_source_rangecoder_comp; +extern const char *ff_source_ffv1_vlc_comp; +extern const char *ff_source_ffv1_common_comp; +extern const char *ff_source_ffv1_dec_setup_comp; +extern const char *ff_source_ffv1_reset_comp; +extern const char *ff_source_ffv1_dec_comp; + +const FFVulkanDecodeDescriptor ff_vk_dec_ffv1_desc = { + .codec_id = AV_CODEC_ID_FFV1, + .decode_extension = FF_VK_EXT_PUSH_DESCRIPTOR, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct FFv1VulkanDecodePicture { + FFVulkanDecodePicture vp; + + AVBufferRef *slice_state; + uint32_t plane_state_size; + uint32_t slice_state_size; + uint32_t slice_data_size; + + AVBufferRef *slice_offset_buf; + uint32_t *slice_offset; + int slice_num; + + AVBufferRef *slice_status_buf; + int crc_checked; +} FFv1VulkanDecodePicture; + +typedef struct FFv1VulkanDecodeContext { + AVBufferRef *intermediate_frames_ref[2]; /* 16/32 bit */ + + FFVulkanShader setup; + FFVulkanShader reset[2]; /* AC/Golomb */ + FFVulkanShader decode[2][2][2]; /* 16/32 bit, AC/Golomb, Normal/RGB */ + + FFVkBuffer rangecoder_static_buf; + FFVkBuffer quant_buf; + FFVkBuffer crc_tab_buf; + + AVBufferPool *slice_state_pool; + AVBufferPool *slice_offset_pool; + AVBufferPool *slice_status_pool; +} FFv1VulkanDecodeContext; + +typedef struct FFv1VkParameters { + VkDeviceAddress slice_data; + VkDeviceAddress slice_state; + + int fmt_lut[4]; + uint32_t img_size[2]; + uint32_t chroma_shift[2]; + + uint32_t plane_state_size; + uint32_t crcref; + int rct_offset; + + uint8_t extend_lookup[8]; + uint8_t bits_per_raw_sample; + uint8_t quant_table_count; + uint8_t version; + uint8_t micro_version; + uint8_t key_frame; + uint8_t planes; + uint8_t codec_planes; + uint8_t color_planes; + uint8_t transparency; + uint8_t planar_rgb; + uint8_t colorspace; + uint8_t ec; + uint8_t golomb; + uint8_t check_crc; + uint8_t padding[3]; +} FFv1VkParameters; + +static void add_push_data(FFVulkanShader *shd) +{ + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLC(1, u8buf slice_data; ); + GLSLC(1, u8buf slice_state; ); + GLSLC(0, ); + GLSLC(1, ivec4 fmt_lut; ); + GLSLC(1, uvec2 img_size; ); + GLSLC(1, uvec2 chroma_shift; ); + GLSLC(0, ); + GLSLC(1, uint plane_state_size; ); + GLSLC(1, uint32_t crcref; ); + GLSLC(1, int rct_offset; ); + GLSLC(0, ); + GLSLC(1, uint8_t extend_lookup[8]; ); + GLSLC(1, uint8_t bits_per_raw_sample; ); + GLSLC(1, uint8_t quant_table_count; ); + GLSLC(1, uint8_t version; ); + GLSLC(1, uint8_t micro_version; ); + GLSLC(1, uint8_t key_frame; ); + GLSLC(1, uint8_t planes; ); + GLSLC(1, uint8_t codec_planes; ); + GLSLC(1, uint8_t color_planes; ); + GLSLC(1, uint8_t transparency; ); + GLSLC(1, uint8_t planar_rgb; ); + GLSLC(1, uint8_t colorspace; ); + GLSLC(1, uint8_t ec; ); + GLSLC(1, uint8_t golomb; ); + GLSLC(1, uint8_t check_crc; ); + GLSLC(1, uint8_t padding[3]; ); + GLSLC(0, }; ); + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkParameters), + VK_SHADER_STAGE_COMPUTE_BIT); +} + +static int vk_ffv1_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + FFV1Context *f = avctx->priv_data; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + enum AVPixelFormat sw_format = hwfc->sw_format; + + int max_contexts; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + + fp->slice_num = 0; + + max_contexts = 0; + for (int i = 0; i < f->quant_table_count; i++) + max_contexts = FFMAX(f->context_count[i], max_contexts); + + /* Allocate slice buffer data */ + if (f->ac == AC_GOLOMB_RICE) + fp->plane_state_size = 8; + else + fp->plane_state_size = CONTEXT_SIZE; + + fp->plane_state_size *= max_contexts; + fp->slice_state_size = fp->plane_state_size*f->plane_count; + + fp->slice_data_size = 256; /* Overestimation for the SliceContext struct */ + fp->slice_state_size += fp->slice_data_size; + fp->slice_state_size = FFALIGN(fp->slice_state_size, 8); + + fp->crc_checked = f->ec && (avctx->err_recognition & AV_EF_CRCCHECK); + + /* Host map the input slices data if supported */ + if (ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + /* Allocate slice state data */ + if (f->picture.f->flags & AV_FRAME_FLAG_KEY) { + err = ff_vk_get_pooled_buffer(&ctx->s, &fv->slice_state_pool, + &fp->slice_state, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, f->slice_count*fp->slice_state_size, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (err < 0) + return err; + } else { + FFv1VulkanDecodePicture *fpl = f->hwaccel_last_picture_private; + fp->slice_state = av_buffer_ref(fpl->slice_state); + if (!fp->slice_state) + return AVERROR(ENOMEM); + } + + /* Allocate slice offsets buffer */ + err = ff_vk_get_pooled_buffer(&ctx->s, &fv->slice_offset_pool, + &fp->slice_offset_buf, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, 2*f->slice_count*sizeof(uint32_t), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (err < 0) + return err; + + /* Allocate slice status buffer */ + err = ff_vk_get_pooled_buffer(&ctx->s, &fv->slice_status_pool, + &fp->slice_status_buf, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, 2*f->slice_count*sizeof(uint32_t), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (err < 0) + return err; + + /* Prepare frame to be used */ + err = ff_vk_decode_prepare_frame_sdr(dec, f->picture.f, vp, 1, + FF_VK_REP_NATIVE, 0); + if (err < 0) + return err; + + /* Create a temporaty frame for RGB */ + if (is_rgb) { + vp->dpb_frame = av_frame_alloc(); + if (!vp->dpb_frame) + return AVERROR(ENOMEM); + + err = av_hwframe_get_buffer(fv->intermediate_frames_ref[f->use32bit], + vp->dpb_frame, 0); + if (err < 0) + return err; + } + + return 0; +} + +static int vk_ffv1_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + FFV1Context *f = avctx->priv_data; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + FFVkBuffer *slice_offset = (FFVkBuffer *)fp->slice_offset_buf->data; + FFVkBuffer *slices_buf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; + + if (slices_buf && slices_buf->host_ref) { + AV_WN32(slice_offset->mapped_mem + (2*fp->slice_num + 0)*sizeof(uint32_t), + data - slices_buf->mapped_mem); + AV_WN32(slice_offset->mapped_mem + (2*fp->slice_num + 1)*sizeof(uint32_t), + size); + + fp->slice_num++; + } else { + int err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + &fp->slice_num, + (const uint32_t **)&fp->slice_offset); + if (err < 0) + return err; + + AV_WN32(slice_offset->mapped_mem + (2*(fp->slice_num - 1) + 0)*sizeof(uint32_t), + fp->slice_offset[fp->slice_num - 1]); + AV_WN32(slice_offset->mapped_mem + (2*(fp->slice_num - 1) + 1)*sizeof(uint32_t), + size); + } + + return 0; +} + +static int vk_ffv1_end_frame(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + FFV1Context *f = avctx->priv_data; + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + FFv1VkParameters pd; + FFv1VkResetParameters pd_reset; + + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + enum AVPixelFormat sw_format = hwfc->sw_format; + + int bits = f->avctx->bits_per_raw_sample > 0 ? f->avctx->bits_per_raw_sample : 8; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + int color_planes = av_pix_fmt_desc_get(avctx->sw_pix_fmt)->nb_components; + + FFVulkanShader *reset_shader; + FFVulkanShader *decode_shader; + + FFv1VulkanDecodePicture *fp = f->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &fp->vp; + + FFVkBuffer *slices_buf = (FFVkBuffer *)vp->slices_buf->data; + FFVkBuffer *slice_state = (FFVkBuffer *)fp->slice_state->data; + FFVkBuffer *slice_offset = (FFVkBuffer *)fp->slice_offset_buf->data; + FFVkBuffer *slice_status = (FFVkBuffer *)fp->slice_status_buf->data; + + VkImageView rct_image_views[AV_NUM_DATA_POINTERS]; + + AVFrame *decode_dst = is_rgb ? vp->dpb_frame : f->picture.f; + VkImageView *decode_dst_view = is_rgb ? rct_image_views : vp->view.out; + + VkImageMemoryBarrier2 img_bar[37]; + int nb_img_bar = 0; + VkBufferMemoryBarrier2 buf_bar[8]; + int nb_buf_bar = 0; + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + ff_vk_exec_start(&ctx->s, exec); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, f->picture.f, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + err = ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, + f->picture.f); + if (err < 0) + return err; + + if (is_rgb) { + RET(ff_vk_create_imageviews(&ctx->s, exec, rct_image_views, + vp->dpb_frame, FF_VK_REP_NATIVE)); + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, vp->dpb_frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_CLEAR_BIT)); + ff_vk_frame_barrier(&ctx->s, exec, decode_dst, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + } + + if (!(f->picture.f->flags & AV_FRAME_FLAG_KEY)) { + FFv1VulkanDecodePicture *fpl = f->hwaccel_last_picture_private; + FFVulkanDecodePicture *vpl = &fpl->vp; + + /* Wait on the previous frame */ + RET(ff_vk_exec_add_dep_wait_sem(&ctx->s, exec, vpl->sem, vpl->sem_value, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)); + } + + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &fp->slice_state, 1, 1)); + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &fp->slice_status_buf, 1, 1)); + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &fp->slice_offset_buf, 1, 0)); + fp->slice_offset_buf = NULL; + + /* Entry barrier for the slice state */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_state->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_state->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_state->buf, + .offset = 0, + .size = fp->slice_data_size*f->slice_count, + }; + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + slice_state->stage = buf_bar[0].dstStageMask; + slice_state->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + nb_img_bar = 0; + + /* Setup shader */ + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 1, 0, + slice_offset, + 0, 2*f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, &fv->setup, + 1, 2, 0, + slice_status, + 0, 2*f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&ctx->s, exec, &fv->setup); + pd = (FFv1VkParameters) { + .slice_data = slices_buf->address, + .slice_state = slice_state->address + f->slice_count*fp->slice_data_size, + + .img_size[0] = f->picture.f->width, + .img_size[1] = f->picture.f->height, + .chroma_shift[0] = f->chroma_h_shift, + .chroma_shift[1] = f->chroma_v_shift, + + .plane_state_size = fp->plane_state_size, + .crcref = f->crcref, + .rct_offset = 1 << bits, + + .bits_per_raw_sample = bits, + .quant_table_count = f->quant_table_count, + .version = f->version, + .micro_version = f->micro_version, + .key_frame = f->picture.f->flags & AV_FRAME_FLAG_KEY, + .planes = av_pix_fmt_count_planes(sw_format), + .codec_planes = f->plane_count, + .color_planes = color_planes, + .transparency = f->transparency, + .planar_rgb = ff_vk_mt_is_np_rgb(sw_format) && + (ff_vk_count_images((AVVkFrame *)f->picture.f->data[0]) > 1), + .colorspace = f->colorspace, + .ec = f->ec, + .golomb = f->ac == AC_GOLOMB_RICE, + .check_crc = !!(avctx->err_recognition & AV_EF_CRCCHECK), + }; + for (int i = 0; i < f->quant_table_count; i++) + pd.extend_lookup[i] = (f->quant_tables[i][3][127] != 0) || + (f->quant_tables[i][4][127] != 0); + + + /* For some reason the C FFv1 encoder/decoder treats these differently */ + if (sw_format == AV_PIX_FMT_GBRP10 || sw_format == AV_PIX_FMT_GBRP12 || + sw_format == AV_PIX_FMT_GBRP14) + memcpy(pd.fmt_lut, (int [4]) { 2, 1, 0, 3 }, 4*sizeof(int)); + else if (sw_format == AV_PIX_FMT_X2BGR10) + memcpy(pd.fmt_lut, (int [4]) { 0, 2, 1, 3 }, 4*sizeof(int)); + else + ff_vk_set_perm(sw_format, pd.fmt_lut, 0); + + ff_vk_shader_update_push_const(&ctx->s, exec, &fv->setup, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, 1); + + if (is_rgb) { + AVVkFrame *vkf = (AVVkFrame *)vp->dpb_frame->data[0]; + for (int i = 0; i < color_planes; i++) + vk->CmdClearColorImage(exec->buf, vkf->img[i], VK_IMAGE_LAYOUT_GENERAL, + &((VkClearColorValue) { 0 }), + 1, &((VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + })); + } + + /* Reset shader */ + reset_shader = &fv->reset[f->ac == AC_GOLOMB_RICE]; + ff_vk_shader_update_desc_buffer(&ctx->s, exec, reset_shader, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + + ff_vk_exec_bind_shader(&ctx->s, exec, reset_shader); + + pd_reset = (FFv1VkResetParameters) { + .slice_state = slice_state->address + f->slice_count*fp->slice_data_size, + .plane_state_size = fp->plane_state_size, + .codec_planes = f->plane_count, + .key_frame = f->picture.f->flags & AV_FRAME_FLAG_KEY, + .version = f->version, + .micro_version = f->micro_version, + }; + for (int i = 0; i < f->quant_table_count; i++) + pd_reset.context_count[i] = f->context_count[i]; + + ff_vk_shader_update_push_const(&ctx->s, exec, reset_shader, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd_reset), &pd_reset); + + /* Sync between setup and reset shaders */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_state->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_state->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_state->buf, + .offset = 0, + .size = fp->slice_data_size*f->slice_count, + }; + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + slice_state->stage = buf_bar[0].dstStageMask; + slice_state->access = buf_bar[0].dstAccessMask; + nb_buf_bar = 0; + nb_img_bar = 0; + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, + f->plane_count); + + /* Decode */ + decode_shader = &fv->decode[f->use32bit][f->ac == AC_GOLOMB_RICE][is_rgb]; + ff_vk_shader_update_desc_buffer(&ctx->s, exec, decode_shader, + 1, 0, 0, + slice_state, + 0, fp->slice_data_size*f->slice_count, + VK_FORMAT_UNDEFINED); + ff_vk_shader_update_img_array(&ctx->s, exec, decode_shader, + decode_dst, decode_dst_view, + 1, 1, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + ff_vk_shader_update_desc_buffer(&ctx->s, exec, decode_shader, + 1, 2, 0, + slice_status, + 0, 2*f->slice_count*sizeof(uint32_t), + VK_FORMAT_UNDEFINED); + if (is_rgb) + ff_vk_shader_update_img_array(&ctx->s, exec, decode_shader, + f->picture.f, vp->view.out, + 1, 3, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&ctx->s, exec, decode_shader); + ff_vk_shader_update_push_const(&ctx->s, exec, decode_shader, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + + /* Sync between reset and decode shaders */ + buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + .srcStageMask = slice_state->stage, + .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .srcAccessMask = slice_state->access, + .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT | + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slice_state->buf, + .offset = fp->slice_data_size*f->slice_count, + .size = f->slice_count*(fp->slice_state_size - fp->slice_data_size), + }; + + /* Input frame barrier */ + ff_vk_frame_barrier(&ctx->s, exec, f->picture.f, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT | + (!is_rgb ? VK_ACCESS_SHADER_READ_BIT : 0), + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + if (is_rgb) + ff_vk_frame_barrier(&ctx->s, exec, vp->dpb_frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + .pBufferMemoryBarriers = buf_bar, + .bufferMemoryBarrierCount = nb_buf_bar, + }); + slice_state->stage = buf_bar[0].dstStageMask; + slice_state->access = buf_bar[0].dstAccessMask; + nb_img_bar = 0; + nb_buf_bar = 0; + + vk->CmdDispatch(exec->buf, f->num_h_slices, f->num_v_slices, 1); + + err = ff_vk_exec_submit(&ctx->s, exec); + if (err < 0) + return err; + + /* We don't need the temporary frame after decoding */ + av_frame_free(&vp->dpb_frame); + +fail: + return 0; +} + +static void define_shared_code(FFVulkanShader *shd, int use32bit) +{ + int smp_bits = use32bit ? 32 : 16; + + GLSLC(0, #define DECODE ); + + av_bprintf(&shd->src, "#define RGB_LINECACHE %i\n" ,RGB_LINECACHE); + av_bprintf(&shd->src, "#define CONTEXT_SIZE %i\n" ,CONTEXT_SIZE); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_MASK 0x%x\n" ,MAX_QUANT_TABLE_MASK); + + GLSLF(0, #define TYPE int%i_t ,smp_bits); + GLSLF(0, #define VTYPE2 i%ivec2 ,smp_bits); + GLSLF(0, #define VTYPE3 i%ivec3 ,smp_bits); + GLSLD(ff_source_rangecoder_comp); + GLSLD(ff_source_ffv1_common_comp); +} + +static int init_setup_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVkSPIRVCompiler *spv, + FFVulkanShader *shd) +{ + int err; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + + RET(ff_vk_shader_init(s, shd, "ffv1_dec_setup", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + 1, 1, 1, + 0)); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + add_push_data(shd); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "crc_ieee_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint32_t crc_ieee[256];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 1, 0)); + + define_shared_code(shd, 0 /* Irrelevant */); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + { + .name = "slice_offsets_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_quali = "readonly", + .buf_content = "uint32_t slice_offsets", + .buf_elems = 2*f->max_slice_count, + }, + { + .name = "slice_status_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_quali = "writeonly", + .buf_content = "uint32_t slice_status", + .buf_elems = 2*f->max_slice_count, + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3, 0, 0)); + + GLSLD(ff_source_ffv1_dec_setup_comp); + + RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_reset_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVkSPIRVCompiler *spv, + FFVulkanShader *shd, int ac) +{ + int err; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + int wg_dim = FFMIN(s->props.properties.limits.maxComputeWorkGroupSize[0], 1024); + + RET(ff_vk_shader_init(s, shd, "ffv1_dec_reset", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + wg_dim, 1, 1, + 0)); + + if (ac == AC_GOLOMB_RICE) + av_bprintf(&shd->src, "#define GOLOMB\n"); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLF(1, uint context_count[%i]; ,MAX_QUANT_TABLES); + GLSLC(1, u8buf slice_state; ); + GLSLC(1, uint plane_state_size; ); + GLSLC(1, uint8_t codec_planes; ); + GLSLC(1, uint8_t key_frame; ); + GLSLC(1, uint8_t version; ); + GLSLC(1, uint8_t micro_version; ); + GLSLC(1, uint8_t padding[1]; ); + GLSLC(0, }; ); + ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkResetParameters), + VK_SHADER_STAGE_COMPUTE_BIT); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 1, 0)); + + define_shared_code(shd, 0 /* Bit depth irrelevant for the reset shader */); + if (ac == AC_GOLOMB_RICE) + GLSLD(ff_source_ffv1_vlc_comp); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .mem_quali = "readonly", + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 1, 0, 0)); + + GLSLD(ff_source_ffv1_reset_comp); + + RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_decode_shader(FFV1Context *f, FFVulkanContext *s, + FFVkExecPool *pool, FFVkSPIRVCompiler *spv, + FFVulkanShader *shd, + AVHWFramesContext *dec_frames_ctx, + AVHWFramesContext *out_frames_ctx, + int use32bit, int ac, int rgb) +{ + int err; + FFVulkanDescriptorSetBinding *desc_set; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + int use_cached_reader = ac != AC_GOLOMB_RICE && + s->driver_props.driverID == VK_DRIVER_ID_MESA_RADV; + + RET(ff_vk_shader_init(s, shd, "ffv1_dec", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2" }, 2, + use_cached_reader ? CONTEXT_SIZE : 1, 1, 1, + 0)); + + if (ac == AC_GOLOMB_RICE) + av_bprintf(&shd->src, "#define GOLOMB\n"); + + if (rgb) + av_bprintf(&shd->src, "#define RGB\n"); + + if (use_cached_reader) + av_bprintf(&shd->src, "#define CACHED_SYMBOL_READER 1\n"); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + add_push_data(shd); + + av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES); + av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS); + av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "rangecoder_static_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t zero_one_state[512];", + }, + { + .name = "quant_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]" + "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];", + }, + }; + + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 1, 0)); + + define_shared_code(shd, use32bit); + if (ac == AC_GOLOMB_RICE) + GLSLD(ff_source_ffv1_vlc_comp); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "slice_data_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .buf_content = "SliceContext slice_ctx", + .buf_elems = f->max_slice_count, + }, + { + .name = "dec", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(dec_frames_ctx->sw_format, + FF_VK_REP_NATIVE), + .elems = av_pix_fmt_count_planes(dec_frames_ctx->sw_format), + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + { + .name = "slice_status_buf", + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_quali = "writeonly", + .buf_content = "uint32_t slice_status", + .buf_elems = 2*f->max_slice_count, + }, + { + .name = "dst", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .dimensions = 2, + .mem_layout = ff_vk_shader_rep_fmt(out_frames_ctx->sw_format, + FF_VK_REP_NATIVE), + .mem_quali = "writeonly", + .elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format), + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 3 + rgb, 0, 0)); + + GLSLD(ff_source_ffv1_dec_comp); + + RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static int init_indirect(AVCodecContext *avctx, FFVulkanContext *s, + AVBufferRef **dst, enum AVPixelFormat sw_format) +{ + int err; + AVHWFramesContext *frames_ctx; + AVVulkanFramesContext *vk_frames; + FFV1Context *f = avctx->priv_data; + + *dst = av_hwframe_ctx_alloc(s->device_ref); + if (!(*dst)) + return AVERROR(ENOMEM); + + frames_ctx = (AVHWFramesContext *)((*dst)->data); + frames_ctx->format = AV_PIX_FMT_VULKAN; + frames_ctx->sw_format = sw_format; + frames_ctx->width = s->frames->width; + frames_ctx->height = f->num_v_slices*RGB_LINECACHE; + + vk_frames = frames_ctx->hwctx; + vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; + vk_frames->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + vk_frames->usage = VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + err = av_hwframe_ctx_init(*dst); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize frame pool with format %s: %s\n", + av_get_pix_fmt_name(sw_format), av_err2str(err)); + av_buffer_unref(dst); + return err; + } + + return 0; +} + +static void vk_decode_ffv1_uninit(FFVulkanDecodeShared *ctx) +{ + FFv1VulkanDecodeContext *fv = ctx->sd_ctx; + + ff_vk_shader_free(&ctx->s, &fv->setup); + + for (int i = 0; i < 2; i++) /* 16/32 bit */ + av_buffer_unref(&fv->intermediate_frames_ref[i]); + + for (int i = 0; i < 2; i++) /* AC/Golomb */ + ff_vk_shader_free(&ctx->s, &fv->reset[i]); + + for (int i = 0; i < 2; i++) /* 16/32 bit */ + for (int j = 0; j < 2; j++) /* AC/Golomb */ + for (int k = 0; k < 2; k++) /* Normal/RGB */ + ff_vk_shader_free(&ctx->s, &fv->decode[i][j][k]); + + ff_vk_free_buf(&ctx->s, &fv->quant_buf); + ff_vk_free_buf(&ctx->s, &fv->rangecoder_static_buf); + ff_vk_free_buf(&ctx->s, &fv->crc_tab_buf); + + av_buffer_pool_uninit(&fv->slice_state_pool); + av_buffer_pool_uninit(&fv->slice_offset_pool); + av_buffer_pool_uninit(&fv->slice_status_pool); + + av_freep(&fv); +} + +static int vk_decode_ffv1_init(AVCodecContext *avctx) +{ + int err; + FFV1Context *f = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = NULL; + FFv1VulkanDecodeContext *fv; + FFVkSPIRVCompiler *spv; + + if (f->version < 3 || + (f->version == 4 && f->micro_version > 3)) + return AVERROR(ENOTSUP); + + spv = ff_vk_spirv_init(); + if (!spv) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n"); + return AVERROR_EXTERNAL; + } + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + ctx = dec->shared_ctx; + + fv = ctx->sd_ctx = av_mallocz(sizeof(*fv)); + if (!fv) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->sd_ctx_free = &vk_decode_ffv1_uninit; + + /* Intermediate frame pool for RCT */ + for (int i = 0; i < 2; i++) { /* 16/32 bit */ + RET(init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref[i], + i ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16)); + } + + /* Setup shader */ + RET(init_setup_shader(f, &ctx->s, &ctx->exec_pool, spv, &fv->setup)); + + /* Reset shaders */ + for (int i = 0; i < 2; i++) { /* AC/Golomb */ + RET(init_reset_shader(f, &ctx->s, &ctx->exec_pool, + spv, &fv->reset[i], !i ? AC_RANGE_CUSTOM_TAB : 0)); + } + + /* Decode shaders */ + for (int i = 0; i < 2; i++) { /* 16/32 bit */ + for (int j = 0; j < 2; j++) { /* AC/Golomb */ + for (int k = 0; k < 2; k++) { /* Normal/RGB */ + AVHWFramesContext *dec_frames_ctx; + dec_frames_ctx = k ? (AVHWFramesContext *)fv->intermediate_frames_ref[i]->data : + (AVHWFramesContext *)avctx->hw_frames_ctx->data; + RET(init_decode_shader(f, &ctx->s, &ctx->exec_pool, + spv, &fv->decode[i][j][k], + dec_frames_ctx, + (AVHWFramesContext *)avctx->hw_frames_ctx->data, + i, + !j ? AC_RANGE_CUSTOM_TAB : AC_GOLOMB_RICE, + k)); + } + } + } + + /* Range coder data */ + RET(ff_ffv1_vk_init_state_transition_data(&ctx->s, + &fv->rangecoder_static_buf, + f)); + + /* Quantization table data */ + RET(ff_ffv1_vk_init_quant_table_data(&ctx->s, + &fv->quant_buf, + f)); + + /* CRC table buffer */ + RET(ff_ffv1_vk_init_crc_table_data(&ctx->s, + &fv->crc_tab_buf, + f)); + + /* Update setup global descriptors */ + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->setup, 0, 0, 0, + &fv->rangecoder_static_buf, + 0, fv->rangecoder_static_buf.size, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->setup, 0, 1, 0, + &fv->crc_tab_buf, + 0, fv->crc_tab_buf.size, + VK_FORMAT_UNDEFINED)); + + /* Update decode global descriptors */ + for (int i = 0; i < 2; i++) { /* 16/32 bit */ + for (int j = 0; j < 2; j++) { /* AC/Golomb */ + for (int k = 0; k < 2; k++) { /* Normal/RGB */ + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode[i][j][k], 0, 0, 0, + &fv->rangecoder_static_buf, + 0, fv->rangecoder_static_buf.size, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode[i][j][k], 0, 1, 0, + &fv->quant_buf, + 0, fv->quant_buf.size, + VK_FORMAT_UNDEFINED)); + } + } + } + +fail: + spv->uninit(&spv); + + return err; +} + +static void vk_ffv1_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + AVVulkanDeviceContext *hwctx = dev_ctx->hwctx; + + FFv1VulkanDecodePicture *fp = data; + FFVulkanDecodePicture *vp = &fp->vp; + FFVkBuffer *slice_status = (FFVkBuffer *)fp->slice_status_buf->data; + + ff_vk_decode_free_frame(dev_ctx, vp); + + /* Invalidate slice/output data if needed */ + if (!(slice_status->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + VkMappedMemoryRange invalidate_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = slice_status->mem, + .offset = 0, + .size = 2*fp->slice_num*sizeof(uint32_t), + }; + vp->invalidate_memory_ranges(hwctx->act_dev, + 1, &invalidate_data); + } + + for (int i = 0; i < fp->slice_num; i++) { + uint32_t crc_res = 0; + if (fp->crc_checked) + crc_res = AV_RN32(slice_status->mapped_mem + 2*i*sizeof(uint32_t) + 0); + uint32_t status = AV_RN32(slice_status->mapped_mem + 2*i*sizeof(uint32_t) + 4); + if (status || crc_res) + av_log(dev_ctx, AV_LOG_ERROR, "Slice %i status: 0x%x, CRC 0x%x\n", + i, status, crc_res); + } + + av_buffer_unref(&vp->slices_buf); + av_buffer_unref(&fp->slice_state); + av_buffer_unref(&fp->slice_offset_buf); + av_buffer_unref(&fp->slice_status_buf); +} + +const FFHWAccel ff_ffv1_vulkan_hwaccel = { + .p.name = "ffv1_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_FFV1, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_ffv1_start_frame, + .decode_slice = &vk_ffv1_decode_slice, + .end_frame = &vk_ffv1_end_frame, + .free_frame_priv = &vk_ffv1_free_frame_priv, + .frame_priv_data_size = sizeof(FFv1VulkanDecodePicture), + .init = &vk_decode_ffv1_init, + .update_thread_context = &ff_vk_update_thread_context, + .decode_params = &ff_vk_params_invalidate, + .flush = &ff_vk_decode_flush, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_glslang.c b/libavcodec/vulkan_glslang.c new file mode 100644 index 0000000000..9aa41567a3 --- /dev/null +++ b/libavcodec/vulkan_glslang.c @@ -0,0 +1,19 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/vulkan_glslang.c" diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c index 05ac884138..ebe305e7b5 100644 --- a/libavcodec/vulkan_h264.c +++ b/libavcodec/vulkan_h264.c @@ -24,6 +24,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc = { .codec_id = AV_CODEC_ID_H264, .decode_extension = FF_VK_EXT_VIDEO_DECODE_H264, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, @@ -97,7 +98,7 @@ static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ctx->common.layered_dpb ? dpb_slot_index : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -358,23 +359,18 @@ static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_h264_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { int err; int dpb_slot_index = 0; H264Context *h = avctx->priv_data; + H264Picture *pic = h->cur_pic_ptr; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; H264VulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; - if (!dec->session_params) { - err = vk_h264_create_params(avctx, &dec->session_params); - if (err < 0) - return err; - } - /* Fill in main slot */ dpb_slot_index = 0; for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) { @@ -470,7 +466,7 @@ static int vk_h264_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -505,20 +501,45 @@ static int vk_h264_decode_slice(AVCodecContext *avctx, static int vk_h264_end_frame(AVCodecContext *avctx) { const H264Context *h = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + H264Picture *pic = h->cur_pic_ptr; H264VulkanDecodePicture *hp = pic->hwaccel_picture_private; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodePicture *vp = &hp->vp; FFVulkanDecodePicture *rvp[H264_MAX_PICTURE_COUNT] = { 0 }; AVFrame *rav[H264_MAX_PICTURE_COUNT] = { 0 }; +#ifdef VK_KHR_video_maintenance2 + StdVideoH264ScalingLists vksps_scaling; + StdVideoH264HrdParameters vksps_vui_header; + StdVideoH264SequenceParameterSetVui vksps_vui; + StdVideoH264SequenceParameterSet vksps; + StdVideoH264ScalingLists vkpps_scaling; + StdVideoH264PictureParameterSet vkpps; + VkVideoDecodeH264InlineSessionParametersInfoKHR h264_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + set_sps(h->ps.sps, &vksps_scaling, + &vksps_vui_header, &vksps_vui, &vksps); + set_pps(h->ps.pps, h->ps.sps, &vkpps_scaling, &vkpps); + h264_params = (VkVideoDecodeH264InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSPS = &vksps, + .pStdPPS = &vkpps, + }; + hp->h264_pic_info.pNext = &h264_params; + } +#endif + if (!hp->h264_pic_info.sliceCount) return 0; if (!vp->slices_buf) return AVERROR(EINVAL); - if (!dec->session_params) { + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { int err = vk_h264_create_params(avctx, &dec->session_params); if (err < 0) return err; @@ -535,13 +556,13 @@ static int vk_h264_end_frame(AVCodecContext *avctx) rav[i] = hp->ref_src[i]->f; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", vp->slices_size, hp->h264_pic_info.sliceCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_h264_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_h264_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; H264VulkanDecodePicture *hp = data; @@ -567,5 +588,5 @@ const FFHWAccel ff_h264_vulkan_hwaccel = { .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c index 0b20005687..5e15c6b931 100644 --- a/libavcodec/vulkan_hevc.c +++ b/libavcodec/vulkan_hevc.c @@ -26,6 +26,7 @@ const FFVulkanDecodeDescriptor ff_vk_dec_hevc_desc = { .codec_id = AV_CODEC_ID_HEVC, .decode_extension = FF_VK_EXT_VIDEO_DECODE_H265, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR, .ext_props = { .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, @@ -163,7 +164,7 @@ static int vk_hevc_fill_pict(AVCodecContext *avctx, HEVCFrame **ref_src, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = ctx->common.layered_dpb ? pic_id : 0, - .imageViewBinding = vkpic->img_view_ref, + .imageViewBinding = vkpic->view.ref[0], }; *ref_slot = (VkVideoReferenceSlotInfoKHR) { @@ -708,26 +709,21 @@ static int vk_hevc_create_params(AVCodecContext *avctx, AVBufferRef **buf) } static int vk_hevc_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size) { int err; HEVCContext *h = avctx->priv_data; HEVCLayerContext *l = &h->layers[h->cur_layer]; + HEVCFrame *pic = h->cur_frame; - FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; const HEVCPPS *pps = h->pps; const HEVCSPS *sps = pps->sps; int nb_refs = 0; - if (!dec->session_params) { - err = vk_hevc_create_params(avctx, &dec->session_params); - if (err < 0) - return err; - } - hp->h265pic = (StdVideoDecodeH265PictureInfo) { .flags = (StdVideoDecodeH265PictureInfoFlags) { .IrapPicFlag = IS_IRAP(h), @@ -822,7 +818,7 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, - .imageViewBinding = vp->img_view_out, + .imageViewBinding = vp->view.out[0], }, }; @@ -850,6 +846,8 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) { const HEVCContext *h = avctx->priv_data; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + HEVCFrame *pic = h->cur_frame; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; @@ -857,13 +855,45 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) AVFrame *rav[HEVC_MAX_REFS] = { 0 }; int err; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; + +#ifdef VK_KHR_video_maintenance2 + HEVCHeaderPPS vkpps_p; + StdVideoH265PictureParameterSet vkpps; + HEVCHeaderSPS vksps_p; + StdVideoH265SequenceParameterSet vksps; + HEVCHeaderVPSSet vkvps_ps[HEVC_MAX_SUB_LAYERS]; + HEVCHeaderVPS vkvps_p; + StdVideoH265VideoParameterSet vkvps; + VkVideoDecodeH265InlineSessionParametersInfoKHR h265_params; + + if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2) { + set_pps(pps, sps, &vkpps_p.scaling, &vkpps, &vkpps_p.pal); + set_sps(sps, pps->sps_id, &vksps_p.scaling, &vksps_p.vui_header, + &vksps_p.vui, &vksps, vksps_p.nal_hdr, + vksps_p.vcl_hdr, &vksps_p.ptl, &vksps_p.dpbm, + &vksps_p.pal, vksps_p.str, &vksps_p.ltr); + + vkvps_p.sls = vkvps_ps; + set_vps(sps->vps, &vkvps, &vkvps_p.ptl, &vkvps_p.dpbm, + vkvps_p.hdr, vkvps_p.sls); + + h265_params = (VkVideoDecodeH265InlineSessionParametersInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_INLINE_SESSION_PARAMETERS_INFO_KHR, + .pStdSPS = &vksps, + .pStdPPS = &vkpps, + .pStdVPS = &vkvps, + }; + hp->h265_pic_info.pNext = &h265_params; + } +#endif + if (!hp->h265_pic_info.sliceSegmentCount) return 0; - if (!dec->session_params) { - const HEVCPPS *pps = h->pps; - const HEVCSPS *sps = pps->sps; - + if (!dec->session_params && + !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) { if (!pps) { unsigned int pps_id = h->sh.pps_id; if (pps_id < HEVC_MAX_PPS_COUNT && h->ps.pps_list[pps_id] != NULL) @@ -891,13 +921,13 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) rvp[i] = &rfhp->vp; } - av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", + av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", vp->slices_size, hp->h265_pic_info.sliceSegmentCount); return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } -static void vk_hevc_free_frame_priv(FFRefStructOpaque _hwctx, void *data) +static void vk_hevc_free_frame_priv(AVRefStructOpaque _hwctx, void *data) { AVHWDeviceContext *hwctx = _hwctx.nc; HEVCVulkanDecodePicture *hp = data; @@ -923,5 +953,5 @@ const FFHWAccel ff_hevc_vulkan_hwaccel = { .uninit = &ff_vk_decode_uninit, .frame_params = &ff_vk_frame_params, .priv_data_size = sizeof(FFVulkanDecodeContext), - .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vulkan_prores_raw.c b/libavcodec/vulkan_prores_raw.c new file mode 100644 index 0000000000..7a1f97a640 --- /dev/null +++ b/libavcodec/vulkan_prores_raw.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2025 Lynne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "vulkan_decode.h" +#include "hwaccel_internal.h" + +#include "prores_raw.h" +#include "libavutil/vulkan_spirv.h" +#include "libavutil/mem.h" + +extern const char *ff_source_common_comp; +extern const char *ff_source_prores_raw_comp; + +const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc = { + .codec_id = AV_CODEC_ID_PRORES_RAW, + .decode_extension = FF_VK_EXT_PUSH_DESCRIPTOR, + .queue_flags = VK_QUEUE_COMPUTE_BIT, +}; + +typedef struct ProResRAWVulkanDecodePicture { + FFVulkanDecodePicture vp; + + AVBufferRef *tile_data; + uint32_t nb_tiles; +} ProResRAWVulkanDecodePicture; + +typedef struct ProResRAWVulkanDecodeContext { + FFVulkanShader decode[2]; + + AVBufferPool *tile_data_pool; + + FFVkBuffer uniform_buf; +} ProResRAWVulkanDecodeContext; + +typedef struct DecodePushData { + VkDeviceAddress tile_data; + VkDeviceAddress pkt_data; + uint32_t frame_size[2]; + uint32_t tile_size[2]; + uint8_t qmat[64]; +} DecodePushData; + +typedef struct TileData { + int32_t pos[2]; + uint32_t offset; + uint32_t size; +} TileData; + +static int vk_prores_raw_start_frame(AVCodecContext *avctx, + const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx; + ProResRAWContext *prr = avctx->priv_data; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + /* Host map the input tile data if supported */ + if (ctx->s.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) + ff_vk_host_map_buffer(&ctx->s, &vp->slices_buf, buffer_ref->data, + buffer_ref, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + /* Allocate tile data */ + err = ff_vk_get_pooled_buffer(&ctx->s, &prv->tile_data_pool, + &pp->tile_data, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + NULL, prr->nb_tiles*sizeof(TileData), + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (err < 0) + return err; + + /* Prepare frame to be used */ + err = ff_vk_decode_prepare_frame_sdr(dec, prr->frame, vp, 1, + FF_VK_REP_FLOAT, 0); + if (err < 0) + return err; + + return 0; +} + +static int vk_prores_raw_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + ProResRAWContext *prr = avctx->priv_data; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + FFVkBuffer *tile_data_buf = (FFVkBuffer *)pp->tile_data->data; + TileData *td = (TileData *)tile_data_buf->mapped_mem; + FFVkBuffer *slices_buf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; + + td[pp->nb_tiles].pos[0] = prr->tiles[pp->nb_tiles].x; + td[pp->nb_tiles].pos[1] = prr->tiles[pp->nb_tiles].y; + td[pp->nb_tiles].size = size; + + if (vp->slices_buf && slices_buf->host_ref) { + td[pp->nb_tiles].offset = data - slices_buf->mapped_mem; + pp->nb_tiles++; + } else { + int err; + td[pp->nb_tiles].offset = vp->slices_size; + err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, + &pp->nb_tiles, NULL); + if (err < 0) + return err; + } + + return 0; +} + +static int vk_prores_raw_end_frame(AVCodecContext *avctx) +{ + int err; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + ProResRAWContext *prr = avctx->priv_data; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx; + + ProResRAWVulkanDecodePicture *pp = prr->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &pp->vp; + + FFVkBuffer *slices_buf = (FFVkBuffer *)vp->slices_buf->data; + FFVkBuffer *tile_data = (FFVkBuffer *)pp->tile_data->data; + + VkImageMemoryBarrier2 img_bar[8]; + int nb_img_bar = 0; + + FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool); + ff_vk_exec_start(&ctx->s, exec); + + /* Prepare deps */ + RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, prr->frame, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + + err = ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, + prr->frame); + if (err < 0) + return err; + + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &pp->tile_data, 1, 0)); + pp->tile_data = NULL; + RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0)); + vp->slices_buf = NULL; + + ff_vk_frame_barrier(&ctx->s, exec, prr->frame, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_ACCESS_2_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + nb_img_bar = 0; + + FFVulkanShader *decode_shader = &prv->decode[prr->version]; + ff_vk_shader_update_img_array(&ctx->s, exec, decode_shader, + prr->frame, vp->view.out, + 0, 0, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + + ff_vk_exec_bind_shader(&ctx->s, exec, decode_shader); + + /* Update push data */ + DecodePushData pd_decode = (DecodePushData) { + .tile_data = tile_data->address, + .pkt_data = slices_buf->address, + .frame_size[0] = avctx->width, + .frame_size[1] = avctx->height, + .tile_size[0] = prr->tw, + .tile_size[1] = prr->th, + }; + memcpy(pd_decode.qmat, prr->qmat, 64); + ff_vk_shader_update_push_const(&ctx->s, exec, decode_shader, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd_decode), &pd_decode); + + vk->CmdDispatch(exec->buf, prr->nb_tw, prr->nb_th, 1); + + err = ff_vk_exec_submit(&ctx->s, exec); + if (err < 0) + return err; + +fail: + return 0; +} + +static int init_decode_shader(ProResRAWContext *prr, FFVulkanContext *s, + FFVkExecPool *pool, FFVkSPIRVCompiler *spv, + FFVulkanShader *shd, int version) +{ + int err; + FFVulkanDescriptorSetBinding *desc_set; + int parallel_rows = 1; + + uint8_t *spv_data; + size_t spv_len; + void *spv_opaque = NULL; + + if (s->props.properties.limits.maxComputeWorkGroupInvocations < 512 || + s->props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) + parallel_rows = 0; + + RET(ff_vk_shader_init(s, shd, "prores_raw", + VK_SHADER_STAGE_COMPUTE_BIT, + (const char *[]) { "GL_EXT_buffer_reference", + "GL_EXT_buffer_reference2", + "GL_EXT_null_initializer" }, 3, + parallel_rows ? 8 : 1 /* 8x8 transforms, 8-point width */, + version == 0 ? 8 : 16 /* Horizontal blocks */, + 4 /* Components */, + 0)); + + if (parallel_rows) + GLSLC(0, #define PARALLEL_ROWS ); + + /* Common codec header */ + GLSLD(ff_source_common_comp); + + GLSLC(0, layout(buffer_reference, buffer_reference_align = 16) buffer TileData { ); + GLSLC(1, ivec2 pos; ); + GLSLC(1, uint offset; ); + GLSLC(1, uint size; ); + GLSLC(0, }; ); + GLSLC(0, ); + GLSLC(0, layout(push_constant, scalar) uniform pushConstants { ); + GLSLC(1, TileData tile_data; ); + GLSLC(1, u8buf pkt_data; ); + GLSLC(1, uvec2 frame_size; ); + GLSLC(1, uvec2 tile_size; ); + GLSLC(1, uint8_t qmat[64]; ); + GLSLC(0, }; ); + GLSLC(0, ); + ff_vk_shader_add_push_const(shd, 0, sizeof(DecodePushData), + VK_SHADER_STAGE_COMPUTE_BIT); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "dst", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .mem_layout = "r16", + .mem_quali = "writeonly", + .dimensions = 2, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 1, 0, 0)); + + desc_set = (FFVulkanDescriptorSetBinding []) { + { + .name = "dct_scale_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "float idct_8x8_scales[64];", + }, + { + .name = "scan_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t scan[64];", + }, + { + .name = "dc_cb_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "uint8_t dc_cb[13];", + }, + { + .name = "ac_cb_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t ac_cb[95];", + }, + { + .name = "rn_cb_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t rn_cb[28];", + }, + { + .name = "ln_cb_buf", + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .mem_layout = "scalar", + .buf_content = "int16_t ln_cb[15];", + }, + }; + RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 6, 1, 0)); + + GLSLD(ff_source_prores_raw_comp); + + RET(spv->compile_shader(s, spv, shd, &spv_data, &spv_len, "main", + &spv_opaque)); + RET(ff_vk_shader_link(s, shd, spv_data, spv_len, "main")); + + RET(ff_vk_shader_register_exec(s, pool, shd)); + +fail: + if (spv_opaque) + spv->free_shader(spv, &spv_opaque); + + return err; +} + +static void vk_decode_prores_raw_uninit(FFVulkanDecodeShared *ctx) +{ + ProResRAWVulkanDecodeContext *fv = ctx->sd_ctx; + + ff_vk_shader_free(&ctx->s, &fv->decode[0]); + ff_vk_shader_free(&ctx->s, &fv->decode[1]); + + ff_vk_free_buf(&ctx->s, &fv->uniform_buf); + + av_buffer_pool_uninit(&fv->tile_data_pool); + + av_freep(&fv); +} + +static int vk_decode_prores_raw_init(AVCodecContext *avctx) +{ + int err; + ProResRAWContext *prr = avctx->priv_data; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + + FFVkSPIRVCompiler *spv = ff_vk_spirv_init(); + if (!spv) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n"); + return AVERROR_EXTERNAL; + } + + err = ff_vk_decode_init(avctx); + if (err < 0) + return err; + + FFVulkanDecodeShared *ctx = dec->shared_ctx; + ProResRAWVulkanDecodeContext *prv = ctx->sd_ctx = av_mallocz(sizeof(*prv)); + if (!prv) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->sd_ctx_free = &vk_decode_prores_raw_uninit; + + /* Setup decode shader */ + RET(init_decode_shader(prr, &ctx->s, &ctx->exec_pool, spv, &prv->decode[0], 0)); + RET(init_decode_shader(prr, &ctx->s, &ctx->exec_pool, spv, &prv->decode[1], 1)); + + /* Size in bytes of each codebook table */ + size_t cb_size[5] = { + 13*sizeof(uint8_t), + 95*sizeof(int16_t), + 28*sizeof(int16_t), + 15*sizeof(int16_t), + }; + + /* Offset of each codebook table */ + size_t cb_offset[5]; + size_t ua = ctx->s.props.properties.limits.minUniformBufferOffsetAlignment; + cb_offset[0] = 64*sizeof(float) + 64*sizeof(uint8_t); + cb_offset[1] = cb_offset[0] + FFALIGN(cb_size[0], ua); + cb_offset[2] = cb_offset[1] + FFALIGN(cb_size[1], ua); + cb_offset[3] = cb_offset[2] + FFALIGN(cb_size[2], ua); + cb_offset[4] = cb_offset[3] + FFALIGN(cb_size[3], ua); + + RET(ff_vk_create_buf(&ctx->s, &prv->uniform_buf, + 64*sizeof(float) + 64*sizeof(uint8_t) + cb_offset[4] + 256, + NULL, NULL, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); + + uint8_t *uniform_buf; + RET(ff_vk_map_buffer(&ctx->s, &prv->uniform_buf, &uniform_buf, 0)); + + /* DCT scales */ + float *dct_scale_buf = (float *)uniform_buf; + double idct_8_scales[8] = { + cos(4.0*M_PI/16.0) / 2.0, + cos(1.0*M_PI/16.0) / 2.0, + cos(2.0*M_PI/16.0) / 2.0, + cos(3.0*M_PI/16.0) / 2.0, + cos(4.0*M_PI/16.0) / 2.0, + cos(5.0*M_PI/16.0) / 2.0, + cos(6.0*M_PI/16.0) / 2.0, + cos(7.0*M_PI/16.0) / 2.0, + }; + for (int i = 0; i < 64; i++) + dct_scale_buf[i] = (float)(idct_8_scales[i >> 3] * + idct_8_scales[i & 7]); + + /* Scan table */ + uint8_t *scan_buf = uniform_buf + 64*sizeof(float); + for (int i = 0; i < 64; i++) + scan_buf[prr->scan[i]] = i; + + /* Codebooks */ + memcpy(uniform_buf + cb_offset[0], ff_prores_raw_dc_cb, + sizeof(ff_prores_raw_dc_cb)); + memcpy(uniform_buf + cb_offset[1], ff_prores_raw_ac_cb, + sizeof(ff_prores_raw_ac_cb)); + memcpy(uniform_buf + cb_offset[2], ff_prores_raw_rn_cb, + sizeof(ff_prores_raw_rn_cb)); + memcpy(uniform_buf + cb_offset[3], ff_prores_raw_ln_cb, + sizeof(ff_prores_raw_ln_cb)); + + RET(ff_vk_unmap_buffer(&ctx->s, &prv->uniform_buf, 1)); + + /* Done; update descriptors */ + for (int i = 0; i < 2; i++) { + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &prv->decode[i], 1, 0, 0, + &prv->uniform_buf, + 0, 64*sizeof(float), + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &prv->decode[i], 1, 1, 0, + &prv->uniform_buf, + 64*sizeof(float), 64*sizeof(uint8_t), + VK_FORMAT_UNDEFINED)); + for (int j = 0; j < 4; j++) + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &prv->decode[i], 1, 2 + j, 0, + &prv->uniform_buf, + cb_offset[j], cb_size[j], + VK_FORMAT_UNDEFINED)); + } + +fail: + spv->uninit(&spv); + + return err; +} + +static void vk_prores_raw_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *dev_ctx = _hwctx.nc; + + ProResRAWVulkanDecodePicture *pp = data; + FFVulkanDecodePicture *vp = &pp->vp; + + ff_vk_decode_free_frame(dev_ctx, vp); +} + +const FFHWAccel ff_prores_raw_vulkan_hwaccel = { + .p.name = "prores_raw_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_PRORES_RAW, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_prores_raw_start_frame, + .decode_slice = &vk_prores_raw_decode_slice, + .end_frame = &vk_prores_raw_end_frame, + .free_frame_priv = &vk_prores_raw_free_frame_priv, + .frame_priv_data_size = sizeof(ProResRAWVulkanDecodePicture), + .init = &vk_decode_prores_raw_init, + .update_thread_context = &ff_vk_update_thread_context, + .decode_params = &ff_vk_params_invalidate, + .flush = &ff_vk_decode_flush, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE, +}; diff --git a/libavcodec/vulkan_shaderc.c b/libavcodec/vulkan_shaderc.c new file mode 100644 index 0000000000..9f60bf4dfd --- /dev/null +++ b/libavcodec/vulkan_shaderc.c @@ -0,0 +1,19 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/vulkan_shaderc.c" diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c index 3a04d60d68..819940460f 100644 --- a/libavcodec/vulkan_video.c +++ b/libavcodec/vulkan_video.c @@ -33,7 +33,6 @@ static const struct FFVkFormatMapEntry { { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GRAYF32, VK_IMAGE_ASPECT_COLOR_BIT }, /* RGB formats */ - { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGBA, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_R8G8B8_UNORM, AV_PIX_FMT_RGB24, VK_IMAGE_ASPECT_COLOR_BIT }, @@ -84,11 +83,16 @@ static const struct FFVkFormatMapEntry { { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P12, ASPECT_3PLANE }, { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P16, ASPECT_3PLANE }, - /* Single plane 422 at 8, 10 and 12 bits */ + /* Single plane 422 at 8, 10, 12 and 16 bits */ { VK_FORMAT_G8B8G8R8_422_UNORM, AV_PIX_FMT_YUYV422, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_B8G8R8G8_422_UNORM, AV_PIX_FMT_UYVY422, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, AV_PIX_FMT_Y210, VK_IMAGE_ASPECT_COLOR_BIT }, { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, AV_PIX_FMT_Y212, VK_IMAGE_ASPECT_COLOR_BIT }, + { VK_FORMAT_G16B16G16R16_422_UNORM, AV_PIX_FMT_Y216, VK_IMAGE_ASPECT_COLOR_BIT }, + + /* Single plane 444 at 10 and 12 bits */ + { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_XV30, VK_IMAGE_ASPECT_COLOR_BIT }, + { VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT }, }; static const int nb_vk_format_map = FF_ARRAY_ELEMS(vk_format_map); @@ -222,6 +226,37 @@ StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc) } } +StdVideoAV1Level ff_vk_av1_level_to_vk(int level) +{ + switch (level) { + case 20: return STD_VIDEO_AV1_LEVEL_2_0; + case 21: return STD_VIDEO_AV1_LEVEL_2_1; + case 22: return STD_VIDEO_AV1_LEVEL_2_2; + case 23: return STD_VIDEO_AV1_LEVEL_2_3; + case 30: return STD_VIDEO_AV1_LEVEL_3_0; + case 31: return STD_VIDEO_AV1_LEVEL_3_1; + case 32: return STD_VIDEO_AV1_LEVEL_3_2; + case 33: return STD_VIDEO_AV1_LEVEL_3_3; + case 40: return STD_VIDEO_AV1_LEVEL_4_0; + case 41: return STD_VIDEO_AV1_LEVEL_4_1; + case 42: return STD_VIDEO_AV1_LEVEL_4_2; + case 43: return STD_VIDEO_AV1_LEVEL_4_3; + case 50: return STD_VIDEO_AV1_LEVEL_5_0; + case 51: return STD_VIDEO_AV1_LEVEL_5_1; + case 52: return STD_VIDEO_AV1_LEVEL_5_2; + case 53: return STD_VIDEO_AV1_LEVEL_5_3; + case 60: return STD_VIDEO_AV1_LEVEL_6_0; + case 61: return STD_VIDEO_AV1_LEVEL_6_1; + case 62: return STD_VIDEO_AV1_LEVEL_6_2; + case 63: return STD_VIDEO_AV1_LEVEL_6_3; + case 70: return STD_VIDEO_AV1_LEVEL_7_0; + case 71: return STD_VIDEO_AV1_LEVEL_7_1; + case 72: return STD_VIDEO_AV1_LEVEL_7_2; + default: + case 73: return STD_VIDEO_AV1_LEVEL_7_3; + } +} + StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile) { switch (profile) { @@ -243,41 +278,16 @@ StdVideoH265ProfileIdc ff_vk_h265_profile_to_vk(int profile) } } -int ff_vk_h264_profile_to_av(StdVideoH264ProfileIdc profile) +StdVideoAV1Profile ff_vk_av1_profile_to_vk(int profile) { switch (profile) { - case STD_VIDEO_H264_PROFILE_IDC_BASELINE: return AV_PROFILE_H264_CONSTRAINED_BASELINE; - case STD_VIDEO_H264_PROFILE_IDC_MAIN: return AV_PROFILE_H264_MAIN; - case STD_VIDEO_H264_PROFILE_IDC_HIGH: return AV_PROFILE_H264_HIGH; - case STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE: return AV_PROFILE_H264_HIGH_444_PREDICTIVE; - default: return AV_PROFILE_UNKNOWN; + case AV_PROFILE_AV1_MAIN: return STD_VIDEO_AV1_PROFILE_MAIN; + case AV_PROFILE_AV1_HIGH: return STD_VIDEO_AV1_PROFILE_HIGH; + case AV_PROFILE_AV1_PROFESSIONAL: return STD_VIDEO_AV1_PROFILE_PROFESSIONAL; + default: return STD_VIDEO_AV1_PROFILE_INVALID; } } -int ff_vk_h265_profile_to_av(StdVideoH264ProfileIdc profile) -{ - switch (profile) { - case STD_VIDEO_H265_PROFILE_IDC_MAIN: return AV_PROFILE_HEVC_MAIN; - case STD_VIDEO_H265_PROFILE_IDC_MAIN_10: return AV_PROFILE_HEVC_MAIN_10; - case STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS: return AV_PROFILE_HEVC_REXT; - default: return AV_PROFILE_UNKNOWN; - } -} - -int ff_vk_video_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, - VkQueueFlagBits family, VkVideoCodecOperationFlagBitsKHR caps) -{ - for (int i = 0; i < s->hwctx->nb_qf; i++) { - if ((s->hwctx->qf[i].flags & family) && - (s->hwctx->qf[i].video_caps & caps)) { - qf->queue_family = s->hwctx->qf[i].idx; - qf->nb_queues = s->hwctx->qf[i].num; - return 0; - } - } - return AVERROR(ENOTSUP); -} - int ff_vk_create_view(FFVulkanContext *s, FFVkVideoCommon *common, VkImageView *view, VkImageAspectFlags *aspect, AVVkFrame *src, VkFormat vkf, int is_dpb) diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h index c205f7b88f..1b29f7adc7 100644 --- a/libavcodec/vulkan_video.h +++ b/libavcodec/vulkan_video.h @@ -20,7 +20,7 @@ #define AVCODEC_VULKAN_VIDEO_H #include "avcodec.h" -#include "vulkan.h" +#include "libavutil/vulkan.h" #include @@ -63,12 +63,6 @@ VkVideoChromaSubsamplingFlagBitsKHR ff_vk_subsampling_from_av_desc(const AVPixFm */ VkVideoComponentBitDepthFlagBitsKHR ff_vk_depth_from_av_depth(int depth); -/** - * Chooses a QF and loads it into a context. - */ -int ff_vk_video_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, - VkQueueFlagBits family, VkVideoCodecOperationFlagBitsKHR caps); - /** * Convert level from Vulkan to AV. */ @@ -77,14 +71,14 @@ int ff_vk_h265_level_to_av(StdVideoH265LevelIdc level); StdVideoH264LevelIdc ff_vk_h264_level_to_vk(int level_idc); StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc); +StdVideoAV1Level ff_vk_av1_level_to_vk(int level); /** * Convert profile from/to AV to Vulkan */ StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile); StdVideoH265ProfileIdc ff_vk_h265_profile_to_vk(int profile); -int ff_vk_h264_profile_to_av(StdVideoH264ProfileIdc profile); -int ff_vk_h265_profile_to_av(StdVideoH264ProfileIdc profile); +StdVideoAV1Profile ff_vk_av1_profile_to_vk(int profile); /** * Creates image views for video frames. diff --git a/libavcodec/vulkan_vp9.c b/libavcodec/vulkan_vp9.c new file mode 100644 index 0000000000..f8ce73dc90 --- /dev/null +++ b/libavcodec/vulkan_vp9.c @@ -0,0 +1,370 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "vp9shared.h" + +#include "vulkan_decode.h" + +const FFVulkanDecodeDescriptor ff_vk_dec_vp9_desc = { + .codec_id = AV_CODEC_ID_VP9, + .decode_extension = FF_VK_EXT_VIDEO_DECODE_VP9, + .queue_flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + .decode_op = VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_SPEC_VERSION, + }, +}; + +typedef struct VP9VulkanDecodePicture { + FFVulkanDecodePicture vp; + + /* TODO: investigate if this can be removed to make decoding completely + * independent. */ + FFVulkanDecodeContext *dec; + + /* Current picture */ + StdVideoVP9ColorConfig color_config; + StdVideoVP9Segmentation segmentation; + StdVideoVP9LoopFilter loop_filter; + StdVideoDecodeVP9PictureInfo std_pic_info; + VkVideoDecodeVP9PictureInfoKHR vp9_pic_info; + + const VP9Frame *ref_src[8]; + + uint8_t frame_id_set; + uint8_t frame_id; + uint8_t ref_frame_sign_bias_mask; +} VP9VulkanDecodePicture; + +static int vk_vp9_fill_pict(AVCodecContext *avctx, const VP9Frame **ref_src, + VkVideoReferenceSlotInfoKHR *ref_slot, /* Main structure */ + VkVideoPictureResourceInfoKHR *ref, /* Goes in ^ */ + const VP9Frame *pic, int is_current) +{ + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; + VP9VulkanDecodePicture *hp = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vkpic = &hp->vp; + + int err = ff_vk_decode_prepare_frame(dec, pic->tf.f, vkpic, is_current, + dec->dedicated_dpb); + if (err < 0) + return err; + + *ref = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .codedOffset = (VkOffset2D){ 0, 0 }, + .codedExtent = (VkExtent2D){ pic->tf.f->width, pic->tf.f->height }, + .baseArrayLayer = (dec->dedicated_dpb && ctx->common.layered_dpb) ? + hp->frame_id : 0, + .imageViewBinding = vkpic->view.ref[0], + }; + + *ref_slot = (VkVideoReferenceSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR, + .slotIndex = hp->frame_id, + .pPictureResource = ref, + }; + + if (ref_src) + *ref_src = pic; + + return 0; +} + +static enum StdVideoVP9InterpolationFilter remap_interp(uint8_t is_filter_switchable, + uint8_t raw_interpolation_filter_type) +{ + static const enum StdVideoVP9InterpolationFilter remap[] = { + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SHARP, + STD_VIDEO_VP9_INTERPOLATION_FILTER_BILINEAR, + }; + if (is_filter_switchable) + return STD_VIDEO_VP9_INTERPOLATION_FILTER_SWITCHABLE; + return remap[raw_interpolation_filter_type]; +} + +static int vk_vp9_start_frame(AVCodecContext *avctx, + av_unused const AVBufferRef *buffer_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + int err; + int ref_count = 0; + const VP9SharedContext *s = avctx->priv_data; + uint32_t frame_id_alloc_mask = 0; + + const VP9Frame *pic = &s->frames[CUR_FRAME]; + FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + uint8_t profile = (pic->frame_header->profile_high_bit << 1) | pic->frame_header->profile_low_bit; + + VP9VulkanDecodePicture *ap = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + + /* Use the current frame_ids in ref_frames[] to decide occupied frame_ids */ + for (int i = 0; i < STD_VIDEO_VP9_NUM_REF_FRAMES; i++) { + const VP9VulkanDecodePicture* rp = s->ref_frames[i].hwaccel_picture_private; + if (rp) + frame_id_alloc_mask |= 1 << rp->frame_id; + } + + if (!ap->frame_id_set) { + unsigned slot_idx = 0; + for (unsigned i = 0; i < 32; i++) { + if (!(frame_id_alloc_mask & (1 << i))) { + slot_idx = i; + break; + } + } + ap->frame_id = slot_idx; + ap->frame_id_set = 1; + frame_id_alloc_mask |= (1 << slot_idx); + } + + for (int i = 0; i < STD_VIDEO_VP9_REFS_PER_FRAME; i++) { + const int idx = pic->frame_header->ref_frame_idx[i]; + const VP9Frame *ref_frame = &s->ref_frames[idx]; + VP9VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; + int found = 0; + + if (!ref_frame->tf.f) + continue; + + for (int j = 0; j < ref_count; j++) { + if (vp->ref_slots[j].slotIndex == hp->frame_id) { + found = 1; + break; + } + } + if (found) + continue; + + err = vk_vp9_fill_pict(avctx, &ap->ref_src[ref_count], + &vp->ref_slots[ref_count], &vp->refs[ref_count], + ref_frame, 0); + if (err < 0) + return err; + + ref_count++; + } + + err = vk_vp9_fill_pict(avctx, NULL, &vp->ref_slot, &vp->ref, + pic, 1); + if (err < 0) + return err; + + ap->loop_filter = (StdVideoVP9LoopFilter) { + .flags = (StdVideoVP9LoopFilterFlags) { + .loop_filter_delta_enabled = pic->frame_header->loop_filter_delta_enabled, + .loop_filter_delta_update = pic->frame_header->loop_filter_delta_update, + }, + .loop_filter_level = pic->frame_header->loop_filter_level, + .loop_filter_sharpness = pic->frame_header->loop_filter_sharpness, + .update_ref_delta = 0x0, + .update_mode_delta = 0x0, + }; + + for (int i = 0; i < 2; i++) + ap->loop_filter.update_mode_delta |= pic->frame_header->update_mode_delta[i]; + + for (int i = 0; i < STD_VIDEO_VP9_MAX_REF_FRAMES; i++) { + ap->loop_filter.loop_filter_ref_deltas[i] = pic->frame_header->loop_filter_ref_deltas[i]; + ap->loop_filter.update_ref_delta |= pic->frame_header->update_ref_delta[i]; + } + for (int i = 0; i < STD_VIDEO_VP9_LOOP_FILTER_ADJUSTMENTS; i++) + ap->loop_filter.loop_filter_mode_deltas[i] = pic->frame_header->loop_filter_mode_deltas[i]; + + ap->segmentation = (StdVideoVP9Segmentation) { + .flags = (StdVideoVP9SegmentationFlags) { + .segmentation_update_map = pic->frame_header->segmentation_update_map, + .segmentation_temporal_update = pic->frame_header->segmentation_temporal_update, + .segmentation_update_data = pic->frame_header->segmentation_update_data, + .segmentation_abs_or_delta_update = pic->frame_header->segmentation_abs_or_delta_update, + }, + }; + + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTATION_TREE_PROBS; i++) + ap->segmentation.segmentation_tree_probs[i] = pic->frame_header->segmentation_tree_probs[i]; + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTATION_PRED_PROB; i++) + ap->segmentation.segmentation_pred_prob[i] = pic->frame_header->segmentation_pred_prob[i]; + for (int i = 0; i < STD_VIDEO_VP9_MAX_SEGMENTS; i++) { + ap->segmentation.FeatureEnabled[i] = 0x0; + for (int j = 0; j < STD_VIDEO_VP9_SEG_LVL_MAX; j++) { + ap->segmentation.FeatureEnabled[i] |= pic->frame_header->feature_enabled[i][j] << j; + ap->segmentation.FeatureData[i][j] = pic->frame_header->feature_sign[i][j] ? + -pic->frame_header->feature_value[i][j] : + +pic->frame_header->feature_value[i][j]; + } + } + + ap->color_config = (StdVideoVP9ColorConfig) { + .flags = (StdVideoVP9ColorConfigFlags) { + .color_range = pic->frame_header->color_range, + }, + .BitDepth = profile < 2 ? 8 : + pic->frame_header->ten_or_twelve_bit ? 12 : 10, + .subsampling_x = pic->frame_header->subsampling_x, + .subsampling_y = pic->frame_header->subsampling_y, + .color_space = pic->frame_header->color_space, + }; + + ap->std_pic_info = (StdVideoDecodeVP9PictureInfo) { + .flags = (StdVideoDecodeVP9PictureInfoFlags) { + .error_resilient_mode = pic->frame_header->error_resilient_mode, + .intra_only = pic->frame_header->intra_only, + .allow_high_precision_mv = pic->frame_header->allow_high_precision_mv, + .refresh_frame_context = pic->frame_header->refresh_frame_context, + .frame_parallel_decoding_mode = pic->frame_header->frame_parallel_decoding_mode, + .segmentation_enabled = pic->frame_header->segmentation_enabled, + .show_frame = pic->frame_header->segmentation_enabled, + .UsePrevFrameMvs = s->h.use_last_frame_mvs, + }, + .profile = profile, + .frame_type = pic->frame_header->frame_type, + .frame_context_idx = pic->frame_header->frame_context_idx, + .reset_frame_context = pic->frame_header->reset_frame_context, + .refresh_frame_flags = pic->frame_header->refresh_frame_flags, + .ref_frame_sign_bias_mask = 0x0, + .interpolation_filter = remap_interp(pic->frame_header->is_filter_switchable, + pic->frame_header->raw_interpolation_filter_type), + .base_q_idx = pic->frame_header->base_q_idx, + .delta_q_y_dc = pic->frame_header->delta_q_y_dc, + .delta_q_uv_dc = pic->frame_header->delta_q_uv_dc, + .delta_q_uv_ac = pic->frame_header->delta_q_uv_ac, + .tile_cols_log2 = pic->frame_header->tile_cols_log2, + .tile_rows_log2 = pic->frame_header->tile_rows_log2, + /* Reserved */ + .pColorConfig = &ap->color_config, + .pLoopFilter = &ap->loop_filter, + .pSegmentation = &ap->segmentation, + }; + + for (int i = VP9_LAST_FRAME; i <= VP9_ALTREF_FRAME; i++) + ap->std_pic_info.ref_frame_sign_bias_mask |= pic->frame_header->ref_frame_sign_bias[i] << i; + + ap->vp9_pic_info = (VkVideoDecodeVP9PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PICTURE_INFO_KHR, + .pStdPictureInfo = &ap->std_pic_info, + .uncompressedHeaderOffset = 0, + .compressedHeaderOffset = s->h.uncompressed_header_size, + .tilesOffset = s->h.uncompressed_header_size + + s->h.compressed_header_size, + }; + + for (int i = 0; i < STD_VIDEO_VP9_REFS_PER_FRAME; i++) { + const int idx = pic->frame_header->ref_frame_idx[i]; + const VP9Frame *ref_frame = &s->ref_frames[idx]; + VP9VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; + + if (!ref_frame->tf.f) + ap->vp9_pic_info.referenceNameSlotIndices[i] = -1; + else + ap->vp9_pic_info.referenceNameSlotIndices[i] = hp->frame_id; + } + + vp->decode_info = (VkVideoDecodeInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR, + .pNext = &ap->vp9_pic_info, + .flags = 0x0, + .pSetupReferenceSlot = &vp->ref_slot, + .referenceSlotCount = ref_count, + .pReferenceSlots = vp->ref_slots, + .dstPictureResource = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .codedOffset = (VkOffset2D){ 0, 0 }, + .codedExtent = (VkExtent2D){ pic->tf.f->width, pic->tf.f->height }, + .baseArrayLayer = 0, + .imageViewBinding = vp->view.out[0], + }, + }; + + ap->dec = dec; + + return 0; +} + +static int vk_vp9_decode_slice(AVCodecContext *avctx, + const uint8_t *data, + uint32_t size) +{ + int err; + const VP9SharedContext *s = avctx->priv_data; + VP9VulkanDecodePicture *ap = s->frames[CUR_FRAME].hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + + err = ff_vk_decode_add_slice(avctx, vp, data, size, 0, NULL, NULL); + if (err < 0) + return err; + + return 0; +} + +static int vk_vp9_end_frame(AVCodecContext *avctx) +{ + const VP9SharedContext *s = avctx->priv_data; + + const VP9Frame *pic = &s->frames[CUR_FRAME]; + VP9VulkanDecodePicture *ap = pic->hwaccel_picture_private; + FFVulkanDecodePicture *vp = &ap->vp; + FFVulkanDecodePicture *rvp[STD_VIDEO_VP9_REFS_PER_FRAME] = { 0 }; + AVFrame *rav[STD_VIDEO_VP9_REFS_PER_FRAME] = { 0 }; + + for (int i = 0; i < vp->decode_info.referenceSlotCount; i++) { + const VP9Frame *rp = ap->ref_src[i]; + VP9VulkanDecodePicture *rhp = rp->hwaccel_picture_private; + + rvp[i] = &rhp->vp; + rav[i] = ap->ref_src[i]->tf.f; + } + + av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes\n", + vp->slices_size); + + return ff_vk_decode_frame(avctx, pic->tf.f, vp, rav, rvp); +} + +static void vk_vp9_free_frame_priv(AVRefStructOpaque _hwctx, void *data) +{ + AVHWDeviceContext *hwctx = _hwctx.nc; + VP9VulkanDecodePicture *ap = data; + + /* Free frame resources, this also destroys the session parameters. */ + ff_vk_decode_free_frame(hwctx, &ap->vp); +} + +const FFHWAccel ff_vp9_vulkan_hwaccel = { + .p.name = "vp9_vulkan", + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VP9, + .p.pix_fmt = AV_PIX_FMT_VULKAN, + .start_frame = &vk_vp9_start_frame, + .decode_slice = &vk_vp9_decode_slice, + .end_frame = &vk_vp9_end_frame, + .free_frame_priv = &vk_vp9_free_frame_priv, + .frame_priv_data_size = sizeof(VP9VulkanDecodePicture), + .init = &ff_vk_decode_init, + .update_thread_context = &ff_vk_update_thread_context, + .flush = &ff_vk_decode_flush, + .uninit = &ff_vk_decode_uninit, + .frame_params = &ff_vk_frame_params, + .priv_data_size = sizeof(FFVulkanDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vvc.h b/libavcodec/vvc.h index 92639779c1..5490ddb4c8 100644 --- a/libavcodec/vvc.h +++ b/libavcodec/vvc.h @@ -154,6 +154,9 @@ enum { // {sps, ph}_num_{ver, hor}_virtual_boundaries should in [0, 3] VVC_MAX_VBS = 3, + + // 8.4.5.3 Decoding process for palette mode - maxNumPalettePredictorSize + VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE = 63 }; #endif /* AVCODEC_VVC_H */ diff --git a/libavcodec/vvc/Makefile b/libavcodec/vvc/Makefile index 6a28d32bc2..10125ffc2d 100644 --- a/libavcodec/vvc/Makefile +++ b/libavcodec/vvc/Makefile @@ -14,4 +14,5 @@ OBJS-$(CONFIG_VVC_DECODER) += vvc/dec.o \ vvc/mvs.o \ vvc/ps.o \ vvc/refs.o \ + vvc/sei.o \ vvc/thread.o \ diff --git a/libavcodec/vvc/cabac.c b/libavcodec/vvc/cabac.c index 0d45eec751..c2dbd46709 100644 --- a/libavcodec/vvc/cabac.c +++ b/libavcodec/vvc/cabac.c @@ -928,6 +928,32 @@ static int truncated_binary_decode(VVCLocalContext *lc, const int c_max) return v; } +// 9.3.3.5 k-th order Exp - Golomb binarization process +static int kth_order_egk_decode(CABACContext *c, int k, const int max) +{ + int bit = 1; + int value = 0; + int symbol = 0; + + while (bit) { + bit = get_cabac_bypass(c); + if (max - value < (bit << k)) + return AVERROR_INVALIDDATA; + value += bit << k++; + } + + if (--k) { + for (int i = 0; i < k; i++) + symbol = (symbol << 1) | get_cabac_bypass(c); + value += symbol; + } + + if (value > max) + return AVERROR_INVALIDDATA; + + return value; +} + // 9.3.3.6 Limited k-th order Exp-Golomb binarization process static int limited_kth_order_egk_decode(CABACContext *c, const int k, const int max_pre_ext_len, const int trunc_suffix_len) { @@ -947,6 +973,17 @@ static int limited_kth_order_egk_decode(CABACContext *c, const int k, const int return val; } +// 9.3.3.7 Fixed-length binarization process +static int fixed_length_decode(CABACContext* c, const int len) +{ + int value = 0; + + for (int i = 0; i < len; i++) + value = (value << 1) | get_cabac_bypass(c); + + return value; +} + static av_always_inline void get_left_top(const VVCLocalContext *lc, uint8_t *left, uint8_t *top, const int x0, const int y0, const uint8_t *left_ctx, const uint8_t *top_ctx) @@ -990,11 +1027,7 @@ int ff_vvc_sao_type_idx_decode(VVCLocalContext *lc) int ff_vvc_sao_band_position_decode(VVCLocalContext *lc) { - int value = get_cabac_bypass(&lc->ep->cc); - - for (int i = 0; i < 4; i++) - value = (value << 1) | get_cabac_bypass(&lc->ep->cc); - return value; + return fixed_length_decode(&lc->ep->cc, 5); } int ff_vvc_sao_offset_abs_decode(VVCLocalContext *lc) @@ -1014,9 +1047,7 @@ int ff_vvc_sao_offset_sign_decode(VVCLocalContext *lc) int ff_vvc_sao_eo_class_decode(VVCLocalContext *lc) { - int ret = get_cabac_bypass(&lc->ep->cc) << 1; - ret |= get_cabac_bypass(&lc->ep->cc); - return ret; + return (get_cabac_bypass(&lc->ep->cc) << 1) | get_cabac_bypass(&lc->ep->cc); } int ff_vvc_alf_ctb_flag(VVCLocalContext *lc, const int rx, const int ry, const int c_idx) @@ -1257,11 +1288,19 @@ int ff_vvc_pred_mode_ibc_flag(VVCLocalContext *lc, const int is_chroma) return GET_CABAC(PRED_MODE_IBC_FLAG + inc); } +static av_always_inline +uint8_t get_mip_inc(VVCLocalContext *lc, const uint8_t *ctx) +{ + uint8_t left = 0, top = 0; + get_left_top(lc, &left, &top, lc->cu->x0, lc->cu->y0, ctx, ctx); + return (left & 1) + (top & 1); +} + int ff_vvc_intra_mip_flag(VVCLocalContext *lc, const uint8_t *intra_mip_flag) { const int w = lc->cu->cb_width; const int h = lc->cu->cb_height; - const int inc = (w > h * 2 || h > w * 2) ? 3 : get_inc(lc, intra_mip_flag); + const int inc = (w > h * 2 || h > w * 2) ? 3 : get_mip_inc(lc, intra_mip_flag); return GET_CABAC(INTRA_MIP_FLAG + inc); } @@ -1343,6 +1382,58 @@ int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc) return (get_cabac_bypass(&lc->ep->cc) << 1) | get_cabac_bypass(&lc->ep->cc); } +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 0, max); +} + +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 0, max); +} + +int ff_vvc_new_palette_entries(VVCLocalContext *lc, const int bit_depth) +{ + return fixed_length_decode(&lc->ep->cc, bit_depth); +} + +bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc) +{ + return get_cabac_bypass(&lc->ep->cc); +} + +bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc) +{ + return GET_CABAC(PALETTE_TRANSPOSE_FLAG); +} + +bool ff_vvc_run_copy_flag(VVCLocalContext *lc, const int prev_run_type, const int prev_run_position, const int cur_pos) +{ + uint8_t run_left_lut[] = { 0, 1, 2, 3, 4 }; + uint8_t run_top_lut[] = { 5, 6, 6, 7, 7 }; + + int bin_dist = cur_pos - prev_run_position - 1; + uint8_t *run_lut = prev_run_type == 1 ? run_top_lut : run_left_lut; + uint8_t ctx_inc = bin_dist <= 4 ? run_lut[bin_dist] : run_lut[4]; + + return GET_CABAC(RUN_COPY_FLAG + ctx_inc); +} + +bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc) +{ + return GET_CABAC(COPY_ABOVE_PALETTE_INDICES_FLAG); +} + +int ff_vvc_palette_idx_idc(VVCLocalContext *lc, const int max_palette_index, const bool adjust) +{ + return truncated_binary_decode(lc, max_palette_index - adjust); +} + +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max) +{ + return kth_order_egk_decode(&lc->ep->cc, 5, max); +} + int ff_vvc_general_merge_flag(VVCLocalContext *lc) { return GET_CABAC(GENERAL_MERGE_FLAG); @@ -1450,12 +1541,7 @@ int ff_vvc_merge_idx(VVCLocalContext *lc) int ff_vvc_merge_gpm_partition_idx(VVCLocalContext *lc) { - int i = 0; - - for (int j = 0; j < 6; j++) - i = (i << 1) | get_cabac_bypass(&lc->ep->cc); - - return i; + return fixed_length_decode(&lc->ep->cc, 6); } int ff_vvc_merge_gpm_idx(VVCLocalContext *lc, const int idx) @@ -1622,6 +1708,11 @@ int ff_vvc_tu_y_coded_flag(VVCLocalContext *lc) return lc->parse.prev_tu_cbf_y; } +int ff_vvc_cu_act_enabled_flag(VVCLocalContext *lc) +{ + return GET_CABAC(CU_ACT_ENABLED_FLAG); +} + int ff_vvc_cu_qp_delta_abs(VVCLocalContext *lc) { int v, i, k; diff --git a/libavcodec/vvc/cabac.h b/libavcodec/vvc/cabac.h index e9bc98e23a..6a0e713d19 100644 --- a/libavcodec/vvc/cabac.h +++ b/libavcodec/vvc/cabac.h @@ -81,6 +81,15 @@ int ff_vvc_intra_luma_mpm_remainder(VVCLocalContext *lc); int ff_vvc_cclm_mode_flag(VVCLocalContext *lc); int ff_vvc_cclm_mode_idx(VVCLocalContext *lc); int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc); +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max); +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int max); +int ff_vvc_new_palette_entries(VVCLocalContext *lc, int bit_dpeth); +bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc); +bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc); +bool ff_vvc_run_copy_flag(VVCLocalContext *lc, int prev_run_type, int prev_run_position, int cur_pos); +bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc); +int ff_vvc_palette_idx_idc(VVCLocalContext *lc, int max_palette_index, bool adjust); +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max); //inter int ff_vvc_general_merge_flag(VVCLocalContext *lc); @@ -111,6 +120,7 @@ int ff_vvc_bcw_idx(VVCLocalContext *lc, int no_backward_pred_flag); int ff_vvc_tu_cb_coded_flag(VVCLocalContext *lc); int ff_vvc_tu_cr_coded_flag(VVCLocalContext *lc, int tu_cb_coded_flag); int ff_vvc_tu_y_coded_flag(VVCLocalContext *lc); +int ff_vvc_cu_act_enabled_flag(VVCLocalContext *lc); int ff_vvc_cu_chroma_qp_offset_flag(VVCLocalContext *lc); int ff_vvc_cu_chroma_qp_offset_idx(VVCLocalContext *lc); int ff_vvc_tu_joint_cbcr_residual_flag(VVCLocalContext *lc, int tu_cb_coded_flag, int tu_cr_coded_flag); diff --git a/libavcodec/vvc/ctu.c b/libavcodec/vvc/ctu.c index b33ad576cf..18cbe0fe0f 100644 --- a/libavcodec/vvc/ctu.c +++ b/libavcodec/vvc/ctu.c @@ -20,11 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/refstruct.h" +#include "libavutil/error.h" +#include "libavutil/refstruct.h" #include "cabac.h" #include "ctu.h" #include "inter.h" +#include "intra.h" #include "mvs.h" #define PROF_TEMP_SIZE (PROF_BLOCK_SIZE) * sizeof(int16_t) @@ -38,7 +40,7 @@ typedef enum VVCModeType { MODE_TYPE_INTRA, } VVCModeType; -static void set_tb_pos(const VVCFrameContext *fc, const TransformBlock *tb) +static void set_tb_size(const VVCFrameContext *fc, const TransformBlock *tb) { const int x_tb = tb->x0 >> MIN_TU_LOG2; const int y_tb = tb->y0 >> MIN_TU_LOG2; @@ -50,10 +52,6 @@ static void set_tb_pos(const VVCFrameContext *fc, const TransformBlock *tb) for (int y = y_tb; y < end; y++) { const int off = y * fc->ps.pps->min_tu_width + x_tb; - for (int i = 0; i < width; i++) { - fc->tab.tb_pos_x0[is_chroma][off + i] = tb->x0; - fc->tab.tb_pos_y0[is_chroma][off + i] = tb->y0; - } memset(fc->tab.tb_width [is_chroma] + off, tb->tb_width, width); memset(fc->tab.tb_height[is_chroma] + off, tb->tb_height, width); } @@ -213,7 +211,7 @@ static void set_qp_c(VVCLocalContext *lc) static TransformUnit* alloc_tu(VVCFrameContext *fc, CodingUnit *cu) { - TransformUnit *tu = ff_refstruct_pool_get(fc->tu_pool); + TransformUnit *tu = av_refstruct_pool_get(fc->tu_pool); if (!tu) return NULL; @@ -241,6 +239,7 @@ static TransformUnit* add_tu(VVCFrameContext *fc, CodingUnit *cu, const int x0, tu->height = tu_height; tu->joint_cbcr_residual_flag = 0; memset(tu->coded_flag, 0, sizeof(tu->coded_flag)); + tu->avail[LUMA] = tu->avail[CHROMA] = 0; tu->nb_tbs = 0; return tu; @@ -267,6 +266,7 @@ static TransformBlock* add_tb(TransformUnit *tu, VVCLocalContext *lc, tb->ts = 0; tb->coeffs = lc->coeffs; lc->coeffs += tb_width * tb_height; + tu->avail[!!c_idx] = true; return tb; } @@ -393,9 +393,11 @@ static int hls_transform_unit(VVCLocalContext *lc, int x0, int y0,int tu_width, if (ret < 0) return ret; set_tb_tab(fc->tab.tu_coded_flag[tb->c_idx], tu->coded_flag[tb->c_idx], fc, tb); + } else if (cu->act_enabled_flag) { + memset(tb->coeffs, 0, tb->tb_width * tb->tb_height * sizeof(*tb->coeffs)); } if (tb->c_idx != CR) - set_tb_pos(fc, tb); + set_tb_size(fc, tb); if (tb->c_idx == CB) set_tb_tab(fc->tab.tu_joint_cbcr_residual_flag, tu->joint_cbcr_residual_flag, fc, tb); } @@ -503,16 +505,15 @@ static int skipped_transform_tree(VVCLocalContext *lc, int x0, int y0,int tu_wid SKIPPED_TRANSFORM_TREE(x0, y0 + trafo_height); } else { TransformUnit *tu = add_tu(fc, lc->cu, x0, y0, tu_width, tu_height); - const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; - const int c_start = cu->tree_type == DUAL_TREE_CHROMA ? CB : LUMA; - const int c_end = has_chroma ? VVC_MAX_SAMPLE_ARRAYS : CB; + int start, end; if (!tu) return AVERROR_INVALIDDATA; - for (int i = c_start; i < c_end; i++) { + ff_vvc_channel_range(&start, &end, cu->tree_type, sps->r->sps_chroma_format_idc); + for (int i = start; i < end; i++) { TransformBlock *tb = add_tb(tu, lc, x0, y0, tu_width >> sps->hshift[i], tu_height >> sps->vshift[i], i); if (i != CR) - set_tb_pos(fc, tb); + set_tb_size(fc, tb); } } @@ -897,7 +898,7 @@ static void derive_chroma_intra_pred_mode(VVCLocalContext *lc, enum IntraPredMode luma_intra_pred_mode = SAMPLE_CTB(fc->tab.ipm, x_cb, y_cb); if (cu->tree_type == SINGLE_TREE && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444 && - intra_chroma_pred_mode == 4 && intra_mip_flag) { + (intra_chroma_pred_mode == 4 || cu->act_enabled_flag) && intra_mip_flag) { cu->mip_chroma_direct_flag = 1; cu->intra_pred_mode_c = luma_intra_pred_mode; return; @@ -948,6 +949,12 @@ static void derive_chroma_intra_pred_mode(VVCLocalContext *lc, } } +static av_always_inline uint8_t pack_mip_info(int intra_mip_flag, + int intra_mip_transposed_flag, int intra_mip_mode) +{ + return (intra_mip_mode << 2) | (intra_mip_transposed_flag << 1) | intra_mip_flag; +} + static void intra_luma_pred_modes(VVCLocalContext *lc) { VVCFrameContext *fc = lc->fc; @@ -976,9 +983,9 @@ static void intra_luma_pred_modes(VVCLocalContext *lc) int x = y_cb * pps->min_cb_width + x_cb; for (int y = 0; y < (cb_height>>log2_min_cb_size); y++) { int width = cb_width>>log2_min_cb_size; - memset(&fc->tab.imf[x], cu->intra_mip_flag, width); - fc->tab.imtf[x] = intra_mip_transposed_flag; - fc->tab.imm[x] = intra_mip_mode; + const uint8_t mip_info = pack_mip_info(cu->intra_mip_flag, + intra_mip_transposed_flag, intra_mip_mode); + memset(&fc->tab.imf[x], mip_info, width); x += pps->min_cb_width; } cu->intra_pred_mode_y = intra_mip_mode; @@ -1003,34 +1010,38 @@ static void intra_luma_pred_modes(VVCLocalContext *lc) static void intra_chroma_pred_modes(VVCLocalContext *lc) { - const VVCSPS *sps = lc->fc->ps.sps; - CodingUnit *cu = lc->cu; - const int hs = sps->hshift[CHROMA]; - const int vs = sps->vshift[CHROMA]; + const VVCSPS *sps = lc->fc->ps.sps; + CodingUnit *cu = lc->cu; + const int hs = sps->hshift[CHROMA]; + const int vs = sps->vshift[CHROMA]; + int cclm_mode_flag = 0; + int cclm_mode_idx = 0; + int intra_chroma_pred_mode = 0; - cu->mip_chroma_direct_flag = 0; - if (sps->r->sps_bdpcm_enabled_flag && - (cu->cb_width >> hs) <= sps->max_ts_size && - (cu->cb_height >> vs) <= sps->max_ts_size) { - cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = ff_vvc_intra_bdpcm_chroma_flag(lc); + if (!cu->act_enabled_flag) { + cu->mip_chroma_direct_flag = 0; + if (sps->r->sps_bdpcm_enabled_flag && + (cu->cb_width >> hs) <= sps->max_ts_size && + (cu->cb_height >> vs) <= sps->max_ts_size) { + cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = ff_vvc_intra_bdpcm_chroma_flag(lc); + } + if (cu->bdpcm_flag[CHROMA]) { + cu->intra_pred_mode_c = ff_vvc_intra_bdpcm_chroma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; + } else { + const int cclm_enabled = get_cclm_enabled(lc, cu->x0, cu->y0); + + if (cclm_enabled) + cclm_mode_flag = ff_vvc_cclm_mode_flag(lc); + + if (cclm_mode_flag) + cclm_mode_idx = ff_vvc_cclm_mode_idx(lc); + else + intra_chroma_pred_mode = ff_vvc_intra_chroma_pred_mode(lc); + } } - if (cu->bdpcm_flag[CHROMA]) { - cu->intra_pred_mode_c = ff_vvc_intra_bdpcm_chroma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; - } else { - const int cclm_enabled = get_cclm_enabled(lc, cu->x0, cu->y0); - int cclm_mode_flag = 0; - int cclm_mode_idx = 0; - int intra_chroma_pred_mode = 0; - if (cclm_enabled) - cclm_mode_flag = ff_vvc_cclm_mode_flag(lc); - - if (cclm_mode_flag) - cclm_mode_idx = ff_vvc_cclm_mode_idx(lc); - else - intra_chroma_pred_mode = ff_vvc_intra_chroma_pred_mode(lc); + if (!cu->bdpcm_flag[CHROMA]) derive_chroma_intra_pred_mode(lc, cclm_mode_flag, cclm_mode_idx, intra_chroma_pred_mode); - } } static PredMode pred_mode_decode(VVCLocalContext *lc, @@ -1043,13 +1054,15 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, const H266RawSliceHeader *rsh = lc->sc->sh.r; const int ch_type = tree_type == DUAL_TREE_CHROMA ? 1 : 0; const int is_4x4 = cu->cb_width == 4 && cu->cb_height == 4; + const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; + const int hs = sps->hshift[CHROMA]; + const int vs = sps->vshift[CHROMA]; int pred_mode_flag; int pred_mode_ibc_flag; PredMode pred_mode; cu->skip_flag = 0; if (!IS_I(rsh) || sps->r->sps_ibc_enabled_flag) { - const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; if (tree_type != DUAL_TREE_CHROMA && ((!is_4x4 && mode_type != MODE_TYPE_INTRA) || (sps->r->sps_ibc_enabled_flag && !is_128))) { @@ -1084,6 +1097,14 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, pred_mode = MODE_INTRA; } + if (pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && + mode_type != MODE_TYPE_INTER && ((cu->cb_width * cu->cb_height) > + (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && + (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { + if (ff_vvc_pred_mode_plt_flag(lc)) + pred_mode = MODE_PLT; + } + set_cb_tab(lc, fc->tab.cpm[cu->ch_type], pred_mode); if (tree_type == SINGLE_TREE) set_cb_tab(lc, fc->tab.cpm[CHROMA], pred_mode); @@ -1180,7 +1201,7 @@ static CodingUnit* alloc_cu(VVCLocalContext *lc, const int x0, const int y0) const int rx = x0 >> sps->ctb_log2_size_y; const int ry = y0 >> sps->ctb_log2_size_y; CodingUnit **cus = fc->tab.cus + ry * pps->ctb_width + rx; - CodingUnit *cu = ff_refstruct_pool_get(fc->cu_pool); + CodingUnit *cu = av_refstruct_pool_get(fc->cu_pool); if (!cu) return NULL; @@ -1240,16 +1261,18 @@ static void set_cu_tabs(const VVCLocalContext *lc, const CodingUnit *cu) set_cb_tab(lc, fc->tab.mmi, pu->mi.motion_model_idc); set_cb_tab(lc, fc->tab.msf, pu->merge_subblock_flag); - if (cu->tree_type != DUAL_TREE_CHROMA) + if (cu->tree_type != DUAL_TREE_CHROMA) { set_cb_tab(lc, fc->tab.skip, cu->skip_flag); + set_cb_tab(lc, fc->tab.pcmf[LUMA], cu->bdpcm_flag[LUMA]); + } + if (cu->tree_type != DUAL_TREE_LUMA) + set_cb_tab(lc, fc->tab.pcmf[CHROMA], cu->bdpcm_flag[CHROMA]); while (tu) { for (int j = 0; j < tu->nb_tbs; j++) { const TransformBlock *tb = tu->tbs + j; if (tb->c_idx != LUMA) set_qp_c_tab(lc, tu, tb); - if (tb->c_idx != CR && cu->bdpcm_flag[tb->c_idx]) - set_tb_tab(fc->tab.pcmf[tb->c_idx], 1, fc, tb); } tu = tu->next; } @@ -1493,7 +1516,7 @@ static int hls_merge_data(VVCLocalContext *lc) static void hls_mvd_coding(VVCLocalContext *lc, Mv* mvd) { - int16_t mv[2]; + int32_t mv[2]; for (int i = 0; i < 2; i++) { mv[i] = ff_vvc_abs_mvd_greater0_flag(lc); @@ -1750,8 +1773,8 @@ static void fill_dmvr_info(const VVCLocalContext *lc) const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; - if (cu->pred_mode == MODE_IBC) { - ff_vvc_set_intra_mvf(lc, 1); + if (cu->pred_mode == MODE_IBC || cu->pred_mode == MODE_PLT) { + ff_vvc_set_intra_mvf(lc, true, cu->pred_mode == MODE_IBC ? PF_IBC : PF_PLT, false); } else { const VVCPPS *pps = fc->ps.pps; const int w = cu->cb_width >> MIN_PU_LOG2; @@ -1778,15 +1801,17 @@ static int inter_data(VVCLocalContext *lc) pu->general_merge_flag = ff_vvc_general_merge_flag(lc); if (pu->general_merge_flag) { - hls_merge_data(lc); - } else if (cu->pred_mode == MODE_IBC){ + ret = hls_merge_data(lc); + } else if (cu->pred_mode == MODE_IBC) { ret = mvp_data_ibc(lc); } else { ret = mvp_data(lc); } - if (cu->pred_mode == MODE_IBC) - { + if (ret) + return ret; + + if (cu->pred_mode == MODE_IBC) { ff_vvc_update_hmvp(lc, mi); } else if (!pu->merge_gpm_flag && !pu->inter_affine_flag && !pu->merge_subblock_flag) { refine_regular_subblock(lc); @@ -1798,17 +1823,357 @@ static int inter_data(VVCLocalContext *lc) return ret; } +static TransformUnit* palette_add_tu(VVCLocalContext *lc, const int start, const int end, const VVCTreeType tree_type) +{ + CodingUnit *cu = lc->cu; + const VVCSPS *sps = lc->fc->ps.sps; + TransformUnit *tu = add_tu(lc->fc, cu, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + + if (!tu) + return NULL; + + for (int c = start; c < end; c++) { + const int w = tu->width >> sps->hshift[c]; + const int h = tu->height >> sps->vshift[c]; + TransformBlock *tb = add_tb(tu, lc, tu->x0, tu->y0, w, h, c); + if (c != CR) + set_tb_size(lc->fc, tb); + } + + for (int i = 0; i < FF_ARRAY_ELEMS(cu->plt); i++) + cu->plt[i].size = 0; + + return tu; +} + +static int palette_predicted(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size, const int max_entries) +{ + CodingUnit *cu = lc->cu; + int nb_predicted = 0; + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int i = 0; i < predictor_size && nb_predicted < max_entries; i++) { + const int run = ff_vvc_palette_predictor_run(lc, predictor_size - i); + if (run < 0) + return run; + + if (run == 1) + break; + + if (run > 1) + i += run - 1; + + predictor_reused[i] = true; + for (int c = start; c < end; c++) + cu->plt[c].entries[nb_predicted] = lc->ep->pp[c].entries[i]; + nb_predicted++; + } + + for (int c = start; c < end; c++) + cu->plt[c].size = nb_predicted; + + return 0; +} + +static int palette_signaled(VVCLocalContext *lc, const bool local_dual_tree, + const int start, const int end, const int max_entries) +{ + const VVCSPS *sps = lc->fc->ps.sps; + CodingUnit *cu = lc->cu; + const int nb_predicted = cu->plt[start].size; + const int nb_signaled = nb_predicted < max_entries ? ff_vvc_num_signalled_palette_entries(lc, max_entries - nb_predicted) : 0; + const int size = nb_predicted + nb_signaled; + const bool dual_tree_luma = local_dual_tree && cu->tree_type == DUAL_TREE_LUMA; + + if (nb_signaled < 0) + return AVERROR_INVALIDDATA; + + for (int c = start; c < end; c++) { + Palette *plt = cu->plt + c; + for (int i = nb_predicted; i < size; i++) { + plt->entries[i] = ff_vvc_new_palette_entries(lc, sps->bit_depth); + if (dual_tree_luma) { + plt[CB].entries[i] = 1 << (sps->bit_depth - 1); + plt[CR].entries[i] = 1 << (sps->bit_depth - 1); + } + } + plt->size = size; + } + + return 0; +} + +static void palette_update_predictor(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size) +{ + CodingUnit *cu = lc->cu; + const int max_predictor = VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE >> (cu->tree_type != SINGLE_TREE && !local_dual_tree); + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int c = start; c < end; c++) { + Palette *pp = lc->ep->pp + c; + Palette *plt = cu->plt + c; + int i = cu->plt[start].size;; + + // copy unused predictors to the end of plt + for (int j = 0; j < predictor_size && i < max_predictor; j++) { + if (!predictor_reused[j]) { + plt->entries[i] = pp->entries[j]; + i++; + } + } + + memcpy(pp->entries, plt->entries, i * sizeof(pp->entries[0])); + pp->size = i; + } +} + +static void palette_qp(VVCLocalContext *lc, VVCTreeType tree_type, const bool escape_present) +{ + const VVCFrameContext *fc = lc->fc; + const VVCPPS *pps = fc->ps.pps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const CodingUnit *cu = lc->cu; + + if (tree_type != DUAL_TREE_CHROMA) { + const bool has_qp_delta = escape_present && + pps->r->pps_cu_qp_delta_enabled_flag && !lc->parse.is_cu_qp_delta_coded; + set_qp_y(lc, cu->x0, cu->y0, has_qp_delta); + } + + if (tree_type != DUAL_TREE_LUMA) { + if (rsh->sh_cu_chroma_qp_offset_enabled_flag && !lc->parse.is_cu_chroma_qp_offset_coded) + chroma_qp_offset_decode(lc, 0, 1); + set_qp_c(lc); + } +} + +#define PALETTE_SET_PIXEL(xc, yc, pix) \ + do { \ + const int off = ((xc) >> hs) + ((yc) >> vs) * tb->tb_width; \ + if (sps->bit_depth == 8) \ + u8[off] = pix; \ + else \ + u16[off] = pix; \ + } while (0) + +#define PALETTE_INDEX(x, y) index[(y) * width + (x)] + +// 6.5.3 Horizontal and vertical traverse scan order array initialization process +// The hTravScan and vTravScan tables require approximately 576 KB of memory. +// To save space, we use a macro to achieve the same functionality. +#define TRAV_COL(p, wlog, mask) ((p & mask) ^ (-((p >> wlog) & 1) & mask)) +#define TRAV_ROW(p, hlog) (p >> hlog) +#define TRAV(trans, p, wlog, hlog, mask) (trans ? TRAV_ROW((p), hlog) : TRAV_COL((p), wlog, mask)) +#define TRAV_X(pos) TRAV(transpose, pos, wlog2, hlog2, wmask) +#define TRAV_Y(pos) TRAV(!transpose, pos, hlog2, wlog2, hmask) + +static int palette_subblock_data(VVCLocalContext *lc, + const int max_index, const int subset_id, const bool transpose, + uint8_t *run_type, uint8_t *index, int *prev_run_pos, bool *adjust) +{ + const CodingUnit *cu = lc->cu; + TransformUnit *tu = cu->tus.head; + const VVCSPS *sps = lc->fc->ps.sps; + const int width = tu->tbs[0].tb_width; + const int height = tu->tbs[0].tb_height; + const int min_pos = subset_id << 4; + const int max_pos = FFMIN(min_pos + 16, width * height); + const int wmask = width - 1; + const int hmask = height - 1; + const int wlog2 = av_log2(width); + const int hlog2 = av_log2(height); + const int start_idx = tu->tbs[0].c_idx; + const uint8_t esc = cu->plt[tu->tbs[0].c_idx].size; + uint8_t run_copy[16] = { 0 }; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + + if (i > 0 && max_index > 0) + run_copy[i - min_pos] = ff_vvc_run_copy_flag(lc, run_type[i - 1], *prev_run_pos, i); + + run_type[i] = 0; + if (max_index > 0 && !run_copy[i - min_pos]) { + if (((!transpose && yc > 0) || (transpose && xc > 0)) + && i > 0 && !run_type[i - 1]) { + run_type[i] = ff_vvc_copy_above_palette_indices_flag(lc); + } + *prev_run_pos = i; + } else if (i > 0) { + run_type[i] = run_type[i - 1]; + } + } + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + const int prev_xc = i > 0 ? TRAV_X(i - 1) : 0; + const int prev_yc = i > 0 ? TRAV_Y(i - 1) : 0; + + int idx = 0; + if (max_index > 0 && !run_copy[i - min_pos] && !run_type[i]) { + if (max_index - *adjust > 0) + idx = ff_vvc_palette_idx_idc(lc, max_index, *adjust); + if (i > 0) { + const int ref_idx = !run_type[i - 1] ? + PALETTE_INDEX(prev_xc, prev_yc) : PALETTE_INDEX(xc - transpose, yc - !transpose); + idx += (idx >= ref_idx); + } + *adjust = true; + } else { + idx = PALETTE_INDEX(prev_xc, prev_yc); + } + + if (!run_type[i]) + PALETTE_INDEX(xc, yc) = idx; + else + PALETTE_INDEX(xc, yc) = PALETTE_INDEX(xc - transpose, yc - !transpose); + } + + for (int c = 0; c < tu->nb_tbs; c++) { + TransformBlock *tb = &tu->tbs[c]; + const int c_idx = tb->c_idx; + const Palette *plt = &cu->plt[c_idx]; + const int scale = ff_vvc_palette_derive_scale(lc, tu, tb); + const int hs = sps->hshift[c_idx] - sps->hshift[start_idx]; + const int vs = sps->vshift[c_idx] - sps->vshift[start_idx]; + uint8_t *u8 = (uint8_t *)tb->coeffs; + uint16_t *u16 = (uint16_t *)tb->coeffs; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + if (!(xc & hs) && !(yc & vs)) { + const int v = PALETTE_INDEX(xc, yc); + if (v == esc) { + const int coeff = ff_vvc_palette_escape_val(lc, (1 << sps->bit_depth) - 1); + if (coeff < 0) + return AVERROR_INVALIDDATA; + const int pixel = av_clip_intp2(RSHIFT(coeff * scale, 6), sps->bit_depth); + PALETTE_SET_PIXEL(xc, yc, pixel); + } else { + PALETTE_SET_PIXEL(xc, yc, plt->entries[v]); + } + } + } + } + + return 0; +} + +static int hls_palette_coding(VVCLocalContext *lc, const VVCTreeType tree_type) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + CodingUnit *cu = lc->cu; + Palette *pp = lc->ep->pp; + const int max_entries = tree_type == SINGLE_TREE ? 31 : 15; + const bool local_dual_tree = tree_type != SINGLE_TREE && + (!IS_I(rsh) || (IS_I(rsh) && !sps->r->sps_qtbtt_dual_tree_intra_flag)); + bool escape_present = false; + bool transpose = false; + bool adjust = false; + int max_index = 0; + int prev_run_pos = 0; + + int predictor_size, start, end, ret; + bool reused[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE]; + uint8_t run_type[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + uint8_t index[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + + TransformUnit *tu; + + ff_vvc_channel_range(&start, &end, tree_type, sps->r->sps_chroma_format_idc); + + tu = palette_add_tu(lc, start, end, tree_type); + if (!tu) + return AVERROR(ENOMEM); + + predictor_size = pp[start].size; + memset(reused, 0, sizeof(reused[0]) * predictor_size); + + ret = palette_predicted(lc, local_dual_tree, start, end, reused, predictor_size, max_entries); + if (ret < 0) + return ret; + + ret = palette_signaled(lc, local_dual_tree, start, end, max_entries); + if (ret < 0) + return ret; + + palette_update_predictor(lc, local_dual_tree, start, end, reused, predictor_size); + + if (cu->plt[start].size > 0) + escape_present = ff_vvc_palette_escape_val_present_flag(lc); + + max_index = cu->plt[start].size - 1 + escape_present; + if (max_index > 0) { + adjust = false; + transpose = ff_vvc_palette_transpose_flag(lc); + } + + palette_qp(lc, tree_type, escape_present); + + index[0] = 0; + for (int i = 0; i <= (tu->tbs[0].tb_width * tu->tbs[0].tb_height - 1) >> 4; i++) { + ret = palette_subblock_data(lc, max_index, i, transpose, + run_type, index, &prev_run_pos, &adjust); + if (ret < 0) + return ret; + } + + return 0; +} + +static int intra_data(VVCLocalContext *lc) +{ + const VVCSPS *sps = lc->fc->ps.sps; + const CodingUnit *cu = lc->cu; + const VVCTreeType tree_type = cu->tree_type; + const bool pred_mode_plt_flag = cu->pred_mode == MODE_PLT; + int ret = 0; + + if (tree_type == SINGLE_TREE || tree_type == DUAL_TREE_LUMA) { + if (pred_mode_plt_flag) { + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; + ff_vvc_set_intra_mvf(lc, false, PF_PLT, false); + } else { + intra_luma_pred_modes(lc); + ff_vvc_set_intra_mvf(lc, false, PF_INTRA, cu->ciip_flag); + } + } + if ((tree_type == SINGLE_TREE || tree_type == DUAL_TREE_CHROMA) && sps->r->sps_chroma_format_idc) { + if (pred_mode_plt_flag && tree_type == DUAL_TREE_CHROMA) { + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; + } else if (!pred_mode_plt_flag) { + intra_chroma_pred_modes(lc); + } + } + + return ret; +} + static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, int cb_height, int cqt_depth, const VVCTreeType tree_type, VVCModeType mode_type) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const H266RawSliceHeader *rsh = lc->sc->sh.r; - const int hs = sps->hshift[CHROMA]; - const int vs = sps->vshift[CHROMA]; - const int is_128 = cb_width > 64 || cb_height > 64; - int pred_mode_plt_flag = 0; - int ret; + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const int is_128 = cb_width > 64 || cb_height > 64; + int ret = 0; CodingUnit *cu = add_cu(lc, x0, y0, cb_width, cb_height, cqt_depth, tree_type); @@ -1821,54 +2186,26 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in mode_type = MODE_TYPE_INTRA; cu->pred_mode = pred_mode_decode(lc, tree_type, mode_type); - if (cu->pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && - mode_type != MODE_TYPE_INTER && ((cb_width * cb_height) > - (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && - (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { - pred_mode_plt_flag = ff_vvc_pred_mode_plt_flag(lc); - if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } - } - if (cu->pred_mode == MODE_INTRA && sps->r->sps_act_enabled_flag && tree_type == SINGLE_TREE) { - avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); - return AVERROR_PATCHWELCOME; - } - if (cu->pred_mode == MODE_INTRA || cu->pred_mode == MODE_PLT) { - if (tree_type == SINGLE_TREE || tree_type == DUAL_TREE_LUMA) { - if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } else { - intra_luma_pred_modes(lc); - } - ff_vvc_set_intra_mvf(lc, 0); - } - if ((tree_type == SINGLE_TREE || tree_type == DUAL_TREE_CHROMA) && sps->r->sps_chroma_format_idc) { - if (pred_mode_plt_flag && tree_type == DUAL_TREE_CHROMA) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } else if (!pred_mode_plt_flag) { - if (!cu->act_enabled_flag) - intra_chroma_pred_modes(lc); - } - } - } else if (tree_type != DUAL_TREE_CHROMA) { /* MODE_INTER or MODE_IBC */ - if ((ret = inter_data(lc)) < 0) - return ret; - } - if (cu->pred_mode != MODE_INTRA && !pred_mode_plt_flag && !lc->cu->pu.general_merge_flag) + if (cu->pred_mode == MODE_INTRA && sps->r->sps_act_enabled_flag && tree_type == SINGLE_TREE) + cu->act_enabled_flag = ff_vvc_cu_act_enabled_flag(lc); + + if (cu->pred_mode == MODE_INTRA || cu->pred_mode == MODE_PLT) + ret = intra_data(lc); + else if (tree_type != DUAL_TREE_CHROMA) /* MODE_INTER or MODE_IBC */ + ret = inter_data(lc); + + if (ret < 0) + return ret; + + if (cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && !lc->cu->pu.general_merge_flag) cu->coded_flag = ff_vvc_cu_coded_flag(lc); else - cu->coded_flag = !(cu->skip_flag || pred_mode_plt_flag); + cu->coded_flag = !(cu->skip_flag || cu->pred_mode == MODE_PLT); if (cu->coded_flag) { sbt_info(lc, sps); - if (sps->r->sps_act_enabled_flag && cu->pred_mode != MODE_INTRA && tree_type == SINGLE_TREE) { - avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); - return AVERROR_PATCHWELCOME; - } + if (sps->r->sps_act_enabled_flag && cu->pred_mode != MODE_INTRA && tree_type == SINGLE_TREE) + cu->act_enabled_flag = ff_vvc_cu_act_enabled_flag(lc); lc->parse.lfnst_dc_only = 1; lc->parse.lfnst_zero_out_sig_coeff_flag = 1; lc->parse.mts_dc_only = 1; @@ -1879,7 +2216,7 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in cu->lfnst_idx = lfnst_idx_decode(lc); cu->mts_idx = mts_idx_decode(lc); set_qp_c(lc); - } else { + } else if (cu->pred_mode != MODE_PLT) { ret = skipped_transform_tree_unit(lc); if (ret < 0) return ret; @@ -2286,6 +2623,7 @@ static void alf_params(VVCLocalContext *lc, const int rx, const int ry) ALFParams *alf = &CTB(fc->tab.alf, rx, ry); alf->ctb_flag[LUMA] = alf->ctb_flag[CB] = alf->ctb_flag[CR] = 0; + alf->ctb_cc_idc[0] = alf->ctb_cc_idc[1] = 0; if (sh->sh_alf_enabled_flag) { alf->ctb_flag[LUMA] = ff_vvc_alf_ctb_flag(lc, rx, ry, LUMA); if (alf->ctb_flag[LUMA]) { @@ -2316,7 +2654,6 @@ static void alf_params(VVCLocalContext *lc, const int rx, const int ry) const uint8_t cc_enabled[] = { sh->sh_alf_cc_cb_enabled_flag, sh->sh_alf_cc_cr_enabled_flag }; const uint8_t cc_aps_id[] = { sh->sh_alf_cc_cb_aps_id, sh->sh_alf_cc_cr_aps_id }; for (int i = 0; i < 2; i++) { - alf->ctb_cc_idc[i] = 0; if (cc_enabled[i]) { const VVCALF *aps = fc->ps.alf_list[cc_aps_id[i]]; alf->ctb_cc_idc[i] = ff_vvc_alf_ctb_cc_idc(lc, rx, ry, i, aps->num_cc_filters[i]); @@ -2385,13 +2722,19 @@ static int has_inter_luma(const CodingUnit *cu) return cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && cu->tree_type != DUAL_TREE_CHROMA; } -static int pred_get_y(const int y0, const Mv *mv, const int height) +static int pred_get_y(const VVCLocalContext *lc, const int y0, const Mv *mv, const int height) { - return FFMAX(0, y0 + (mv->y >> 4) + height); + const VVCPPS *pps = lc->fc->ps.pps; + const int idx = lc->sc->sh.r->curr_subpic_idx; + const int top = pps->subpic_y[idx]; + const int bottom = top + pps->subpic_height[idx]; + + return av_clip(y0 + (mv->y >> 4) + height, top, bottom); } -static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES], const VVCFrameContext *fc) +static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES], const VVCLocalContext *lc) { + const VVCFrameContext *fc = lc->fc; const PredictionUnit *pu = &cu->pu; if (pu->merge_gpm_flag) { @@ -2399,7 +2742,7 @@ static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES] const MvField *mvf = pu->gpm_mv + i; const int lx = mvf->pred_flag - PF_L0; const int idx = mvf->ref_idx[lx]; - const int y = pred_get_y(cu->y0, mvf->mv + lx, cu->cb_height); + const int y = pred_get_y(lc, cu->y0, mvf->mv + lx, cu->cb_height); max_y[lx][idx] = FFMAX(max_y[lx][idx], y); } @@ -2417,7 +2760,7 @@ static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES] const PredFlag mask = 1 << lx; if (mvf->pred_flag & mask) { const int idx = mvf->ref_idx[lx]; - const int y = pred_get_y(y0, mvf->mv + lx, sbh); + const int y = pred_get_y(lc, y0, mvf->mv + lx, sbh); max_y[lx][idx] = FFMAX(max_y[lx][idx], y + max_dmvr_off); } @@ -2444,7 +2787,7 @@ static void ctu_get_pred(VVCLocalContext *lc, const int rs) while (cu) { if (has_inter_luma(cu)) { - cu_get_max_y(cu, ctu->max_y, fc); + cu_get_max_y(cu, ctu->max_y, lc); ctu->has_dmvr |= cu->pu.dmvr_flag; } cu = cu->next; @@ -2542,11 +2885,11 @@ void ff_vvc_ctu_free_cus(CodingUnit **cus) while (*head) { TransformUnit *tu = *head; *head = tu->next; - ff_refstruct_unref(&tu); + av_refstruct_unref(&tu); } cu->tus.tail = NULL; - ff_refstruct_unref(&cu); + av_refstruct_unref(&cu); } } @@ -2566,3 +2909,12 @@ void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, persistent_rice_adaptation_enabled_flag ? 2 * (av_log2(bit_depth - 10)) : 0; } } + +void ff_vvc_channel_range(int *start, int *end, const VVCTreeType tree_type, const uint8_t chroma_format_idc) +{ + const bool has_chroma = chroma_format_idc && tree_type != DUAL_TREE_LUMA; + const bool has_luma = tree_type != DUAL_TREE_CHROMA; + + *start = has_luma ? LUMA : CB; + *end = has_chroma ? VVC_MAX_SAMPLE_ARRAYS : CB; +} diff --git a/libavcodec/vvc/ctu.h b/libavcodec/vvc/ctu.h index eab4612561..e37bacf9dd 100644 --- a/libavcodec/vvc/ctu.h +++ b/libavcodec/vvc/ctu.h @@ -23,6 +23,8 @@ #ifndef AVCODEC_VVC_CTU_H #define AVCODEC_VVC_CTU_H +#include + #include "libavcodec/cabac.h" #include "libavutil/mem_internal.h" @@ -34,6 +36,7 @@ #define MIN_CU_SIZE 4 #define MIN_CU_LOG2 2 #define MAX_CU_DEPTH 7 +#define MAX_PALETTE_CU_SIZE 64 #define MAX_PARTS_IN_CTU ((MAX_CTU_SIZE >> MIN_CU_LOG2) * (MAX_CTU_SIZE >> MIN_CU_LOG2)) @@ -172,6 +175,7 @@ typedef struct TransformUnit { int y0; int width; int height; + bool avail[CHROMA + 1]; // contains luma/chroma block uint8_t joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag @@ -221,6 +225,7 @@ typedef enum PredFlag { PF_L1 = 0x2, PF_BI = 0x3, PF_IBC = PF_L0 | 0x4, + PF_PLT = 0x8, } PredFlag; typedef enum IntraPredMode { @@ -274,6 +279,11 @@ typedef struct PredictionUnit { int cb_prof_flag[2]; } PredictionUnit; +typedef struct Palette { + uint8_t size; + uint16_t entries[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE]; +} Palette; + typedef struct CodingUnit { VVCTreeType tree_type; int x0; @@ -323,6 +333,8 @@ typedef struct CodingUnit { int8_t qp[4]; ///< QpY, Qp′Cb, Qp′Cr, Qp′CbCr + Palette plt[VVC_MAX_SAMPLE_ARRAYS]; + PredictionUnit pu; struct CodingUnit *next; ///< RefStruct reference @@ -353,6 +365,8 @@ typedef struct EntryPoint { int stat_coeff[VVC_MAX_SAMPLE_ARRAYS]; ///< StatCoeff + Palette pp[VVC_MAX_SAMPLE_ARRAYS]; // PalettePredictor + VVCCabacState cabac_state[VVC_CONTEXTS]; CABACContext cc; @@ -486,5 +500,6 @@ void ff_vvc_decode_neighbour(VVCLocalContext *lc, int x_ctb, int y_ctb, int rx, void ff_vvc_ctu_free_cus(CodingUnit **cus); int ff_vvc_get_qPy(const VVCFrameContext *fc, int xc, int yc); void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, int bit_depth, int persistent_rice_adaptation_enabled_flag); +void ff_vvc_channel_range(int *start, int *end, VVCTreeType tree_type, uint8_t chroma_format_idc); #endif // AVCODEC_VVC_CTU_H diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index edf2607f50..6f52306080 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -20,19 +20,27 @@ * 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/bytestream.h" #include "libavcodec/codec_internal.h" #include "libavcodec/decode.h" +#include "libavcodec/hwaccel_internal.h" +#include "libavcodec/hwconfig.h" #include "libavcodec/profiles.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" +#include "libavcodec/aom_film_grain.h" +#include "libavcodec/thread.h" #include "libavutil/cpu.h" #include "libavutil/mem.h" #include "libavutil/thread.h" +#include "libavutil/film_grain_params.h" #include "dec.h" #include "ctu.h" #include "data.h" #include "refs.h" #include "thread.h" +#include "config_components.h" #define TAB_MAX 32 @@ -125,7 +133,6 @@ static void min_cb_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 1, changed); TL_ADD(imf, pic_size_in_min_cb); - TL_ADD(imm, pic_size_in_min_cb); for (int i = LUMA; i <= CHROMA; i++) TL_ADD(cb_width[i], pic_size_in_min_cb); //is_a0_available requires this @@ -140,7 +147,6 @@ static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 0, changed); TL_ADD(skip, pic_size_in_min_cb); - TL_ADD(imtf, pic_size_in_min_cb); TL_ADD(ipm, pic_size_in_min_cb); for (int i = LUMA; i <= CHROMA; i++) { @@ -150,6 +156,7 @@ static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc) TL_ADD(cb_height[i], pic_size_in_min_cb); TL_ADD(cp_mv[i], pic_size_in_min_cb * MAX_CONTROL_POINTS); TL_ADD(cpm[i], pic_size_in_min_cb); + TL_ADD(pcmf[i], pic_size_in_min_cb); } // For luma, qp can only change at the CU level, so the qp tab size is related to the CU. TL_ADD(qp[LUMA], pic_size_in_min_cb); @@ -189,9 +196,6 @@ static void min_tu_tl_init(TabList *l, VVCFrameContext *fc) TL_ADD(tu_joint_cbcr_residual_flag, pic_size_in_min_tu); - for (int i = LUMA; i <= CHROMA; i++) - TL_ADD(pcmf[i], pic_size_in_min_tu); - for (int i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) { TL_ADD(tu_coded_flag[i], pic_size_in_min_tu); @@ -209,8 +213,6 @@ static void min_tu_nz_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 0, changed); for (int i = LUMA; i <= CHROMA; i++) { - TL_ADD(tb_pos_x0[i], pic_size_in_min_tu); - TL_ADD(tb_pos_y0[i], pic_size_in_min_tu); TL_ADD(tb_width[i], pic_size_in_min_tu); TL_ADD(tb_height[i], pic_size_in_min_tu); } @@ -355,8 +357,8 @@ static void pic_arrays_free(VVCFrameContext *fc) { free_cus(fc); frame_context_for_each_tl(fc, tl_free); - ff_refstruct_pool_uninit(&fc->rpl_tab_pool); - ff_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); + av_refstruct_pool_uninit(&fc->rpl_tab_pool); + av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); memset(&fc->tab.sz, 0, sizeof(fc->tab.sz)); } @@ -381,16 +383,16 @@ static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc) memset(fc->tab.slice_idx, -1, sizeof(*fc->tab.slice_idx) * ctu_count); if (fc->tab.sz.ctu_count != ctu_count) { - ff_refstruct_pool_uninit(&fc->rpl_tab_pool); - fc->rpl_tab_pool = ff_refstruct_pool_alloc(ctu_count * sizeof(RefPicListTab), 0); + av_refstruct_pool_uninit(&fc->rpl_tab_pool); + fc->rpl_tab_pool = av_refstruct_pool_alloc(ctu_count * sizeof(RefPicListTab), 0); if (!fc->rpl_tab_pool) return AVERROR(ENOMEM); } if (fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu) { - ff_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); - fc->tab_dmvr_mvf_pool = ff_refstruct_pool_alloc( - pic_size_in_min_pu * sizeof(MvField), FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); + av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool); + fc->tab_dmvr_mvf_pool = av_refstruct_pool_alloc( + pic_size_in_min_pu * sizeof(MvField), AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME); if (!fc->tab_dmvr_mvf_pool) return AVERROR(ENOMEM); } @@ -471,8 +473,8 @@ static void slices_free(VVCFrameContext *fc) for (int i = 0; i < fc->nb_slices_allocated; i++) { SliceContext *slice = fc->slices[i]; if (slice) { - ff_refstruct_unref(&slice->ref); - ff_refstruct_unref(&slice->sh.r); + av_refstruct_unref(&slice->ref); + av_refstruct_unref(&slice->sh.r); eps_free(slice); av_free(slice); } @@ -509,36 +511,56 @@ static int slices_realloc(VVCFrameContext *fc) return 0; } -static int ep_init_cabac_decoder(SliceContext *sc, const int index, - const H2645NAL *nal, GetBitContext *gb, const CodedBitstreamUnit *unit) +static int get_ep_size(const H266RawSliceHeader *rsh, const GetByteContext *gb, + const H2645NAL *nal, const int header_size, const int ep_index) { - const H266RawSlice *slice = unit->content_ref; - const H266RawSliceHeader *rsh = sc->sh.r; - EntryPoint *ep = sc->eps + index; int size; - int ret; - if (index < rsh->num_entry_points) { + if (ep_index < rsh->num_entry_points) { int skipped = 0; - int64_t start = (gb->index >> 3); - int64_t end = start + rsh->sh_entry_point_offset_minus1[index] + 1; - while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= start + slice->header_size) { + int64_t start = bytestream2_tell(gb); + int64_t end = start + rsh->sh_entry_point_offset_minus1[ep_index] + 1; + while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= start + header_size) { skipped++; } - while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= end + slice->header_size) { + while (skipped < nal->skipped_bytes && nal->skipped_bytes_pos[skipped] <= end + header_size) { end--; skipped++; } size = end - start; - size = av_clip(size, 0, get_bits_left(gb) / 8); + size = av_clip(size, 0, bytestream2_get_bytes_left(gb)); } else { - size = get_bits_left(gb) / 8; + size = bytestream2_get_bytes_left(gb); } - av_assert0(gb->buffer + get_bits_count(gb) / 8 + size <= gb->buffer_end); - ret = ff_init_cabac_decoder (&ep->cc, gb->buffer + get_bits_count(gb) / 8, size); + return size; +} + +static int ep_init_cabac_decoder(EntryPoint *ep, GetByteContext *gb, const int size) +{ + int ret; + + av_assert0(size <= bytestream2_get_bytes_left(gb)); + ret = ff_init_cabac_decoder(&ep->cc, gb->buffer, size); if (ret < 0) return ret; - skip_bits(gb, size * 8); + bytestream2_skipu(gb, size); + return 0; +} + +static int ep_init(EntryPoint *ep, const int ctu_addr, const int ctu_end, + GetByteContext *gb, const int size) +{ + const int ret = ep_init_cabac_decoder(ep, gb, size); + + if (ret < 0) + return ret; + + ep->ctu_start = ctu_addr; + ep->ctu_end = ctu_end; + + for (int c_idx = LUMA; c_idx <= CR; c_idx++) + ep->pp[c_idx].size = 0; + return 0; } @@ -549,7 +571,7 @@ static int slice_init_entry_points(SliceContext *sc, const H266RawSlice *slice = unit->content_ref; int nb_eps = sh->r->num_entry_points + 1; int ctu_addr = 0; - GetBitContext gb; + GetByteContext gb; int ret; if (sc->nb_eps != nb_eps) { @@ -560,25 +582,23 @@ static int slice_init_entry_points(SliceContext *sc, sc->nb_eps = nb_eps; } - ret = init_get_bits8(&gb, slice->data, slice->data_size); - if (ret < 0) - return ret; + bytestream2_init(&gb, slice->data, slice->data_size); + for (int i = 0; i < sc->nb_eps; i++) { - EntryPoint *ep = sc->eps + i; + const int size = get_ep_size(sc->sh.r, &gb, nal, slice->header_size, i); + const int ctu_end = (i + 1 == sc->nb_eps ? sh->num_ctus_in_curr_slice : sh->entry_point_start_ctu[i]); + EntryPoint *ep = sc->eps + i; - ep->ctu_start = ctu_addr; - ep->ctu_end = (i + 1 == sc->nb_eps ? sh->num_ctus_in_curr_slice : sh->entry_point_start_ctu[i]); + ret = ep_init(ep, ctu_addr, ctu_end, &gb, size); + if (ret < 0) + return ret; for (int j = ep->ctu_start; j < ep->ctu_end; j++) { const int rs = sc->sh.ctb_addr_in_curr_slice[j]; fc->tab.slice_idx[rs] = sc->slice_idx; } - ret = ep_init_cabac_decoder(sc, i, nal, &gb, unit); - if (ret < 0) - return ret; - if (i + 1 < sc->nb_eps) ctu_addr = sh->entry_point_start_ctu[i]; } @@ -601,15 +621,25 @@ static int ref_frame(VVCFrame *dst, const VVCFrame *src) if (ret < 0) return ret; - ff_refstruct_replace(&dst->sps, src->sps); - ff_refstruct_replace(&dst->pps, src->pps); + av_refstruct_replace(&dst->sps, src->sps); + av_refstruct_replace(&dst->pps, src->pps); - ff_refstruct_replace(&dst->progress, src->progress); + if (src->needs_fg) { + ret = av_frame_ref(dst->frame_grain, src->frame_grain); + if (ret < 0) + return ret; - ff_refstruct_replace(&dst->tab_dmvr_mvf, src->tab_dmvr_mvf); + dst->needs_fg = src->needs_fg; + } - ff_refstruct_replace(&dst->rpl_tab, src->rpl_tab); - ff_refstruct_replace(&dst->rpl, src->rpl); + av_refstruct_replace(&dst->progress, src->progress); + + av_refstruct_replace(&dst->tab_dmvr_mvf, src->tab_dmvr_mvf); + + av_refstruct_replace(&dst->rpl_tab, src->rpl_tab); + av_refstruct_replace(&dst->rpl, src->rpl); + av_refstruct_replace(&dst->hwaccel_picture_private, + src->hwaccel_picture_private); dst->nb_rpl_elems = src->nb_rpl_elems; dst->poc = src->poc; @@ -629,18 +659,20 @@ static av_cold void frame_context_free(VVCFrameContext *fc) { slices_free(fc); - ff_refstruct_pool_uninit(&fc->tu_pool); - ff_refstruct_pool_uninit(&fc->cu_pool); + av_refstruct_pool_uninit(&fc->tu_pool); + av_refstruct_pool_uninit(&fc->cu_pool); for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) { ff_vvc_unref_frame(fc, &fc->DPB[i], ~0); av_frame_free(&fc->DPB[i].frame); + av_frame_free(&fc->DPB[i].frame_grain); } ff_vvc_frame_thread_free(fc); pic_arrays_free(fc); av_frame_free(&fc->output_frame); ff_vvc_frame_ps_free(&fc->ps); + ff_vvc_sei_reset(&fc->sei); } static av_cold int frame_context_init(VVCFrameContext *fc, AVCodecContext *avctx) @@ -656,12 +688,16 @@ static av_cold int frame_context_init(VVCFrameContext *fc, AVCodecContext *avctx fc->DPB[j].frame = av_frame_alloc(); if (!fc->DPB[j].frame) return AVERROR(ENOMEM); + + fc->DPB[j].frame_grain = av_frame_alloc(); + if (!fc->DPB[j].frame_grain) + return AVERROR(ENOMEM); } - fc->cu_pool = ff_refstruct_pool_alloc(sizeof(CodingUnit), 0); + fc->cu_pool = av_refstruct_pool_alloc(sizeof(CodingUnit), 0); if (!fc->cu_pool) return AVERROR(ENOMEM); - fc->tu_pool = ff_refstruct_pool_alloc(sizeof(TransformUnit), 0); + fc->tu_pool = av_refstruct_pool_alloc(sizeof(TransformUnit), 0); if (!fc->tu_pool) return AVERROR(ENOMEM); @@ -672,8 +708,6 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) { int ret; - fc->ref = NULL; - // copy refs from the last frame if (s->nb_frames && s->nb_fcs > 1) { VVCFrameContext *prev = get_frame_context(s, fc, -1); @@ -685,6 +719,10 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) return ret; } } + + ret = ff_vvc_sei_replace(&fc->sei, &prev->sei); + if (ret < 0) + return ret; } if (IS_IDR(s)) { @@ -700,6 +738,66 @@ static int frame_context_setup(VVCFrameContext *fc, VVCContext *s) return 0; } +/* SEI does not affect decoding, so we ignore the return value */ +static void decode_prefix_sei(VVCFrameContext *fc, VVCContext *s) +{ + CodedBitstreamFragment *frame = &s->current_frame; + + for (int i = 0; i < frame->nb_units; i++) { + const CodedBitstreamUnit *unit = frame->units + i; + + if (unit->type == VVC_PREFIX_SEI_NUT) { + int ret = ff_vvc_sei_decode(&fc->sei, unit->content_ref, fc); + if (ret < 0) + return; + } + } +} + +static int set_side_data(VVCContext *s, VVCFrameContext *fc) +{ + AVFrame *out = fc->ref->frame; + + return ff_h2645_sei_to_frame(out, &fc->sei.common, AV_CODEC_ID_VVC, s->avctx, + NULL, fc->ps.sps->bit_depth, fc->ps.sps->bit_depth, fc->ref->poc); +} + +static int check_film_grain(VVCContext *s, VVCFrameContext *fc) +{ + int ret; + + fc->ref->needs_fg = (fc->sei.common.film_grain_characteristics && + fc->sei.common.film_grain_characteristics->present || + fc->sei.common.aom_film_grain.enable) && + !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && + !s->avctx->hwaccel; + + if (fc->ref->needs_fg && + (fc->sei.common.film_grain_characteristics && + fc->sei.common.film_grain_characteristics->present && + !ff_h274_film_grain_params_supported(fc->sei.common.film_grain_characteristics->model_id, + fc->ref->frame->format) || + !av_film_grain_params_select(fc->ref->frame))) { + av_log_once(s->avctx, AV_LOG_WARNING, AV_LOG_DEBUG, &s->film_grain_warning_shown, + "Unsupported film grain parameters. Ignoring film grain.\n"); + fc->ref->needs_fg = 0; + } + + if (fc->ref->needs_fg) { + fc->ref->frame_grain->format = fc->ref->frame->format; + fc->ref->frame_grain->width = fc->ref->frame->width; + fc->ref->frame_grain->height = fc->ref->frame->height; + + ret = ff_thread_get_buffer(s->avctx, fc->ref->frame_grain, 0); + if (ret < 0) + return ret; + + return av_frame_copy_props(fc->ref->frame_grain, fc->ref->frame); + } + + return 0; +} + static int frame_start(VVCContext *s, VVCFrameContext *fc, SliceContext *sc) { const VVCPH *ph = &fc->ps.ph; @@ -713,6 +811,16 @@ static int frame_start(VVCContext *s, VVCFrameContext *fc, SliceContext *sc) if ((ret = ff_vvc_set_new_ref(s, fc, &fc->frame)) < 0) goto fail; + decode_prefix_sei(fc, s); + + ret = set_side_data(s, fc); + if (ret < 0) + goto fail; + + ret = check_film_grain(s, fc); + if (ret < 0) + goto fail; + if (!IS_IDR(s)) ff_vvc_bump_frame(s, fc); @@ -744,7 +852,7 @@ static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, if (ret < 0) return ret; - ff_refstruct_replace(&sc->ref, unit->content_ref); + av_refstruct_replace(&sc->ref, unit->content_ref); if (is_first_slice) { ret = frame_start(s, fc, sc); @@ -770,18 +878,51 @@ static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, return 0; } -static void export_frame_params(VVCContext *s, const VVCFrameContext *fc) +static enum AVPixelFormat get_format(AVCodecContext *avctx, const VVCSPS *sps) +{ +#define HWACCEL_MAX CONFIG_VVC_VAAPI_HWACCEL + + enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; + + switch (sps->pix_fmt) { + case AV_PIX_FMT_YUV420P: +#if CONFIG_VVC_VAAPI_HWACCEL + *fmt++ = AV_PIX_FMT_VAAPI; +#endif + break; + case AV_PIX_FMT_YUV420P10: +#if CONFIG_VVC_VAAPI_HWACCEL + *fmt++ = AV_PIX_FMT_VAAPI; +#endif + break; + } + + *fmt++ = sps->pix_fmt; + *fmt = AV_PIX_FMT_NONE; + + return ff_get_format(avctx, pix_fmts); +} + +static int export_frame_params(VVCContext *s, const VVCFrameContext *fc) { AVCodecContext *c = s->avctx; const VVCSPS *sps = fc->ps.sps; const VVCPPS *pps = fc->ps.pps; - c->pix_fmt = sps->pix_fmt; - c->coded_width = pps->width; - c->coded_height = pps->height; - c->width = pps->width - ((pps->r->pps_conf_win_left_offset + pps->r->pps_conf_win_right_offset) << sps->hshift[CHROMA]); - c->height = pps->height - ((pps->r->pps_conf_win_top_offset + pps->r->pps_conf_win_bottom_offset) << sps->vshift[CHROMA]); - c->has_b_frames = sps->r->sps_dpb_params.dpb_max_num_reorder_pics[sps->r->sps_max_sublayers_minus1]; + // Reset the format if pix_fmt/w/h change. + if (c->sw_pix_fmt != sps->pix_fmt || c->coded_width != pps->width || c->coded_height != pps->height) { + c->coded_width = pps->width; + c->coded_height = pps->height; + c->sw_pix_fmt = sps->pix_fmt; + c->pix_fmt = get_format(c, sps); + if (c->pix_fmt < 0) + return AVERROR_INVALIDDATA; + } + + c->width = pps->width - ((pps->r->pps_conf_win_left_offset + pps->r->pps_conf_win_right_offset) << sps->hshift[CHROMA]); + c->height = pps->height - ((pps->r->pps_conf_win_top_offset + pps->r->pps_conf_win_bottom_offset) << sps->vshift[CHROMA]); + + return 0; } static int frame_setup(VVCFrameContext *fc, VVCContext *s) @@ -794,11 +935,15 @@ static int frame_setup(VVCFrameContext *fc, VVCContext *s) if (ret < 0) return ret; - export_frame_params(s, fc); - return ret; + ret = export_frame_params(s, fc); + if (ret < 0) + return ret; + + return 0; } -static int decode_slice(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, const CodedBitstreamUnit *unit) +static int decode_slice(VVCContext *s, VVCFrameContext *fc, AVBufferRef *buf_ref, + const H2645NAL *nal, const CodedBitstreamUnit *unit) { int ret; SliceContext *sc; @@ -824,12 +969,27 @@ static int decode_slice(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, ret = slice_init_entry_points(sc, fc, nal, unit); if (ret < 0) return ret; + + if (s->avctx->hwaccel) { + if (is_first_slice) { + ret = FF_HW_CALL(s->avctx, start_frame, buf_ref, NULL, 0); + if (ret < 0) + return ret; + } + + ret = FF_HW_CALL(s->avctx, decode_slice, + nal->raw_data, nal->raw_size); + if (ret < 0) + return ret; + } + fc->nb_slices++; return 0; } -static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *nal, const CodedBitstreamUnit *unit) +static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, AVBufferRef *buf_ref, + const H2645NAL *nal, const CodedBitstreamUnit *unit) { int ret; @@ -855,7 +1015,7 @@ static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *n case VVC_IDR_N_LP: case VVC_CRA_NUT: case VVC_GDR_NUT: - ret = decode_slice(s, fc, nal, unit); + ret = decode_slice(s, fc, buf_ref, nal, unit); if (ret < 0) return ret; break; @@ -865,6 +1025,15 @@ static int decode_nal_unit(VVCContext *s, VVCFrameContext *fc, const H2645NAL *n if (ret < 0) return ret; break; + case VVC_PREFIX_SEI_NUT: + /* handle by decode_prefix_sei() */ + break; + + case VVC_SUFFIX_SEI_NUT: + /* SEI does not affect decoding, so we ignore the return value*/ + if (fc) + ff_vvc_sei_decode(&fc->sei, unit->content_ref, fc); + break; } return 0; @@ -877,6 +1046,7 @@ static int decode_nal_units(VVCContext *s, VVCFrameContext *fc, AVPacket *avpkt) int ret = 0; s->last_eos = s->eos; s->eos = 0; + fc->ref = NULL; ff_cbs_fragment_reset(frame); ret = ff_cbs_read_packet(s->cbc, frame, avpkt); @@ -892,7 +1062,7 @@ static int decode_nal_units(VVCContext *s, VVCFrameContext *fc, AVPacket *avpkt) if (unit->type == VVC_EOB_NUT || unit->type == VVC_EOS_NUT) { s->last_eos = 1; } else { - ret = decode_nal_unit(s, fc, nal, unit); + ret = decode_nal_unit(s, fc, avpkt->buf, nal, unit); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -908,16 +1078,48 @@ fail: return ret; } -static int set_output_format(const VVCContext *s, const AVFrame *output) +static int frame_end(VVCContext *s, VVCFrameContext *fc) { - AVCodecContext *c = s->avctx; + const AVFilmGrainParams *fgp; int ret; - if (output->width != c->width || output->height != c->height) { - if ((ret = ff_set_dimensions(c, output->width, output->height)) < 0) - return ret; + if (fc->ref->needs_fg) { + av_assert0(fc->ref->frame_grain->buf[0]); + fgp = av_film_grain_params_select(fc->ref->frame); + switch (fgp->type) { + case AV_FILM_GRAIN_PARAMS_NONE: + av_assert0(0); + return AVERROR_BUG; + case AV_FILM_GRAIN_PARAMS_H274: + ret = ff_h274_apply_film_grain(fc->ref->frame_grain, fc->ref->frame, + &s->h274db, fgp); + if (ret < 0) + return ret; + break; + case AV_FILM_GRAIN_PARAMS_AV1: + ret = ff_aom_apply_film_grain(fc->ref->frame_grain, fc->ref->frame, fgp); + if (ret < 0) + return ret; + break; + } } - c->pix_fmt = output->format; + + if (!s->avctx->hwaccel && s->avctx->err_recognition & AV_EF_CRCCHECK) { + VVCSEI *sei = &fc->sei; + if (sei->picture_hash.present) { + ret = ff_h274_hash_init(&s->hash_ctx, sei->picture_hash.hash_type); + if (ret < 0) + return ret; + + ret = ff_h274_hash_verify(s->hash_ctx, &sei->picture_hash, fc->ref->frame, fc->ps.pps->width, fc->ps.pps->height); + av_log(s->avctx, ret < 0 ? AV_LOG_ERROR : AV_LOG_DEBUG, + "Verifying checksum for frame with decode_order %d: %s\n", + (int)fc->decode_order, ret < 0 ? "incorrect": "correct"); + if (ret < 0 && (s->avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + } + } + return 0; } @@ -926,11 +1128,12 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) VVCFrameContext *delayed = get_frame_context(s, s->fcs, s->nb_frames - s->nb_delayed); int ret = ff_vvc_frame_wait(s, delayed); - if (!ret && delayed->output_frame->buf[0] && output) { - av_frame_move_ref(output, delayed->output_frame); - ret = set_output_format(s, output); - if (!ret) + if (!ret) { + ret = frame_end(s, delayed); + if (ret >= 0 && delayed->output_frame->buf[0] && output) { + av_frame_move_ref(output, delayed->output_frame); *got_output = 1; + } } s->nb_delayed--; @@ -939,17 +1142,26 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *output, int *got_output) { - int ret = ff_vvc_frame_submit(s, fc); + int ret; - if (ret < 0) { - ff_vvc_report_frame_finished(fc->ref); - return ret; + if (s->avctx->hwaccel) { + if (ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Hardware accelerator failed to decode picture\n"); + ff_vvc_unref_frame(fc, fc->ref, ~0); + return ret; + } + } else { + if (ret = ff_vvc_frame_submit(s, fc) < 0) { + ff_vvc_report_frame_finished(fc->ref); + return ret; + } } s->nb_frames++; s->nb_delayed++; - if (s->nb_delayed >= s->nb_fcs) { + if (s->nb_delayed >= s->nb_fcs || s->avctx->hwaccel) { if ((ret = wait_delayed_frame(s, output, got_output)) < 0) return ret; } @@ -972,11 +1184,7 @@ static int get_decoded_frame(VVCContext *s, AVFrame *output, int *got_output) ret = ff_vvc_output_frame(s, last, output, 0, 1); if (ret < 0) return ret; - if (ret) { - *got_output = ret; - if ((ret = set_output_format(s, output)) < 0) - return ret; - } + *got_output = ret; } return 0; } @@ -1000,7 +1208,7 @@ static int vvc_decode_frame(AVCodecContext *avctx, AVFrame *output, if (ret < 0) return ret; - if (!fc->ft) + if (!fc->ft || !fc->ref) return avpkt->size; ret = submit_frame(s, fc, output, got_output); @@ -1040,6 +1248,7 @@ static av_cold int vvc_decode_free(AVCodecContext *avctx) frame_context_free(s->fcs + i); av_free(s->fcs); } + ff_h274_hash_freep(&s->hash_ctx); ff_vvc_ps_uninit(&s->ps); ff_cbs_close(&s->cbc); @@ -1112,4 +1321,10 @@ const FFCodec ff_vvc_decoder = { .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, .p.profiles = NULL_IF_CONFIG_SMALL(ff_vvc_profiles), + .hw_configs = (const AVCodecHWConfigInternal *const []) { +#if CONFIG_VVC_VAAPI_HWACCEL + HWACCEL_VAAPI(vvc), +#endif + NULL + }, }; diff --git a/libavcodec/vvc/dec.h b/libavcodec/vvc/dec.h index d27cf52ca2..5f8065b38b 100644 --- a/libavcodec/vvc/dec.h +++ b/libavcodec/vvc/dec.h @@ -26,9 +26,11 @@ #include "libavcodec/videodsp.h" #include "libavcodec/vvc.h" +#include "libavcodec/h274.h" #include "ps.h" #include "dsp.h" +#include "sei.h" #define LUMA 0 #define CHROMA 1 @@ -70,12 +72,15 @@ typedef struct VVCWindow { typedef struct VVCFrame { struct AVFrame *frame; - + struct AVFrame *frame_grain; const VVCSPS *sps; ///< RefStruct reference const VVCPPS *pps; ///< RefStruct reference struct MvField *tab_dmvr_mvf; ///< RefStruct reference RefPicListTab **rpl_tab; ///< RefStruct reference RefPicListTab *rpl; ///< RefStruct reference + + int needs_fg; ///< 1 if grain needs to be applied by the decoder + int nb_rpl_elems; int ctb_count; @@ -101,6 +106,8 @@ typedef struct VVCFrame { * A combination of VVC_FRAME_FLAG_* */ uint8_t flags; + + void *hwaccel_picture_private; ///< hardware accelerator private data } VVCFrame; typedef struct SliceContext { @@ -122,6 +129,7 @@ typedef struct VVCFrameContext { struct AVFrame *output_frame; VVCFrameParamSets ps; + VVCSEI sei; SliceContext **slices; int nb_slices; @@ -136,11 +144,11 @@ typedef struct VVCFrameContext { uint64_t decode_order; - struct FFRefStructPool *tab_dmvr_mvf_pool; - struct FFRefStructPool *rpl_tab_pool; + struct AVRefStructPool *tab_dmvr_mvf_pool; + struct AVRefStructPool *rpl_tab_pool; - struct FFRefStructPool *cu_pool; - struct FFRefStructPool *tu_pool; + struct AVRefStructPool *cu_pool; + struct AVRefStructPool *tu_pool; struct { int16_t *slice_idx; @@ -159,9 +167,7 @@ typedef struct VVCFrameContext { uint8_t *skip; ///< CuSkipFlag[][] uint8_t *ispmf; ///< intra_sub_partitions_mode_flag uint8_t *msm[2]; ///< MttSplitMode[][][] in 32 pixels - uint8_t *imf; ///< IntraMipFlag[][] - uint8_t *imtf; ///< intra_mip_transposed_flag[][] - uint8_t *imm; ///< intra_mip_mode[][] + uint8_t *imf; ///< IntraMipFlag[][], intra_mip_transposed_flag[][], intra_mip_mode[][] uint8_t *ipm; ///< IntraPredModeY[][] uint8_t *cpm[2]; ///< CuPredMode[][][] uint8_t *msf; ///< MergeSubblockFlag[][] @@ -172,8 +178,6 @@ typedef struct VVCFrameContext { uint8_t *tu_coded_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< tu_y_coded_flag[][], tu_cb_coded_flag[][], tu_cr_coded_flag[][] uint8_t *tu_joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag[][] - int *tb_pos_x0[2]; - int *tb_pos_y0[2]; uint8_t *tb_width[2]; uint8_t *tb_height[2]; uint8_t *pcmf[2]; @@ -218,6 +222,7 @@ typedef struct VVCContext { CodedBitstreamFragment current_frame; VVCParamSets ps; + H274FilmGrainDatabase h274db; int temporal_id; ///< temporal_id_plus1 - 1 int poc_tid0; @@ -228,6 +233,7 @@ typedef struct VVCContext { enum VVCNALUnitType vcl_unit_type; int no_output_before_recovery_flag; ///< NoOutputBeforeRecoveryFlag int gdr_recovery_point_poc; ///< recoveryPointPocVal + int film_grain_warning_shown; /** * Sequence counters for decoded and output frames, so that old @@ -236,13 +242,15 @@ typedef struct VVCContext { uint16_t seq_decode; uint16_t seq_output; - struct AVExecutor *executor; + struct FFExecutor *executor; VVCFrameContext *fcs; int nb_fcs; uint64_t nb_frames; ///< processed frames int nb_delayed; ///< delayed frames + + H274HashContext *hash_ctx; } VVCContext ; #endif /* AVCODEC_VVC_DEC_H */ diff --git a/libavcodec/vvc/dsp.c b/libavcodec/vvc/dsp.c index 433353c32c..af392f2754 100644 --- a/libavcodec/vvc/dsp.c +++ b/libavcodec/vvc/dsp.c @@ -44,6 +44,15 @@ static int vvc_sad(const int16_t *src0, const int16_t *src1, int dx, int dy, return sad; } +static av_always_inline void unpack_mip_info(int *intra_mip_transposed_flag, + int *intra_mip_mode, const uint8_t mip_info) +{ + if (intra_mip_transposed_flag) + *intra_mip_transposed_flag = (mip_info >> 1) & 0x1; + if (intra_mip_mode) + *intra_mip_mode = (mip_info >> 2) & 0xf; +} + typedef struct IntraEdgeParams { uint8_t* top; uint8_t* left; @@ -102,6 +111,8 @@ void ff_vvc_dsp_init(VVCDSPContext *vvcdsp, int bit_depth) #if ARCH_AARCH64 ff_vvc_dsp_init_aarch64(vvcdsp, bit_depth); +#elif ARCH_RISCV + ff_vvc_dsp_init_riscv(vvcdsp, bit_depth); #elif ARCH_X86 ff_vvc_dsp_init_x86(vvcdsp, bit_depth); #endif diff --git a/libavcodec/vvc/dsp.h b/libavcodec/vvc/dsp.h index 635ebcafed..ae22900931 100644 --- a/libavcodec/vvc/dsp.h +++ b/libavcodec/vvc/dsp.h @@ -106,7 +106,7 @@ struct VVCLocalContext; typedef struct VVCIntraDSPContext { void (*intra_cclm_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h); - void (*lmcs_scale_chroma)(struct VVCLocalContext *lc, int *dst, const int *coeff, int w, int h, int x0_cu, int y0_cu); + void (*lmcs_scale_chroma)(struct VVCLocalContext *lc, int *coeff, int w, int h, int x0_cu, int y0_cu); void (*intra_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h, int c_idx); void (*pred_planar)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride); void (*pred_mip)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride, @@ -122,11 +122,12 @@ typedef struct VVCIntraDSPContext { typedef struct VVCItxDSPContext { void (*add_residual)(uint8_t *dst, const int *res, int width, int height, ptrdiff_t stride); - void (*add_residual_joint)(uint8_t *dst, const int *res, int width, int height, ptrdiff_t stride, int c_sign, int shift); - void (*pred_residual_joint)(int *buf, int width, int height, int c_sign, int shift); + void (*pred_residual_joint)(int *dst, const int *src, int width, int height, int c_sign, int shift); void (*itx[VVC_N_TX_TYPE][VVC_N_TX_SIZE])(int *coeffs, ptrdiff_t step, size_t nz); void (*transform_bdpcm)(int *coeffs, int width, int height, int vertical, int log2_transform_range); + + void (*adaptive_color_transform)(int *y, int *u, int *v, int width, int height); } VVCItxDSPContext; typedef struct VVCLMCSDSPContext { @@ -179,6 +180,7 @@ typedef struct VVCDSPContext { void ff_vvc_dsp_init(VVCDSPContext *hpc, int bit_depth); void ff_vvc_dsp_init_aarch64(VVCDSPContext *hpc, const int bit_depth); +void ff_vvc_dsp_init_riscv(VVCDSPContext *hpc, const int bit_depth); void ff_vvc_dsp_init_x86(VVCDSPContext *hpc, const int bit_depth); #endif /* AVCODEC_VVC_DSP_H */ diff --git a/libavcodec/vvc/dsp_template.c b/libavcodec/vvc/dsp_template.c index 1aa1e027bd..13bd8cd4a1 100644 --- a/libavcodec/vvc/dsp_template.c +++ b/libavcodec/vvc/dsp_template.c @@ -45,32 +45,12 @@ static void FUNC(add_residual)(uint8_t *_dst, const int *res, } } -static void FUNC(add_residual_joint)(uint8_t *_dst, const int *res, - const int w, const int h, const ptrdiff_t _stride, const int c_sign, const int shift) -{ - pixel *dst = (pixel *)_dst; - - const int stride = _stride / sizeof(pixel); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - const int r = ((*res) * c_sign) >> shift; - dst[x] = av_clip_pixel(dst[x] + r); - res++; - } - dst += stride; - } -} - -static void FUNC(pred_residual_joint)(int *buf, const int w, const int h, +static void FUNC(pred_residual_joint)(int *dst, const int *src, const int w, const int h, const int c_sign, const int shift) { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - *buf = ((*buf) * c_sign) >> shift; - buf++; - } - } + const int size = w * h; + for (int i = 0; i < size; i++) + dst[i] = (src[i] * c_sign) >> shift; } static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height, @@ -94,6 +74,24 @@ static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height } } +// 8.7.4.6 Residual modification process for blocks using colour space conversion +static void FUNC(adaptive_color_transform)(int *y, int *u, int *v, const int width, const int height) +{ + const int size = width * height; + const int bits = BIT_DEPTH + 1; + + for (int i = 0; i < size; i++) { + const int y0 = av_clip_intp2(y[i], bits); + const int cg = av_clip_intp2(u[i], bits); + const int co = av_clip_intp2(v[i], bits); + const int t = y0 - (cg >> 1); + + y[i] = cg + t; + u[i] = t - (co >> 1); + v[i] = co + u[i]; + } +} + static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) { #define VVC_ITX(TYPE, type, s) \ @@ -106,7 +104,6 @@ static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) VVC_ITX(TYPE, type, 32); itx->add_residual = FUNC(add_residual); - itx->add_residual_joint = FUNC(add_residual_joint); itx->pred_residual_joint = FUNC(pred_residual_joint); itx->transform_bdpcm = FUNC(transform_bdpcm); VVC_ITX(DCT2, dct2, 2) @@ -115,6 +112,8 @@ static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) VVC_ITX_COMMON(DCT8, dct8) VVC_ITX_COMMON(DST7, dst7) + itx->adaptive_color_transform = FUNC(adaptive_color_transform); + #undef VVC_ITX #undef VVC_ITX_COMMON } diff --git a/libavcodec/vvc/filter.c b/libavcodec/vvc/filter.c index 25bef45eed..3815668bcf 100644 --- a/libavcodec/vvc/filter.c +++ b/libavcodec/vvc/filter.c @@ -385,6 +385,9 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con { RefPicList *rpl = lc->sc->rpl; + if (curr->pred_flag == PF_PLT) + return 0; + if (curr->pred_flag == PF_IBC) return FFABS(neigh->mv[0].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 8; @@ -451,15 +454,15 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con //part of 8.8.3.3 Derivation process of transform block boundary static void derive_max_filter_length_luma(const VVCFrameContext *fc, const int qx, const int qy, - const int is_intra, const int has_subblock, const int vertical, uint8_t *max_len_p, uint8_t *max_len_q) + const int size_q, const int has_subblock, const int vertical, uint8_t *max_len_p, uint8_t *max_len_q) { const int px = vertical ? qx - 1 : qx; const int py = !vertical ? qy - 1 : qy; const uint8_t *tb_size = vertical ? fc->tab.tb_width[LUMA] : fc->tab.tb_height[LUMA]; const int size_p = tb_size[(py >> MIN_TU_LOG2) * fc->ps.pps->min_tu_width + (px >> MIN_TU_LOG2)]; - const int size_q = tb_size[(qy >> MIN_TU_LOG2) * fc->ps.pps->min_tu_width + (qx >> MIN_TU_LOG2)]; const int min_cb_log2 = fc->ps.sps->min_cb_log2_size_y; const int off_p = (py >> min_cb_log2) * fc->ps.pps->min_cb_width + (px >> min_cb_log2); + if (size_p <= 4 || size_q <= 4) { *max_len_p = *max_len_q = 1; } else { @@ -525,7 +528,7 @@ static void vvc_deblock_subblock_bs(const VVCLocalContext *lc, } static av_always_inline int deblock_bs(const VVCLocalContext *lc, - const int x_p, const int y_p, const int x_q, const int y_q, + const int x_p, const int y_p, const int x_q, const int y_q, const CodingUnit *cu, const TransformUnit *tu, const RefPicList *rpl_p, const int c_idx, const int off_to_cb, const uint8_t has_sub_block) { const VVCFrameContext *fc = lc->fc; @@ -542,12 +545,10 @@ static av_always_inline int deblock_bs(const VVCLocalContext *lc, const MvField *mvf_q = &tab_mvf[pu_q]; const uint8_t chroma = !!c_idx; const int tu_p = (y_p >> log2_min_tu_size) * min_tu_width + (x_p >> log2_min_tu_size); - const int tu_q = (y_q >> log2_min_tu_size) * min_tu_width + (x_q >> log2_min_tu_size); - const uint8_t pcmf = fc->tab.pcmf[chroma][tu_p] && fc->tab.pcmf[chroma][tu_q]; const int cb_p = (y_p >> log2_min_cb_size) * min_cb_width + (x_p >> log2_min_cb_size); - const int cb_q = (y_q >> log2_min_cb_size) * min_cb_width + (x_q >> log2_min_cb_size); - const uint8_t intra = fc->tab.cpm[chroma][cb_p] == MODE_INTRA || fc->tab.cpm[chroma][cb_q] == MODE_INTRA; - const uint8_t same_mode = fc->tab.cpm[chroma][cb_p] == fc->tab.cpm[chroma][cb_q]; + const uint8_t pcmf = fc->tab.pcmf[chroma][cb_p] && cu->bdpcm_flag[chroma]; + const uint8_t intra = fc->tab.cpm[chroma][cb_p] == MODE_INTRA || cu->pred_mode == MODE_INTRA; + const uint8_t same_mode = fc->tab.cpm[chroma][cb_p] == cu->pred_mode; if (pcmf) return 0; @@ -557,12 +558,12 @@ static av_always_inline int deblock_bs(const VVCLocalContext *lc, if (chroma) { return fc->tab.tu_coded_flag[c_idx][tu_p] || - fc->tab.tu_coded_flag[c_idx][tu_q] || fc->tab.tu_joint_cbcr_residual_flag[tu_p] || - fc->tab.tu_joint_cbcr_residual_flag[tu_q]; + tu->coded_flag[c_idx] || + tu->joint_cbcr_residual_flag; } - if (fc->tab.tu_coded_flag[LUMA][tu_p] || fc->tab.tu_coded_flag[LUMA][tu_q]) + if (fc->tab.tu_coded_flag[LUMA][tu_p] || tu->coded_flag[LUMA]) return 1; if ((off_to_cb && ((off_to_cb % 8) || !has_sub_block))) @@ -606,27 +607,23 @@ static int deblock_is_boundary(const VVCLocalContext *lc, const int boundary, } static void vvc_deblock_bs_luma(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height, const int rs, const int vertical) + const int x0, const int y0, const int width, const int height, + const CodingUnit *cu, const TransformUnit *tu, int rs, const int vertical) { - const VVCFrameContext *fc = lc->fc; - const MvField *tab_mvf = fc->tab.mvf; - const int mask = LUMA_GRID - 1; - const int log2_min_pu_size = MIN_PU_LOG2; - const int min_pu_width = fc->ps.pps->min_pu_width; - const int min_cb_log2 = fc->ps.sps->min_cb_log2_size_y; - const int min_cb_width = fc->ps.pps->min_cb_width; - const int pos = vertical ? x0 : y0; - const int off_q = (y0 >> min_cb_log2) * min_cb_width + (x0 >> min_cb_log2); - const int cb = (vertical ? fc->tab.cb_pos_x : fc->tab.cb_pos_y )[LUMA][off_q]; - const int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width + - (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &cu->pu; + const int mask = LUMA_GRID - 1; + const int pos = vertical ? x0 : y0; + const int cb = vertical ? cu->x0 : cu->y0; + const int is_intra = cu->pred_mode == MODE_INTRA; + const int cb_size = vertical ? cu->cb_width : cu->cb_height; + const int has_sb = !is_intra && (pu->merge_subblock_flag || pu->inter_affine_flag) && cb_size > 8; if (deblock_is_boundary(lc, pos > 0 && !(pos & mask), pos, rs, vertical)) { const int is_vb = is_virtual_boundary(fc, pos, vertical); const int size = vertical ? height : width; + const int size_q = vertical ? width : height; const int off = cb - pos; - const int cb_size = (vertical ? fc->tab.cb_width : fc->tab.cb_height)[LUMA][off_q]; - const int has_sb = !is_intra && (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) && cb_size > 8; const int flag = vertical ? BOUNDARY_LEFT_SLICE : BOUNDARY_UPPER_SLICE; const RefPicList *rpl_p = (lc->boundary_flags & flag) ? ff_vvc_get_ref_list(fc, fc->ref, x0 - vertical, y0 - !vertical) : lc->sc->rpl; @@ -635,24 +632,23 @@ static void vvc_deblock_bs_luma(const VVCLocalContext *lc, const int x = x0 + i * !vertical; const int y = y0 + i * vertical; uint8_t max_len_p, max_len_q; - const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, rpl_p, LUMA, off, has_sb); + const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, cu, tu, rpl_p, LUMA, off, has_sb); TAB_BS(fc->tab.bs[vertical][LUMA], x, y) = bs; - derive_max_filter_length_luma(fc, x, y, is_intra, has_sb, vertical, &max_len_p, &max_len_q); + derive_max_filter_length_luma(fc, x, y, size_q, has_sb, vertical, &max_len_p, &max_len_q); TAB_MAX_LEN(fc->tab.max_len_p[vertical], x, y) = max_len_p; TAB_MAX_LEN(fc->tab.max_len_q[vertical], x, y) = max_len_q; } } - if (!is_intra) { - if (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) - vvc_deblock_subblock_bs(lc, cb, x0, y0, width, height, vertical); - } + if (has_sb) + vvc_deblock_subblock_bs(lc, cb, x0, y0, width, height, vertical); } static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height, const int rs, const int vertical) + const int x0, const int y0, const int width, const int height, + const CodingUnit *cu, const TransformUnit *tu, const int rs, const int vertical) { const VVCFrameContext *fc = lc->fc; const int shift = (vertical ? fc->ps.sps->hshift : fc->ps.sps->vshift)[CHROMA]; @@ -667,7 +663,7 @@ static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, for (int i = 0; i < size; i += 2) { const int x = x0 + i * !vertical; const int y = y0 + i * vertical; - const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, NULL, c_idx, 0, 0); + const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, cu, tu, NULL, c_idx, 0, 0); TAB_BS(fc->tab.bs[vertical][c_idx], x, y) = bs; } @@ -678,28 +674,24 @@ static void vvc_deblock_bs_chroma(const VVCLocalContext *lc, typedef void (*deblock_bs_fn)(const VVCLocalContext *lc, const int x0, const int y0, const int width, const int height, const int rs, const int vertical); -static void vvc_deblock_bs(const VVCLocalContext *lc, const int x0, const int y0, const int rs, const int vertical) +void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs) { const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; - const VVCPPS *pps = fc->ps.pps; - const int ctb_size = sps->ctb_size_y; - const int x_end = FFMIN(x0 + ctb_size, pps->width) >> MIN_TU_LOG2; - const int y_end = FFMIN(y0 + ctb_size, pps->height) >> MIN_TU_LOG2; - const int has_chroma = !!sps->r->sps_chroma_format_idc; - deblock_bs_fn deblock_bs[] = { - vvc_deblock_bs_luma, vvc_deblock_bs_chroma - }; + const int x0 = rx << sps->ctb_log2_size_y; + const int y0 = ry << sps->ctb_log2_size_y; - for (int is_chroma = 0; is_chroma <= has_chroma; is_chroma++) { - const int hs = sps->hshift[is_chroma]; - const int vs = sps->vshift[is_chroma]; - for (int y = y0 >> MIN_TU_LOG2; y < y_end; y++) { - for (int x = x0 >> MIN_TU_LOG2; x < x_end; x++) { - const int off = y * fc->ps.pps->min_tu_width + x; - if ((fc->tab.tb_pos_x0[is_chroma][off] >> MIN_TU_LOG2) == x && (fc->tab.tb_pos_y0[is_chroma][off] >> MIN_TU_LOG2) == y) { - deblock_bs[is_chroma](lc, x << MIN_TU_LOG2, y << MIN_TU_LOG2, - fc->tab.tb_width[is_chroma][off] << hs, fc->tab.tb_height[is_chroma][off] << vs, rs, vertical); + ff_vvc_decode_neighbour(lc, x0, y0, rx, ry, rs); + for (const CodingUnit *cu = fc->tab.cus[rs]; cu; cu = cu->next) { + for (const TransformUnit *tu = cu->tus.head; tu; tu = tu->next) { + for (int vertical = 0; vertical <= 1; vertical++) { + if (tu->avail[LUMA]) + vvc_deblock_bs_luma(lc, tu->x0, tu->y0, tu->width, tu->height, cu, tu, rs, vertical); + if (tu->avail[CHROMA]) { + if (cu->isp_split_type != ISP_NO_SPLIT && cu->tree_type == SINGLE_TREE) + vvc_deblock_bs_chroma(lc, cu->x0, cu->y0, cu->cb_width, cu->cb_height, cu, tu, rs, vertical); + else + vvc_deblock_bs_chroma(lc, tu->x0, tu->y0, tu->width, tu->height, cu, tu, rs, vertical); } } } @@ -783,19 +775,15 @@ static int get_qp(const VVCFrameContext *fc, const uint8_t *src, const int x, co static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, const int vertical) { - VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; - const int ctb_size = fc->ps.sps->ctb_size_y; - const DBParams *params = fc->tab.deblock + rs; - int x_end = FFMIN(x0 + ctb_size, fc->ps.pps->width); - int y_end = FFMIN(y0 + ctb_size, fc->ps.pps->height); - - //not use this yet, may needed by plt. - const uint8_t no_p[4] = { 0 }; - const uint8_t no_q[4] = { 0 } ; - - vvc_deblock_bs(lc, x0, y0, rs, vertical); + VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; + const int ctb_size = fc->ps.sps->ctb_size_y; + const DBParams *params = fc->tab.deblock + rs; + int x_end = FFMIN(x0 + ctb_size, fc->ps.pps->width); + int y_end = FFMIN(y0 + ctb_size, fc->ps.pps->height); + const int log2_min_cb_size = fc->ps.sps->min_cb_log2_size_y; + const int min_cb_width = fc->ps.pps->min_cb_width; if (!vertical) { FFSWAP(int, x_end, y_end); @@ -815,6 +803,8 @@ static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, const uint8_t horizontal_ctu_edge = !vertical && !(x % ctb_size); int32_t bs[4], beta[4], tc[4] = { 0 }, all_zero_bs = 1; uint8_t max_len_p[4], max_len_q[4]; + uint8_t no_p[4] = { 0 }; + uint8_t no_q[4] = { 0 }; for (int i = 0; i < DEBLOCK_STEP >> (2 - vs); i++) { int tx = x; @@ -831,6 +821,13 @@ static void vvc_deblock(const VVCLocalContext *lc, int x0, int y0, const int rs, tc[i] = TC_CALC(qp, bs[i]) ; max_filter_length(fc, tx, ty, c_idx, vertical, horizontal_ctu_edge, bs[i], &max_len_p[i], &max_len_q[i]); all_zero_bs = 0; + + if (sps->r->sps_palette_enabled_flag) { + const int cu_q = (ty >> log2_min_cb_size) * min_cb_width + (tx >> log2_min_cb_size); + const int cu_p = (ty - !vertical >> log2_min_cb_size) * min_cb_width + (tx - vertical >> log2_min_cb_size); + no_q[i] = fc->tab.cpm[!!c_idx][cu_q] == MODE_PLT; + no_p[i] = cu_p >= 0 && fc->tab.cpm[!!c_idx][cu_p] == MODE_PLT; + } } } diff --git a/libavcodec/vvc/filter.h b/libavcodec/vvc/filter.h index 03cc74e071..29abbd98ce 100644 --- a/libavcodec/vvc/filter.h +++ b/libavcodec/vvc/filter.h @@ -33,6 +33,15 @@ */ void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x0, const int y0); +/** + * derive boundary strength for the CTU + * @param lc local context for CTU + * @param rx raster x position for the CTU + * @param ry raster y position for the CTU + * @param rs raster position for the CTU + */ +void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs); + /** * vertical deblock filter for the CTU * @param lc local context for CTU diff --git a/libavcodec/vvc/inter_template.c b/libavcodec/vvc/inter_template.c index c073a73e76..aee4994c17 100644 --- a/libavcodec/vvc/inter_template.c +++ b/libavcodec/vvc/inter_template.c @@ -472,6 +472,9 @@ static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, const i (filter[0] * src[x] + \ filter[1] * src[x + stride]) +#define DMVR_FILTER2(filter, src0, src1) \ + (filter[0] * src0 + filter[1] * src1) + //8.5.3.2.2 Luma sample bilinear interpolation process static void FUNC(dmvr)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, const int height, const intptr_t mx, const intptr_t my, const int width) @@ -541,31 +544,31 @@ static void FUNC(dmvr_v)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src static void FUNC(dmvr_hv)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride, const int height, const intptr_t mx, const intptr_t my, const int width) { - int16_t tmp_array[(MAX_PB_SIZE + BILINEAR_EXTRA) * MAX_PB_SIZE]; - int16_t *tmp = tmp_array; + int16_t tmp_array[MAX_PB_SIZE * 2]; + int16_t *tmp0 = tmp_array; + int16_t *tmp1 = tmp_array + MAX_PB_SIZE; const pixel *src = (const pixel*)_src; const ptrdiff_t src_stride = _src_stride / sizeof(pixel); - const int8_t *filter = ff_vvc_inter_luma_dmvr_filters[mx]; + const int8_t *filter_x = ff_vvc_inter_luma_dmvr_filters[mx]; + const int8_t *filter_y = ff_vvc_inter_luma_dmvr_filters[my]; const int shift1 = BIT_DEPTH - 6; const int offset1 = 1 << (shift1 - 1); const int shift2 = 4; const int offset2 = 1 << (shift2 - 1); src -= BILINEAR_EXTRA_BEFORE * src_stride; - for (int y = 0; y < height + BILINEAR_EXTRA; y++) { - for (int x = 0; x < width; x++) - tmp[x] = (DMVR_FILTER(src, 1) + offset1) >> shift1; - src += src_stride; - tmp += MAX_PB_SIZE; - } + for (int x = 0; x < width; x++) + tmp0[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1; + src += src_stride; - tmp = tmp_array + BILINEAR_EXTRA_BEFORE * MAX_PB_SIZE; - filter = ff_vvc_inter_luma_dmvr_filters[my]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) - dst[x] = (DMVR_FILTER(tmp, MAX_PB_SIZE) + offset2) >> shift2; - tmp += MAX_PB_SIZE; + for (int y = 1; y < height + BILINEAR_EXTRA; y++) { + for (int x = 0; x < width; x++) { + tmp1[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1; + dst[x] = (DMVR_FILTER2(filter_y, tmp0[x], tmp1[x]) + offset2) >> shift2; + } + src += src_stride; dst += MAX_PB_SIZE; + FFSWAP(int16_t *, tmp0, tmp1); } } diff --git a/libavcodec/vvc/intra.c b/libavcodec/vvc/intra.c index 41ed89c946..52a138ef1c 100644 --- a/libavcodec/vvc/intra.c +++ b/libavcodec/vvc/intra.c @@ -27,6 +27,10 @@ #include "intra.h" #include "itx_1d.h" +#define POS(c_idx, x, y) \ + &fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \ + (((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)] + static int is_cclm(enum IntraPredMode mode) { return mode == INTRA_LT_CCLM || mode == INTRA_L_CCLM || mode == INTRA_T_CCLM; @@ -164,28 +168,6 @@ static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalConte *trv = mts_to_trv[cu->mts_idx]; } -static void add_residual_for_joint_coding_chroma(VVCLocalContext *lc, - const TransformUnit *tu, TransformBlock *tb, const int chroma_scale) -{ - const VVCFrameContext *fc = lc->fc; - const CodingUnit *cu = lc->cu; - const int c_sign = 1 - 2 * fc->ps.ph.r->ph_joint_cbcr_sign_flag; - const int shift = tu->coded_flag[1] ^ tu->coded_flag[2]; - const int c_idx = 1 + tu->coded_flag[1]; - const ptrdiff_t stride = fc->frame->linesize[c_idx]; - const int hs = fc->ps.sps->hshift[c_idx]; - const int vs = fc->ps.sps->vshift[c_idx]; - uint8_t *dst = &fc->frame->data[c_idx][(tb->y0 >> vs) * stride + - ((tb->x0 >> hs) << fc->ps.sps->pixel_shift)]; - if (chroma_scale) { - fc->vvcdsp.itx.pred_residual_joint(tb->coeffs, tb->tb_width, tb->tb_height, c_sign, shift); - fc->vvcdsp.intra.lmcs_scale_chroma(lc, tb->coeffs, tb->coeffs, tb->tb_width, tb->tb_height, cu->x0, cu->y0); - fc->vvcdsp.itx.add_residual(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride); - } else { - fc->vvcdsp.itx.add_residual_joint(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride, c_sign, shift); - } -} - static int add_reconstructed_area(VVCLocalContext *lc, const int ch_type, const int x0, const int y0, const int w, const int h) { const VVCSPS *sps = lc->fc->ps.sps; @@ -303,21 +285,15 @@ static void scale(int *out, const int *in, const int w, const int h, const int s // part of 8.7.3 Scaling process for transform coefficients static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb) { - const VVCSPS *sps = lc->fc->ps.sps; - const H266RawSliceHeader *rsh = lc->sc->sh.r; - const CodingUnit *cu = lc->cu; - int qp, qp_act_offset; + const VVCSPS *sps = lc->fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const CodingUnit *cu = lc->cu; + const bool is_jcbcr = tb->c_idx && tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR]; + const int idx = is_jcbcr ? JCBCR : tb->c_idx; + const int qp = cu->qp[idx] + (idx ? 0 : sps->qp_bd_offset); + const int act_offset[] = { -5, 1, 3, 1 }; + const int qp_act_offset = cu->act_enabled_flag ? act_offset[idx] : 0; - if (tb->c_idx == 0) { - //fix me - qp = cu->qp[LUMA] + sps->qp_bd_offset; - qp_act_offset = cu->act_enabled_flag ? -5 : 0; - } else { - const int is_jcbcr = tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR]; - const int idx = is_jcbcr ? JCBCR : tb->c_idx; - qp = cu->qp[idx]; - qp_act_offset = cu->act_enabled_flag ? 1 : 0; - } if (tb->ts) { const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts; @@ -336,29 +312,30 @@ static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, Transf tb->bd_offset = (1 << tb->bd_shift) >> 1; } +static const uint8_t rem6[63 + 8 * 6 + 1] = { + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, +}; + +static const uint8_t div6[63 + 8 * 6 + 1] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, +}; + +const static int level_scale[2][6] = { + { 40, 45, 51, 57, 64, 72 }, + { 57, 64, 72, 80, 90, 102 } +}; + //8.7.3 Scaling process for transform coefficients static av_always_inline int derive_scale(const TransformBlock *tb, const int sh_dep_quant_used_flag) { - static const uint8_t rem6[63 + 8 * 6 + 1] = { - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, - }; - - static const uint8_t div6[63 + 8 * 6 + 1] = { - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, - 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, - 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, - }; - - const static int level_scale[2][6] = { - { 40, 45, 51, 57, 64, 72 }, - { 57, 64, 72, 80, 90, 102 } - }; const int addin = sh_dep_quant_used_flag && !tb->ts; const int qp = tb->qp + addin; @@ -390,10 +367,10 @@ static const uint8_t* derive_scale_m(const VVCLocalContext *lc, const TransformB const int log2_matrix_size = (id < 2) ? 1 : (id < 8) ? 2 : 3; uint8_t *p = scale_m; - av_assert0(!sps->r->sps_scaling_matrix_for_alternative_colour_space_disabled_flag); - if (!rsh->sh_explicit_scaling_list_used_flag || tb->ts || - sps->r->sps_scaling_matrix_for_lfnst_disabled_flag && cu->apply_lfnst_flag[tb->c_idx]) + (sps->r->sps_scaling_matrix_for_lfnst_disabled_flag && cu->apply_lfnst_flag[tb->c_idx]) || + (sps->r->sps_scaling_matrix_for_alternative_colour_space_disabled_flag && + sps->r->sps_scaling_matrix_designated_colour_space_flag == cu->act_enabled_flag)) return ff_vvc_default_scale_m; if (!sl) { @@ -515,29 +492,67 @@ static void transform_bdpcm(TransformBlock *tb, const VVCLocalContext *lc, const tb->max_scan_x = tb->tb_width - 1; } -static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int tu_idx, const int target_ch_type) +static void lmcs_scale_chroma(VVCLocalContext *lc, TransformUnit *tu, TransformBlock *tb, const int target_ch_type) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const VVCSH *sh = &lc->sc->sh; - const CodingUnit *cu = lc->cu; - const int ps = fc->ps.sps->pixel_shift; - DECLARE_ALIGNED(32, int, temp)[MAX_TB_SIZE * MAX_TB_SIZE]; + const VVCFrameContext *fc = lc->fc; + const VVCSH *sh = &lc->sc->sh; + const CodingUnit *cu = lc->cu; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const int w = tb->tb_width; + const int h = tb->tb_height; + const int chroma_scale = ch_type && sh->r->sh_lmcs_used_flag && fc->ps.ph.r->ph_chroma_residual_scale_flag && (w * h > 4); + const int has_jcbcr = tu->joint_cbcr_residual_flag && c_idx; + + for (int j = 0; j < 1 + has_jcbcr; j++) { + const bool is_jcbcr = j > 0; + const int jcbcr_idx = CB + tu->coded_flag[CB]; + TransformBlock *jcbcr = &tu->tbs[jcbcr_idx - tu->tbs[0].c_idx]; + int *coeffs = is_jcbcr ? jcbcr->coeffs : tb->coeffs; + + if (!j && has_jcbcr) { + const int c_sign = 1 - 2 * fc->ps.ph.r->ph_joint_cbcr_sign_flag; + const int shift = tu->coded_flag[CB] ^ tu->coded_flag[CR]; + fc->vvcdsp.itx.pred_residual_joint(jcbcr->coeffs, tb->coeffs, w, h, c_sign, shift); + } + if (chroma_scale) + fc->vvcdsp.intra.lmcs_scale_chroma(lc, coeffs, w, h, cu->x0, cu->y0); + } +} + +static void add_residual(const VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; for (int i = 0; i < tu->nb_tbs; i++) { - TransformBlock *tb = &tu->tbs[i]; - const int c_idx = tb->c_idx; - const int ch_type = c_idx > 0; + TransformBlock *tb = tu->tbs + i; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const ptrdiff_t stride = fc->frame->linesize[c_idx]; + const bool has_residual = tb->has_coeffs || cu->act_enabled_flag || + (c_idx && tu->joint_cbcr_residual_flag); + uint8_t *dst = POS(c_idx, tb->x0, tb->y0); - if (ch_type == target_ch_type && tb->has_coeffs) { - const int w = tb->tb_width; - const int h = tb->tb_height; - const int chroma_scale = ch_type && sh->r->sh_lmcs_used_flag && fc->ps.ph.r->ph_chroma_residual_scale_flag && (w * h > 4); - const ptrdiff_t stride = fc->frame->linesize[c_idx]; - const int hs = sps->hshift[c_idx]; - const int vs = sps->vshift[c_idx]; - uint8_t *dst = &fc->frame->data[c_idx][(tb->y0 >> vs) * stride + ((tb->x0 >> hs) << ps)]; + if (ch_type == target_ch_type && has_residual) + fc->vvcdsp.itx.add_residual(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride); + } +} +static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + TransformBlock *tbs = tu->tbs; + const bool is_act_luma = cu->act_enabled_flag && target_ch_type == LUMA; + + for (int i = 0; i < tu->nb_tbs; i++) { + TransformBlock *tb = tbs + i; + const int c_idx = tb->c_idx; + const int ch_type = c_idx > 0; + const bool do_itx = is_act_luma || !cu->act_enabled_flag && ch_type == target_ch_type; + + if (tb->has_coeffs && do_itx) { if (cu->bdpcm_flag[tb->c_idx]) transform_bdpcm(tb, lc, cu); dequant(lc, tu, tb); @@ -547,22 +562,22 @@ static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int tu_idx, if (cu->apply_lfnst_flag[c_idx]) ilfnst_transform(lc, tb); derive_transform_type(fc, lc, tb, &trh, &trv); - if (w > 1 && h > 1) + if (tb->tb_width > 1 && tb->tb_height > 1) itx_2d(fc, tb, trh, trv); else itx_1d(fc, tb, trh, trv); } - - if (chroma_scale) - fc->vvcdsp.intra.lmcs_scale_chroma(lc, temp, tb->coeffs, w, h, cu->x0, cu->y0); - // TODO: Address performance issue here by combining transform, lmcs_scale_chroma, and add_residual into one function. - // Complete this task before implementing ASM code. - fc->vvcdsp.itx.add_residual(dst, chroma_scale ? temp : tb->coeffs, w, h, stride); - - if (tu->joint_cbcr_residual_flag && tb->c_idx) - add_residual_for_joint_coding_chroma(lc, tu, tb, chroma_scale); + lmcs_scale_chroma(lc, tu, tb, target_ch_type); } } + + if (is_act_luma) { + fc->vvcdsp.itx.adaptive_color_transform( + tbs[LUMA].coeffs, tbs[CB].coeffs, tbs[CR].coeffs, + tbs[LUMA].tb_width, tbs[LUMA].tb_height); + } + + add_residual(lc, tu, target_ch_type); } static int reconstruct(VVCLocalContext *lc) @@ -576,17 +591,13 @@ static int reconstruct(VVCLocalContext *lc) TransformUnit *tu = cu->tus.head; for (int i = 0; tu; i++) { predict_intra(lc, tu, i, ch_type); - itransform(lc, tu, i, ch_type); + itransform(lc, tu, ch_type); tu = tu->next; } } return 0; } -#define POS(c_idx, x, y) \ - &fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \ - (((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)] - #define IBC_POS(c_idx, x, y) \ (fc->tab.ibc_vir_buf[c_idx] + \ (x << ps) + (y + ((cu->y0 & ~(sps->ctb_size_y - 1)) >> vs)) * ibc_stride) @@ -639,11 +650,11 @@ static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu) { const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; - const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; - const int start = cu->tree_type == DUAL_TREE_CHROMA; - const int end = has_chroma ? CR : LUMA; + int start, end; - for (int c_idx = start; c_idx <= end; c_idx++) { + ff_vvc_channel_range(&start, &end, cu->tree_type, sps->r->sps_chroma_format_idc); + + for (int c_idx = start; c_idx < end; c_idx++) { const int hs = sps->hshift[c_idx]; const int vs = sps->vshift[c_idx]; const int ps = sps->pixel_shift; @@ -658,6 +669,38 @@ static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu) } } +int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb) +{ + const VVCSPS *sps = lc->fc->ps.sps; + const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts; + int qp; + + derive_qp(lc, tu, tb); + qp = FFMAX(qp_prime_ts_min, tb->qp); + return level_scale[0][rem6[qp]] << div6[qp]; +} + +// 8.4.5.3 Decoding process for palette mode +static void vvc_predict_palette(VVCLocalContext *lc) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + TransformUnit *tu = cu->tus.head; + const VVCSPS *sps = fc->ps.sps; + const int ps = sps->pixel_shift; + + for (int i = 0; i < tu->nb_tbs; i++) { + TransformBlock *tb = &tu->tbs[i]; + const int c_idx = tb->c_idx; + const int w = tb->tb_width; + const int h = tb->tb_height; + const ptrdiff_t stride = fc->frame->linesize[c_idx]; + uint8_t *dst = POS(c_idx, cu->x0, cu->y0); + + av_image_copy_plane(dst, stride, (uint8_t*)tb->coeffs, w << ps, w << ps, h); + } +} + int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry) { const VVCFrameContext *fc = lc->fc; @@ -678,6 +721,8 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in ff_vvc_predict_ciip(lc); else if (cu->pred_mode == MODE_IBC) vvc_predict_ibc(lc); + else if (cu->pred_mode == MODE_PLT) + vvc_predict_palette(lc); if (cu->coded_flag) { ret = reconstruct(lc); } else { @@ -693,4 +738,3 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in ff_vvc_ctu_free_cus(fc->tab.cus + rs); return ret; } - diff --git a/libavcodec/vvc/intra.h b/libavcodec/vvc/intra.h index 8a02699135..1201c70836 100644 --- a/libavcodec/vvc/intra.h +++ b/libavcodec/vvc/intra.h @@ -45,5 +45,6 @@ int ff_vvc_intra_pred_angle_derive(int pred_mode); int ff_vvc_intra_inv_angle_derive(int pred_mode); int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu, int tb_width, int tb_height, int c_idx, int pred_mode_intra); +int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb); #endif // AVCODEC_VVC_INTRA_H diff --git a/libavcodec/vvc/intra_template.c b/libavcodec/vvc/intra_template.c index 62342c8142..3ec6c72213 100644 --- a/libavcodec/vvc/intra_template.c +++ b/libavcodec/vvc/intra_template.c @@ -428,7 +428,7 @@ static int FUNC(lmcs_derive_chroma_scale)(VVCLocalContext *lc, const int x0, con } // 8.7.5.3 Picture reconstruction with luma dependent chroma residual scaling process for chroma samples -static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *dst, const int *coeff, +static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *coeff, const int width, const int height, const int x0_cu, const int y0_cu) { const int chroma_scale = FUNC(lmcs_derive_chroma_scale)(lc, x0_cu, y0_cu); @@ -438,11 +438,10 @@ static void FUNC(lmcs_scale_chroma)(VVCLocalContext *lc, int *dst, const int *co const int c = av_clip_intp2(*coeff, BIT_DEPTH); if (c > 0) - *dst = (c * chroma_scale + (1 << 10)) >> 11; + *coeff = (c * chroma_scale + (1 << 10)) >> 11; else - *dst = -((-c * chroma_scale + (1 << 10)) >> 11); + *coeff = -((-c * chroma_scale + (1 << 10)) >> 11); coeff++; - dst++; } } } @@ -627,8 +626,9 @@ static void FUNC(intra_pred)(const VVCLocalContext *lc, int x0, int y0, FUNC(prepare_intra_edge_params)(lc, &edge, src, stride, x, y, w, h, c_idx, is_intra_mip, mode, ref_idx, need_pdpc); if (is_intra_mip) { - int intra_mip_transposed_flag = SAMPLE_CTB(fc->tab.imtf, x_cb, y_cb); - int intra_mip_mode = SAMPLE_CTB(fc->tab.imm, x_cb, y_cb); + int intra_mip_transposed_flag; + int intra_mip_mode; + unpack_mip_info(&intra_mip_transposed_flag, &intra_mip_mode, intra_mip_flag); fc->vvcdsp.intra.pred_mip((uint8_t *)src, edge.top, edge.left, w, h, stride, intra_mip_mode, intra_mip_transposed_flag); diff --git a/libavcodec/vvc/intra_utils.c b/libavcodec/vvc/intra_utils.c index 8c40eb1b16..e44c3dcd04 100644 --- a/libavcodec/vvc/intra_utils.c +++ b/libavcodec/vvc/intra_utils.c @@ -184,16 +184,16 @@ int ff_vvc_intra_pred_angle_derive(const int pred_mode) return intra_pred_angle; } -#define ROUND(f) (int)(f < 0 ? -(-f + 0.5) : (f + 0.5)) int ff_vvc_intra_inv_angle_derive(const int intra_pred_angle) { - float inv_angle; - av_assert0(intra_pred_angle); - inv_angle = 32 * 512.0 / intra_pred_angle; - return ROUND(inv_angle); + av_assert2(intra_pred_angle != 0); + if (intra_pred_angle > 0) + return ROUNDED_DIV(32*512, intra_pred_angle); + else + return -ROUNDED_DIV(32*512, -intra_pred_angle); } -//8.4.5.2.7 Wide angle intra prediction mode mapping proces +//8.4.5.2.7 Wide angle intra prediction mode mapping process int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu, const int tb_width, const int tb_height, const int c_idx, int pred_mode_intra) { diff --git a/libavcodec/vvc/mvs.c b/libavcodec/vvc/mvs.c index 86ad310035..955fe4b9fd 100644 --- a/libavcodec/vvc/mvs.c +++ b/libavcodec/vvc/mvs.c @@ -144,7 +144,9 @@ static int derive_temporal_colocated_mvs(const VVCLocalContext *lc, MvField temp const SliceContext *sc = lc->sc; RefPicList* refPicList = sc->rpl; - if (temp_col.pred_flag == PF_INTRA) + if (temp_col.pred_flag == PF_INTRA || + temp_col.pred_flag == PF_IBC || + temp_col.pred_flag == PF_PLT) return 0; if (sb_flag){ @@ -266,7 +268,7 @@ void ff_vvc_set_mvf(const VVCLocalContext *lc, const int x0, const int y0, const } } -void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const int dmvr) +void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const bool dmvr, const PredFlag pf, const bool ciip_flag) { const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; @@ -277,7 +279,10 @@ void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, const int dmvr) for (int dx = 0; dx < cu->cb_width; dx += min_pu_size) { const int x = cu->x0 + dx; const int y = cu->y0 + dy; - TAB_MVF(x, y).pred_flag = PF_INTRA; + MvField *mv = &TAB_MVF(x, y); + + mv->pred_flag = pf; + mv->ciip_flag = ciip_flag; } } } @@ -599,7 +604,19 @@ static void init_neighbour_context(NeighbourContext *ctx, const VVCLocalContext static av_always_inline PredMode pred_flag_to_mode(PredFlag pred) { - return pred == PF_IBC ? MODE_IBC : (pred == PF_INTRA ? MODE_INTRA : MODE_INTER); + static const PredMode lut[] = { + MODE_INTRA, // PF_INTRA + MODE_INTER, // PF_L0 + MODE_INTER, // PF_L1 + MODE_INTER, // PF_BI + 0, // invalid + MODE_IBC, // PF_IBC + 0, // invalid + 0, // invalid + MODE_PLT, // PF_PLT + }; + + return lut[pred]; } static int check_available(Neighbour *n, const VVCLocalContext *lc, const int check_mer) @@ -909,7 +926,7 @@ static void affine_cps_from_nb(const VVCLocalContext *lc, } } -//derive affine neighbour's postion, width and height, +//derive affine neighbour's position, width and height, static int affine_neighbour_cb(const VVCFrameContext *fc, const int x_nb, const int y_nb, int *x_cb, int *y_cb, int *cbw, int *cbh) { const int log2_min_cb_size = fc->ps.sps->min_cb_log2_size_y; @@ -1627,12 +1644,12 @@ static int ibc_spatial_candidates(const VVCLocalContext *lc, const int merge_idx init_neighbour_context(&nctx, lc); - if (check_available(a1, lc, 1)) { + if (check_available(a1, lc, 0)) { cand_list[num_cands++] = TAB_MVF(a1->x, a1->y).mv[L0]; if (num_cands > merge_idx) return 1; } - if (check_available(b1, lc, 1)) { + if (check_available(b1, lc, 0)) { const MvField *mvf = &TAB_MVF(b1->x, b1->y); if (!num_cands || !IS_SAME_MV(&cand_list[0], mvf->mv)) { cand_list[num_cands++] = mvf->mv[L0]; diff --git a/libavcodec/vvc/mvs.h b/libavcodec/vvc/mvs.h index b2242b2a4d..7150c0b8cf 100644 --- a/libavcodec/vvc/mvs.h +++ b/libavcodec/vvc/mvs.h @@ -43,6 +43,6 @@ void ff_vvc_update_hmvp(VVCLocalContext *lc, const MotionInfo *mi); int ff_vvc_no_backward_pred_flag(const VVCLocalContext *lc); MvField* ff_vvc_get_mvf(const VVCFrameContext *fc, const int x0, const int y0); void ff_vvc_set_mvf(const VVCLocalContext *lc, const int x0, const int y0, const int w, const int h, const MvField *mvf); -void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, int dmvr); +void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, bool dmvr, PredFlag pf, bool ciip_flag); #endif //AVCODEC_VVC_MVS_H diff --git a/libavcodec/vvc/ps.c b/libavcodec/vvc/ps.c index ff9a6c7a15..6eec0fe586 100644 --- a/libavcodec/vvc/ps.c +++ b/libavcodec/vvc/ps.c @@ -20,11 +20,14 @@ * 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/cbs_h266.h" +#include "libavcodec/decode.h" +#include "libavcodec/h2645data.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" #include "data.h" #include "ps.h" #include "dec.h" @@ -179,12 +182,58 @@ static void sps_ladf(VVCSPS* sps) } } -static int sps_derive(VVCSPS *sps, void *log_ctx) +#define EXTENDED_SAR 255 +static void sps_vui(AVCodecContext *c, const H266RawVUI *vui) +{ + AVRational sar = (AVRational){ 0, 1 }; + if (vui->vui_aspect_ratio_info_present_flag) { + if (vui->vui_aspect_ratio_idc < FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) + sar = ff_h2645_pixel_aspect[vui->vui_aspect_ratio_idc]; + else if (vui->vui_aspect_ratio_idc == EXTENDED_SAR) { + sar = (AVRational){ vui->vui_sar_width, vui->vui_sar_height }; + } else { + av_log(c, AV_LOG_WARNING, "Unknown SAR index: %u.\n", vui->vui_aspect_ratio_idc); + } + } + ff_set_sar(c, sar); + + if (vui->vui_colour_description_present_flag) { + c->color_primaries = vui->vui_colour_primaries; + c->color_trc = vui->vui_transfer_characteristics; + c->colorspace = vui->vui_matrix_coeffs; + c->color_range = vui->vui_full_range_flag ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + // Set invalid values to "unspecified" + if (!av_color_primaries_name(c->color_primaries)) + c->color_primaries = AVCOL_PRI_UNSPECIFIED; + if (!av_color_transfer_name(c->color_trc)) + c->color_trc = AVCOL_TRC_UNSPECIFIED; + if (!av_color_space_name(c->colorspace)) + c->colorspace = AVCOL_SPC_UNSPECIFIED; + } else { + c->color_primaries = AVCOL_PRI_UNSPECIFIED; + c->color_trc = AVCOL_TRC_UNSPECIFIED; + c->colorspace = AVCOL_SPC_UNSPECIFIED; + c->color_range = AVCOL_RANGE_MPEG; + } +} + + +static void sps_export_stream_params(AVCodecContext *c, const VVCSPS *sps) +{ + const H266RawSPS *r = sps->r; + + c->has_b_frames = !!r->sps_dpb_params.dpb_max_num_reorder_pics[r->sps_max_sublayers_minus1]; + if (r->sps_vui_parameters_present_flag) + sps_vui(c, &r->vui); +} + +static int sps_derive(VVCSPS *sps, AVCodecContext *c) { int ret; const H266RawSPS *r = sps->r; - ret = sps_bit_depth(sps, log_ctx); + ret = sps_bit_depth(sps, c); if (ret < 0) return ret; sps_poc(sps); @@ -196,38 +245,39 @@ static int sps_derive(VVCSPS *sps, void *log_ctx) if (ret < 0) return ret; } + sps_export_stream_params(c, sps); return 0; } -static void sps_free(FFRefStructOpaque opaque, void *obj) +static void sps_free(AVRefStructOpaque opaque, void *obj) { VVCSPS *sps = obj; - ff_refstruct_unref(&sps->r); + av_refstruct_unref(&sps->r); } -static const VVCSPS *sps_alloc(const H266RawSPS *rsps, void *log_ctx) +static const VVCSPS *sps_alloc(const H266RawSPS *rsps, AVCodecContext *c) { int ret; - VVCSPS *sps = ff_refstruct_alloc_ext(sizeof(*sps), 0, NULL, sps_free); + VVCSPS *sps = av_refstruct_alloc_ext(sizeof(*sps), 0, NULL, sps_free); if (!sps) return NULL; - ff_refstruct_replace(&sps->r, rsps); + av_refstruct_replace(&sps->r, rsps); - ret = sps_derive(sps, log_ctx); + ret = sps_derive(sps, c); if (ret < 0) goto fail; return sps; fail: - ff_refstruct_unref(&sps); + av_refstruct_unref(&sps); return NULL; } -static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx, int is_clvss) +static int decode_sps(VVCParamSets *ps, AVCodecContext *c, const H266RawSPS *rsps, int is_clvss) { const int sps_id = rsps->sps_seq_parameter_set_id; const VVCSPS *old_sps = ps->sps_list[sps_id]; @@ -238,17 +288,18 @@ static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx, i } if (old_sps) { - if (old_sps->r == rsps || !memcmp(old_sps->r, rsps, sizeof(*old_sps->r))) + if (old_sps->r == rsps || !memcmp(old_sps->r, rsps, sizeof(*old_sps->r))) { + ps->sps_id_used |= (1 << sps_id); return 0; - else if (ps->sps_id_used & (1 << sps_id)) + } else if (ps->sps_id_used & (1 << sps_id)) return AVERROR_INVALIDDATA; } - sps = sps_alloc(rsps, log_ctx); + sps = sps_alloc(rsps, c); if (!sps) return AVERROR(ENOMEM); - ff_refstruct_unref(&ps->sps_list[sps_id]); + av_refstruct_unref(&ps->sps_list[sps_id]); ps->sps_list[sps_id] = sps; ps->sps_id_used |= (1 << sps_id); @@ -358,6 +409,8 @@ static int pps_add_ctus(VVCPPS *pps, int *off, const int rx, const int ry, int start = *off; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { + if (*off >= pps->ctb_count) + return AVERROR_INVALIDDATA; pps->ctb_addr_in_slice[*off] = ctu_rs(rx + x, ry + y, pps); (*off)++; } @@ -365,15 +418,21 @@ static int pps_add_ctus(VVCPPS *pps, int *off, const int rx, const int ry, return *off - start; } -static void pps_single_slice_picture(VVCPPS *pps, int *off) +static int pps_single_slice_picture(VVCPPS *pps, int *off) { + pps->num_ctus_in_slice[0] = 0; for (int j = 0; j < pps->r->num_tile_rows; j++) { for (int i = 0; i < pps->r->num_tile_columns; i++) { - pps->num_ctus_in_slice[0] = pps_add_ctus(pps, off, + const int ret = pps_add_ctus(pps, off, pps->col_bd[i], pps->row_bd[j], pps->r->col_width_val[i], pps->r->row_height_val[j]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[0] += ret; } } + + return 0; } static void subpic_tiles(int *tile_x, int *tile_y, int *tile_x_end, int *tile_y_end, @@ -400,25 +459,36 @@ static void subpic_tiles(int *tile_x, int *tile_y, int *tile_x_end, int *tile_y_ (*tile_y_end)++; } -static void pps_subpic_less_than_one_tile_slice(VVCPPS *pps, const VVCSPS *sps, const int i, const int tx, const int ty, int *off) +static int pps_subpic_less_than_one_tile_slice(VVCPPS *pps, const VVCSPS *sps, const int i, const int tx, const int ty, int *off) { - pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, - pps->col_bd[tx], pps->row_bd[ty], - pps->r->col_width_val[tx], sps->r->sps_subpic_height_minus1[i] + 1); + const int ret = pps_add_ctus(pps, off, + sps->r->sps_subpic_ctu_top_left_x[i], sps->r->sps_subpic_ctu_top_left_y[i], + sps->r->sps_subpic_width_minus1[i] + 1, sps->r->sps_subpic_height_minus1[i] + 1); + if (ret < 0) + return ret; + + pps->num_ctus_in_slice[i] = ret; + return 0; } -static void pps_subpic_one_or_more_tiles_slice(VVCPPS *pps, const int tile_x, const int tile_y, const int x_end, const int y_end, const int i, int *off) +static int pps_subpic_one_or_more_tiles_slice(VVCPPS *pps, const int tile_x, const int tile_y, const int x_end, const int y_end, + const int i, int *off) { for (int ty = tile_y; ty < y_end; ty++) { for (int tx = tile_x; tx < x_end; tx++) { - pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, + const int ret = pps_add_ctus(pps, off, pps->col_bd[tx], pps->row_bd[ty], pps->r->col_width_val[tx], pps->r->row_height_val[ty]); + if (ret < 0) + return ret; + + pps->num_ctus_in_slice[i] += ret; } } + return 0; } -static void pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *off) +static int pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *off) { int tx, ty, x_end, y_end; @@ -427,19 +497,27 @@ static void pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *o subpic_tiles(&tx, &ty, &x_end, &y_end, sps, pps, i); if (ty + 1 == y_end && sps->r->sps_subpic_height_minus1[i] + 1 < pps->r->row_height_val[ty]) - pps_subpic_less_than_one_tile_slice(pps, sps, i, tx, ty, off); + return pps_subpic_less_than_one_tile_slice(pps, sps, i, tx, ty, off); else - pps_subpic_one_or_more_tiles_slice(pps, tx, ty, x_end, y_end, i, off); + return pps_subpic_one_or_more_tiles_slice(pps, tx, ty, x_end, y_end, i, off); } -static void pps_single_slice_per_subpic(VVCPPS *pps, const VVCSPS *sps, int *off) +static int pps_single_slice_per_subpic(VVCPPS *pps, const VVCSPS *sps, int *off) { + int ret; + if (!sps->r->sps_subpic_info_present_flag) { - pps_single_slice_picture(pps, off); + ret = pps_single_slice_picture(pps, off); + if (ret < 0) + return ret; } else { - for (int i = 0; i < pps->r->pps_num_slices_in_pic_minus1 + 1; i++) - pps_subpic_slice(pps, sps, i, off); + for (int i = 0; i < pps->r->pps_num_slices_in_pic_minus1 + 1; i++) { + const int ret = pps_subpic_slice(pps, sps, i, off); + if (ret < 0) + return ret; + } } + return 0; } static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) @@ -451,16 +529,20 @@ static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) ctu_xy(&rx, &ry, tile_x, tile_y, pps); ctu_y_end = ry + r->row_height_val[tile_y]; while (ry < ctu_y_end) { + int ret; pps->slice_start_offset[i] = *off; - pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, rx, ry, + ret = pps_add_ctus(pps, off, rx, ry, r->col_width_val[tile_x], r->slice_height_in_ctus[i]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[i] = ret; ry += r->slice_height_in_ctus[i++]; } i--; return i; } -static void pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, int *off) +static int pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, int *off, bool *tile_in_slice) { const H266RawPPS *r = pps->r; int rx, ry, tile_x, tile_y; @@ -470,57 +552,91 @@ static void pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, pps->num_ctus_in_slice[i] = 0; for (int ty = tile_y; ty <= tile_y + r->pps_slice_height_in_tiles_minus1[i]; ty++) { for (int tx = tile_x; tx <= tile_x + r->pps_slice_width_in_tiles_minus1[i]; tx++) { + int ret; + const int idx = ty * r->num_tile_columns + tx; + if (tile_in_slice[idx]) + return AVERROR_INVALIDDATA; + tile_in_slice[idx] = true; ctu_xy(&rx, &ry, tx, ty, pps); - pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, rx, ry, + ret = pps_add_ctus(pps, off, rx, ry, r->col_width_val[tx], r->row_height_val[ty]); + if (ret < 0) + return ret; + pps->num_ctus_in_slice[i] += ret; } } + + return 0; } -static void pps_rect_slice(VVCPPS *pps, const VVCSPS *sps) +static int pps_rect_slice(VVCPPS *pps, const VVCSPS *sps) { const H266RawPPS *r = pps->r; - int tile_idx = 0, off = 0; + bool tile_in_slice[VVC_MAX_TILES_PER_AU] = {false}; + int tile_idx = 0, off = 0, ret; if (r->pps_single_slice_per_subpic_flag) { - pps_single_slice_per_subpic(pps, sps, &off); - return; + return pps_single_slice_per_subpic(pps, sps, &off); } for (int i = 0; i < r->pps_num_slices_in_pic_minus1 + 1; i++) { if (!r->pps_slice_width_in_tiles_minus1[i] && !r->pps_slice_height_in_tiles_minus1[i]) { - i = pps_one_tile_slices(pps, tile_idx, i, &off); + if (tile_in_slice[tile_idx]) + return AVERROR_INVALIDDATA; + tile_in_slice[tile_idx] = true; + ret = pps_one_tile_slices(pps, tile_idx, i, &off); + if (ret < 0) + return ret; + i = ret; } else { - pps_multi_tiles_slice(pps, tile_idx, i, &off); + ret = pps_multi_tiles_slice(pps, tile_idx, i, &off, tile_in_slice); + if (ret < 0) + return ret; } tile_idx = next_tile_idx(tile_idx, i, r); } + + for (int i = 0; i < r->num_tiles_in_pic; i++) { + if (!tile_in_slice[i]) + return AVERROR_INVALIDDATA; + } + + return 0; } -static void pps_no_rect_slice(VVCPPS* pps) +static int pps_no_rect_slice(VVCPPS* pps) { const H266RawPPS* r = pps->r; int rx, ry, off = 0; for (int tile_y = 0; tile_y < r->num_tile_rows; tile_y++) { for (int tile_x = 0; tile_x < r->num_tile_columns; tile_x++) { + int ret; ctu_xy(&rx, &ry, tile_x, tile_y, pps); - pps_add_ctus(pps, &off, rx, ry, r->col_width_val[tile_x], r->row_height_val[tile_y]); + ret = pps_add_ctus(pps, &off, rx, ry, r->col_width_val[tile_x], r->row_height_val[tile_y]); + if (ret < 0) + return ret; } } + + return 0; } static int pps_slice_map(VVCPPS *pps, const VVCSPS *sps) { + int ret; + pps->ctb_addr_in_slice = av_calloc(pps->ctb_count, sizeof(*pps->ctb_addr_in_slice)); if (!pps->ctb_addr_in_slice) return AVERROR(ENOMEM); if (pps->r->pps_rect_slice_flag) - pps_rect_slice(pps, sps); - else - pps_no_rect_slice(pps); + return pps_rect_slice(pps, sps); + + ret = pps_no_rect_slice(pps); + if (ret < 0) + return ret; return 0; } @@ -572,11 +688,11 @@ static int pps_derive(VVCPPS *pps, const VVCSPS *sps) return 0; } -static void pps_free(FFRefStructOpaque opaque, void *obj) +static void pps_free(AVRefStructOpaque opaque, void *obj) { VVCPPS *pps = obj; - ff_refstruct_unref(&pps->r); + av_refstruct_unref(&pps->r); av_freep(&pps->col_bd); av_freep(&pps->row_bd); @@ -588,12 +704,12 @@ static void pps_free(FFRefStructOpaque opaque, void *obj) static const VVCPPS *pps_alloc(const H266RawPPS *rpps, const VVCSPS *sps) { int ret; - VVCPPS *pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); + VVCPPS *pps = av_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free); if (!pps) return NULL; - ff_refstruct_replace(&pps->r, rpps); + av_refstruct_replace(&pps->r, rpps); ret = pps_derive(pps, sps); if (ret < 0) @@ -602,7 +718,7 @@ static const VVCPPS *pps_alloc(const H266RawPPS *rpps, const VVCSPS *sps) return pps; fail: - ff_refstruct_unref(&pps); + av_refstruct_unref(&pps); return NULL; } @@ -621,13 +737,13 @@ static int decode_pps(VVCParamSets *ps, const H266RawPPS *rpps) if (!pps) return AVERROR(ENOMEM); - ff_refstruct_unref(&ps->pps_list[pps_id]); + av_refstruct_unref(&ps->pps_list[pps_id]); ps->pps_list[pps_id] = pps; return ret; } -static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, void *log_ctx, int is_clvss) +static int decode_ps(VVCParamSets *ps, AVCodecContext *c, const CodedBitstreamH266Context *h266, int is_clvss) { const H266RawPictureHeader *ph = h266->ph; const H266RawPPS *rpps; @@ -645,10 +761,16 @@ static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, vo if (!rsps) return AVERROR_INVALIDDATA; - ret = decode_sps(ps, rsps, log_ctx, is_clvss); + ret = decode_sps(ps, c, rsps, is_clvss); if (ret < 0) return ret; + if (rsps->sps_log2_ctu_size_minus5 > 2) { + // CTU > 128 are reserved in vvc spec v3 + av_log(c, AV_LOG_ERROR, "CTU size > 128. \n"); + return AVERROR_PATCHWELCOME; + } + ret = decode_pps(ps, rpps); if (ret < 0) return ret; @@ -728,7 +850,7 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw uint16_t input_pivot[LMCS_MAX_BIN_SIZE]; uint16_t scale_coeff[LMCS_MAX_BIN_SIZE]; uint16_t inv_scale_coeff[LMCS_MAX_BIN_SIZE]; - int i, delta_crs; + int i, delta_crs, sum_cw = 0; if (bit_depth > LMCS_MAX_BIT_DEPTH) return AVERROR_PATCHWELCOME; @@ -736,11 +858,15 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw return AVERROR_INVALIDDATA; lmcs->min_bin_idx = rlmcs->lmcs_min_bin_idx; - lmcs->max_bin_idx = LMCS_MAX_BIN_SIZE - 1 - rlmcs->lmcs_min_bin_idx; + lmcs->max_bin_idx = LMCS_MAX_BIN_SIZE - 1 - rlmcs->lmcs_delta_max_bin_idx; memset(cw, 0, sizeof(cw)); - for (int i = lmcs->min_bin_idx; i <= lmcs->max_bin_idx; i++) + for (int i = lmcs->min_bin_idx; i <= lmcs->max_bin_idx; i++) { cw[i] = org_cw + (1 - 2 * rlmcs->lmcs_delta_sign_cw_flag[i]) * rlmcs->lmcs_delta_abs_cw[i]; + sum_cw += cw[i]; + } + if (sum_cw > (1 << bit_depth) - 1) + return AVERROR_INVALIDDATA; delta_crs = (1 - 2 * rlmcs->lmcs_delta_sign_crs_flag) * rlmcs->lmcs_delta_abs_crs; @@ -748,19 +874,26 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw for (i = 0; i < LMCS_MAX_BIN_SIZE; i++) { input_pivot[i] = i * org_cw; lmcs->pivot[i + 1] = lmcs->pivot[i] + cw[i]; + if (i >= lmcs->min_bin_idx && i <= lmcs->max_bin_idx && + lmcs->pivot[i] % (1 << (bit_depth - 5)) != 0 && + lmcs->pivot[i] >> (bit_depth - 5) == lmcs->pivot[i + 1] >> (bit_depth - 5)) + return AVERROR_INVALIDDATA; scale_coeff[i] = (cw[i] * (1 << 11) + off) >> shift; if (cw[i] == 0) { inv_scale_coeff[i] = 0; lmcs->chroma_scale_coeff[i] = (1 << 11); } else { + const int cw_plus_d = cw[i] + delta_crs; + if (cw_plus_d < (org_cw >> 3) || cw_plus_d > ((org_cw << 3) - 1)) + return AVERROR_INVALIDDATA; inv_scale_coeff[i] = org_cw * (1 << 11) / cw[i]; - lmcs->chroma_scale_coeff[i] = org_cw * (1 << 11) / (cw[i] + delta_crs); + lmcs->chroma_scale_coeff[i] = org_cw * (1 << 11) / cw_plus_d; } } //derive lmcs_fwd_lut for (uint16_t sample = 0; sample < max; sample++) { - const int idx_y = sample / org_cw; + const int idx_y = sample >> shift; const uint16_t fwd_sample = lmcs_derive_lut_sample(sample, lmcs->pivot, input_pivot, scale_coeff, idx_y, max); if (bit_depth > 8) @@ -776,6 +909,7 @@ static int lmcs_derive_lut(VVCLMCS *lmcs, const H266RawAPS *rlmcs, const H266Raw uint16_t inv_sample; while (i <= lmcs->max_bin_idx && sample >= lmcs->pivot[i + 1]) i++; + i = FFMIN(i, LMCS_MAX_BIN_SIZE - 1); inv_sample = lmcs_derive_lut_sample(sample, input_pivot, lmcs->pivot, inv_scale_coeff, i, max); @@ -862,7 +996,7 @@ static int decode_ph(VVCFrameParamSets *fps, const H266RawPictureHeader *rph, vo const H266RawPPS *pps = fps->pps->r; ph->r = rph; - ff_refstruct_replace(&ph->rref, rph_ref); + av_refstruct_replace(&ph->rref, rph_ref); ret = ph_derive(ph, sps, pps, poc_tid0, is_clvss); if (ret < 0) return ret; @@ -884,15 +1018,15 @@ static int decode_frame_ps(VVCFrameParamSets *fps, const VVCParamSets *ps, if (!rpps) return AVERROR_INVALIDDATA; - ff_refstruct_replace(&fps->sps, ps->sps_list[rpps->pps_seq_parameter_set_id]); - ff_refstruct_replace(&fps->pps, ps->pps_list[rpps->pps_pic_parameter_set_id]); + av_refstruct_replace(&fps->sps, ps->sps_list[rpps->pps_seq_parameter_set_id]); + av_refstruct_replace(&fps->pps, ps->pps_list[rpps->pps_pic_parameter_set_id]); ret = decode_ph(fps, ph, h266->ph_ref, poc_tid0, is_clvss); if (ret < 0) return ret; if (ph->ph_explicit_scaling_list_enabled_flag) - ff_refstruct_replace(&fps->sl, ps->scaling_list[ph->ph_scaling_list_aps_id]); + av_refstruct_replace(&fps->sl, ps->scaling_list[ph->ph_scaling_list_aps_id]); if (ph->ph_lmcs_enabled_flag) { ret = lmcs_derive_lut(&fps->lmcs, ps->lmcs_list[ph->ph_lmcs_aps_id], fps->sps->r); @@ -901,7 +1035,7 @@ static int decode_frame_ps(VVCFrameParamSets *fps, const VVCParamSets *ps, } for (int i = 0; i < FF_ARRAY_ELEMS(fps->alf_list); i++) - ff_refstruct_replace(&fps->alf_list[i], ps->alf_list[i]); + av_refstruct_replace(&fps->alf_list[i], ps->alf_list[i]); return 0; } @@ -934,7 +1068,7 @@ int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) decode_recovery_flag(s); is_clvss = IS_CLVSS(s); - ret = decode_ps(ps, h266, s->avctx, is_clvss); + ret = decode_ps(ps, s->avctx, h266, is_clvss); if (ret < 0) return ret; @@ -945,26 +1079,26 @@ int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) void ff_vvc_frame_ps_free(VVCFrameParamSets *fps) { - ff_refstruct_unref(&fps->sps); - ff_refstruct_unref(&fps->pps); - ff_refstruct_unref(&fps->ph.rref); - ff_refstruct_unref(&fps->sl); + av_refstruct_unref(&fps->sps); + av_refstruct_unref(&fps->pps); + av_refstruct_unref(&fps->ph.rref); + av_refstruct_unref(&fps->sl); for (int i = 0; i < FF_ARRAY_ELEMS(fps->alf_list); i++) - ff_refstruct_unref(&fps->alf_list[i]); + av_refstruct_unref(&fps->alf_list[i]); } void ff_vvc_ps_uninit(VVCParamSets *ps) { for (int i = 0; i < FF_ARRAY_ELEMS(ps->scaling_list); i++) - ff_refstruct_unref(&ps->scaling_list[i]); + av_refstruct_unref(&ps->scaling_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->lmcs_list); i++) - ff_refstruct_unref(&ps->lmcs_list[i]); + av_refstruct_unref(&ps->lmcs_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->alf_list); i++) - ff_refstruct_unref(&ps->alf_list[i]); + av_refstruct_unref(&ps->alf_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++) - ff_refstruct_unref(&ps->sps_list[i]); + av_refstruct_unref(&ps->sps_list[i]); for (int i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) - ff_refstruct_unref(&ps->pps_list[i]); + av_refstruct_unref(&ps->pps_list[i]); } static void alf_coeff(int16_t *coeff, @@ -1043,15 +1177,23 @@ static void alf_derive(VVCALF *alf, const H266RawAPS *aps) alf_cc(alf, aps); } +static void alf_free(AVRefStructOpaque unused, void *obj) +{ + VVCALF *alf = obj; + + av_refstruct_unref(&alf->r); +} + static int aps_decode_alf(const VVCALF **alf, const H266RawAPS *aps) { - VVCALF *a = ff_refstruct_allocz(sizeof(*a)); + VVCALF *a = av_refstruct_alloc_ext(sizeof(*a), 0, NULL, alf_free); if (!a) return AVERROR(ENOMEM); alf_derive(a, aps); - ff_refstruct_replace(alf, a); - ff_refstruct_unref(&a); + av_refstruct_replace(&a->r, aps); + av_refstruct_replace(alf, a); + av_refstruct_unref(&a); return 0; } @@ -1099,17 +1241,17 @@ static void scaling_derive(VVCScalingList *sl, const H266RawAPS *aps) //dc if (id >= SL_START_16x16) { if (!aps->scaling_list_copy_mode_flag[id] && !aps->scaling_list_pred_mode_flag[id]) { - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = 8; + dc += 8; } else if (!aps->scaling_list_pred_id_delta[id]) { - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = 16; + dc += 16; } else { const int ref_id = id - aps->scaling_list_pred_id_delta[id]; if (ref_id >= SL_START_16x16) dc += sl->scaling_matrix_dc_rec[ref_id - SL_START_16x16]; else dc += sl->scaling_matrix_rec[ref_id][0]; - sl->scaling_matrix_dc_rec[id - SL_START_16x16] = dc & 255; } + sl->scaling_matrix_dc_rec[id - SL_START_16x16] = dc & 255; } //ac @@ -1131,13 +1273,13 @@ static void scaling_derive(VVCScalingList *sl, const H266RawAPS *aps) static int aps_decode_scaling(const VVCScalingList **scaling, const H266RawAPS *aps) { - VVCScalingList *sl = ff_refstruct_allocz(sizeof(*sl)); + VVCScalingList *sl = av_refstruct_allocz(sizeof(*sl)); if (!sl) return AVERROR(ENOMEM); scaling_derive(sl, aps); - ff_refstruct_replace(scaling, sl); - ff_refstruct_unref(&sl); + av_refstruct_replace(scaling, sl); + av_refstruct_unref(&sl); return 0; } @@ -1155,7 +1297,7 @@ int ff_vvc_decode_aps(VVCParamSets *ps, const CodedBitstreamUnit *unit) ret = aps_decode_alf(&ps->alf_list[aps->aps_adaptation_parameter_set_id], aps); break; case VVC_ASP_TYPE_LMCS: - ff_refstruct_replace(&ps->lmcs_list[aps->aps_adaptation_parameter_set_id], aps); + av_refstruct_replace(&ps->lmcs_list[aps->aps_adaptation_parameter_set_id], aps); break; case VVC_ASP_TYPE_SCALING: ret = aps_decode_scaling(&ps->scaling_list[aps->aps_adaptation_parameter_set_id], aps); @@ -1198,7 +1340,7 @@ static int sh_alf_aps(const VVCSH *sh, const VVCFrameParamSets *fps) return 0; } -static void sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) +static int sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) { const int slice_address = sh->r->sh_slice_address; @@ -1222,6 +1364,11 @@ static void sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps sh->num_ctus_in_curr_slice += pps->r->row_height_val[tile_y] * pps->r->col_width_val[tile_x]; } } + + if (!sh->num_ctus_in_curr_slice) + return AVERROR_INVALIDDATA; + + return 0; } static void sh_qp_y(VVCSH *sh, const H266RawPPS *pps, const H266RawPictureHeader *ph) @@ -1318,7 +1465,9 @@ static int sh_derive(VVCSH *sh, const VVCFrameParamSets *fps) const H266RawPictureHeader *ph = fps->ph.r; int ret; - sh_slice_address(sh, sps, fps->pps); + ret = sh_slice_address(sh, sps, fps->pps); + if (ret < 0) + return ret; ret = sh_alf_aps(sh, fps); if (ret < 0) return ret; @@ -1338,7 +1487,7 @@ int ff_vvc_decode_sh(VVCSH *sh, const VVCFrameParamSets *fps, const CodedBitstre if (!fps->sps || !fps->pps) return AVERROR_INVALIDDATA; - ff_refstruct_replace(&sh->r, unit->content_ref); + av_refstruct_replace(&sh->r, unit->content_ref); ret = sh_derive(sh, fps); if (ret < 0) diff --git a/libavcodec/vvc/ps.h b/libavcodec/vvc/ps.h index 9203e2c57f..3ec2238c17 100644 --- a/libavcodec/vvc/ps.h +++ b/libavcodec/vvc/ps.h @@ -169,6 +169,7 @@ typedef struct VVCPH { #define ALF_NUM_COEFF_CC 7 typedef struct VVCALF { + const H266RawAPS *r; int16_t luma_coeff [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA]; uint8_t luma_clip_idx [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA]; diff --git a/libavcodec/vvc/refs.c b/libavcodec/vvc/refs.c index 133ff9eaba..1840caa4ec 100644 --- a/libavcodec/vvc/refs.c +++ b/libavcodec/vvc/refs.c @@ -21,18 +21,16 @@ */ #include +#include #include "libavutil/mem.h" #include "libavutil/thread.h" -#include "libavcodec/refstruct.h" +#include "libavutil/refstruct.h" #include "libavcodec/thread.h" +#include "libavcodec/decode.h" #include "refs.h" -#define VVC_FRAME_FLAG_OUTPUT (1 << 0) -#define VVC_FRAME_FLAG_SHORT_REF (1 << 1) -#define VVC_FRAME_FLAG_LONG_REF (1 << 2) -#define VVC_FRAME_FLAG_BUMPING (1 << 3) typedef struct FrameProgress { atomic_int progress[VVC_PROGRESS_LAST]; @@ -50,19 +48,28 @@ void ff_vvc_unref_frame(VVCFrameContext *fc, VVCFrame *frame, int flags) return; frame->flags &= ~flags; + if (!(frame->flags & ~VVC_FRAME_FLAG_CORRUPT)) + frame->flags = 0; if (!frame->flags) { av_frame_unref(frame->frame); - ff_refstruct_unref(&frame->sps); - ff_refstruct_unref(&frame->pps); - ff_refstruct_unref(&frame->progress); - ff_refstruct_unref(&frame->tab_dmvr_mvf); + if (frame->needs_fg) { + av_frame_unref(frame->frame_grain); + frame->needs_fg = 0; + } - ff_refstruct_unref(&frame->rpl); + av_refstruct_unref(&frame->sps); + av_refstruct_unref(&frame->pps); + av_refstruct_unref(&frame->progress); + + av_refstruct_unref(&frame->tab_dmvr_mvf); + + av_refstruct_unref(&frame->rpl); frame->nb_rpl_elems = 0; - ff_refstruct_unref(&frame->rpl_tab); + av_refstruct_unref(&frame->rpl_tab); frame->collocated_ref = NULL; + av_refstruct_unref(&frame->hwaccel_picture_private); } } @@ -89,7 +96,7 @@ void ff_vvc_flush_dpb(VVCFrameContext *fc) ff_vvc_unref_frame(fc, &fc->DPB[i], ~0); } -static void free_progress(FFRefStructOpaque unused, void *obj) +static void free_progress(AVRefStructOpaque unused, void *obj) { FrameProgress *p = (FrameProgress *)obj; @@ -101,13 +108,13 @@ static void free_progress(FFRefStructOpaque unused, void *obj) static FrameProgress *alloc_progress(void) { - FrameProgress *p = ff_refstruct_alloc_ext(sizeof(*p), 0, NULL, free_progress); + FrameProgress *p = av_refstruct_alloc_ext(sizeof(*p), 0, NULL, free_progress); if (p) { p->has_lock = !ff_mutex_init(&p->lock, NULL); p->has_cond = !ff_cond_init(&p->cond, NULL); if (!p->has_lock || !p->has_cond) - ff_refstruct_unref(&p); + av_refstruct_unref(&p); } return p; } @@ -123,40 +130,52 @@ static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) if (frame->frame->buf[0]) continue; - frame->sps = ff_refstruct_ref_c(fc->ps.sps); - frame->pps = ff_refstruct_ref_c(fc->ps.pps); + frame->sps = av_refstruct_ref_c(fc->ps.sps); + frame->pps = av_refstruct_ref_c(fc->ps.pps); ret = ff_thread_get_buffer(s->avctx, frame->frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) return NULL; - frame->rpl = ff_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab)); + frame->rpl = av_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab)); if (!frame->rpl) goto fail; frame->nb_rpl_elems = s->current_frame.nb_units; - frame->tab_dmvr_mvf = ff_refstruct_pool_get(fc->tab_dmvr_mvf_pool); + frame->tab_dmvr_mvf = av_refstruct_pool_get(fc->tab_dmvr_mvf_pool); if (!frame->tab_dmvr_mvf) goto fail; - frame->rpl_tab = ff_refstruct_pool_get(fc->rpl_tab_pool); + frame->rpl_tab = av_refstruct_pool_get(fc->rpl_tab_pool); if (!frame->rpl_tab) goto fail; frame->ctb_count = pps->ctb_width * pps->ctb_height; for (int j = 0; j < frame->ctb_count; j++) frame->rpl_tab[j] = frame->rpl; - win->left_offset = pps->r->pps_scaling_win_left_offset << sps->hshift[CHROMA]; - win->right_offset = pps->r->pps_scaling_win_right_offset << sps->hshift[CHROMA]; - win->top_offset = pps->r->pps_scaling_win_top_offset << sps->vshift[CHROMA]; - win->bottom_offset = pps->r->pps_scaling_win_bottom_offset << sps->vshift[CHROMA]; + win->left_offset = pps->r->pps_scaling_win_left_offset * (1 << sps->hshift[CHROMA]); + win->right_offset = pps->r->pps_scaling_win_right_offset * (1 << sps->hshift[CHROMA]); + win->top_offset = pps->r->pps_scaling_win_top_offset * (1 << sps->vshift[CHROMA]); + win->bottom_offset = pps->r->pps_scaling_win_bottom_offset * (1 << sps->vshift[CHROMA]); frame->ref_width = pps->r->pps_pic_width_in_luma_samples - win->left_offset - win->right_offset; frame->ref_height = pps->r->pps_pic_height_in_luma_samples - win->bottom_offset - win->top_offset; + if (fc->sei.frame_field_info.present) { + if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) + frame->frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD || + fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD) + frame->frame->flags |= AV_FRAME_FLAG_INTERLACED; + } + frame->progress = alloc_progress(); if (!frame->progress) goto fail; + ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private); + if (ret < 0) + goto fail; + return frame; fail: ff_vvc_unref_frame(fc, frame, ~0); @@ -166,6 +185,36 @@ fail: return NULL; } +static void set_pict_type(AVFrame *frame, const VVCContext *s, const VVCFrameContext *fc) +{ + bool has_b = false, has_inter = false; + + if (IS_IRAP(s)) { + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + return; + } + + if (fc->ps.ph.r->ph_inter_slice_allowed_flag) { + // At this point, fc->slices is not fully initialized; we need to inspect the CBS directly. + const CodedBitstreamFragment *current = &s->current_frame; + for (int i = 0; i < current->nb_units && !has_b; i++) { + const CodedBitstreamUnit *unit = current->units + i; + if (unit->content_ref && unit->type <= VVC_RSV_IRAP_11) { + const H266RawSliceHeader *rsh = unit->content_ref; + has_inter |= !IS_I(rsh); + has_b |= IS_B(rsh); + } + } + } + if (!has_inter) + frame->pict_type = AV_PICTURE_TYPE_I; + else if (has_b) + frame->pict_type = AV_PICTURE_TYPE_B; + else + frame->pict_type = AV_PICTURE_TYPE_P; +} + int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame) { const VVCPH *ph= &fc->ps.ph; @@ -187,6 +236,7 @@ int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame) if (!ref) return AVERROR(ENOMEM); + set_pict_type(ref->frame, s, fc); *frame = ref->frame; fc->ref = ref; @@ -246,11 +296,19 @@ int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *out, const if (nb_output) { VVCFrame *frame = &fc->DPB[min_idx]; - ret = av_frame_ref(out, frame->frame); + if (frame->flags & VVC_FRAME_FLAG_CORRUPT) + frame->frame->flags |= AV_FRAME_FLAG_CORRUPT; + + ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame); + + if (!ret && !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) + av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS); + if (frame->flags & VVC_FRAME_FLAG_BUMPING) ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT | VVC_FRAME_FLAG_BUMPING); else ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT); + if (ret < 0) return ret; @@ -355,7 +413,7 @@ static VVCFrame *generate_missing_ref(VVCContext *s, VVCFrameContext *fc, int po frame->poc = poc; frame->sequence = s->seq_decode; - frame->flags = 0; + frame->flags = VVC_FRAME_FLAG_CORRUPT; ff_vvc_report_frame_finished(frame); @@ -390,6 +448,19 @@ static int add_candidate_ref(VVCContext *s, VVCFrameContext *fc, RefPicList *lis if (ref == fc->ref || list->nb_refs >= VVC_MAX_REF_ENTRIES) return AVERROR_INVALIDDATA; + if (!IS_CVSS(s)) { + const bool ref_corrupt = !ref || (ref->flags & VVC_FRAME_FLAG_CORRUPT); + const bool recovering = s->no_output_before_recovery_flag && !GDR_IS_RECOVERED(s); + + if (ref_corrupt && !recovering) { + if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) + return AVERROR_INVALIDDATA; + + fc->ref->flags |= VVC_FRAME_FLAG_CORRUPT; + } + } + if (!ref) { ref = generate_missing_ref(s, fc, poc); if (!ref) diff --git a/libavcodec/vvc/refs.h b/libavcodec/vvc/refs.h index 8ae33d4a9a..a3081a76be 100644 --- a/libavcodec/vvc/refs.h +++ b/libavcodec/vvc/refs.h @@ -25,6 +25,12 @@ #include "dec.h" +#define VVC_FRAME_FLAG_OUTPUT (1 << 0) +#define VVC_FRAME_FLAG_SHORT_REF (1 << 1) +#define VVC_FRAME_FLAG_LONG_REF (1 << 2) +#define VVC_FRAME_FLAG_BUMPING (1 << 3) +#define VVC_FRAME_FLAG_CORRUPT (1 << 4) + int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, struct AVFrame *out, int no_output_of_prior_pics_flag, int flush); void ff_vvc_bump_frame(VVCContext *s, VVCFrameContext *fc); int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, struct AVFrame **frame); diff --git a/libavcodec/vvc/sei.c b/libavcodec/vvc/sei.c new file mode 100644 index 0000000000..cd202edb2a --- /dev/null +++ b/libavcodec/vvc/sei.c @@ -0,0 +1,254 @@ +/* + * VVC Supplementary Enhancement Information messages + * + * copyright (c) 2024 Wu Jianhua + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sei.h" +#include "dec.h" +#include "libavutil/refstruct.h" + +static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h, const SEIRawFilmGrainCharacteristics *s, const VVCFrameContext *fc) +{ + const VVCSPS *sps = fc->ps.sps; + + h->present = !s->fg_characteristics_cancel_flag; + if (h->present) { + h->model_id = s->fg_model_id; + h->separate_colour_description_present_flag = s->fg_separate_colour_description_present_flag; + if (h->separate_colour_description_present_flag) { + h->bit_depth_luma = s->fg_bit_depth_luma_minus8 + 8; + h->bit_depth_chroma = s->fg_bit_depth_chroma_minus8 + 8; + h->full_range = s->fg_full_range_flag; + h->color_primaries = s->fg_colour_primaries; + h->transfer_characteristics = s->fg_transfer_characteristics; + h->matrix_coeffs = s->fg_matrix_coeffs; + } else { + if (!sps) { + av_log(fc->log_ctx, AV_LOG_ERROR, + "No active SPS for film_grain_characteristics.\n"); + return AVERROR_INVALIDDATA; + } + h->bit_depth_luma = sps->bit_depth; + h->bit_depth_chroma = sps->bit_depth; + h->full_range = sps->r->vui.vui_full_range_flag; + h->color_primaries = sps->r->vui.vui_colour_primaries; + h->transfer_characteristics = sps->r->vui.vui_transfer_characteristics; + h->matrix_coeffs = sps->r->vui.vui_matrix_coeffs ; + } + + h->blending_mode_id = s->fg_blending_mode_id; + h->log2_scale_factor = s->fg_log2_scale_factor; + + for (int c = 0; c < 3; c++) { + h->comp_model_present_flag[c] = s->fg_comp_model_present_flag[c]; + if (h->comp_model_present_flag[c]) { + h->num_intensity_intervals[c] = s->fg_num_intensity_intervals_minus1[c] + 1; + h->num_model_values[c] = s->fg_num_model_values_minus1[c] + 1; + + if (h->num_model_values[c] > 6) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < h->num_intensity_intervals[c]; i++) { + h->intensity_interval_lower_bound[c][i] = s->fg_intensity_interval_lower_bound[c][i]; + h->intensity_interval_upper_bound[c][i] = s->fg_intensity_interval_upper_bound[c][i]; + for (int j = 0; j < h->num_model_values[c]; j++) + h->comp_model_value[c][i][j] = s->fg_comp_model_value[c][i][j]; + } + } + } + + h->persistence_flag = s->fg_characteristics_persistence_flag; + } + + return 0; +} + +static int decode_decoded_picture_hash(H274SEIPictureHash *h, const SEIRawDecodedPictureHash *s) +{ + h->present = 1; + h->hash_type = s->dph_sei_hash_type; + if (h->hash_type == 0) + memcpy(h->md5, s->dph_sei_picture_md5, sizeof(h->md5)); + else if (h->hash_type == 1) + memcpy(h->crc, s->dph_sei_picture_crc, sizeof(h->crc)); + else if (h->hash_type == 2) + memcpy(h->checksum, s->dph_sei_picture_checksum, sizeof(h->checksum)); + + return 0; +} + +static int decode_display_orientation(H2645SEIDisplayOrientation *h, const SEIRawDisplayOrientation *s) +{ + int degrees[] = { 0, 0x8000, 0x4000, 0xC000 }; + + h->present = !s->display_orientation_cancel_flag; + if (h->present) { + if (s->display_orientation_transform_type > 7) + return AVERROR_INVALIDDATA; + + h->vflip = 0; + if (s->display_orientation_transform_type == 1 || + s->display_orientation_transform_type == 3 || + s->display_orientation_transform_type == 4 || + s->display_orientation_transform_type == 6) { + h->hflip = 1; + } else { + h->hflip = 0; + } + h->anticlockwise_rotation = degrees[s->display_orientation_transform_type >> 1]; + } + + return 0; +} + +static int decode_content_light_level_info(H2645SEIContentLight *h, const SEIRawContentLightLevelInfo *s) +{ + h->present = 1; + h->max_content_light_level = s->max_content_light_level; + h->max_pic_average_light_level = s->max_pic_average_light_level; + + return 0; +} + +static int decode_frame_field_info(H274SEIFrameFieldInfo *h, const SEIRawFrameFieldInformation *s) +{ + if (s->ffi_source_scan_type > 3) + return AVERROR_INVALIDDATA; + + h->present = 1; + if (s->ffi_field_pic_flag) { + if (s->ffi_bottom_field_flag) + h->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; + else + h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD; + } else { + h->display_elemental_periods = s->ffi_display_elemental_periods_minus1 + 1; + } + + h->source_scan_type = s->ffi_source_scan_type; + h->duplicate_flag = s->ffi_duplicate_flag; + + return 0; +} + +static int decode_ambient_viewing_environment(H2645SEIAmbientViewingEnvironment *h, const SEIRawAmbientViewingEnvironment *s) +{ + h->present = 1; + h->ambient_illuminance = s->ambient_illuminance; + h->ambient_light_x = s->ambient_light_x; + h->ambient_light_y = s->ambient_light_y; + + return 0; +} + +static int decode_mastering_display_colour_volume(H2645SEIMasteringDisplay *h, const SEIRawMasteringDisplayColourVolume *s) +{ + h->present = 1; + + for (int c = 0; c < 3; c++) { + h->display_primaries[c][0] = s->display_primaries_x[c]; + h->display_primaries[c][1] = s->display_primaries_y[c]; + } + + h->white_point[0] = s->white_point_x; + h->white_point[1] = s->white_point_y; + + h->max_luminance = s->max_display_mastering_luminance; + h->min_luminance = s->min_display_mastering_luminance; + + return 0; +} + +int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc) +{ + H2645SEI *c = &s->common; + + if (!sei) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < sei->message_list.nb_messages; i++) { + int ret = 0; + SEIRawMessage *message = &sei->message_list.messages[i]; + void *payload = message->payload; + + switch (message->payload_type) { + case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: + av_refstruct_unref(&c->film_grain_characteristics); + c->film_grain_characteristics = av_refstruct_allocz(sizeof(*c->film_grain_characteristics)); + if (!c->film_grain_characteristics) + return AVERROR(ENOMEM); + ret = decode_film_grain_characteristics(c->film_grain_characteristics, payload, fc); + break; + + case SEI_TYPE_DECODED_PICTURE_HASH: + ret = decode_decoded_picture_hash(&s->picture_hash, payload); + break; + + case SEI_TYPE_DISPLAY_ORIENTATION: + ret = decode_display_orientation(&s->common.display_orientation, payload); + break; + + case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: + ret = decode_content_light_level_info(&s->common.content_light, payload); + break; + + case SEI_TYPE_FRAME_FIELD_INFO: + ret = decode_frame_field_info(&s->frame_field_info, payload); + break; + + case SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT: + ret = decode_ambient_viewing_environment(&s->common.ambient_viewing_environment, payload); + break; + + case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: + ret = decode_mastering_display_colour_volume(&s->common.mastering_display, payload); + break; + + default: + av_log(fc->log_ctx, AV_LOG_DEBUG, "Skipped %s SEI %d\n", + sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ? + "PREFIX" : "SUFFIX", message->payload_type); + return FF_H2645_SEI_MESSAGE_UNHANDLED; + } + + if (ret == AVERROR(ENOMEM)) + return ret; + if (ret < 0) + av_log(fc->log_ctx, AV_LOG_WARNING, "Failure to parse %s SEI %d: %s\n", + sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ? + "PREFIX" : "SUFFIX", message->payload_type, av_err2str(ret)); + } + + return 0; +} + +int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src) +{ + dst->picture_hash.present = 0; // drop hash + dst->frame_field_info.present = 0; // drop field info + return ff_h2645_sei_ctx_replace(&dst->common, &src->common); +} + +void ff_vvc_sei_reset(VVCSEI *s) +{ + ff_h2645_sei_reset(&s->common); + s->picture_hash.present = 0; + s->frame_field_info.present = 0; +} diff --git a/libavcodec/vvc/sei.h b/libavcodec/vvc/sei.h new file mode 100644 index 0000000000..578b48a0e4 --- /dev/null +++ b/libavcodec/vvc/sei.h @@ -0,0 +1,48 @@ +/* + * VVC Supplementary Enhancement Information messages + * + * copyright (c) 2024 Wu Jianhua + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_VVC_SEI_H +#define AVCODEC_VVC_SEI_H + +#include + +#include "libavcodec/get_bits.h" +#include "libavcodec/cbs.h" +#include "libavcodec/cbs_h266.h" +#include "libavcodec/h2645_sei.h" +#include "libavcodec/sei.h" +#include "libavcodec/vvc.h" +#include "libavcodec/h274.h" + +typedef struct VVCSEI { + H2645SEI common; + H274SEIPictureHash picture_hash; + H274SEIFrameFieldInfo frame_field_info; +} VVCSEI; + +struct VVCFrameContext; + +int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc); +int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src); +void ff_vvc_sei_reset(VVCSEI *s); + +#endif /* AVCODEC_VVC_SEI_H */ diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c index 86a7753c6a..2138341b0f 100644 --- a/libavcodec/vvc/thread.c +++ b/libavcodec/vvc/thread.c @@ -22,7 +22,7 @@ #include -#include "libavutil/executor.h" +#include "libavcodec/executor.h" #include "libavutil/mem.h" #include "libavutil/thread.h" @@ -42,6 +42,7 @@ typedef struct ProgressListener { typedef enum VVCTaskStage { VVC_TASK_STAGE_INIT, // for CTU(0, 0) only VVC_TASK_STAGE_PARSE, + VVC_TASK_STAGE_DEBLOCK_BS, VVC_TASK_STAGE_INTER, VVC_TASK_STAGE_RECON, VVC_TASK_STAGE_LMCS, @@ -55,7 +56,7 @@ typedef enum VVCTaskStage { typedef struct VVCTask { union { struct VVCTask *next; //for executor debug only - AVTask task; + FFTask task; } u; VVCTaskStage stage; @@ -103,13 +104,29 @@ typedef struct VVCFrameThread { AVCond cond; } VVCFrameThread; +#define PRIORITY_LOWEST 2 static void add_task(VVCContext *s, VVCTask *t) { - VVCFrameThread *ft = t->fc->ft; + VVCFrameThread *ft = t->fc->ft; + FFTask *task = &t->u.task; + const int priorities[] = { + 0, // VVC_TASK_STAGE_INIT, + 0, // VVC_TASK_STAGE_PARSE, + 1, // VVC_TASK_STAGE_DEBLOCK_BS + // For an 8K clip, a CTU line completed in the reference frame may trigger 64 and more inter tasks. + // We assign these tasks the lowest priority to avoid being overwhelmed with inter tasks. + PRIORITY_LOWEST, // VVC_TASK_STAGE_INTER + 1, // VVC_TASK_STAGE_RECON, + 1, // VVC_TASK_STAGE_LMCS, + 1, // VVC_TASK_STAGE_DEBLOCK_V, + 1, // VVC_TASK_STAGE_DEBLOCK_H, + 1, // VVC_TASK_STAGE_SAO, + 1, // VVC_TASK_STAGE_ALF, + }; atomic_fetch_add(&ft->nb_scheduled_tasks, 1); - - av_executor_execute(s->executor, &t->u.task); + task->priority = priorities[t->stage]; + ff_executor_execute(s->executor, task); } static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry) @@ -166,6 +183,8 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin // l:left, r:right, t: top, b: bottom static const uint8_t target_score[] = { + 2, //VVC_TASK_STAGE_DEBLOCK_BS,need l + t parse + 0, //VVC_TASK_STAGE_INTER, not used 2, //VVC_TASK_STAGE_RECON, need l + rt recon 3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon 1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v @@ -187,7 +206,7 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin } else if (stage == VVC_TASK_STAGE_INTER) { target = atomic_load(&t->target_inter_score); } else { - target = target_score[stage - VVC_TASK_STAGE_RECON]; + target = target_score[stage - VVC_TASK_STAGE_DEBLOCK_BS]; } //+1 for previous stage @@ -264,6 +283,13 @@ static void add_progress_listener(VVCFrame *ref, ProgressListener *l, ff_vvc_add_progress_listener(ref, (VVCProgressListener*)l); } +static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps) +{ + memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state)); + memcpy(next->pp, ep->pp, sizeof(next->pp)); + ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag); +} + static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t) { VVCFrameThread *ft = fc->ft; @@ -273,10 +299,8 @@ static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceC if (sps->r->sps_entropy_coding_sync_enabled_flag) { if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) { EntryPoint *next = ep + 1; - if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) { - memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state)); - ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag); - } + if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1)) + ep_init_wpp(next, ep, sps); } if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1)) frame_thread_add_score(s, ft, t->rx, t->ry + 1, VVC_TASK_STAGE_PARSE); @@ -333,6 +357,10 @@ static void task_stage_done(const VVCTask *t, VVCContext *s) //this is a reserve map of ready_score, ordered by zigzag if (stage == VVC_TASK_STAGE_PARSE) { + ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_BS); + ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_BS); + if (t->rx < 0 || t->rx >= ft->ctu_width || t->ry < 0 || t->ry >= ft->ctu_height) + return; parse_task_done(s, fc, t->rx, t->ry); } else if (stage == VVC_TASK_STAGE_RECON) { ADD(-1, 1, VVC_TASK_STAGE_RECON); @@ -372,38 +400,6 @@ static int task_is_stage_ready(VVCTask *t, int add) return task_has_target_score(t, stage, score); } -static int task_ready(const AVTask *_t, void *user_data) -{ - VVCTask *t = (VVCTask*)_t; - - return task_is_stage_ready(t, 0); -} - -#define CHECK(a, b) \ - do { \ - if ((a) != (b)) \ - return (a) < (b); \ - } while (0) - -static int task_priority_higher(const AVTask *_a, const AVTask *_b) -{ - const VVCTask *a = (const VVCTask*)_a; - const VVCTask *b = (const VVCTask*)_b; - - - if (a->stage <= VVC_TASK_STAGE_PARSE || b->stage <= VVC_TASK_STAGE_PARSE) { - CHECK(a->stage, b->stage); - CHECK(a->fc->decode_order, b->fc->decode_order); //decode order - CHECK(a->ry, b->ry); - return a->rx < b->rx; - } - - CHECK(a->fc->decode_order, b->fc->decode_order); //decode order - CHECK(a->rx + a->ry + a->stage, b->rx + b->ry + b->stage); //zigzag with type - CHECK(a->rx + a->ry, b->rx + b->ry); //zigzag - return a->ry < b->ry; -} - static void check_colocation(VVCContext *s, VVCTask *t) { const VVCFrameContext *fc = t->fc; @@ -498,6 +494,14 @@ static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t) return 0; } +static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t) +{ + if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) + ff_vvc_deblock_bs(lc, t->rx, t->ry, t->rs); + + return 0; +} + static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { VVCFrameContext *fc = lc->fc; @@ -602,11 +606,10 @@ static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t) return 0; } -#define VVC_THREAD_DEBUG -#ifdef VVC_THREAD_DEBUG const static char* task_name[] = { "INIT", "P", + "B", "I", "R", "L", @@ -615,7 +618,6 @@ const static char* task_name[] = { "S", "A" }; -#endif typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t); @@ -628,6 +630,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) static const run_func run[] = { run_init, run_parse, + run_deblock_bs, run_inter, run_recon, run_lmcs, @@ -637,9 +640,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) run_alf, }; -#ifdef VVC_THREAD_DEBUG - av_log(s->avctx, AV_LOG_DEBUG, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry); -#endif + ff_dlog(s->avctx, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry); lc->sc = t->sc; @@ -655,13 +656,13 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) "frame %5d, %s(%3d, %3d) failed with %d\r\n", (int)fc->decode_order, task_name[stage], t->rx, t->ry, ret); } + if (!ret) + task_stage_done(t, s); } - - task_stage_done(t, s); return; } -static int task_run(AVTask *_t, void *local_context, void *user_data) +static int task_run(FFTask *_t, void *local_context, void *user_data) { VVCTask *t = (VVCTask*)_t; VVCContext *s = (VVCContext *)user_data; @@ -683,21 +684,20 @@ static int task_run(AVTask *_t, void *local_context, void *user_data) return 0; } -AVExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count) +FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count) { - AVTaskCallbacks callbacks = { + FFTaskCallbacks callbacks = { s, sizeof(VVCLocalContext), - task_priority_higher, - task_ready, + PRIORITY_LOWEST + 1, task_run, }; - return av_executor_alloc(&callbacks, thread_count); + return ff_executor_alloc(&callbacks, thread_count); } -void ff_vvc_executor_free(AVExecutor **e) +void ff_vvc_executor_free(FFExecutor **e) { - av_executor_free(e); + ff_executor_free(e); } void ff_vvc_frame_thread_free(VVCFrameContext *fc) @@ -719,9 +719,9 @@ static void frame_thread_init_score(VVCFrameContext *fc) const VVCFrameThread *ft = fc->ft; VVCTask task; - task_init(&task, VVC_TASK_STAGE_RECON, fc, 0, 0); + task_init(&task, VVC_TASK_STAGE_PARSE, fc, 0, 0); - for (int i = VVC_TASK_STAGE_RECON; i < VVC_TASK_STAGE_LAST; i++) { + for (int i = VVC_TASK_STAGE_PARSE; i < VVC_TASK_STAGE_LAST; i++) { task.stage = i; for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) { @@ -822,6 +822,13 @@ int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) } } } + for (int rs = 0; rs < ft->ctu_count; rs++) { + const VVCTask *t = ft->tasks + rs; + if (!t->sc) { + av_log(s->avctx, AV_LOG_ERROR, "frame %5d, CTU(%d, %d) not belong to any slice\r\n", (int)fc->decode_order, t->rx, t->ry); + return AVERROR_INVALIDDATA; + } + } frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT); return 0; @@ -839,8 +846,6 @@ int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) ff_mutex_unlock(&ft->lock); ff_vvc_report_frame_finished(fc->ref); -#ifdef VVC_THREAD_DEBUG - av_log(s->avctx, AV_LOG_DEBUG, "frame %5d done\r\n", (int)fc->decode_order); -#endif + ff_dlog(s->avctx, "frame %5d done\r\n", (int)fc->decode_order); return ft->ret; } diff --git a/libavcodec/vvc/thread.h b/libavcodec/vvc/thread.h index 7b15dbee59..b89aee3b32 100644 --- a/libavcodec/vvc/thread.h +++ b/libavcodec/vvc/thread.h @@ -25,8 +25,8 @@ #include "dec.h" -struct AVExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count); -void ff_vvc_executor_free(struct AVExecutor **e); +struct FFExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count); +void ff_vvc_executor_free(struct FFExecutor **e); int ff_vvc_frame_thread_init(VVCFrameContext *fc); void ff_vvc_frame_thread_free(VVCFrameContext *fc); diff --git a/libavcodec/vvc_parser.c b/libavcodec/vvc_parser.c index 8d32d66573..0c7362dde4 100644 --- a/libavcodec/vvc_parser.c +++ b/libavcodec/vvc_parser.c @@ -300,14 +300,14 @@ static int get_pu_info(PuInfo *info, const CodedBitstreamH266Context *h266, } info->pps = h266->pps[info->ph->ph_pic_parameter_set_id]; if (!info->pps) { - av_log(logctx, AV_LOG_ERROR, "PPS id %d is not avaliable.\n", + av_log(logctx, AV_LOG_ERROR, "PPS id %d is not available.\n", info->ph->ph_pic_parameter_set_id); ret = AVERROR_INVALIDDATA; goto error; } info->sps = h266->sps[info->pps->pps_seq_parameter_set_id]; if (!info->sps) { - av_log(logctx, AV_LOG_ERROR, "SPS id %d is not avaliable.\n", + av_log(logctx, AV_LOG_ERROR, "SPS id %d is not available.\n", info->pps->pps_seq_parameter_set_id); ret = AVERROR_INVALIDDATA; goto error; @@ -357,7 +357,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, return 1; } - if ((ret = ff_cbs_read(ctx->cbc, pu, buf, buf_size)) < 0) { + if ((ret = ff_cbs_read(ctx->cbc, pu, NULL, buf, buf_size)) < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to parse picture unit.\n"); goto end; } diff --git a/libavcodec/wasm/hevc/Makefile b/libavcodec/wasm/hevc/Makefile new file mode 100644 index 0000000000..7e8ab3776e --- /dev/null +++ b/libavcodec/wasm/hevc/Makefile @@ -0,0 +1,4 @@ +OBJS-$(CONFIG_HEVC_DECODER) += wasm/hevc/dsp_init.o + +SIMD128-OBJS-$(CONFIG_HEVC_DECODER) += wasm/hevc/idct.o \ + wasm/hevc/sao.o diff --git a/libavcodec/wasm/hevc/dsp_init.c b/libavcodec/wasm/hevc/dsp_init.c new file mode 100644 index 0000000000..8672bbc2e1 --- /dev/null +++ b/libavcodec/wasm/hevc/dsp_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_internal.h" +#include "libavcodec/hevc/dsp.h" +#include "libavcodec/wasm/hevc/idct.h" +#include "libavcodec/wasm/hevc/sao.h" + +av_cold void ff_hevc_dsp_init_wasm(HEVCDSPContext *c, const int bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (!CPUEXT(cpu_flags, SIMD128)) + return; + +#if HAVE_SIMD128 + if (bit_depth == 8) { + c->idct[0] = ff_hevc_idct_4x4_8_simd128; + c->idct[1] = ff_hevc_idct_8x8_8_simd128; + c->idct[2] = ff_hevc_idct_16x16_8_simd128; + c->idct[3] = ff_hevc_idct_32x32_8_simd128; + + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8x8_8_simd128; + c->sao_band_filter[1] = + c->sao_band_filter[2] = + c->sao_band_filter[3] = + c->sao_band_filter[4] = ff_hevc_sao_band_filter_16x16_8_simd128; + + c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_8_simd128; + c->sao_edge_filter[1] = + c->sao_edge_filter[2] = + c->sao_edge_filter[3] = + c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_16x16_8_simd128; + } else if (bit_depth == 10) { + c->idct[0] = ff_hevc_idct_4x4_10_simd128; + c->idct[1] = ff_hevc_idct_8x8_10_simd128; + c->idct[2] = ff_hevc_idct_16x16_10_simd128; + c->idct[3] = ff_hevc_idct_32x32_10_simd128; + } +#endif +} diff --git a/libavcodec/wasm/hevc/idct.c b/libavcodec/wasm/hevc/idct.c new file mode 100644 index 0000000000..828fc26a49 --- /dev/null +++ b/libavcodec/wasm/hevc/idct.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/wasm/hevc/idct.h" + +#include + +#include "libavutil/mem_internal.h" + +static const int8_t transform[] = { + 64, 83, 64, 36, 89, 75, 50, 18, + 90, 87, 80, 70, 57, 43, 25, 9, + 90, 90, 88, 85, 82, 78, 73, 67, + 61, 54, 46, 38, 31, 22, 13, 4, +}; + +static inline void transpose_4x8h(v128_t *src) +{ + v128_t t0 = wasm_i16x8_shuffle(src[0], src[1], 0, 8, 2, 10, 4, 12, 6, 14); + v128_t t1 = wasm_i16x8_shuffle(src[0], src[1], 1, 9, 3, 11, 5, 13, 7, 15); + v128_t t2 = wasm_i16x8_shuffle(src[2], src[3], 0, 8, 2, 10, 4, 12, 6, 14); + v128_t t3 = wasm_i16x8_shuffle(src[2], src[3], 1, 9, 3, 11, 5, 13, 7, 15); + + src[0] = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + src[2] = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + src[1] = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + src[3] = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); +} + +static inline void transpose_8x8h(v128_t *src) +{ + transpose_4x8h(src); + transpose_4x8h(&src[4]); +} + +static inline void tr_4x4(v128_t *src, v128_t *trans, int shift) +{ + v128_t tmp[4]; + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); + v128_t e0 = wasm_i32x4_extmul_low_i16x8(src[0], trans[0]); + v128_t e1 = wasm_i32x4_extmul_low_i16x8(src[0], trans[0]); + v128_t o0 = wasm_i32x4_extmul_low_i16x8(src[1], trans[1]); + v128_t o1 = wasm_i32x4_extmul_low_i16x8(src[1], trans[3]); + + tmp[0] = wasm_i32x4_extmul_low_i16x8(src[2], trans[0]); + tmp[1] = wasm_i32x4_extmul_low_i16x8(src[2], trans[0]); + tmp[2] = wasm_i32x4_extmul_low_i16x8(src[3], trans[3]); + tmp[3] = wasm_i32x4_extmul_low_i16x8(src[3], trans[1]); + e0 = wasm_i32x4_add(e0, tmp[0]); + e1 = wasm_i32x4_sub(e1, tmp[1]); + o0 = wasm_i32x4_add(o0, tmp[2]); + o1 = wasm_i32x4_sub(o1, tmp[3]); + + tmp[0] = wasm_i32x4_add(e0, o0); + tmp[1] = wasm_i32x4_sub(e0, o0); + tmp[2] = wasm_i32x4_add(e1, o1); + tmp[3] = wasm_i32x4_sub(e1, o1); + + tmp[0] = wasm_i32x4_add(tmp[0], add); + tmp[1] = wasm_i32x4_add(tmp[1], add); + tmp[2] = wasm_i32x4_add(tmp[2], add); + tmp[3] = wasm_i32x4_add(tmp[3], add); + tmp[0] = wasm_i32x4_shr(tmp[0], shift); + tmp[1] = wasm_i32x4_shr(tmp[1], shift); + tmp[2] = wasm_i32x4_shr(tmp[2], shift); + tmp[3] = wasm_i32x4_shr(tmp[3], shift); + + src[0] = wasm_i16x8_narrow_i32x4(tmp[0], tmp[0]); + src[3] = wasm_i16x8_narrow_i32x4(tmp[1], tmp[1]); + src[1] = wasm_i16x8_narrow_i32x4(tmp[2], tmp[2]); + src[2] = wasm_i16x8_narrow_i32x4(tmp[3], tmp[3]); +} + +static void idct_4x4(int16_t *coeffs, int bit_depth) +{ + v128_t src[4]; + v128_t trans[4]; + + src[0] = wasm_v128_load64_zero(&coeffs[0]); + src[1] = wasm_v128_load64_zero(&coeffs[4]); + src[2] = wasm_v128_load64_zero(&coeffs[8]); + src[3] = wasm_v128_load64_zero(&coeffs[12]); + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + + tr_4x4(src, trans, 7); + transpose_4x8h(src); + + tr_4x4(src, trans, 20 - bit_depth); + transpose_4x8h(src); + + src[0] = wasm_i64x2_shuffle(src[0], src[1], 0, 2); + src[2] = wasm_i64x2_shuffle(src[2], src[3], 0, 2); + wasm_v128_store(&coeffs[0], src[0]); + wasm_v128_store(&coeffs[8], src[2]); +} + +void ff_hevc_idct_4x4_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_4x4(coeffs, 8); +} + +void ff_hevc_idct_4x4_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_4x4(coeffs, 10); +} + +static inline void shift_narrow_low(v128_t src, v128_t *dst, v128_t add, int shift) +{ + src = wasm_i32x4_add(src, add); + src = wasm_i32x4_shr(src, shift); + *dst = wasm_i64x2_shuffle(wasm_i16x8_narrow_i32x4(src, src), *dst, 0, 3); +} + +static inline void shift_narrow_high(v128_t src, v128_t *dst, v128_t add, int shift) +{ + src = wasm_i32x4_add(src, add); + src = wasm_i32x4_shr(src, shift); + *dst = wasm_i64x2_shuffle(wasm_i16x8_narrow_i32x4(src, src), *dst, 2, 0); +} + +#define tr_4x4_8(in0, in1, in2, in3, dst0, dst1, dst2, dst3, trans, half0, half1) \ + do { \ + v128_t e0, e1, o0, o1; \ + v128_t tmp[4]; \ + \ + e0 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in0, trans[0]); \ + e1 = e0; \ + o0 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in1, trans[1]); \ + o1 = wasm_i32x4_extmul_ ## half0 ## _i16x8(in1, trans[3]); \ + \ + tmp[0] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in2, trans[0]); \ + tmp[1] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in2, trans[0]); \ + tmp[2] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in3, trans[3]); \ + tmp[3] = wasm_i32x4_extmul_ ## half1 ## _i16x8(in3, trans[1]); \ + e0 = wasm_i32x4_add(e0, tmp[0]); \ + e1 = wasm_i32x4_sub(e1, tmp[1]); \ + o0 = wasm_i32x4_add(o0, tmp[2]); \ + o1 = wasm_i32x4_sub(o1, tmp[3]); \ + dst0 = wasm_i32x4_add(e0, o0); \ + dst1 = wasm_i32x4_add(e1, o1); \ + dst2 = wasm_i32x4_sub(e1, o1); \ + dst3 = wasm_i32x4_sub(e0, o0); \ + } while (0) + +#define tr_8x4(src0, src1, half0, half1, trans, shift) \ + do { \ + v128_t v24, v25, v26, v27, v28, v29, v30, v31; \ + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); \ + \ + tr_4x4_8(src0[0], src0[2], src1[0], src1[2], v24, v25, v26, v27, trans, half0, half1); \ + \ + v30 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[6]); \ + v28 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[4]); \ + v29 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[5]); \ + v30 = wasm_i32x4_sub(v30, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[4])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[5])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[7])); \ + \ + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[7])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[6])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[4])); \ + \ + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[5])); \ + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[7])); \ + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[6])); \ + \ + v31 = wasm_i32x4_add(v26, v30); \ + v26 = wasm_i32x4_sub(v26, v30); \ + shift_narrow_ ## half0 (v31, &src0[2], add, shift); \ + v31 = wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[1], trans[7]); \ + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_ ## half0 ## _i16x8(src0[3], trans[6])); \ + v31 = wasm_i32x4_add(v31, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[1], trans[5])); \ + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_ ## half1 ## _i16x8(src1[3], trans[4])); \ + shift_narrow_ ## half1 (v26, &src1[1], add, shift); \ + v26 = wasm_i32x4_add(v24, v28); \ + v24 = wasm_i32x4_sub(v24, v28); \ + v28 = wasm_i32x4_add(v25, v29); \ + v25 = wasm_i32x4_sub(v25, v29); \ + v30 = wasm_i32x4_add(v27, v31); \ + v27 = wasm_i32x4_sub(v27, v31); \ + shift_narrow_ ## half0 (v26, &src0[0], add, shift); \ + shift_narrow_ ## half1 (v24, &src1[3], add, shift); \ + shift_narrow_ ## half0 (v28, &src0[1], add, shift); \ + shift_narrow_ ## half1 (v25, &src1[2], add, shift); \ + shift_narrow_ ## half0 (v30, &src0[3], add, shift); \ + shift_narrow_ ## half1 (v27, &src1[0], add, shift); \ + } while (0) + +static void idct_8x8(int16_t *coeffs, int bit_depth) +{ + v128_t src[8]; + v128_t trans[8]; + v128_t *src1; + int shift1 = 7; + int shift2 = 20 - bit_depth; + + src[0] = wasm_v128_load(coeffs + 0 * 8); + src[1] = wasm_v128_load(coeffs + 1 * 8); + src[2] = wasm_v128_load(coeffs + 2 * 8); + src[3] = wasm_v128_load(coeffs + 3 * 8); + src[4] = wasm_v128_load(coeffs + 4 * 8); + src[5] = wasm_v128_load(coeffs + 5 * 8); + src[6] = wasm_v128_load(coeffs + 6 * 8); + src[7] = wasm_v128_load(coeffs + 7 * 8); + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + trans[4] = wasm_i16x8_const_splat(transform[4]); + trans[5] = wasm_i16x8_const_splat(transform[5]); + trans[6] = wasm_i16x8_const_splat(transform[6]); + trans[7] = wasm_i16x8_const_splat(transform[7]); + + src1 = &src[4]; + tr_8x4(src, src1, low, low, trans, shift1); + tr_8x4(src, src1, high, high, trans, shift1); + transpose_8x8h(src); + tr_8x4(src, src, low, high, trans, shift2); + tr_8x4(src1, src1, low, high, trans, shift2); + transpose_8x8h(src); + + wasm_v128_store(&coeffs[0 * 8], src[0]); + wasm_v128_store(&coeffs[1 * 8], src[1]); + wasm_v128_store(&coeffs[2 * 8], src[2]); + wasm_v128_store(&coeffs[3 * 8], src[3]); + wasm_v128_store(&coeffs[4 * 8], src[4]); + wasm_v128_store(&coeffs[5 * 8], src[5]); + wasm_v128_store(&coeffs[6 * 8], src[6]); + wasm_v128_store(&coeffs[7 * 8], src[7]); +} + +void ff_hevc_idct_8x8_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_8x8(coeffs, 8); +} + +void ff_hevc_idct_8x8_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_8x8(coeffs, 10); +} + +#define load16(x1, x3, x2, in0, in1, in2, in3) \ + in0 = wasm_v128_load64_zero(x1); \ + in0 = wasm_v128_load64_lane(x3, in0, 1); \ + x1 += x2; \ + x3 += x2; \ + in1 = wasm_v128_load64_zero(x1); \ + in1 = wasm_v128_load64_lane(x3, in1, 1); \ + x1 += x2; \ + x3 += x2; \ + in2 = wasm_v128_load64_zero(x1); \ + in2 = wasm_v128_load64_lane(x3, in2, 1); \ + x1 += x2; \ + x3 += x2; \ + in3 = wasm_v128_load64_zero(x1); \ + in3 = wasm_v128_load64_lane(x3, in3, 1); \ + x1 += x2; \ + x3 += x2; \ + +#define bufferfly(e, o, p, m) \ + p = wasm_i32x4_add(e, o); \ + m = wasm_i32x4_sub(e, o); \ + +static void tr16_8x4(v128_t in0, v128_t in1, v128_t in2, v128_t in3, + const v128_t *trans, char *sp, int offset) +{ + v128_t v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31; + + tr_4x4_8(in0, in1, in2, in3, v24, v25, v26, v27, trans, low, low); + + v28 = wasm_i32x4_extmul_high_i16x8(in0, trans[4]); + v29 = wasm_i32x4_extmul_high_i16x8(in0, trans[5]); + v30 = wasm_i32x4_extmul_high_i16x8(in0, trans[6]); + v31 = wasm_i32x4_extmul_high_i16x8(in0, trans[7]); + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in1, trans[5])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in1, trans[7])); + v30 = wasm_i32x4_sub(v30, wasm_i32x4_extmul_high_i16x8(in1, trans[4])); + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_high_i16x8(in1, trans[6])); + + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in2, trans[6])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in2, trans[4])); + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_high_i16x8(in2, trans[7])); + v31 = wasm_i32x4_add(v31, wasm_i32x4_extmul_high_i16x8(in2, trans[5])); + + v28 = wasm_i32x4_add(v28, wasm_i32x4_extmul_high_i16x8(in3, trans[7])); + v29 = wasm_i32x4_sub(v29, wasm_i32x4_extmul_high_i16x8(in3, trans[6])); + v30 = wasm_i32x4_add(v30, wasm_i32x4_extmul_high_i16x8(in3, trans[5])); + v31 = wasm_i32x4_sub(v31, wasm_i32x4_extmul_high_i16x8(in3, trans[4])); + + bufferfly(v24, v28, v16, v23); + bufferfly(v25, v29, v17, v22); + bufferfly(v26, v30, v18, v21); + bufferfly(v27, v31, v19, v20); + + sp += offset; + wasm_v128_store(sp, v16); sp += 16; + wasm_v128_store(sp, v17); sp += 16; + wasm_v128_store(sp, v18); sp += 16; + wasm_v128_store(sp, v19); sp += 16; + wasm_v128_store(sp, v20); sp += 16; + wasm_v128_store(sp, v21); sp += 16; + wasm_v128_store(sp, v22); sp += 16; + wasm_v128_store(sp, v23); +} + +static void scale(v128_t *out0, v128_t *out1, v128_t *out2, v128_t *out3, + v128_t in0, v128_t in1, v128_t in2, v128_t in3, + v128_t in4, v128_t in5, v128_t in6, v128_t in7, + int shift) +{ + v128_t add = wasm_i32x4_splat(1 << (shift - 1)); + + in0 = wasm_i32x4_add(in0, add); + in1 = wasm_i32x4_add(in1, add); + in2 = wasm_i32x4_add(in2, add); + in3 = wasm_i32x4_add(in3, add); + in4 = wasm_i32x4_add(in4, add); + in5 = wasm_i32x4_add(in5, add); + in6 = wasm_i32x4_add(in6, add); + in7 = wasm_i32x4_add(in7, add); + + in0 = wasm_i32x4_shr(in0, shift); + in1 = wasm_i32x4_shr(in1, shift); + in2 = wasm_i32x4_shr(in2, shift); + in3 = wasm_i32x4_shr(in3, shift); + in4 = wasm_i32x4_shr(in4, shift); + in5 = wasm_i32x4_shr(in5, shift); + in6 = wasm_i32x4_shr(in6, shift); + in7 = wasm_i32x4_shr(in7, shift); + + *out0 = wasm_i16x8_narrow_i32x4(in0, in1); + *out1 = wasm_i16x8_narrow_i32x4(in2, in3); + *out2 = wasm_i16x8_narrow_i32x4(in4, in5); + *out3 = wasm_i16x8_narrow_i32x4(in6, in7); +} + +static void transpose16_4x4_2(v128_t *r0, v128_t *r1, v128_t *r2, v128_t *r3) +{ + v128_t t0, t1, t2, t3, t4, t5; + + t0 = wasm_i16x8_shuffle(*r0, *r1, 0, 8, 2, 10, 4, 12, 6, 14); + t1 = wasm_i16x8_shuffle(*r0, *r1, 1, 9, 3, 11, 5, 13, 7, 15); + t2 = wasm_i16x8_shuffle(*r2, *r3, 0, 8, 2, 10, 4, 12, 6, 14); + t3 = wasm_i16x8_shuffle(*r2, *r3, 1, 9, 3, 11, 5, 13, 7, 15); + t4 = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + t5 = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + t0 = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + t2 = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); + *r0 = wasm_i64x2_shuffle(t4, *r0, 0, 3); + *r2 = wasm_i64x2_shuffle(t5, *r2, 0, 3); + *r1 = wasm_i64x2_shuffle(t0, *r1, 0, 3); + *r3 = wasm_i64x2_shuffle(t2, *r3, 0, 3); + + t0 = wasm_i16x8_shuffle(*r3, *r2, 0, 8, 2, 10, 4, 12, 6, 14); + t1 = wasm_i16x8_shuffle(*r3, *r2, 1, 9, 3, 11, 5, 13, 7, 15); + t2 = wasm_i16x8_shuffle(*r1, *r0, 0, 8, 2, 10, 4, 12, 6, 14); + t3 = wasm_i16x8_shuffle(*r1, *r0, 1, 9, 3, 11, 5, 13, 7, 15); + t4 = wasm_i32x4_shuffle(t0, t2, 0, 4, 2, 6); + t5 = wasm_i32x4_shuffle(t0, t2, 1, 5, 3, 7); + t0 = wasm_i32x4_shuffle(t1, t3, 0, 4, 2, 6); + t2 = wasm_i32x4_shuffle(t1, t3, 1, 5, 3, 7); + *r3 = wasm_i64x2_shuffle(*r3, t4, 0, 3); + *r1 = wasm_i64x2_shuffle(*r1, t5, 0, 3); + *r2 = wasm_i64x2_shuffle(*r2, t0, 0, 3); + *r0 = wasm_i64x2_shuffle(*r0, t2, 0, 3); +} + +static void store16(v128_t in0, v128_t in1, v128_t in2, v128_t in3, + char *x1, char *x3, int x1_step, int x3_step) +{ + wasm_v128_store64_lane(x1, in0, 0); + wasm_v128_store64_lane(x3, in0, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in1, 0); + wasm_v128_store64_lane(x3, in1, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in2, 0); + wasm_v128_store64_lane(x3, in2, 1); + x1 += x1_step; + x3 += x3_step; + + wasm_v128_store64_lane(x1, in3, 0); + wasm_v128_store64_lane(x3, in3, 1); +} + + +static void store_to_stack(char *sp, int off1, int off2, + v128_t in0, v128_t in2, v128_t in4, v128_t in6, + v128_t in7, v128_t in5, v128_t in3, v128_t in1) +{ + char *x1 = sp + off1; + char *x3 = sp + off2; + + wasm_v128_store(x1, in0); + wasm_v128_store(x3, in1); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in2); + wasm_v128_store(x3, in3); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in4); + wasm_v128_store(x3, in5); + x1 += 16; + x3 -= 16; + wasm_v128_store(x1, in6); + wasm_v128_store(x3, in7); +} + +#define sum_sub(out, in0, in1, operation, half) \ + out = wasm_i32x4_ ## operation (out, wasm_i32x4_extmul_ ## half ## _i16x8(in0, in1)); + +#define add_member(in, t0, t1, t2, t3, t4, t5, t6, t7, op0, op1, op2, op3, op4, op5, op6, op7, half) \ + do { \ + sum_sub(v21, in, t0, op0, half) \ + sum_sub(v22, in, t1, op1, half) \ + sum_sub(v23, in, t2, op2, half) \ + sum_sub(v24, in, t3, op3, half) \ + sum_sub(v25, in, t4, op4, half) \ + sum_sub(v26, in, t5, op5, half) \ + sum_sub(v27, in, t6, op6, half) \ + sum_sub(v28, in, t7, op7, half) \ + } while (0) + +#define butterfly16(in0, in1, in2, in3, in4, in5, in6, in7) \ + do { \ + v20 = wasm_i32x4_add(in0, in1); \ + in0 = wasm_i32x4_sub(in0, in1); \ + in1 = wasm_i32x4_add(in2, in3); \ + in2 = wasm_i32x4_sub(in2, in3); \ + in3 = wasm_i32x4_add(in4, in5); \ + in4 = wasm_i32x4_sub(in4, in5); \ + in5 = wasm_i32x4_add(in6, in7); \ + in6 = wasm_i32x4_sub(in6, in7); \ + } while (0) + +static void tr_16x4(char *src, char *buf, char *sp, + int shift, int offset, int step) +{ + char *x1, *x3, *x4; + int x2; + v128_t trans[8]; + v128_t v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31; + + trans[0] = wasm_i16x8_const_splat(transform[0]); + trans[1] = wasm_i16x8_const_splat(transform[1]); + trans[2] = wasm_i16x8_const_splat(transform[2]); + trans[3] = wasm_i16x8_const_splat(transform[3]); + trans[4] = wasm_i16x8_const_splat(transform[4]); + trans[5] = wasm_i16x8_const_splat(transform[5]); + trans[6] = wasm_i16x8_const_splat(transform[6]); + trans[7] = wasm_i16x8_const_splat(transform[7]); + + x1 = src; + x3 = src + step * 64; + x2 = step * 128; + load16(x1, x3, x2, v16, v17, v18, v19); + tr16_8x4(v16, v17, v18, v19, trans, sp, offset); + + x1 = src + step * 32; + x3 = src + step * 3 * 32; + x2 = step * 128; + load16(x1, x3, x2, v20, v17, v18, v19); + + trans[0] = wasm_i16x8_const_splat(transform[0 + 8]); + trans[1] = wasm_i16x8_const_splat(transform[1 + 8]); + trans[2] = wasm_i16x8_const_splat(transform[2 + 8]); + trans[3] = wasm_i16x8_const_splat(transform[3 + 8]); + trans[4] = wasm_i16x8_const_splat(transform[4 + 8]); + trans[5] = wasm_i16x8_const_splat(transform[5 + 8]); + trans[6] = wasm_i16x8_const_splat(transform[6 + 8]); + trans[7] = wasm_i16x8_const_splat(transform[7 + 8]); + + v21 = wasm_i32x4_extmul_low_i16x8(v20, trans[0]); + v22 = wasm_i32x4_extmul_low_i16x8(v20, trans[1]); + v23 = wasm_i32x4_extmul_low_i16x8(v20, trans[2]); + v24 = wasm_i32x4_extmul_low_i16x8(v20, trans[3]); + v25 = wasm_i32x4_extmul_low_i16x8(v20, trans[4]); + v26 = wasm_i32x4_extmul_low_i16x8(v20, trans[5]); + v27 = wasm_i32x4_extmul_low_i16x8(v20, trans[6]); + v28 = wasm_i32x4_extmul_low_i16x8(v20, trans[7]); + + add_member(v20, trans[1], trans[4], trans[7], trans[5], + trans[2], trans[0], trans[3], trans[6], + add, add, add, sub, sub, sub, sub, sub, high); + add_member(v17, trans[2], trans[7], trans[3], trans[1], + trans[6], trans[4], trans[0], trans[5], + add, add, sub, sub, sub, add, add, add, low); + add_member(v17, trans[3], trans[5], trans[1], trans[7], + trans[0], trans[6], trans[2], trans[4], + add, sub, sub, add, add, add, sub, sub, high); + add_member(v18, trans[4], trans[2], trans[6], trans[0], + trans[7], trans[1], trans[5], trans[3], + add, sub, sub, add, sub, sub, add, add, low); + add_member(v18, trans[5], trans[0], trans[4], trans[6], + trans[1], trans[3], trans[7], trans[2], + add, sub, add, add, sub, add, add, sub, high); + add_member(v19, trans[6], trans[3], trans[0], trans[2], + trans[5], trans[7], trans[4], trans[1], + add, sub, add, sub, add, add, sub, add, low); + add_member(v19, trans[7], trans[6], trans[5], trans[4], + trans[3], trans[2], trans[1], trans[0], + add, sub, add, sub, add, sub, add, sub, high); + + x4 = &sp[offset]; + v16 = wasm_v128_load(x4); + x4 += 16; + v17 = wasm_v128_load(x4); + x4 += 16; + v18 = wasm_v128_load(x4); + x4 += 16; + v19 = wasm_v128_load(x4); + butterfly16(v16, v21, v17, v22, v18, v23, v19, v24); + + if (shift > 0) { + scale(&v29, &v30, &v31, &v24, + v20, v16, v21, v17, v22, v18, v23, v19, + shift); + transpose16_4x4_2(&v29, &v30, &v31, &v24); + x1 = buf; + x3 = &buf[24 + 3 * 32]; + store16(v29, v30, v31, v24, x1, x3, 32, -32); + } else { + store_to_stack(sp, offset, offset + 240, + v20, v21, v22, v23, v19, v18, v17, v16); + } + + x4 = &sp[offset + 64]; + v16 = wasm_v128_load(x4); + x4 += 16; + v17 = wasm_v128_load(x4); + x4 += 16; + v18 = wasm_v128_load(x4); + x4 += 16; + v19 = wasm_v128_load(x4); + butterfly16(v16, v25, v17, v26, v18, v27, v19, v28); + + if (shift > 0) { + scale(&v29, &v30, &v31, &v20, + v20, v16, v25, v17, v26, v18, v27, v19, + shift); + transpose16_4x4_2(&v29, &v30, &v31, &v20); + x1 = &buf[8]; + x3 = &buf[16 + 3 * 32]; + store16(v29, v30, v31, v20, x1, x3, 32, -32); + } else { + store_to_stack(sp, offset + 64, offset + 176, + v20, v25, v26, v27, v19, v18, v17, v16); + } +} + +static void idct_16x16(char *coeffs, int bit_depth) +{ + DECLARE_ALIGNED(16, char, sp)[640]; + + for (int i = 0; i < 4; i++) { + char *x5 = &coeffs[8 * i]; + char *x6 = &sp[8 * i * 16]; + tr_16x4(x5, x6, sp, 7, 512, 1); + } + + for (int i = 0; i < 4; i++) { + char *x5 = &sp[8 * i]; + char *x6 = &coeffs[8 * i * 16]; + tr_16x4(x5, x6, sp, 20 - bit_depth, 512, 1); + } +} + +void ff_hevc_idct_16x16_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_16x16((char *)coeffs, 8); +} + +void ff_hevc_idct_16x16_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_16x16((char *)coeffs, 10); +} + +#define add_member32(in, t0, t1, t2, t3, op0, op1, op2, op3, half) \ + do { \ + sum_sub(v24, in, t0, op0, half) \ + sum_sub(v25, in, t1, op1, half) \ + sum_sub(v26, in, t2, op2, half) \ + sum_sub(v27, in, t3, op3, half) \ + } while (0) + +#define butterfly32(in0, in1, in2, in3, out) \ + do { \ + out = wasm_i32x4_add(in0, in1); \ + in0 = wasm_i32x4_sub(in0, in1); \ + in1 = wasm_i32x4_add(in2, in3); \ + in2 = wasm_i32x4_sub(in2, in3); \ + } while (0) + +static void tr_32x4(char *x5, char *x11, char *sp, int shift) +{ + char *x1, *x3, *x4; + // transform in v0 - v4 + v128_t v0[4]; + v128_t v1[4]; + v128_t v2[4]; + v128_t v3[4]; + v128_t v4, v5, v6, v7, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33; + + tr_16x4(x5, x11, sp, 0, 2048, 4); + + // load32 + x1 = &x5[64]; + x3 = &x1[128]; + v4 = wasm_v128_load64_zero(x1); + v4 = wasm_v128_load64_lane(x3, v4, 1); + x1 += 256; + x3 += 256; + v5 = wasm_v128_load64_zero(x1); + v5 = wasm_v128_load64_lane(x3, v5, 1); + x1 += 256; + x3 += 256; + v6 = wasm_v128_load64_zero(x1); + v6 = wasm_v128_load64_lane(x3, v6, 1); + x1 += 256; + x3 += 256; + v7 = wasm_v128_load64_zero(x1); + v7 = wasm_v128_load64_lane(x3, v7, 1); + x1 += 256; + x3 += 256; + v16 = wasm_v128_load64_zero(x1); + v16 = wasm_v128_load64_lane(x3, v16, 1); + x1 += 256; + x3 += 256; + v17 = wasm_v128_load64_zero(x1); + v17 = wasm_v128_load64_lane(x3, v17, 1); + x1 += 256; + x3 += 256; + v18 = wasm_v128_load64_zero(x1); + v18 = wasm_v128_load64_lane(x3, v18, 1); + x1 += 256; + x3 += 256; + v19 = wasm_v128_load64_zero(x1); + v19 = wasm_v128_load64_lane(x3, v19, 1); + + // load transform + v0[0] = wasm_i16x8_const_splat(transform[16 + 0]); + v0[1] = wasm_i16x8_const_splat(transform[16 + 1]); + v0[2] = wasm_i16x8_const_splat(transform[16 + 2]); + v0[3] = wasm_i16x8_const_splat(transform[16 + 3]); + v1[0] = wasm_i16x8_const_splat(transform[16 + 4]); + v1[1] = wasm_i16x8_const_splat(transform[16 + 5]); + v1[2] = wasm_i16x8_const_splat(transform[16 + 6]); + v1[3] = wasm_i16x8_const_splat(transform[16 + 7]); + v2[0] = wasm_i16x8_const_splat(transform[16 + 8]); + v2[1] = wasm_i16x8_const_splat(transform[16 + 9]); + v2[2] = wasm_i16x8_const_splat(transform[16 + 10]); + v2[3] = wasm_i16x8_const_splat(transform[16 + 11]); + v3[0] = wasm_i16x8_const_splat(transform[16 + 12]); + v3[1] = wasm_i16x8_const_splat(transform[16 + 13]); + v3[2] = wasm_i16x8_const_splat(transform[16 + 14]); + v3[3] = wasm_i16x8_const_splat(transform[16 + 15]); + + // tr_block1 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v0[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v0[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v0[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v0[3]); + + add_member32(v4, v0[1], v1[0], v1[3], v2[2], add, add, add, add, high); + add_member32(v5, v0[2], v1[3], v3[0], v3[2], add, add, add, sub, low); + add_member32(v5, v0[3], v2[2], v3[2], v1[3], add, add, sub, sub, high); + add_member32(v6, v1[0], v3[1], v2[1], v0[0], add, add, sub, sub, low); + add_member32(v6, v1[1], v3[3], v1[0], v1[2], add, sub, sub, sub, high); + add_member32(v7, v1[2], v3[0], v0[0], v3[1], add, sub, sub, sub, low); + add_member32(v7, v1[3], v2[1], v1[1], v2[3], add, sub, sub, add, high); + add_member32(v16, v2[0], v1[2], v2[2], v1[0], add, sub, sub, add, low); + add_member32(v16, v2[1], v0[3], v3[3], v0[2], add, sub, sub, add, high); + add_member32(v17, v2[2], v0[1], v2[3], v2[1], add, sub, add, add, low); + add_member32(v17, v2[3], v0[2], v1[2], v3[3], add, sub, add, sub, high); + add_member32(v18, v3[0], v1[1], v0[1], v2[0], add, sub, add, sub, low); + add_member32(v18, v3[1], v2[0], v0[3], v0[1], add, sub, add, sub, high); + add_member32(v19, v3[2], v2[3], v2[0], v1[1], add, sub, add, sub, low); + add_member32(v19, v3[3], v3[2], v3[1], v3[0], add, sub, add, sub, high); + + x4 = &sp[2048]; + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = x11; + x3 = &x11[56 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // tr_block2 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v1[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v1[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v1[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v1[3]); + + add_member32(v4, v3[1], v3[3], v3[0], v2[1], add, sub, sub, sub, high); + add_member32(v5, v2[1], v1[0], v0[0], v1[1], sub, sub, sub, sub, low); + add_member32(v5, v0[0], v1[2], v3[1], v2[3], sub, sub, sub, add, high); + add_member32(v6, v2[0], v3[2], v1[1], v0[3], sub, add, add, add, low); + add_member32(v6, v3[2], v0[3], v1[3], v3[1], add, add, add, sub, high); + add_member32(v7, v1[1], v1[3], v2[3], v0[0], add, add, sub, sub, low); + add_member32(v7, v0[3], v3[1], v0[1], v3[3], add, sub, sub, add, high); + add_member32(v16, v3[0], v0[2], v3[2], v0[1], add, sub, sub, add, low); + add_member32(v16, v2[2], v2[0], v1[0], v3[2], sub, sub, add, add, high); + add_member32(v17, v0[1], v3[0], v2[0], v0[2], sub, add, add, sub, low); + add_member32(v17, v1[3], v0[1], v2[2], v3[0], sub, add, sub, sub, high); + add_member32(v18, v3[3], v2[1], v0[2], v1[0], add, add, sub, add, low); + add_member32(v18, v1[2], v2[3], v3[3], v2[2], add, sub, sub, add, high); + add_member32(v19, v0[2], v0[1], v0[3], v1[2], add, sub, add, sub, low); + add_member32(v19, v2[3], v2[2], v2[1], v2[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[8]; + x3 = &x11[48 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // tr_block3 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v2[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v2[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v2[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v2[3]); + add_member32(v4, v1[2], v0[3], v0[0], v0[2], sub, sub, sub, sub, high); + add_member32(v5, v2[2], v3[3], v2[3], v1[2], sub, sub, add, add, low); + add_member32(v5, v1[0], v0[2], v2[1], v3[3], add, add, add, sub, high); + add_member32(v6, v3[0], v2[2], v0[1], v1[3], add, sub, sub, sub, low); + add_member32(v6, v0[2], v2[0], v3[0], v0[0], sub, sub, add, add, high); + add_member32(v7, v3[2], v1[0], v2[0], v2[2], sub, add, add, sub, low); + add_member32(v7, v0[0], v3[2], v0[2], v3[0], add, add, sub, sub, high); + add_member32(v16, v3[3], v0[1], v3[1], v0[3], sub, sub, add, add, low); + add_member32(v16, v0[1], v2[3], v1[3], v1[1], sub, add, add, sub, high); + add_member32(v17, v3[1], v1[3], v0[3], v3[2], add, add, sub, add, low); + add_member32(v17, v0[3], v1[1], v3[2], v2[0], add, sub, add, add, high); + add_member32(v18, v2[3], v3[1], v1[2], v0[1], sub, sub, add, sub, low); + add_member32(v18, v1[1], v0[0], v1[0], v2[1], sub, add, sub, add, high); + add_member32(v19, v2[1], v3[0], v3[3], v3[1], add, sub, add, add, low); + add_member32(v19, v1[3], v1[2], v1[1], v1[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + x4 += 16; + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[16]; + x3 = &x11[40 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); + + // try_block4 + v24 = wasm_i32x4_extmul_low_i16x8(v4, v3[0]); + v25 = wasm_i32x4_extmul_low_i16x8(v4, v3[1]); + v26 = wasm_i32x4_extmul_low_i16x8(v4, v3[2]); + v27 = wasm_i32x4_extmul_low_i16x8(v4, v3[3]); + add_member32(v4, v1[1], v2[0], v2[3], v3[2], sub, sub, sub, sub, high); + add_member32(v5, v0[0], v0[3], v2[0], v3[1], add, add, add, add, low); + add_member32(v5, v2[0], v0[0], v1[1], v3[0], sub, sub, sub, sub, high); + add_member32(v6, v3[3], v1[2], v0[2], v2[3], add, add, add, add, low); + add_member32(v6, v2[1], v2[3], v0[0], v2[2], add, sub, sub, sub, high); + add_member32(v7, v0[2], v3[3], v0[3], v2[1], sub, sub, add, add, low); + add_member32(v7, v1[0], v2[2], v1[2], v2[0], add, add, sub, sub, high); + add_member32(v16, v2[3], v1[1], v2[1], v1[3], sub, sub, add, add, low); + add_member32(v16, v3[1], v0[1], v3[0], v1[2], sub, add, sub, sub, high); + add_member32(v17, v1[2], v1[0], v3[3], v1[1], add, sub, add, add, low); + add_member32(v17, v0[1], v2[1], v3[1], v1[0], sub, add, add, sub, high); + add_member32(v18, v1[3], v3[2], v2[2], v0[3], add, sub, sub, add, low); + add_member32(v18, v3[2], v3[0], v1[3], v0[2], sub, sub, add, sub, high); + add_member32(v19, v2[2], v1[3], v1[0], v0[1], sub, add, sub, add, low); + add_member32(v19, v0[3], v0[2], v0[1], v0[0], add, sub, add, sub, high); + + // scale_store + v28 = wasm_v128_load(x4); + x4 += 16; + v29 = wasm_v128_load(x4); + x4 += 16; + v30 = wasm_v128_load(x4); + x4 += 16; + v31 = wasm_v128_load(x4); + butterfly32(v28, v24, v29, v25, v32); + butterfly32(v30, v26, v31, v27, v33); + scale(&v20, &v21, &v22, &v23, v32, v28, v24, v29, v33, v30, v26, v31, shift); + transpose16_4x4_2(&v20, &v21, &v22, &v23); + x1 = &x11[24]; + x3 = &x11[32 + 3 * 64]; + store16(v20, v21, v22, v23, x1, x3, 64, -64); +} + +static void idct_32x32(char *coeffs, int bit_depth) +{ + DECLARE_ALIGNED(16, char, sp)[2432]; + char *x5, *x11; + + for (int i = 0; i < 8; i++) { + x5 = &coeffs[8 * i]; + x11 = &sp[8 * i * 32]; + tr_32x4(x5, x11, sp, 7); + } + + for (int i = 0; i < 8; i++) { + x5 = &sp[8 * i]; + x11 = &coeffs[8 * i * 32]; + tr_32x4(x5, x11, sp, 20 - bit_depth); + } +} + +void ff_hevc_idct_32x32_8_simd128(int16_t *coeffs, int col_limit) +{ + idct_32x32((char *)coeffs, 8); +} + +void ff_hevc_idct_32x32_10_simd128(int16_t *coeffs, int col_limit) +{ + idct_32x32((char *)coeffs, 10); +} diff --git a/libavcodec/wasm/hevc/idct.h b/libavcodec/wasm/hevc/idct.h new file mode 100644 index 0000000000..05c64ae683 --- /dev/null +++ b/libavcodec/wasm/hevc/idct.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_WASM_HEVC_IDCT_H +#define AVCODEC_WASM_HEVC_IDCT_H + +#include + +void ff_hevc_idct_4x4_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_8_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_8_simd128(int16_t *coeffs, int col_limit); + +void ff_hevc_idct_4x4_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_10_simd128(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_10_simd128(int16_t *coeffs, int col_limit); + +#endif /* AVCODEC_WASM_HEVC_IDCT_H */ diff --git a/libavcodec/wasm/hevc/sao.c b/libavcodec/wasm/hevc/sao.c new file mode 100644 index 0000000000..a863b8e720 --- /dev/null +++ b/libavcodec/wasm/hevc/sao.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sao.h" + +#include + +#include "libavcodec/defs.h" + +#define HEVC_MAX_PB_SIZE 64 + +void ff_hevc_sao_band_filter_8x8_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + ptrdiff_t stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height) +{ + int8_t offset_table[32] = {0}; + v128_t offset_low, offset_high; + + for (int k = 0; k < 4; k++) + offset_table[(k + sao_left_class) & 31] = (int8_t)sao_offset_val[k + 1]; + + offset_low = wasm_v128_load(offset_table); + offset_high = wasm_v128_load(&offset_table[16]); + + for (int y = height; y > 0; y -= 2) { + v128_t src_v, src_high; + v128_t v0, v1; + + src_v = wasm_v128_load64_zero(src); + src += stride_src; + src_v = wasm_v128_load64_lane(src, src_v, 1); + src += stride_src; + + v0 = wasm_u8x16_shr(src_v, 3); + v1 = wasm_i8x16_sub(v0, wasm_i8x16_const_splat(16)); + v0 = wasm_i8x16_swizzle(offset_low, v0); + v1 = wasm_i8x16_swizzle(offset_high, v1); + v0 = wasm_v128_or(v0, v1); + src_high = wasm_u16x8_extend_high_u8x16(src_v); + v1 = wasm_i16x8_extend_high_i8x16(v0); + src_v = wasm_u16x8_extend_low_u8x16(src_v); + v0 = wasm_i16x8_extend_low_i8x16(v0); + + v0 = wasm_i16x8_add_sat(src_v, v0); + v1 = wasm_i16x8_add_sat(src_high, v1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + + wasm_v128_store64_lane(dst, v0, 0); + dst += stride_dst; + wasm_v128_store64_lane(dst, v0, 1); + dst += stride_dst; + } +} + +void ff_hevc_sao_band_filter_16x16_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + ptrdiff_t stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height) +{ + int8_t offset_table[32] = {0}; + v128_t offset_low, offset_high; + + for (int k = 0; k < 4; k++) + offset_table[(k + sao_left_class) & 31] = (int8_t)sao_offset_val[k + 1]; + + offset_low = wasm_v128_load(offset_table); + offset_high = wasm_v128_load(&offset_table[16]); + + for (int y = height; y > 0; y--) { + for (int x = 0; x < width; x += 16) { + v128_t src_v, src_high; + v128_t v0, v1; + + src_v = wasm_v128_load(&src[x]); + + v0 = wasm_u8x16_shr(src_v, 3); + v1 = wasm_i8x16_sub(v0, wasm_i8x16_const_splat(16)); + v0 = wasm_i8x16_swizzle(offset_low, v0); + v1 = wasm_i8x16_swizzle(offset_high, v1); + v0 = wasm_v128_or(v0, v1); + src_high = wasm_u16x8_extend_high_u8x16(src_v); + v1 = wasm_i16x8_extend_high_i8x16(v0); + src_v = wasm_u16x8_extend_low_u8x16(src_v); + v0 = wasm_i16x8_extend_low_i8x16(v0); + + v0 = wasm_i16x8_add_sat(src_v, v0); + v1 = wasm_i16x8_add_sat(src_high, v1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + wasm_v128_store(&dst[x], v0); + } + + dst += stride_dst; + src += stride_src; + } +} + +void ff_hevc_sao_edge_filter_8x8_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height) +{ + 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 + }; + int a_stride, b_stride; + ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + const v128_t edge_idx = wasm_u8x16_make(1, 2, 0, 3, + 4, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + v128_t sao_offset = wasm_v128_load(sao_offset_val); + v128_t one = wasm_i8x16_const_splat(1); + v128_t two = wasm_i8x16_const_splat(2); + + a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; + b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; + for (int y = height; y > 0; y -= 2) { + v128_t v0, v1, v2; + v128_t diff0, diff1; + + v0 = wasm_v128_load64_zero(src); + v1 = wasm_v128_load64_zero(src + a_stride); + v2 = wasm_v128_load64_zero(src + b_stride); + src += stride_src; + v0 = wasm_v128_load64_lane(src, v0, 1); + v1 = wasm_v128_load64_lane(src + a_stride, v1, 1); + v2 = wasm_v128_load64_lane(src + b_stride, v2, 1); + src += stride_src; + + diff0 = wasm_u8x16_gt(v0, v1); + v1 = wasm_u8x16_lt(v0, v1); + diff0 = wasm_i8x16_sub(v1, diff0); + + diff1 = wasm_u8x16_gt(v0, v2); + v2 = wasm_u8x16_lt(v0, v2); + diff1 = wasm_i8x16_sub(v2, diff1); + + v1 = wasm_i8x16_add(diff0, two); + v1 = wasm_i8x16_add(v1, diff1); + + v2 = wasm_i8x16_swizzle(edge_idx, v1); // offset_val + v1 = wasm_i8x16_shl(v2, 1); // Access int16_t + v2 = wasm_i8x16_add(v1, one); // Access upper half of int16_t + diff0 = wasm_i8x16_shuffle(v1, v2, 0, 16, 1, 17, 2, 18, 3, 19, 4, + 20, 5, 21, 6, 22, 7, 23); + diff1 = wasm_i8x16_shuffle(v1, v2, 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); + v1 = wasm_u16x8_extend_high_u8x16(v0); + v0 = wasm_u16x8_extend_low_u8x16(v0); + diff0 = wasm_i8x16_swizzle(sao_offset, diff0); + diff1 = wasm_i8x16_swizzle(sao_offset, diff1); + + v0 = wasm_i16x8_add_sat(v0, diff0); + v1 = wasm_i16x8_add_sat(v1, diff1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + + wasm_v128_store64_lane(dst, v0, 0); + dst += stride_dst; + wasm_v128_store64_lane(dst, v0, 1); + dst += stride_dst; + } +} + +void ff_hevc_sao_edge_filter_16x16_8_simd128(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height) +{ + 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 + }; + int a_stride, b_stride; + ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + const v128_t edge_idx = wasm_u8x16_make(1, 2, 0, 3, + 4, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + v128_t sao_offset = wasm_v128_load(sao_offset_val); + v128_t one = wasm_i8x16_const_splat(1); + v128_t two = wasm_i8x16_const_splat(2); + + a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; + b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; + for (int y = height; y > 0; y--) { + for (int x = 0; x < width; x += 16) { + v128_t v0, v1, v2; + v128_t diff0, diff1; + + v0 = wasm_v128_load(&src[x]); + v1 = wasm_v128_load(&src[x + a_stride]); + v2 = wasm_v128_load(&src[x + b_stride]); + + diff0 = wasm_u8x16_gt(v0, v1); + v1 = wasm_u8x16_lt(v0, v1); + diff0 = wasm_i8x16_sub(v1, diff0); + + diff1 = wasm_u8x16_gt(v0, v2); + v2 = wasm_u8x16_lt(v0, v2); + diff1 = wasm_i8x16_sub(v2, diff1); + + v1 = wasm_i8x16_add(diff0, two); + v1 = wasm_i8x16_add(v1, diff1); + + v2 = wasm_i8x16_swizzle(edge_idx, v1); // offset_val + v1 = wasm_i8x16_shl(v2, 1); // Access int16_t + v2 = wasm_i8x16_add(v1, one); // Access upper half of int16_t + diff0 = wasm_i8x16_shuffle(v1, v2, 0, 16, 1, 17, 2, 18, 3, 19, 4, + 20, 5, 21, 6, 22, 7, 23); + diff1 = wasm_i8x16_shuffle(v1, v2, 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); + v1 = wasm_u16x8_extend_high_u8x16(v0); + v0 = wasm_u16x8_extend_low_u8x16(v0); + diff0 = wasm_i8x16_swizzle(sao_offset, diff0); + diff1 = wasm_i8x16_swizzle(sao_offset, diff1); + + v0 = wasm_i16x8_add_sat(v0, diff0); + v1 = wasm_i16x8_add_sat(v1, diff1); + v0 = wasm_u8x16_narrow_i16x8(v0, v1); + wasm_v128_store(&dst[x], v0); + } + + src += stride_src; + dst += stride_dst; + } +} diff --git a/libavcodec/wasm/hevc/sao.h b/libavcodec/wasm/hevc/sao.h new file mode 100644 index 0000000000..b83d1ab78a --- /dev/null +++ b/libavcodec/wasm/hevc/sao.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Zhao Zhili + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_WASM_HEVC_SAO_H +#define AVCODEC_WASM_HEVC_SAO_H + +#include +#include + +void ff_hevc_sao_band_filter_8x8_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t _stride_dst, + ptrdiff_t _stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height); + +void ff_hevc_sao_band_filter_16x16_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t _stride_dst, + ptrdiff_t _stride_src, + const int16_t *sao_offset_val, + int sao_left_class, int width, + int height); + +void ff_hevc_sao_edge_filter_8x8_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height); + +void ff_hevc_sao_edge_filter_16x16_8_simd128(uint8_t *_dst, const uint8_t *_src, + ptrdiff_t stride_dst, + const int16_t *sao_offset_val, + int eo, int width, int height); + +#endif diff --git a/libavcodec/wavarc.c b/libavcodec/wavarc.c index 93b76c43e8..3169a5f0d6 100644 --- a/libavcodec/wavarc.c +++ b/libavcodec/wavarc.c @@ -881,11 +881,6 @@ const FFCodec ff_wavarc_decoder = { FF_CODEC_DECODE_CB(wavarc_decode), .close = wavarc_close, .p.capabilities = AV_CODEC_CAP_DR1 | -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P), }; diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index bf9aa0cdce..9c74967f74 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -28,7 +28,7 @@ #include "bytestream.h" #include "codec_internal.h" #include "get_bits.h" -#include "refstruct.h" +#include "libavutil/refstruct.h" #include "thread.h" #include "threadprogress.h" #include "unary.h" @@ -110,7 +110,7 @@ typedef struct WavpackContext { DSDContext *dsdctx; ///< RefStruct reference ThreadProgress *curr_progress, *prev_progress; ///< RefStruct references - FFRefStructPool *progress_pool; ///< RefStruct reference + AVRefStructPool *progress_pool; ///< RefStruct reference int dsd_channels; } WavpackContext; @@ -992,9 +992,9 @@ static int wv_dsd_reset(WavpackContext *s, int channels) int i; s->dsd_channels = 0; - ff_refstruct_unref(&s->dsdctx); - ff_refstruct_unref(&s->curr_progress); - ff_refstruct_unref(&s->prev_progress); + av_refstruct_unref(&s->dsdctx); + av_refstruct_unref(&s->curr_progress); + av_refstruct_unref(&s->prev_progress); if (!channels) return 0; @@ -1003,7 +1003,7 @@ static int wv_dsd_reset(WavpackContext *s, int channels) channels > SIZE_MAX / sizeof(*s->dsdctx)) return AVERROR(EINVAL); - s->dsdctx = ff_refstruct_allocz(channels * sizeof(*s->dsdctx)); + s->dsdctx = av_refstruct_allocz(channels * sizeof(*s->dsdctx)); if (!s->dsdctx) return AVERROR(ENOMEM); s->dsd_channels = channels; @@ -1022,26 +1022,26 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) WavpackContext *fsrc = src->priv_data; WavpackContext *fdst = dst->priv_data; - ff_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress); - ff_refstruct_replace(&fdst->dsdctx, fsrc->dsdctx); + av_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress); + av_refstruct_replace(&fdst->dsdctx, fsrc->dsdctx); fdst->dsd_channels = fsrc->dsd_channels; return 0; } -static av_cold int progress_pool_init_cb(FFRefStructOpaque opaque, void *obj) +static av_cold int progress_pool_init_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; return ff_thread_progress_init(progress, 1); } -static void progress_pool_reset_cb(FFRefStructOpaque opaque, void *obj) +static void progress_pool_reset_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; ff_thread_progress_reset(progress); } -static av_cold void progress_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +static av_cold void progress_pool_free_entry_cb(AVRefStructOpaque opaque, void *obj) { ThreadProgress *progress = obj; ff_thread_progress_destroy(progress); @@ -1058,8 +1058,8 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx) #if HAVE_THREADS if (ff_thread_sync_ref(avctx, offsetof(WavpackContext, progress_pool)) == FF_THREAD_IS_FIRST_THREAD) { - s->progress_pool = ff_refstruct_pool_alloc_ext(sizeof(*s->curr_progress), - FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, NULL, + s->progress_pool = av_refstruct_pool_alloc_ext(sizeof(*s->curr_progress), + AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, NULL, progress_pool_init_cb, progress_pool_reset_cb, progress_pool_free_entry_cb, NULL); @@ -1080,7 +1080,7 @@ static av_cold int wavpack_decode_end(AVCodecContext *avctx) av_freep(&s->fdec); s->fdec_num = 0; - ff_refstruct_pool_uninit(&s->progress_pool); + av_refstruct_pool_uninit(&s->progress_pool); wv_dsd_reset(s, 0); return 0; @@ -1552,8 +1552,8 @@ static int wavpack_decode_block(AVCodecContext *avctx, AVFrame *frame, int block av_assert1(!!wc->progress_pool == !!(avctx->active_thread_type & FF_THREAD_FRAME)); if (wc->progress_pool) { if (wc->dsdctx) { - ff_refstruct_unref(&wc->prev_progress); - wc->prev_progress = ff_refstruct_pool_get(wc->progress_pool); + av_refstruct_unref(&wc->prev_progress); + wc->prev_progress = av_refstruct_pool_get(wc->progress_pool); if (!wc->prev_progress) return AVERROR(ENOMEM); FFSWAP(ThreadProgress*, wc->prev_progress, wc->curr_progress); diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c index e99ab951d4..a89f3d1670 100644 --- a/libavcodec/wavpackenc.c +++ b/libavcodec/wavpackenc.c @@ -2980,9 +2980,6 @@ const FFCodec ff_wavpack_encoder = { .init = wavpack_encode_init, FF_CODEC_ENCODE_CB(wavpack_encode_frame), .close = wavpack_encode_close, - .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8P, - AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP), }; diff --git a/libavcodec/wbmpenc.c b/libavcodec/wbmpenc.c index abb66b4ca9..3b624da08f 100644 --- a/libavcodec/wbmpenc.c +++ b/libavcodec/wbmpenc.c @@ -83,8 +83,5 @@ const FFCodec ff_wbmp_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(wbmp_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]){ - AV_PIX_FMT_MONOBLACK, - AV_PIX_FMT_NONE - }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOBLACK), }; diff --git a/libavcodec/webp.c b/libavcodec/webp.c index 7c2a5f0111..7d77d64524 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -253,64 +253,44 @@ static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb) } static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_lengths, - int alphabet_size) + uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1], + uint8_t lens[], uint16_t syms[], + int alphabet_size, void *logctx) { - int len = 0, sym, code = 0, ret; - int max_code_length = 0; - uint16_t *codes; + unsigned nb_codes = 0; + int ret; - /* special-case 1 symbol since the vlc reader cannot handle it */ - for (sym = 0; sym < alphabet_size; sym++) { - if (code_lengths[sym] > 0) { - len++; - code = sym; - if (len > 1) - break; + // Count the number of symbols of each length and transform len_counts + // into an array of offsets. + for (int len = 1; len <= MAX_HUFFMAN_CODE_LENGTH; ++len) { + unsigned cnt = len_counts[len]; + len_counts[len] = nb_codes; + nb_codes += cnt; + } + + for (int sym = 0; sym < alphabet_size; ++sym) { + if (code_lengths[sym]) { + unsigned idx = len_counts[code_lengths[sym]]++; + syms[idx] = sym; + lens[idx] = code_lengths[sym]; } } - if (len == 1) { - r->nb_symbols = 1; - r->simple_symbols[0] = code; - r->simple = 1; - return 0; - } - - for (sym = 0; sym < alphabet_size; sym++) - max_code_length = FFMAX(max_code_length, code_lengths[sym]); - - if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH) - return AVERROR(EINVAL); - - codes = av_malloc_array(alphabet_size, sizeof(*codes)); - if (!codes) - return AVERROR(ENOMEM); - - code = 0; - r->nb_symbols = 0; - for (len = 1; len <= max_code_length; len++) { - for (sym = 0; sym < alphabet_size; sym++) { - if (code_lengths[sym] != len) - continue; - codes[sym] = code++; - r->nb_symbols++; + if (nb_codes <= 1) { + if (nb_codes == 1) { + /* special-case 1 symbol since the vlc reader cannot handle it */ + r->nb_symbols = 1; + r->simple = 1; + r->simple_symbols[0] = syms[0]; } - code <<= 1; - } - if (!r->nb_symbols) { - av_free(codes); + // No symbols return AVERROR_INVALIDDATA; } - - ret = vlc_init(&r->vlc, 8, alphabet_size, - code_lengths, sizeof(*code_lengths), sizeof(*code_lengths), - codes, sizeof(*codes), sizeof(*codes), VLC_INIT_OUTPUT_LE); - if (ret < 0) { - av_free(codes); + ret = ff_vlc_init_from_lengths(&r->vlc, 8, nb_codes, lens, 1, + syms, 2, 2, 0, VLC_INIT_OUTPUT_LE, logctx); + if (ret < 0) return ret; - } r->simple = 0; - av_free(codes); return 0; } @@ -335,23 +315,18 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, HuffReader code_len_hc = { { 0 }, 0, 0, { 0 } }; uint8_t *code_lengths; uint8_t code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 }; - int i, symbol, max_symbol, prev_code_len, ret; + uint8_t reordered_code_length_code_lengths[NUM_CODE_LENGTH_CODES]; + uint16_t reordered_code_length_syms[NUM_CODE_LENGTH_CODES]; + uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1] = { 0 }; + int symbol, max_symbol, prev_code_len, ret; int num_codes = 4 + get_bits(&s->gb, 4); av_assert1(num_codes <= NUM_CODE_LENGTH_CODES); - for (i = 0; i < num_codes; i++) - code_length_code_lengths[code_length_code_order[i]] = get_bits(&s->gb, 3); - - ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, - NUM_CODE_LENGTH_CODES); - if (ret < 0) - return ret; - - code_lengths = av_mallocz(alphabet_size); - if (!code_lengths) { - ret = AVERROR(ENOMEM); - goto finish; + for (int i = 0; i < num_codes; i++) { + unsigned len = get_bits(&s->gb, 3); + code_length_code_lengths[code_length_code_order[i]] = len; + len_counts[len]++; } if (get_bits1(&s->gb)) { @@ -360,35 +335,53 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, if (max_symbol > alphabet_size) { av_log(s->avctx, AV_LOG_ERROR, "max symbol %d > alphabet size %d\n", max_symbol, alphabet_size); - ret = AVERROR_INVALIDDATA; - goto finish; + return AVERROR_INVALIDDATA; } } else { max_symbol = alphabet_size; } + ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, len_counts, + reordered_code_length_code_lengths, + reordered_code_length_syms, + NUM_CODE_LENGTH_CODES, s->avctx); + if (ret < 0) + return ret; + + code_lengths = av_malloc_array(alphabet_size, 2 * sizeof(uint8_t) + sizeof(uint16_t)); + if (!code_lengths) { + ret = AVERROR(ENOMEM); + goto finish; + } + prev_code_len = 8; symbol = 0; + memset(len_counts, 0, sizeof(len_counts)); while (symbol < alphabet_size) { int code_len; if (!max_symbol--) break; code_len = huff_reader_get_symbol(&code_len_hc, &s->gb); - if (code_len < 16) { + if (code_len < 16U) { /* Code length code [0..15] indicates literal code lengths. */ code_lengths[symbol++] = code_len; + len_counts[code_len]++; if (code_len) prev_code_len = code_len; } else { int repeat = 0, length = 0; switch (code_len) { + default: + ret = AVERROR_INVALIDDATA; + goto finish; case 16: /* Code 16 repeats the previous non-zero value [3..6] times, * i.e., 3 + ReadBits(2) times. If code 16 is used before a * non-zero value has been emitted, a value of 8 is repeated. */ repeat = 3 + get_bits(&s->gb, 2); length = prev_code_len; + len_counts[length] += repeat; break; case 17: /* Code 17 emits a streak of zeros [3..10], i.e., @@ -413,7 +406,10 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc, } } - ret = huff_reader_build_canonical(hc, code_lengths, alphabet_size); + ret = huff_reader_build_canonical(hc, code_lengths, len_counts, + code_lengths + symbol, + (uint16_t*)(code_lengths + 2 * symbol), + symbol, s->avctx); finish: ff_vlc_free(&code_len_hc.vlc); @@ -704,6 +700,9 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role, ref_x = FFMAX(0, ref_x); ref_y = FFMAX(0, ref_y); + if (ref_y == y && ref_x >= x) + return AVERROR_INVALIDDATA; + /* copy pixels * source and dest regions can overlap and wrap lines, so just * copy per-pixel */ @@ -1188,6 +1187,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p, *got_frame = 1; p->pict_type = AV_PICTURE_TYPE_I; p->flags |= AV_FRAME_FLAG_KEY; + p->flags |= AV_FRAME_FLAG_LOSSLESS; ret = data_size; free_and_return: @@ -1403,7 +1403,11 @@ static int webp_decode_frame(AVCodecContext *avctx, AVFrame *p, chunk_size, 0); if (ret < 0) return ret; +#if FF_API_CODEC_PROPS +FF_DISABLE_DEPRECATION_WARNINGS avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; +FF_ENABLE_DEPRECATION_WARNINGS +#endif } bytestream2_skip(&gb, chunk_size); break; diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c index 35bdbe805d..90675bc660 100644 --- a/libavcodec/webvttdec.c +++ b/libavcodec/webvttdec.c @@ -21,7 +21,7 @@ /** * @file * WebVTT subtitle decoder - * @see http://dev.w3.org/html5/webvtt/ + * @see https://www.w3.org/TR/webvtt1/ * @todo need to support extended markups and cue settings */ @@ -34,20 +34,41 @@ static const struct { const char *from; const char *to; } webvtt_tag_replace[] = { - {"", "{\\i1}"}, {"", "{\\i0}"}, - {"", "{\\b1}"}, {"", "{\\b0}"}, - {"", "{\\u1}"}, {"", "{\\u0}"}, {"{", "\\{{}"}, {"\\", "\\\xe2\x81\xa0"}, // escape to avoid ASS markup conflicts {">", ">"}, {"<", "<"}, {"‎", "\xe2\x80\x8e"}, {"‏", "\xe2\x80\x8f"}, {"&", "&"}, {" ", "\\h"}, }; +static const struct { + const char from[6]; + const char to[6]; +} webvtt_valid_tags[] = { + {"i", "{\\i1}"}, {"/i", "{\\i0}"}, + {"b", "{\\b1}"}, {"/b", "{\\b0}"}, + {"u", "{\\u1}"}, {"/u", "{\\u0}"}, +}; static int webvtt_event_to_ass(AVBPrint *buf, const char *p) { - int i, again = 0, skip = 0; + int i, again = 0; while (*p) { + if (*p == '<') { + const char *tag_end = strchr(p, '>'); + ptrdiff_t len; + if (!tag_end) + break; + len = tag_end - p + 1; + for (i = 0; i < FF_ARRAY_ELEMS(webvtt_valid_tags); i++) { + const char *from = webvtt_valid_tags[i].from; + if(!strncmp(p + 1, from, strlen(from))) { + av_bprintf(buf, "%s", webvtt_valid_tags[i].to); + break; + } + } + p += len; + again = 1; + } for (i = 0; i < FF_ARRAY_ELEMS(webvtt_tag_replace); i++) { const char *from = webvtt_tag_replace[i].from; @@ -59,21 +80,14 @@ static int webvtt_event_to_ass(AVBPrint *buf, const char *p) break; } } - if (!*p) - break; if (again) { again = 0; - skip = 0; continue; } - if (*p == '<') - skip = 1; - else if (*p == '>') - skip = 0; - else if (p[0] == '\n' && p[1]) + if (p[0] == '\n' && p[1]) av_bprintf(buf, "\\N"); - else if (!skip && *p != '\r') + else if (*p != '\r') av_bprint_chars(buf, *p, 1); p++; } diff --git a/libavcodec/wma.c b/libavcodec/wma.c index da9c914b57..0a34c1b00e 100644 --- a/libavcodec/wma.c +++ b/libavcodec/wma.c @@ -86,8 +86,8 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2) int sample_rate1; int coef_vlc_table; - if (avctx->sample_rate <= 0 || avctx->sample_rate > 50000 || - channels <= 0 || channels > 2 || + if (avctx->sample_rate > 50000 || + channels > 2 || avctx->bit_rate <= 0) return -1; @@ -364,7 +364,7 @@ int ff_wma_total_gain_to_bits(int total_gain) return 9; } -int ff_wma_end(AVCodecContext *avctx) +av_cold int ff_wma_end(AVCodecContext *avctx) { WMACodecContext *s = avctx->priv_data; int i; diff --git a/libavcodec/wmadec.c b/libavcodec/wmadec.c index 3427e482dc..78ea25e109 100644 --- a/libavcodec/wmadec.c +++ b/libavcodec/wmadec.c @@ -368,7 +368,7 @@ static int decode_exp_vlc(WMACodecContext *s, int ch) if ((unsigned) last_exp + 60 >= FF_ARRAY_ELEMS(pow_tab)) { av_log(s->avctx, AV_LOG_ERROR, "Exponent out of range: %d\n", last_exp); - return -1; + return AVERROR_INVALIDDATA; } v = ptab[last_exp]; iv = iptab[last_exp]; @@ -439,8 +439,10 @@ static void wma_window(WMACodecContext *s, float *out) } /** - * @return 0 if OK. 1 if last block of frame. return -1 if - * unrecoverable error. + * @return + * 0 if OK. + * 1 if last block of frame. + * AVERROR if unrecoverable error. */ static int wma_decode_block(WMACodecContext *s) { @@ -468,7 +470,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "prev_block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->prev_block_len_bits = s->frame_len_bits - v; v = get_bits(&s->gb, n); @@ -476,7 +478,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->block_len_bits = s->frame_len_bits - v; } else { @@ -489,7 +491,7 @@ static int wma_decode_block(WMACodecContext *s) av_log(s->avctx, AV_LOG_ERROR, "next_block_len_bits %d out of range\n", s->frame_len_bits - v); - return -1; + return AVERROR_INVALIDDATA; } s->next_block_len_bits = s->frame_len_bits - v; } else { @@ -501,14 +503,14 @@ static int wma_decode_block(WMACodecContext *s) if (s->frame_len_bits - s->block_len_bits >= s->nb_block_sizes){ av_log(s->avctx, AV_LOG_ERROR, "block_len_bits not initialized to a valid value\n"); - return -1; + return AVERROR_INVALIDDATA; } /* now check if the block length is coherent with the frame length */ s->block_len = 1 << s->block_len_bits; if ((s->block_pos + s->block_len) > s->frame_len) { av_log(s->avctx, AV_LOG_ERROR, "frame_len overflow\n"); - return -1; + return AVERROR_INVALIDDATA; } if (channels == 2) @@ -590,7 +592,7 @@ static int wma_decode_block(WMACodecContext *s) if (s->channel_coded[ch]) { if (s->use_exp_vlc) { if (decode_exp_vlc(s, ch) < 0) - return -1; + return AVERROR_INVALIDDATA; } else { decode_exp_lsp(s, ch); } @@ -802,7 +804,7 @@ static int wma_decode_frame(WMACodecContext *s, float **samples, for (;;) { ret = wma_decode_block(s); if (ret < 0) - return -1; + return ret; if (ret) break; } @@ -879,8 +881,10 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; if ((s->last_superframe_len + buf_size - 1) > - MAX_CODED_SUPERFRAME_SIZE) + MAX_CODED_SUPERFRAME_SIZE) { + ret = AVERROR_INVALIDDATA; goto fail; + } q = s->last_superframe + s->last_superframe_len; len = buf_size - 1; @@ -911,14 +915,17 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, av_log(avctx, AV_LOG_ERROR, "Invalid last frame bit offset %d > buf size %d (%d)\n", bit_offset, get_bits_left(&s->gb), buf_size); + ret = AVERROR_INVALIDDATA; goto fail; } if (s->last_superframe_len > 0) { /* add bit_offset bits to last frame */ if ((s->last_superframe_len + ((bit_offset + 7) >> 3)) > - MAX_CODED_SUPERFRAME_SIZE) + MAX_CODED_SUPERFRAME_SIZE) { + ret = AVERROR_INVALIDDATA; goto fail; + } q = s->last_superframe + s->last_superframe_len; len = bit_offset; while (len > 7) { @@ -937,7 +944,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, skip_bits(&s->gb, s->last_bitoffset); /* this frame is stored in the last superframe and in the * current one */ - if (wma_decode_frame(s, samples, samples_offset) < 0) + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; nb_frames--; @@ -954,7 +961,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, s->reset_block_lengths = 1; for (i = 0; i < nb_frames; i++) { - if (wma_decode_frame(s, samples, samples_offset) < 0) + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; } @@ -967,13 +974,14 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, len = buf_size - pos; if (len > MAX_CODED_SUPERFRAME_SIZE || len < 0) { av_log(s->avctx, AV_LOG_ERROR, "len %d invalid\n", len); + ret = AVERROR_INVALIDDATA; goto fail; } s->last_superframe_len = len; memcpy(s->last_superframe, buf + pos, len); } else { /* single frame decode */ - if (wma_decode_frame(s, samples, samples_offset) < 0) + if ((ret = wma_decode_frame(s, samples, samples_offset)) < 0) goto fail; samples_offset += s->frame_len; } @@ -989,7 +997,7 @@ static int wma_decode_superframe(AVCodecContext *avctx, AVFrame *frame, fail: /* when error, we reset the bit reservoir */ s->last_superframe_len = 0; - return -1; + return ret; } static av_cold void flush(AVCodecContext *avctx) @@ -1015,8 +1023,7 @@ const FFCodec ff_wmav1_decoder = { FF_CODEC_DECODE_CB(wma_decode_superframe), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -1032,8 +1039,7 @@ const FFCodec ff_wmav2_decoder = { FF_CODEC_DECODE_CB(wma_decode_superframe), .flush = flush, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c index 6949f08fb6..51487b72b5 100644 --- a/libavcodec/wmaenc.c +++ b/libavcodec/wmaenc.c @@ -79,7 +79,7 @@ static av_cold int encode_init(AVCodecContext *avctx) AV_WL32(extradata, flags1); AV_WL16(extradata + 4, flags2); } else { - av_assert0(0); + av_unreachable("This function is only used with WMAV1/2 encoders"); } avctx->extradata = extradata; s->use_exp_vlc = flags2 & 0x0001; @@ -206,7 +206,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], // FIXME remove duplication relative to decoder if (s->use_variable_block_len) { - av_assert0(0); // FIXME not implemented + av_unreachable("use_variable_block_len unimplemented, set to 0 during init"); } else { /* fixed block len */ s->next_block_len_bits = s->frame_len_bits; @@ -306,7 +306,8 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], if (s->use_exp_vlc) { encode_exp_vlc(s, ch, fixed_exp); } else { - av_assert0(0); // FIXME not implemented + av_unreachable("use_exp_vlc always set to 1 during init"); + // FIXME not implemented // encode_exp_lsp(s, ch); } } @@ -365,7 +366,7 @@ static int encode_frame(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE], init_put_bits(&s->pb, buf, buf_size); if (s->use_bit_reservoir) - av_assert0(0); // FIXME not implemented + av_unreachable("use_bit_reseroir unimplemented, set to 0 during init"); else if (encode_block(s, src_coefs, total_gain) < 0) return INT_MAX; @@ -415,7 +416,6 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, error = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain++); if (error > 0) { av_log(avctx, AV_LOG_ERROR, "Invalid input data or requested bitrate too low, cannot encode\n"); - avpkt->size = 0; return AVERROR(EINVAL); } av_assert0((put_bits_count(&s->pb) & 7) == 0); @@ -425,7 +425,7 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, put_bits(&s->pb, 8, 'N'); flush_put_bits(&s->pb); - av_assert0(put_bits_ptr(&s->pb) - s->pb.buf == avctx->block_align); + av_assert0(put_bytes_output(&s->pb) == avctx->block_align); if (frame->pts != AV_NOPTS_VALUE) avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); @@ -446,8 +446,7 @@ const FFCodec ff_wmav1_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_superframe), .close = ff_wma_end, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif @@ -462,8 +461,7 @@ const FFCodec ff_wmav2_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_superframe), .close = ff_wma_end, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c index 9559fe1faf..f36212e19b 100644 --- a/libavcodec/wmalosslessdec.c +++ b/libavcodec/wmalosslessdec.c @@ -1335,13 +1335,7 @@ const FFCodec ff_wmalossless_decoder = { .close = decode_close, FF_CODEC_DECODE_CB(decode_packet), .flush = flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, - AV_SAMPLE_FMT_S32P, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P), }; diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index a6c4a75632..d87ed0433e 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -370,14 +370,6 @@ static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu int log2_max_num_subframes; int num_possible_block_sizes; - if (avctx->codec_id == AV_CODEC_ID_XMA1 || avctx->codec_id == AV_CODEC_ID_XMA2) - avctx->block_align = 2048; - - if (!avctx->block_align) { - av_log(avctx, AV_LOG_ERROR, "block_align is not set\n"); - return AVERROR(EINVAL); - } - s->avctx = avctx; init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE); @@ -471,11 +463,6 @@ static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu return AVERROR_INVALIDDATA; } - if (s->avctx->sample_rate <= 0) { - av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); - return AVERROR_INVALIDDATA; - } - if (s->nb_channels <= 0) { av_log(avctx, AV_LOG_ERROR, "invalid number of channels %d\n", s->nb_channels); @@ -608,6 +595,11 @@ static av_cold int wmapro_decode_init(AVCodecContext *avctx) { WMAProDecodeCtx *s = avctx->priv_data; + if (!avctx->block_align) { + av_log(avctx, AV_LOG_ERROR, "block_align is not set\n"); + return AVERROR(EINVAL); + } + return decode_init(s, avctx, 0); } @@ -1962,6 +1954,8 @@ static av_cold int xma_decode_init(AVCodecContext *avctx) XMADecodeCtx *s = avctx->priv_data; int i, ret, start_channels = 0; + avctx->block_align = 2048; + if (avctx->ch_layout.nb_channels <= 0 || avctx->extradata_size == 0) return AVERROR_INVALIDDATA; @@ -2100,14 +2094,9 @@ const FFCodec ff_wmapro_decoder = { .init = wmapro_decode_init, .close = wmapro_decode_end, FF_CODEC_DECODE_CB(wmapro_decode_packet), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1, .flush = wmapro_flush, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -2121,13 +2110,8 @@ const FFCodec ff_xma1_decoder = { .close = xma_decode_end, FF_CODEC_DECODE_CB(xma_decode_packet), .flush = xma_flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; @@ -2141,12 +2125,7 @@ const FFCodec ff_xma2_decoder = { .close = xma_decode_end, FF_CODEC_DECODE_CB(xma_decode_packet), .flush = xma_flush, - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, - AV_SAMPLE_FMT_NONE }, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 39868e02b3..7fc735ad1d 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -199,7 +199,7 @@ typedef struct WMAVoiceContext { ///< to #wmavoice_decode_packet() (since ///< they're part of the previous superframe) - uint8_t sframe_cache[SFRAME_CACHE_MAXSIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + uint8_t sframe_cache[SFRAME_CACHE_MAXSIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< ///< cache for superframe data split over ///< multiple packets int sframe_cache_size; ///< set to >0 if we have data from an @@ -249,10 +249,9 @@ typedef struct WMAVoiceContext { ///< only used for comfort noise in #pRNG() int nb_superframes; ///< number of superframes in current packet float gain_pred_err[6]; ///< cache for gain prediction - float excitation_history[MAX_SIGNAL_HISTORY]; - ///< cache of the signal of previous - ///< superframes, used as a history for - ///< signal generation + float excitation_history[MAX_SIGNAL_HISTORY]; ///< cache of the signal of + ///< previous superframes, used as a history + ///< for signal generation float synth_history[MAX_LSPS]; ///< see #excitation_history /** * @} @@ -272,18 +271,16 @@ typedef struct WMAVoiceContext { float postfilter_agc; ///< gain control memory, used in ///< #adaptive_gain_control() float dcf_mem[2]; ///< DC filter history + /// zero filter output (i.e. excitation) by postfilter float zero_exc_pf[MAX_SIGNAL_HISTORY + MAX_SFRAMESIZE]; - ///< zero filter output (i.e. excitation) - ///< by postfilter float denoise_filter_cache[MAX_FRAMESIZE]; int denoise_filter_cache_size; ///< samples in #denoise_filter_cache + /// aligned buffer for LPC tilting DECLARE_ALIGNED(32, float, tilted_lpcs_pf)[0x82]; - ///< aligned buffer for LPC tilting + /// aligned buffer for denoise coefficients DECLARE_ALIGNED(32, float, denoise_coeffs_pf)[0x82]; - ///< aligned buffer for denoise coefficients + /// aligned buffer for postfilter speech synthesis DECLARE_ALIGNED(32, float, synth_filter_out_buf)[0x80 + MAX_LSPS_ALIGN16]; - ///< aligned buffer for postfilter speech - ///< synthesis /** * @} */ @@ -562,7 +559,7 @@ static int kalman_smoothen(WMAVoiceContext *s, int pitch, /* find best fitting point in history */ do { - dot = avpriv_scalarproduct_float_c(in, ptr, size); + dot = ff_scalarproduct_float_c(in, ptr, size); if (dot > optimal_gain) { optimal_gain = dot; best_hist_ptr = ptr; @@ -571,7 +568,7 @@ static int kalman_smoothen(WMAVoiceContext *s, int pitch, if (optimal_gain <= 0) return -1; - dot = avpriv_scalarproduct_float_c(best_hist_ptr, best_hist_ptr, size); + dot = ff_scalarproduct_float_c(best_hist_ptr, best_hist_ptr, size); if (dot <= 0) // would be 1.0 return -1; @@ -601,8 +598,8 @@ static float tilt_factor(const float *lpcs, int n_lpcs) { float rh0, rh1; - rh0 = 1.0 + avpriv_scalarproduct_float_c(lpcs, lpcs, n_lpcs); - rh1 = lpcs[0] + avpriv_scalarproduct_float_c(lpcs, &lpcs[1], n_lpcs - 1); + rh0 = 1.0 + ff_scalarproduct_float_c(lpcs, lpcs, n_lpcs); + rh1 = lpcs[0] + ff_scalarproduct_float_c(lpcs, &lpcs[1], n_lpcs - 1); return rh1 / rh0; } @@ -702,8 +699,8 @@ static void calc_input_response(WMAVoiceContext *s, float *lpcs_src, -1.8 * tilt_factor(coeffs_dst, remainder - 1), coeffs_dst, remainder); } - sq = (1.0 / 64.0) * sqrtf(1 / avpriv_scalarproduct_float_c(coeffs_dst, coeffs_dst, - remainder)); + sq = (1.0 / 64.0) * sqrtf(1 / ff_scalarproduct_float_c(coeffs_dst, coeffs_dst, + remainder)); for (n = 0; n < remainder; n++) coeffs_dst[n] *= sq; } @@ -1381,8 +1378,8 @@ static void synth_block_fcb_acb(WMAVoiceContext *s, GetBitContext *gb, /* Calculate gain for adaptive & fixed codebook signal. * see ff_amr_set_fixed_gain(). */ idx = get_bits(gb, 7); - fcb_gain = expf(avpriv_scalarproduct_float_c(s->gain_pred_err, - gain_coeff, 6) - + fcb_gain = expf(ff_scalarproduct_float_c(s->gain_pred_err, + gain_coeff, 6) - 5.2409161640 + wmavoice_gain_codebook_fcb[idx]); acb_gain = wmavoice_gain_codebook_acb[idx]; pred_err = av_clipf(wmavoice_gain_codebook_fcb[idx], @@ -2030,11 +2027,7 @@ const FFCodec ff_wmavoice_decoder = { .init = wmavoice_decode_init, .close = wmavoice_decode_end, FF_CODEC_DECODE_CB(wmavoice_decode_packet), - .p.capabilities = -#if FF_API_SUBFRAMES - AV_CODEC_CAP_SUBFRAMES | -#endif - AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = wmavoice_flush, }; diff --git a/libavcodec/wmv2.h b/libavcodec/wmv2.h index 6fc9704c3d..409d9456ab 100644 --- a/libavcodec/wmv2.h +++ b/libavcodec/wmv2.h @@ -44,7 +44,7 @@ void ff_mspel_motion(MpegEncContext *s, int motion_x, int motion_y, int h); -static av_always_inline int wmv2_get_cbp_table_index(MpegEncContext *s, int cbp_index) +static av_always_inline int wmv2_get_cbp_table_index(int qscale, int cbp_index) { static const uint8_t map[3][3] = { { 0, 2, 1 }, @@ -52,7 +52,7 @@ static av_always_inline int wmv2_get_cbp_table_index(MpegEncContext *s, int cbp_ { 2, 1, 0 }, }; - return map[(s->qscale > 10) + (s->qscale > 20)][cbp_index]; + return map[(qscale > 10) + (qscale > 20)][cbp_index]; } #endif /* AVCODEC_WMV2_H */ diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index 677467ccc2..512d63b23e 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -37,7 +37,7 @@ #include "wmv2dec.h" typedef struct WMV2DecContext { - MpegEncContext s; + MSMP4DecContext ms; WMV2Context common; IntraX8Context x8; int j_type_bit; @@ -56,12 +56,13 @@ typedef struct WMV2DecContext { DECLARE_ALIGNED(32, int16_t, abt_block2)[6][64]; } WMV2DecContext; -static void wmv2_add_block(WMV2DecContext *w, int16_t *block1, +static void wmv2_add_block(WMV2DecContext *w, int16_t blocks1[][64], uint8_t *dst, int stride, int n) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; - if (s->block_last_index[n] >= 0) { + if (h->c.block_last_index[n] >= 0) { + int16_t *block1 = blocks1[n]; switch (w->abt_type_table[n]) { case 0: w->common.wdsp.idct_add(dst, stride, block1); @@ -69,15 +70,15 @@ static void wmv2_add_block(WMV2DecContext *w, int16_t *block1, case 1: ff_simple_idct84_add(dst, stride, block1); ff_simple_idct84_add(dst + 4 * stride, stride, w->abt_block2[n]); - s->bdsp.clear_block(w->abt_block2[n]); + h->c.bdsp.clear_block(w->abt_block2[n]); break; case 2: ff_simple_idct48_add(dst, stride, block1); ff_simple_idct48_add(dst + 4, stride, w->abt_block2[n]); - s->bdsp.clear_block(w->abt_block2[n]); + h->c.bdsp.clear_block(w->abt_block2[n]); break; default: - av_log(s->avctx, AV_LOG_ERROR, "internal error in WMV2 abt\n"); + av_log(h->c.avctx, AV_LOG_ERROR, "internal error in WMV2 abt\n"); } } } @@ -87,78 +88,77 @@ void ff_wmv2_add_mb(MpegEncContext *s, int16_t block1[6][64], { WMV2DecContext *const w = (WMV2DecContext *) s; - wmv2_add_block(w, block1[0], dest_y, s->linesize, 0); - wmv2_add_block(w, block1[1], dest_y + 8, s->linesize, 1); - wmv2_add_block(w, block1[2], dest_y + 8 * s->linesize, s->linesize, 2); - wmv2_add_block(w, block1[3], dest_y + 8 + 8 * s->linesize, s->linesize, 3); + wmv2_add_block(w, block1, dest_y, s->linesize, 0); + wmv2_add_block(w, block1, dest_y + 8, s->linesize, 1); + wmv2_add_block(w, block1, dest_y + 8 * s->linesize, s->linesize, 2); + wmv2_add_block(w, block1, dest_y + 8 + 8 * s->linesize, s->linesize, 3); if (s->avctx->flags & AV_CODEC_FLAG_GRAY) return; - wmv2_add_block(w, block1[4], dest_cb, s->uvlinesize, 4); - wmv2_add_block(w, block1[5], dest_cr, s->uvlinesize, 5); + wmv2_add_block(w, block1, dest_cb, s->uvlinesize, 4); + wmv2_add_block(w, block1, dest_cr, s->uvlinesize, 5); } static int parse_mb_skip(WMV2DecContext *w) { - int mb_x, mb_y; + H263DecContext *const h = &w->ms.h; int coded_mb_count = 0; - MpegEncContext *const s = &w->s; - uint32_t *const mb_type = s->cur_pic.mb_type; + uint32_t *const mb_type = h->c.cur_pic.mb_type; - w->skip_type = get_bits(&s->gb, 2); + w->skip_type = get_bits(&h->gb, 2); switch (w->skip_type) { case SKIP_TYPE_NONE: - 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] = + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; break; case SKIP_TYPE_MPEG: - if (get_bits_left(&s->gb) < s->mb_height * s->mb_width) + if (get_bits_left(&h->gb) < h->c.mb_height * h->c.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] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; break; case SKIP_TYPE_ROW: - for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - if (get_bits_left(&s->gb) < 1) + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) { + if (get_bits_left(&h->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] = + if (get_bits1(&h->gb)) { + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - mb_type[mb_y * s->mb_stride + mb_x] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; case SKIP_TYPE_COL: - for (mb_x = 0; mb_x < s->mb_width; mb_x++) { - if (get_bits_left(&s->gb) < 1) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) { + if (get_bits_left(&h->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] = + if (get_bits1(&h->gb)) { + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + mb_type[mb_y * h->c.mb_stride + mb_x] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } else { - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - mb_type[mb_y * s->mb_stride + mb_x] = - (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + mb_type[mb_y * h->c.mb_stride + mb_x] = + (get_bits1(&h->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; } - for (mb_y = 0; mb_y < s->mb_height; mb_y++) - for (mb_x = 0; mb_x < s->mb_width; mb_x++) - coded_mb_count += !IS_SKIP(mb_type[mb_y * s->mb_stride + mb_x]); + for (int mb_y = 0; mb_y < h->c.mb_height; mb_y++) + for (int mb_x = 0; mb_x < h->c.mb_width; mb_x++) + coded_mb_count += !IS_SKIP(mb_type[mb_y * h->c.mb_stride + mb_x]); - if (coded_mb_count > get_bits_left(&s->gb)) + if (coded_mb_count > get_bits_left(&h->gb)) return AVERROR_INVALIDDATA; return 0; @@ -166,20 +166,20 @@ static int parse_mb_skip(WMV2DecContext *w) static int decode_ext_header(WMV2DecContext *w) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; GetBitContext gb; int fps; int code; - if (s->avctx->extradata_size < 4) + if (h->c.avctx->extradata_size < 4) return AVERROR_INVALIDDATA; - init_get_bits(&gb, s->avctx->extradata, 32); + init_get_bits(&gb, h->c.avctx->extradata, 32); fps = get_bits(&gb, 5); - s->bit_rate = get_bits(&gb, 11) * 1024; + w->ms.bit_rate = get_bits(&gb, 11) * 1024; w->mspel_bit = get_bits1(&gb); - s->loop_filter = get_bits1(&gb); + h->loop_filter = get_bits1(&gb); w->abt_flag = get_bits1(&gb); w->j_type_bit = get_bits1(&gb); w->top_left_mv_flag = get_bits1(&gb); @@ -189,36 +189,36 @@ static int decode_ext_header(WMV2DecContext *w) if (code == 0) return AVERROR_INVALIDDATA; - s->slice_height = s->mb_height / code; + h->slice_height = h->c.mb_height / code; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) - av_log(s->avctx, AV_LOG_DEBUG, - "fps:%d, br:%"PRId64", qpbit:%d, abt_flag:%d, j_type_bit:%d, " + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->c.avctx, AV_LOG_DEBUG, + "fps:%d, br:%d, qpbit:%d, abt_flag:%d, j_type_bit:%d, " "tl_mv_flag:%d, mbrl_bit:%d, code:%d, loop_filter:%d, " "slices:%d\n", - fps, s->bit_rate, w->mspel_bit, w->abt_flag, w->j_type_bit, - w->top_left_mv_flag, w->per_mb_rl_bit, code, s->loop_filter, + fps, w->ms.bit_rate, w->mspel_bit, w->abt_flag, w->j_type_bit, + w->top_left_mv_flag, w->per_mb_rl_bit, code, h->loop_filter, code); return 0; } -int ff_wmv2_decode_picture_header(MpegEncContext *s) +static int wmv2_decode_picture_header(H263DecContext *const h) { int code; - s->pict_type = get_bits1(&s->gb) + 1; - if (s->pict_type == AV_PICTURE_TYPE_I) { - code = get_bits(&s->gb, 7); - av_log(s->avctx, AV_LOG_DEBUG, "I7:%X/\n", code); + h->c.pict_type = get_bits1(&h->gb) + 1; + if (h->c.pict_type == AV_PICTURE_TYPE_I) { + code = get_bits(&h->gb, 7); + av_log(h->c.avctx, AV_LOG_DEBUG, "I7:%X/\n", code); } - s->chroma_qscale = s->qscale = get_bits(&s->gb, 5); - if (s->qscale <= 0) + h->c.chroma_qscale = h->c.qscale = get_bits(&h->gb, 5); + if (h->c.qscale <= 0) return AVERROR_INVALIDDATA; - if (s->pict_type != AV_PICTURE_TYPE_I && show_bits(&s->gb, 1)) { - GetBitContext gb = s->gb; + if (h->c.pict_type != AV_PICTURE_TYPE_I && show_bits(&h->gb, 1)) { + GetBitContext gb = h->gb; int skip_type = get_bits(&gb, 2); - int run = skip_type == SKIP_TYPE_COL ? s->mb_width : s->mb_height; + int run = skip_type == SKIP_TYPE_COL ? h->c.mb_width : h->c.mb_height; while (run > 0) { int block = FFMIN(run, 25); @@ -233,47 +233,47 @@ int ff_wmv2_decode_picture_header(MpegEncContext *s) return 0; } -int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) +int ff_wmv2_decode_secondary_picture_header(H263DecContext *const h) { - WMV2DecContext *const w = (WMV2DecContext *) s; + WMV2DecContext *const w = (WMV2DecContext *)h; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (h->c.pict_type == AV_PICTURE_TYPE_I) { /* Is filling with zeroes really the right thing to do? */ - memset(s->cur_pic.mb_type, 0, - sizeof(*s->cur_pic.mb_type) * s->mb_height * s->mb_stride); + memset(h->c.cur_pic.mb_type, 0, + sizeof(*h->c.cur_pic.mb_type) * h->c.mb_height * h->c.mb_stride); if (w->j_type_bit) - w->j_type = get_bits1(&s->gb); + w->j_type = get_bits1(&h->gb); else w->j_type = 0; // FIXME check if (!w->j_type) { if (w->per_mb_rl_bit) - s->per_mb_rl_table = get_bits1(&s->gb); + w->ms.per_mb_rl_table = get_bits1(&h->gb); else - s->per_mb_rl_table = 0; + w->ms.per_mb_rl_table = 0; - if (!s->per_mb_rl_table) { - s->rl_chroma_table_index = decode012(&s->gb); - s->rl_table_index = decode012(&s->gb); + if (!w->ms.per_mb_rl_table) { + w->ms.rl_chroma_table_index = decode012(&h->gb); + w->ms.rl_table_index = decode012(&h->gb); } - s->dc_table_index = get_bits1(&s->gb); + w->ms.dc_table_index = get_bits1(&h->gb); // at minimum one bit per macroblock is required at least in a valid frame, // we discard frames much smaller than this. Frames smaller than 1/8 of the // smallest "black/skip" frame generally contain not much recoverable content // while at the same time they have the highest computational requirements // per byte - if (get_bits_left(&s->gb) * 8LL < (s->width+15)/16 * ((s->height+15)/16)) + if (get_bits_left(&h->gb) * 8LL < (h->c.width+15)/16 * ((h->c.height+15)/16)) return AVERROR_INVALIDDATA; } - s->inter_intra_pred = 0; - s->no_rounding = 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + h->c.inter_intra_pred = 0; + h->c.no_rounding = 1; + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "qscale:%d rlc:%d rl:%d dc:%d mbrl:%d j_type:%d \n", - s->qscale, s->rl_chroma_table_index, s->rl_table_index, - s->dc_table_index, s->per_mb_rl_table, w->j_type); + h->c.qscale, w->ms.rl_chroma_table_index, w->ms.rl_table_index, + w->ms.dc_table_index, w->ms.per_mb_rl_table, w->j_type); } } else { int cbp_index; @@ -283,61 +283,61 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) 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); + cbp_index = decode012(&h->gb); + w->cbp_table_index = wmv2_get_cbp_table_index(h->c.qscale, cbp_index); if (w->mspel_bit) - s->mspel = get_bits1(&s->gb); + h->c.mspel = get_bits1(&h->gb); else - s->mspel = 0; // FIXME check + h->c.mspel = 0; // FIXME check if (w->abt_flag) { - w->per_mb_abt = get_bits1(&s->gb) ^ 1; + w->per_mb_abt = get_bits1(&h->gb) ^ 1; if (!w->per_mb_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); } if (w->per_mb_rl_bit) - s->per_mb_rl_table = get_bits1(&s->gb); + w->ms.per_mb_rl_table = get_bits1(&h->gb); else - s->per_mb_rl_table = 0; + w->ms.per_mb_rl_table = 0; - if (!s->per_mb_rl_table) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (!w->ms.per_mb_rl_table) { + w->ms.rl_table_index = decode012(&h->gb); + w->ms.rl_chroma_table_index = w->ms.rl_table_index; } - if (get_bits_left(&s->gb) < 2) + if (get_bits_left(&h->gb) < 2) return AVERROR_INVALIDDATA; - s->dc_table_index = get_bits1(&s->gb); - s->mv_table_index = get_bits1(&s->gb); + w->ms.dc_table_index = get_bits1(&h->gb); + w->ms.mv_table_index = get_bits1(&h->gb); - s->inter_intra_pred = 0; // (s->width * s->height < 320 * 240 && s->bit_rate <= II_BITRATE); - s->no_rounding ^= 1; + h->c.inter_intra_pred = 0; // (h->c.width * h->c.height < 320 * 240 && w->ms.bit_rate <= II_BITRATE); + h->c.no_rounding ^= 1; - if (s->avctx->debug & FF_DEBUG_PICT_INFO) { - av_log(s->avctx, AV_LOG_DEBUG, + if (h->c.avctx->debug & FF_DEBUG_PICT_INFO) { + av_log(h->c.avctx, AV_LOG_DEBUG, "rl:%d rlc:%d dc:%d mv:%d mbrl:%d qp:%d mspel:%d " "per_mb_abt:%d abt_type:%d cbp:%d ii:%d\n", - s->rl_table_index, s->rl_chroma_table_index, - s->dc_table_index, s->mv_table_index, - s->per_mb_rl_table, s->qscale, s->mspel, + w->ms.rl_table_index, w->ms.rl_chroma_table_index, + w->ms.dc_table_index, w->ms.mv_table_index, + w->ms.per_mb_rl_table, h->c.qscale, h->c.mspel, w->per_mb_abt, w->abt_type, w->cbp_table_index, - s->inter_intra_pred); + h->c.inter_intra_pred); } } - s->esc3_level_length = 0; - s->esc3_run_length = 0; + w->ms.esc3_level_length = 0; + w->ms.esc3_run_length = 0; if (w->j_type) { - ff_intrax8_decode_picture(&w->x8, s->cur_pic.ptr, - &s->gb, &s->mb_x, &s->mb_y, - 2 * s->qscale, (s->qscale - 1) | 1, - s->loop_filter, s->low_delay); + ff_intrax8_decode_picture(&w->x8, h->c.cur_pic.ptr, + &h->gb, &h->c.mb_x, &h->c.mb_y, + 2 * h->c.qscale, (h->c.qscale - 1) | 1, + h->loop_filter, h->c.low_delay); - ff_er_add_slice(&w->s.er, 0, 0, - (w->s.mb_x >> 1) - 1, (w->s.mb_y >> 1) - 1, + ff_er_add_slice(&h->c.er, 0, 0, + (h->c.mb_x >> 1) - 1, (h->c.mb_y >> 1) - 1, ER_MB_END); return 1; } @@ -347,38 +347,37 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) static inline void wmv2_decode_motion(WMV2DecContext *w, int *mx_ptr, int *my_ptr) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; - ff_msmpeg4_decode_motion(s, mx_ptr, my_ptr); + ff_msmpeg4_decode_motion(&w->ms, mx_ptr, my_ptr); - if ((((*mx_ptr) | (*my_ptr)) & 1) && s->mspel) - w->common.hshift = get_bits1(&s->gb); + if ((((*mx_ptr) | (*my_ptr)) & 1) && h->c.mspel) + w->common.hshift = get_bits1(&h->gb); else w->common.hshift = 0; } static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) { - MpegEncContext *const s = &w->s; - int xy, wrap, diff, type; - int16_t *A, *B, *C, *mot_val; + H263DecContext *const h = &w->ms.h; + int diff, type; - wrap = s->b8_stride; - xy = s->block_index[0]; + int wrap = h->c.b8_stride; + int xy = h->c.block_index[0]; - mot_val = s->cur_pic.motion_val[0][xy]; + int16_t *mot_val = h->c.cur_pic.motion_val[0][xy]; - A = s->cur_pic.motion_val[0][xy - 1]; - B = s->cur_pic.motion_val[0][xy - wrap]; - C = s->cur_pic.motion_val[0][xy + 2 - wrap]; + const int16_t *A = h->c.cur_pic.motion_val[0][xy - 1]; + const int16_t *B = h->c.cur_pic.motion_val[0][xy - wrap]; + const int16_t *C = h->c.cur_pic.motion_val[0][xy + 2 - wrap]; - if (s->mb_x && !s->first_slice_line && !s->mspel && w->top_left_mv_flag) + if (h->c.mb_x && !h->c.first_slice_line && !h->c.mspel && w->top_left_mv_flag) diff = FFMAX(FFABS(A[0] - B[0]), FFABS(A[1] - B[1])); else diff = 0; if (diff >= 8) - type = get_bits1(&s->gb); + type = get_bits1(&h->gb); else type = 2; @@ -390,7 +389,7 @@ static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) *py = B[1]; } else { /* special case for first (slice) line */ - if (s->first_slice_line) { + if (h->c.first_slice_line) { *px = A[0]; *py = A[1]; } else { @@ -405,86 +404,91 @@ static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) static inline int wmv2_decode_inter_block(WMV2DecContext *w, int16_t *block, int n, int cbp) { - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; static const int sub_cbp_table[3] = { 2, 3, 1 }; int sub_cbp, ret; if (!cbp) { - s->block_last_index[n] = -1; + h->c.block_last_index[n] = -1; return 0; } if (w->per_block_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); w->abt_type_table[n] = w->abt_type; if (w->abt_type) { const uint8_t *scantable = w->abt_type == 1 ? ff_wmv2_scantableA : ff_wmv2_scantableB; - sub_cbp = sub_cbp_table[decode012(&s->gb)]; + sub_cbp = sub_cbp_table[decode012(&h->gb)]; - if (sub_cbp & 1) - if ((ret = ff_msmpeg4_decode_block(s, block, n, 1, scantable)) < 0) + if (sub_cbp & 1) { + ret = ff_msmpeg4_decode_block(&w->ms, block, n, 1, scantable); + if (ret < 0) return ret; + } - if (sub_cbp & 2) - if ((ret = ff_msmpeg4_decode_block(s, w->abt_block2[n], n, 1, scantable)) < 0) + if (sub_cbp & 2) { + ret = ff_msmpeg4_decode_block(&w->ms, w->abt_block2[n], n, 1, scantable); + if (ret < 0) return ret; + } - s->block_last_index[n] = 63; + h->c.block_last_index[n] = 63; return 0; } else { - return ff_msmpeg4_decode_block(s, block, n, 1, - s->inter_scantable.permutated); + return ff_msmpeg4_decode_block(&w->ms, block, n, 1, + h->c.inter_scantable.permutated); } } -static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) +static int wmv2_decode_mb(H263DecContext *const h) { - /* The following is only allowed because this encoder + /* The following is only allowed because this decoder * does not use slice threading. */ - WMV2DecContext *const w = (WMV2DecContext *) s; + WMV2DecContext *const w = (WMV2DecContext *) h; + MSMP4DecContext *const ms = &w->ms; int cbp, code, i, ret; uint8_t *coded_val; if (w->j_type) return 0; - if (s->pict_type == AV_PICTURE_TYPE_P) { - if (IS_SKIP(s->cur_pic.mb_type[s->mb_y * s->mb_stride + s->mb_x])) { + if (h->c.pict_type == AV_PICTURE_TYPE_P) { + if (IS_SKIP(h->c.cur_pic.mb_type[h->c.mb_y * h->c.mb_stride + h->c.mb_x])) { /* skip mb */ - s->mb_intra = 0; + h->c.mb_intra = 0; for (i = 0; i < 6; i++) - s->block_last_index[i] = -1; - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = 0; - s->mv[0][0][1] = 0; - s->mb_skipped = 1; + h->c.block_last_index[i] = -1; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = 0; + h->c.mv[0][0][1] = 0; + h->c.mb_skipped = 1; w->common.hshift = 0; return 0; } - if (get_bits_left(&s->gb) <= 0) + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[w->cbp_table_index], + code = get_vlc2(&h->gb, ff_mb_non_intra_vlc[w->cbp_table_index], MB_NON_INTRA_VLC_BITS, 3); - s->mb_intra = (~code & 0x40) >> 6; + h->c.mb_intra = (~code & 0x40) >> 6; cbp = code & 0x3f; } else { - s->mb_intra = 1; - if (get_bits_left(&s->gb) <= 0) + h->c.mb_intra = 1; + if (get_bits_left(&h->gb) <= 0) return AVERROR_INVALIDDATA; - code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc, + code = get_vlc2(&h->gb, ff_msmp4_mb_i_vlc, MSMP4_MB_INTRA_VLC_BITS, 2); /* predict coded block pattern */ cbp = 0; for (i = 0; i < 6; i++) { int val = ((code >> (5 - i)) & 1); if (i < 4) { - int pred = ff_msmpeg4_coded_block_pred(s, i, &coded_val); + int pred = ff_msmpeg4_coded_block_pred(&h->c, i, &coded_val); val = val ^ pred; *coded_val = val; } @@ -492,64 +496,65 @@ static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) } } - if (!s->mb_intra) { + if (!h->c.mb_intra) { int mx, my; wmv2_pred_motion(w, &mx, &my); if (cbp) { - s->bdsp.clear_blocks(s->block[0]); - if (s->per_mb_rl_table) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + h->c.bdsp.clear_blocks(h->block[0]); + if (ms->per_mb_rl_table) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } if (w->abt_flag && w->per_mb_abt) { - w->per_block_abt = get_bits1(&s->gb); + w->per_block_abt = get_bits1(&h->gb); if (!w->per_block_abt) - w->abt_type = decode012(&s->gb); + w->abt_type = decode012(&h->gb); } else w->per_block_abt = 0; } wmv2_decode_motion(w, &mx, &my); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - s->mv[0][0][0] = mx; - s->mv[0][0][1] = my; + h->c.mv_dir = MV_DIR_FORWARD; + h->c.mv_type = MV_TYPE_16X16; + h->c.mv[0][0][0] = mx; + h->c.mv[0][0][1] = my; for (i = 0; i < 6; i++) { - if ((ret = wmv2_decode_inter_block(w, block[i], i, (cbp >> (5 - i)) & 1)) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + if ((ret = wmv2_decode_inter_block(w, h->block[i], i, (cbp >> (5 - i)) & 1)) < 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding inter block: %d x %d (%d)\n", - s->mb_x, s->mb_y, i); + h->c.mb_x, h->c.mb_y, i); return ret; } } } else { - if (s->pict_type == AV_PICTURE_TYPE_P) - ff_dlog(s->avctx, "%d%d ", s->inter_intra_pred, cbp); - ff_dlog(s->avctx, "I at %d %d %d %06X\n", s->mb_x, s->mb_y, + if (h->c.pict_type == AV_PICTURE_TYPE_P) + ff_dlog(h->c.avctx, "%d%d ", h->c.inter_intra_pred, cbp); + ff_dlog(h->c.avctx, "I at %d %d %d %06X\n", h->c.mb_x, h->c.mb_y, ((cbp & 3) ? 1 : 0) + ((cbp & 0x3C) ? 2 : 0), - show_bits(&s->gb, 24)); - s->ac_pred = get_bits1(&s->gb); - if (s->inter_intra_pred) { - s->h263_aic_dir = get_vlc2(&s->gb, ff_inter_intra_vlc, + show_bits(&h->gb, 24)); + h->c.ac_pred = get_bits1(&h->gb); + if (h->c.inter_intra_pred) { + h->c.h263_aic_dir = get_vlc2(&h->gb, ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 1); - ff_dlog(s->avctx, "%d%d %d %d/", - s->ac_pred, s->h263_aic_dir, s->mb_x, s->mb_y); + ff_dlog(h->c.avctx, "%d%d %d %d/", + h->c.ac_pred, h->c.h263_aic_dir, h->c.mb_x, h->c.mb_y); } - if (s->per_mb_rl_table && cbp) { - s->rl_table_index = decode012(&s->gb); - s->rl_chroma_table_index = s->rl_table_index; + if (ms->per_mb_rl_table && cbp) { + ms->rl_table_index = decode012(&h->gb); + ms->rl_chroma_table_index = ms->rl_table_index; } - s->bdsp.clear_blocks(s->block[0]); + h->c.bdsp.clear_blocks(h->block[0]); for (i = 0; i < 6; i++) { - if ((ret = ff_msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL)) < 0) { - av_log(s->avctx, AV_LOG_ERROR, + ret = ff_msmpeg4_decode_block(ms, h->block[i], i, (cbp >> (5 - i)) & 1, NULL); + if (ret < 0) { + av_log(h->c.avctx, AV_LOG_ERROR, "\nerror while decoding intra block: %d x %d (%d)\n", - s->mb_x, s->mb_y, i); + h->c.mb_x, h->c.mb_y, i); return ret; } } @@ -561,7 +566,8 @@ static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) static av_cold int wmv2_decode_init(AVCodecContext *avctx) { WMV2DecContext *const w = avctx->priv_data; - MpegEncContext *const s = &w->s; + H263DecContext *const h = &w->ms.h; + MpegEncContext *const s = &h->c; int ret; s->private_ctx = &w->common; @@ -569,15 +575,15 @@ static av_cold int wmv2_decode_init(AVCodecContext *avctx) if ((ret = ff_msmpeg4_decode_init(avctx)) < 0) return ret; - s->decode_mb = wmv2_decode_mb; + h->decode_header = wmv2_decode_picture_header; + h->decode_mb = wmv2_decode_mb; ff_wmv2_common_init(s); decode_ext_header(w); - return ff_intrax8_common_init(avctx, &w->x8, - w->s.block, w->s.block_last_index, - w->s.mb_width, w->s.mb_height); + return ff_intrax8_common_init(avctx, &w->x8, h->block[0], + s->mb_width, s->mb_height); } static av_cold int wmv2_decode_end(AVCodecContext *avctx) diff --git a/libavcodec/wmv2dec.h b/libavcodec/wmv2dec.h index bc8745bf6f..1bd0d13725 100644 --- a/libavcodec/wmv2dec.h +++ b/libavcodec/wmv2dec.h @@ -22,9 +22,9 @@ #define AVCODEC_WMV2DEC_H #include "mpegvideo.h" +struct H263DecContext; -int ff_wmv2_decode_picture_header(MpegEncContext * s); -int ff_wmv2_decode_secondary_picture_header(MpegEncContext * s); +int ff_wmv2_decode_secondary_picture_header(struct H263DecContext *const h); void ff_wmv2_add_mb(MpegEncContext *s, int16_t block[6][64], uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr); diff --git a/libavcodec/wmv2enc.c b/libavcodec/wmv2enc.c index fded6f0e76..b6811fde0e 100644 --- a/libavcodec/wmv2enc.c +++ b/libavcodec/wmv2enc.c @@ -28,8 +28,8 @@ #include "msmpeg4enc.h" #include "msmpeg4data.h" #include "msmpeg4_vc1_data.h" +#include "put_bits.h" #include "wmv2.h" -#include "wmv2enc.h" #define WMV2_EXTRADATA_SIZE 4 @@ -49,14 +49,14 @@ typedef struct WMV2EncContext { static int encode_ext_header(WMV2EncContext *w) { - MpegEncContext *const s = &w->msmpeg4.s; + MPVEncContext *const s = &w->msmpeg4.m.s; PutBitContext pb; int code; - init_put_bits(&pb, s->avctx->extradata, WMV2_EXTRADATA_SIZE); + init_put_bits(&pb, s->c.avctx->extradata, WMV2_EXTRADATA_SIZE); - put_bits(&pb, 5, s->avctx->time_base.den / s->avctx->time_base.num); // yes 29.97 -> 29 - put_bits(&pb, 11, FFMIN(s->bit_rate / 1024, 2047)); + put_bits(&pb, 5, s->c.avctx->time_base.den / s->c.avctx->time_base.num); // yes 29.97 -> 29 + put_bits(&pb, 11, FFMIN(w->msmpeg4.m.bit_rate / 1024, 2047)); put_bits(&pb, 1, w->mspel_bit = 1); put_bits(&pb, 1, s->loop_filter); @@ -68,21 +68,172 @@ static int encode_ext_header(WMV2EncContext *w) flush_put_bits(&pb); - s->slice_height = s->mb_height / code; + s->slice_height = s->c.mb_height / code; return 0; } +static int wmv2_encode_picture_header(MPVMainEncContext *const m) +{ + WMV2EncContext *const w = (WMV2EncContext *) m; + MSMPEG4EncContext *const ms = &w->msmpeg4; + MPVEncContext *const s = &m->s; + + put_bits_assume_flushed(&s->pb); + + put_bits(&s->pb, 1, s->c.pict_type - 1); + if (s->c.pict_type == AV_PICTURE_TYPE_I) + put_bits(&s->pb, 7, 0); + put_bits(&s->pb, 5, s->c.qscale); + + ms->dc_table_index = 1; + ms->mv_table_index = 1; /* only if P-frame */ + ms->per_mb_rl_table = 0; + s->c.mspel = 0; + w->per_mb_abt = 0; + w->abt_type = 0; + w->j_type = 0; + + av_assert0(s->flipflop_rounding); + + if (s->c.pict_type == AV_PICTURE_TYPE_I) { + av_assert0(s->c.no_rounding == 1); + if (w->j_type_bit) + put_bits(&s->pb, 1, w->j_type); + + if (w->per_mb_rl_bit) + put_bits(&s->pb, 1, ms->per_mb_rl_table); + + if (!ms->per_mb_rl_table) { + ff_msmpeg4_code012(&s->pb, ms->rl_chroma_table_index); + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); + } + + put_bits(&s->pb, 1, ms->dc_table_index); + + s->c.inter_intra_pred = 0; + } else { + int cbp_index; + + put_bits(&s->pb, 2, SKIP_TYPE_NONE); + + ff_msmpeg4_code012(&s->pb, cbp_index = 0); + w->cbp_table_index = wmv2_get_cbp_table_index(s->c.qscale, cbp_index); + + if (w->mspel_bit) + put_bits(&s->pb, 1, s->c.mspel); + + if (w->abt_flag) { + put_bits(&s->pb, 1, w->per_mb_abt ^ 1); + if (!w->per_mb_abt) + ff_msmpeg4_code012(&s->pb, w->abt_type); + } + + if (w->per_mb_rl_bit) + put_bits(&s->pb, 1, ms->per_mb_rl_table); + + if (!ms->per_mb_rl_table) { + ff_msmpeg4_code012(&s->pb, ms->rl_table_index); + ms->rl_chroma_table_index = ms->rl_table_index; + } + put_bits(&s->pb, 1, ms->dc_table_index); + put_bits(&s->pb, 1, ms->mv_table_index); + + s->c.inter_intra_pred = 0; // (s->c.width * s->c.height < 320 * 240 && m->bit_rate <= II_BITRATE); + } + s->esc3_level_length = 0; + ms->esc3_run_length = 0; + + return 0; +} + +/* Nearly identical to wmv1 but that is just because we do not use the + * useless M$ crap features. It is duplicated here in case someone wants + * to add support for these crap features. */ +static void wmv2_encode_mb(MPVEncContext *const s, int16_t block[][64], + int motion_x, int motion_y) +{ + WMV2EncContext *const w = (WMV2EncContext *) s; + int cbp, coded_cbp, i; + int pred_x, pred_y; + uint8_t *coded_block; + + ff_msmpeg4_handle_slices(s); + + if (!s->c.mb_intra) { + /* compute cbp */ + cbp = 0; + for (i = 0; i < 6; i++) + if (s->c.block_last_index[i] >= 0) + cbp |= 1 << (5 - i); + + put_bits(&s->pb, + ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][1], + ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][0]); + + s->misc_bits += get_bits_diff(s); + /* motion vector */ + ff_h263_pred_motion(&s->c, 0, 0, &pred_x, &pred_y); + ff_msmpeg4_encode_motion(&w->msmpeg4, motion_x - pred_x, + motion_y - pred_y); + s->mv_bits += get_bits_diff(s); + } else { + /* compute cbp */ + cbp = 0; + coded_cbp = 0; + for (i = 0; i < 6; i++) { + int val = (s->c.block_last_index[i] >= 1); + + cbp |= val << (5 - i); + if (i < 4) { + /* predict value for close blocks only for luma */ + int pred = ff_msmpeg4_coded_block_pred(&s->c, i, &coded_block); + *coded_block = val; + val = val ^ pred; + } + coded_cbp |= val << (5 - i); + } + + if (s->c.pict_type == AV_PICTURE_TYPE_I) + put_bits(&s->pb, + ff_msmp4_mb_i_table[coded_cbp][1], + ff_msmp4_mb_i_table[coded_cbp][0]); + else + put_bits(&s->pb, + ff_wmv2_inter_table[w->cbp_table_index][cbp][1], + ff_wmv2_inter_table[w->cbp_table_index][cbp][0]); + put_bits(&s->pb, 1, 0); /* no AC prediction yet */ + if (s->c.inter_intra_pred) { + s->c.h263_aic_dir = 0; + put_bits(&s->pb, + ff_table_inter_intra[s->c.h263_aic_dir][1], + ff_table_inter_intra[s->c.h263_aic_dir][0]); + } + s->misc_bits += get_bits_diff(s); + } + + for (i = 0; i < 6; i++) + ff_msmpeg4_encode_block(s, block[i], i); + if (s->c.mb_intra) + s->i_tex_bits += get_bits_diff(s); + else + s->p_tex_bits += get_bits_diff(s); +} + static av_cold int wmv2_encode_init(AVCodecContext *avctx) { WMV2EncContext *const w = avctx->priv_data; - MpegEncContext *const s = &w->msmpeg4.s; + MPVEncContext *const s = &w->msmpeg4.m.s; + int ret; - s->private_ctx = &w->common; - if (ff_mpv_encode_init(avctx) < 0) - return -1; + w->msmpeg4.m.encode_picture_header = wmv2_encode_picture_header; + s->encode_mb = wmv2_encode_mb; + s->c.private_ctx = &w->common; + ret = ff_mpv_encode_init(avctx); + if (ret < 0) + return ret; - ff_wmv2_common_init(s); + ff_wmv2_common_init(&s->c); avctx->extradata_size = WMV2_EXTRADATA_SIZE; avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); @@ -94,162 +245,18 @@ static av_cold int wmv2_encode_init(AVCodecContext *avctx) return 0; } -int ff_wmv2_encode_picture_header(MpegEncContext *s) -{ - WMV2EncContext *const w = (WMV2EncContext *) s; - - put_bits(&s->pb, 1, s->pict_type - 1); - if (s->pict_type == AV_PICTURE_TYPE_I) - put_bits(&s->pb, 7, 0); - put_bits(&s->pb, 5, s->qscale); - - s->dc_table_index = 1; - s->mv_table_index = 1; /* only if P-frame */ - s->per_mb_rl_table = 0; - s->mspel = 0; - w->per_mb_abt = 0; - w->abt_type = 0; - w->j_type = 0; - - av_assert0(s->flipflop_rounding); - - if (s->pict_type == AV_PICTURE_TYPE_I) { - av_assert0(s->no_rounding == 1); - if (w->j_type_bit) - put_bits(&s->pb, 1, w->j_type); - - if (w->per_mb_rl_bit) - put_bits(&s->pb, 1, s->per_mb_rl_table); - - if (!s->per_mb_rl_table) { - ff_msmpeg4_code012(&s->pb, s->rl_chroma_table_index); - ff_msmpeg4_code012(&s->pb, s->rl_table_index); - } - - put_bits(&s->pb, 1, s->dc_table_index); - - s->inter_intra_pred = 0; - } else { - int cbp_index; - - put_bits(&s->pb, 2, SKIP_TYPE_NONE); - - ff_msmpeg4_code012(&s->pb, cbp_index = 0); - w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index); - - if (w->mspel_bit) - put_bits(&s->pb, 1, s->mspel); - - if (w->abt_flag) { - put_bits(&s->pb, 1, w->per_mb_abt ^ 1); - if (!w->per_mb_abt) - ff_msmpeg4_code012(&s->pb, w->abt_type); - } - - if (w->per_mb_rl_bit) - put_bits(&s->pb, 1, s->per_mb_rl_table); - - if (!s->per_mb_rl_table) { - ff_msmpeg4_code012(&s->pb, s->rl_table_index); - s->rl_chroma_table_index = s->rl_table_index; - } - put_bits(&s->pb, 1, s->dc_table_index); - put_bits(&s->pb, 1, s->mv_table_index); - - s->inter_intra_pred = 0; // (s->width * s->height < 320 * 240 && s->bit_rate <= II_BITRATE); - } - s->esc3_level_length = 0; - s->esc3_run_length = 0; - - return 0; -} - -/* Nearly identical to wmv1 but that is just because we do not use the - * useless M$ crap features. It is duplicated here in case someone wants - * to add support for these crap features. */ -void ff_wmv2_encode_mb(MpegEncContext *s, int16_t block[6][64], - int motion_x, int motion_y) -{ - WMV2EncContext *const w = (WMV2EncContext *) s; - int cbp, coded_cbp, i; - int pred_x, pred_y; - uint8_t *coded_block; - - ff_msmpeg4_handle_slices(s); - - if (!s->mb_intra) { - /* compute cbp */ - cbp = 0; - for (i = 0; i < 6; i++) - if (s->block_last_index[i] >= 0) - cbp |= 1 << (5 - i); - - put_bits(&s->pb, - ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][1], - ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][0]); - - s->misc_bits += get_bits_diff(s); - /* motion vector */ - ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y); - ff_msmpeg4_encode_motion(s, motion_x - pred_x, - motion_y - pred_y); - s->mv_bits += get_bits_diff(s); - } else { - /* compute cbp */ - cbp = 0; - coded_cbp = 0; - for (i = 0; i < 6; i++) { - int val, pred; - val = (s->block_last_index[i] >= 1); - cbp |= val << (5 - i); - if (i < 4) { - /* predict value for close blocks only for luma */ - pred = ff_msmpeg4_coded_block_pred(s, i, &coded_block); - *coded_block = val; - val = val ^ pred; - } - coded_cbp |= val << (5 - i); - } - - if (s->pict_type == AV_PICTURE_TYPE_I) - put_bits(&s->pb, - ff_msmp4_mb_i_table[coded_cbp][1], - ff_msmp4_mb_i_table[coded_cbp][0]); - else - put_bits(&s->pb, - ff_wmv2_inter_table[w->cbp_table_index][cbp][1], - ff_wmv2_inter_table[w->cbp_table_index][cbp][0]); - put_bits(&s->pb, 1, 0); /* no AC prediction yet */ - if (s->inter_intra_pred) { - s->h263_aic_dir = 0; - put_bits(&s->pb, - ff_table_inter_intra[s->h263_aic_dir][1], - ff_table_inter_intra[s->h263_aic_dir][0]); - } - s->misc_bits += get_bits_diff(s); - } - - for (i = 0; i < 6; i++) - ff_msmpeg4_encode_block(s, block[i], i); - if (s->mb_intra) - s->i_tex_bits += get_bits_diff(s); - else - s->p_tex_bits += get_bits_diff(s); -} - const FFCodec ff_wmv2_encoder = { .p.name = "wmv2", CODEC_LONG_NAME("Windows Media Video 8"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_WMV2, .p.priv_class = &ff_mpv_enc_class, - .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(WMV2EncContext), .init = wmv2_encode_init, FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = ff_mpv_encode_end, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .color_ranges = AVCOL_RANGE_MPEG, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), }; diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index 331183f450..ebd2bdb310 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -25,8 +25,8 @@ OBJS-$(CONFIG_LPC) += x86/lpc_init.o OBJS-$(CONFIG_ME_CMP) += x86/me_cmp_init.o OBJS-$(CONFIG_MPEGAUDIODSP) += x86/mpegaudiodsp.o OBJS-$(CONFIG_MPEGVIDEO) += x86/mpegvideo.o -OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.o \ - x86/mpegvideoencdsp_init.o +OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.o +OBJS-$(CONFIG_MPEGVIDEOENCDSP) += x86/mpegvideoencdsp_init.o OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp_init.o OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp_init.o OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp_init.o @@ -44,6 +44,7 @@ OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp_init.o OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp_init.o OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp_init.o OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp_init.o +OBJS-$(CONFIG_APV_DECODER) += x86/apv_dsp_init.o OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o OBJS-$(CONFIG_CFHD_DECODER) += x86/cfhddsp_init.o OBJS-$(CONFIG_CFHD_ENCODER) += x86/cfhdencdsp_init.o @@ -54,13 +55,13 @@ OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp_init.o OBJS-$(CONFIG_FLAC_ENCODER) += x86/flacencdsp_init.o OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp_init.o OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_init.o -OBJS-$(CONFIG_HEVC_DECODER) += x86/hevcdsp_init.o x86/h26x/h2656dsp.o OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp_init.o OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp_init.o OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp_init.o OBJS-$(CONFIG_MPEG4_DECODER) += x86/mpeg4videodsp.o x86/xvididct_init.o OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp_init.o +OBJS-$(CONFIG_PRORES_RAW_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 @@ -122,7 +123,7 @@ X86ASM-OBJS-$(CONFIG_LLVIDENCDSP) += x86/lossless_videoencdsp.o X86ASM-OBJS-$(CONFIG_LPC) += x86/lpc.o X86ASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp.o X86ASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/dct32.o x86/imdct36.o -X86ASM-OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoencdsp.o +X86ASM-OBJS-$(CONFIG_MPEGVIDEOENCDSP) += x86/mpegvideoencdsp.o X86ASM-OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp.o X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_search.o X86ASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp.o @@ -150,6 +151,7 @@ X86ASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp.o X86ASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp.o X86ASM-OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp.o X86ASM-OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp.o +X86ASM-OBJS-$(CONFIG_APV_DECODER) += x86/apv_dsp.o X86ASM-OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsidct.o X86ASM-OBJS-$(CONFIG_CFHD_ENCODER) += x86/cfhdencdsp.o X86ASM-OBJS-$(CONFIG_CFHD_DECODER) += x86/cfhddsp.o @@ -162,19 +164,13 @@ X86ASM-OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp.o ifdef CONFIG_GPL X86ASM-OBJS-$(CONFIG_FLAC_ENCODER) += x86/flac_dsp_gpl.o endif -X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_add_res.o \ - x86/hevc_deblock.o \ - x86/hevc_idct.o \ - x86/hevc_mc.o \ - x86/h26x/h2656_inter.o \ - x86/hevc_sao.o \ - x86/hevc_sao_10bit.o X86ASM-OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp.o X86ASM-OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o +X86ASM-OBJS-$(CONFIG_PRORES_RAW_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 @@ -190,7 +186,9 @@ X86ASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o X86ASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9intrapred.o \ x86/vp9intrapred_16bpp.o \ x86/vp9itxfm.o \ + x86/vp9itxfm_avx512.o \ x86/vp9itxfm_16bpp.o \ + x86/vp9itxfm_16bpp_avx512.o \ x86/vp9lpf.o \ x86/vp9lpf_16bpp.o \ x86/vp9mc.o \ diff --git a/libavcodec/x86/aacencdsp.asm b/libavcodec/x86/aacencdsp.asm index 86eaebcbe5..8e435b7d2a 100644 --- a/libavcodec/x86/aacencdsp.asm +++ b/libavcodec/x86/aacencdsp.asm @@ -96,7 +96,7 @@ cglobal aac_quantize_bands, 5, 5, 6, out, in, scaled, size, is_signed, maxval, Q addps m2, m1 minps m2, m3 andps m5, m4, [inq+sizeq] - orps m2, m5 + xorps m2, m5 cvttps2dq m2, m2 mova [outq+sizeq], m2 add sizeq, mmsize diff --git a/libavcodec/x86/apv_dsp.asm b/libavcodec/x86/apv_dsp.asm new file mode 100644 index 0000000000..60e0f03e16 --- /dev/null +++ b/libavcodec/x86/apv_dsp.asm @@ -0,0 +1,308 @@ +;************************************************************************ +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 + +SECTION_RODATA 32 + +; Full matrix for row transform. +const tmatrix_row + dw 64, 89, 84, 75, 64, 50, 35, 18 + dw 64, -18, -84, 50, 64, -75, -35, 89 + dw 64, 75, 35, -18, -64, -89, -84, -50 + dw 64, -50, -35, 89, -64, -18, 84, -75 + dw 64, 50, -35, -89, -64, 18, 84, 75 + dw 64, -75, 35, 18, -64, 89, -84, 50 + dw 64, 18, -84, -50, 64, 75, -35, -89 + dw 64, -89, 84, -75, 64, -50, 35, -18 + +; Constant pairs for broadcast in column transform. +const tmatrix_col_even + dw 64, 64, 64, -64 + dw 84, 35, 35, -84 +const tmatrix_col_odd + dw 89, 75, 50, 18 + dw 75, -18, -89, -50 + dw 50, -89, 18, 75 + dw 18, -50, 75, -89 + +; Memory targets for vpbroadcastd (register version requires AVX512). +cextern pd_1 +cextern pd_64 + +SECTION .text + +; void ff_apv_decode_transquant_avx2(void *output, +; ptrdiff_t pitch, +; const int16_t *input, +; const int16_t *qmatrix, +; int bit_depth, +; int qp_shift); + +INIT_YMM avx2 + +cglobal apv_decode_transquant, 5, 7, 16, output, pitch, input, qmatrix, bit_depth, qp_shift, tmp + + ; Load input and dequantise + + vpbroadcastd m10, [pd_1] + lea tmpd, [bit_depthd - 2] + movd xm8, qp_shiftm + movd xm9, tmpd + vpslld m10, m10, xm9 + vpsrld m10, m10, 1 + + ; m8 = scalar qp_shift + ; m9 = scalar bd_shift + ; m10 = vector 1 << (bd_shift - 1) + ; m11 = qmatrix load + +%macro LOAD_AND_DEQUANT 2 ; (xmm input, constant offset) + vpmovsxwd m%1, [inputq + %2] + vpmovsxwd m11, [qmatrixq + %2] + vpmaddwd m%1, m%1, m11 + vpslld m%1, m%1, xm8 + vpaddd m%1, m%1, m10 + vpsrad m%1, m%1, xm9 + vpackssdw m%1, m%1, m%1 +%endmacro + + LOAD_AND_DEQUANT 0, 0x00 + LOAD_AND_DEQUANT 1, 0x10 + LOAD_AND_DEQUANT 2, 0x20 + LOAD_AND_DEQUANT 3, 0x30 + LOAD_AND_DEQUANT 4, 0x40 + LOAD_AND_DEQUANT 5, 0x50 + LOAD_AND_DEQUANT 6, 0x60 + LOAD_AND_DEQUANT 7, 0x70 + + ; mN = row N words 0 1 2 3 0 1 2 3 4 5 6 7 4 5 6 7 + + ; Transform columns + ; This applies a 1-D DCT butterfly + + vpunpcklwd m12, m0, m4 + vpunpcklwd m13, m2, m6 + vpunpcklwd m14, m1, m3 + vpunpcklwd m15, m5, m7 + + ; m12 = rows 0 and 4 interleaved + ; m13 = rows 2 and 6 interleaved + ; m14 = rows 1 and 3 interleaved + ; m15 = rows 5 and 7 interleaved + + lea tmpq, [tmatrix_col_even] + vpbroadcastd m0, [tmpq + 0x00] + vpbroadcastd m1, [tmpq + 0x04] + vpbroadcastd m2, [tmpq + 0x08] + vpbroadcastd m3, [tmpq + 0x0c] + + vpmaddwd m4, m12, m0 + vpmaddwd m5, m12, m1 + vpmaddwd m6, m13, m2 + vpmaddwd m7, m13, m3 + vpaddd m8, m4, m6 + vpaddd m9, m5, m7 + vpsubd m10, m5, m7 + vpsubd m11, m4, m6 + + lea tmpq, [tmatrix_col_odd] + vpbroadcastd m0, [tmpq + 0x00] + vpbroadcastd m1, [tmpq + 0x04] + vpbroadcastd m2, [tmpq + 0x08] + vpbroadcastd m3, [tmpq + 0x0c] + + vpmaddwd m4, m14, m0 + vpmaddwd m5, m15, m1 + vpmaddwd m6, m14, m2 + vpmaddwd m7, m15, m3 + vpaddd m12, m4, m5 + vpaddd m13, m6, m7 + + vpbroadcastd m0, [tmpq + 0x10] + vpbroadcastd m1, [tmpq + 0x14] + vpbroadcastd m2, [tmpq + 0x18] + vpbroadcastd m3, [tmpq + 0x1c] + + vpmaddwd m4, m14, m0 + vpmaddwd m5, m15, m1 + vpmaddwd m6, m14, m2 + vpmaddwd m7, m15, m3 + vpaddd m14, m4, m5 + vpaddd m15, m6, m7 + + vpaddd m0, m8, m12 + vpaddd m1, m9, m13 + vpaddd m2, m10, m14 + vpaddd m3, m11, m15 + vpsubd m4, m11, m15 + vpsubd m5, m10, m14 + vpsubd m6, m9, m13 + vpsubd m7, m8, m12 + + ; Mid-transform normalisation + ; Note that outputs here are fitted to 16 bits + + vpbroadcastd m8, [pd_64] + +%macro NORMALISE 1 + vpaddd m%1, m%1, m8 + vpsrad m%1, m%1, 7 + vpackssdw m%1, m%1, m%1 + vpermq m%1, m%1, q3120 +%endmacro + + NORMALISE 0 + NORMALISE 1 + NORMALISE 2 + NORMALISE 3 + NORMALISE 4 + NORMALISE 5 + NORMALISE 6 + NORMALISE 7 + + ; mN = row N words 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + + ; Transform rows + ; This multiplies the rows directly by the transform matrix, + ; avoiding the need to transpose anything + + lea tmpq, [tmatrix_row] + mova m12, [tmpq + 0x00] + mova m13, [tmpq + 0x20] + mova m14, [tmpq + 0x40] + mova m15, [tmpq + 0x60] + +%macro TRANS_ROW_STEP 1 + vpmaddwd m8, m%1, m12 + vpmaddwd m9, m%1, m13 + vpmaddwd m10, m%1, m14 + vpmaddwd m11, m%1, m15 + vphaddd m8, m8, m9 + vphaddd m10, m10, m11 + vphaddd m%1, m8, m10 +%endmacro + + TRANS_ROW_STEP 0 + TRANS_ROW_STEP 1 + TRANS_ROW_STEP 2 + TRANS_ROW_STEP 3 + TRANS_ROW_STEP 4 + TRANS_ROW_STEP 5 + TRANS_ROW_STEP 6 + TRANS_ROW_STEP 7 + + ; Renormalise, clip and store output + + vpbroadcastd m14, [pd_1] + mov tmpd, 20 + sub tmpd, bit_depthd + movd xm9, tmpd + dec tmpd + movd xm13, tmpd + movd xm15, bit_depthd + vpslld m8, m14, xm13 + vpslld m12, m14, xm15 + vpsrld m10, m12, 1 + vpsubd m12, m12, m14 + vpxor m11, m11, m11 + + ; m8 = vector 1 << (bd_shift - 1) + ; m9 = scalar bd_shift + ; m10 = vector 1 << (bit_depth - 1) + ; m11 = zero + ; m12 = vector (1 << bit_depth) - 1 + + cmp bit_depthd, 8 + jne store_10 + + lea tmpq, [pitchq + 2*pitchq] +%macro NORMALISE_AND_STORE_8 4 + vpaddd m%1, m%1, m8 + vpaddd m%2, m%2, m8 + vpaddd m%3, m%3, m8 + vpaddd m%4, m%4, m8 + vpsrad m%1, m%1, xm9 + vpsrad m%2, m%2, xm9 + vpsrad m%3, m%3, xm9 + vpsrad m%4, m%4, xm9 + vpaddd m%1, m%1, m10 + vpaddd m%2, m%2, m10 + vpaddd m%3, m%3, m10 + vpaddd m%4, m%4, m10 + ; m%1 = A0-3 A4-7 + ; m%2 = B0-3 B4-7 + ; m%3 = C0-3 C4-7 + ; m%4 = D0-3 D4-7 + vpackusdw m%1, m%1, m%2 + vpackusdw m%3, m%3, m%4 + ; m%1 = A0-3 B0-3 A4-7 B4-7 + ; m%2 = C0-3 D0-3 C4-7 D4-7 + vpermq m%1, m%1, q3120 + vpermq m%2, m%3, q3120 + ; m%1 = A0-3 A4-7 B0-3 B4-7 + ; m%2 = C0-3 C4-7 D0-3 D4-7 + vpackuswb m%1, m%1, m%2 + ; m%1 = A0-3 A4-7 C0-3 C4-7 B0-3 B4-7 D0-3 D4-7 + vextracti128 xm%2, m%1, 1 + vmovq [outputq], xm%1 + vmovq [outputq + pitchq], xm%2 + vpextrq [outputq + 2*pitchq], xm%1, 1 + vpextrq [outputq + tmpq], xm%2, 1 + lea outputq, [outputq + 4*pitchq] +%endmacro + + NORMALISE_AND_STORE_8 0, 1, 2, 3 + NORMALISE_AND_STORE_8 4, 5, 6, 7 + + RET + +store_10: + +%macro NORMALISE_AND_STORE_10 2 + vpaddd m%1, m%1, m8 + vpaddd m%2, m%2, m8 + vpsrad m%1, m%1, xm9 + vpsrad m%2, m%2, xm9 + vpaddd m%1, m%1, m10 + vpaddd m%2, m%2, m10 + vpmaxsd m%1, m%1, m11 + vpmaxsd m%2, m%2, m11 + vpminsd m%1, m%1, m12 + vpminsd m%2, m%2, m12 + ; m%1 = A0-3 A4-7 + ; m%2 = B0-3 B4-7 + vpackusdw m%1, m%1, m%2 + ; m%1 = A0-3 B0-3 A4-7 B4-7 + vpermq m%1, m%1, q3120 + ; m%1 = A0-3 A4-7 B0-3 B4-7 + mova [outputq], xm%1 + vextracti128 [outputq + pitchq], m%1, 1 + lea outputq, [outputq + 2*pitchq] +%endmacro + + NORMALISE_AND_STORE_10 0, 1 + NORMALISE_AND_STORE_10 2, 3 + NORMALISE_AND_STORE_10 4, 5 + NORMALISE_AND_STORE_10 6, 7 + + RET + +%endif ; ARCH_X86_64 diff --git a/libavcodec/x86/apv_dsp_init.c b/libavcodec/x86/apv_dsp_init.c new file mode 100644 index 0000000000..39360a0ad2 --- /dev/null +++ b/libavcodec/x86/apv_dsp_init.c @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/apv_dsp.h" + +#if ARCH_X86_64 + +void ff_apv_decode_transquant_avx2(void *output, + ptrdiff_t pitch, + const int16_t *input, + const int16_t *qmatrix, + int bit_depth, + int qp_shift); + +av_cold void ff_apv_dsp_init_x86_64(APVDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + dsp->decode_transquant = ff_apv_decode_transquant_avx2; + } +} + +#endif /* ARCH_X86_64 */ diff --git a/libavcodec/x86/cavsdsp.c b/libavcodec/x86/cavsdsp.c index 96680836a1..3d21744ef0 100644 --- a/libavcodec/x86/cavsdsp.c +++ b/libavcodec/x86/cavsdsp.c @@ -51,6 +51,9 @@ static void cavs_idct8_add_sse2(uint8_t *dst, int16_t *block, ptrdiff_t stride) #if HAVE_MMXEXT_INLINE +DECLARE_ASM_CONST(8, uint64_t, pw_42) = 0x002A002A002A002AULL; +DECLARE_ASM_CONST(8, uint64_t, pw_96) = 0x0060006000600060ULL; + /***************************************************************************** * * motion compensation @@ -233,17 +236,17 @@ static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, ptr \ static inline void OPNAME ## cavs_qpel8or16_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ { \ - QPEL_CAVSVNUM(QPEL_CAVSV1,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ + QPEL_CAVSVNUM(QPEL_CAVSV1,OP,ff_pw_64,pw_96,pw_42) \ }\ \ static inline void OPNAME ## cavs_qpel8or16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ { \ - QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_42) \ + QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,pw_42) \ }\ \ static inline void OPNAME ## cavs_qpel8or16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ { \ - QPEL_CAVSVNUM(QPEL_CAVSV3,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ + QPEL_CAVSVNUM(QPEL_CAVSV3,OP,ff_pw_64,pw_96,pw_42) \ }\ \ static void OPNAME ## cavs_qpel8_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ diff --git a/libavcodec/x86/celt_pvq_search.asm b/libavcodec/x86/celt_pvq_search.asm index e9bff02650..3e21b7df81 100644 --- a/libavcodec/x86/celt_pvq_search.asm +++ b/libavcodec/x86/celt_pvq_search.asm @@ -20,7 +20,6 @@ ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ;****************************************************************************** -%include "config.asm" %include "libavutil/x86/x86util.asm" %ifdef __NASM_VER__ @@ -105,7 +104,7 @@ align 16 addps m5, m7 ; m5 = Sxy_new = X[i] + Sxy_norm %if USE_APPROXIMATION == 1 - andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent aproximation error from setting pulses in array padding. + andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent approximation error from setting pulses in array padding. %endif %else diff --git a/libavcodec/x86/constants.c b/libavcodec/x86/constants.c index bc7f2b17b8..c5f3c6428e 100644 --- a/libavcodec/x86/constants.c +++ b/libavcodec/x86/constants.c @@ -37,10 +37,8 @@ DECLARE_ALIGNED(16, const xmm_reg, ff_pw_16) = { 0x0010001000100010ULL, 0x001 DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_20) = { 0x0014001400140014ULL, 0x0014001400140014ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_32) = { 0x0020002000200020ULL, 0x0020002000200020ULL }; -DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; -DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_255) = { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL }; @@ -87,6 +85,8 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pd_16) = { 0x0000001000000010ULL, 0x000 0x0000001000000010ULL, 0x0000001000000010ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_32) = { 0x0000002000000020ULL, 0x0000002000000020ULL, 0x0000002000000020ULL, 0x0000002000000020ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_64) = { 0x0000004000000040ULL, 0x0000004000000040ULL, + 0x0000004000000040ULL, 0x0000004000000040ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_8192) = { 0x0000200000002000ULL, 0x0000200000002000ULL, 0x0000200000002000ULL, 0x0000200000002000ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pd_65535)= { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h index 85da38b7b9..4a55adb5b3 100644 --- a/libavcodec/x86/constants.h +++ b/libavcodec/x86/constants.h @@ -37,10 +37,8 @@ extern const xmm_reg ff_pw_16; extern const xmm_reg ff_pw_18; extern const xmm_reg ff_pw_20; extern const xmm_reg ff_pw_32; -extern const uint64_t ff_pw_42; extern const uint64_t ff_pw_53; extern const xmm_reg ff_pw_64; -extern const uint64_t ff_pw_96; extern const uint64_t ff_pw_128; extern const ymm_reg ff_pw_255; extern const ymm_reg ff_pw_256; @@ -66,6 +64,7 @@ extern const xmm_reg ff_ps_neg; extern const ymm_reg ff_pd_1; extern const ymm_reg ff_pd_16; extern const ymm_reg ff_pd_32; +extern const ymm_reg ff_pd_64; extern const ymm_reg ff_pd_8192; extern const ymm_reg ff_pd_65535; diff --git a/libavcodec/x86/dirac_dwt.asm b/libavcodec/x86/dirac_dwt.asm index 1f3b238aee..46fb6b2dcf 100644 --- a/libavcodec/x86/dirac_dwt.asm +++ b/libavcodec/x86/dirac_dwt.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* x86 optimized discrete wavelet trasnform +;* x86 optimized discrete wavelet transform ;* Copyright (c) 2010 David Conrad ;* ;* This file is part of FFmpeg. diff --git a/libavcodec/x86/diracdsp.asm b/libavcodec/x86/diracdsp.asm index e5e2b11846..6ae7f888b3 100644 --- a/libavcodec/x86/diracdsp.asm +++ b/libavcodec/x86/diracdsp.asm @@ -216,8 +216,9 @@ cglobal add_rect_clamped_%1, 7,9,3, dst, src, stride, idwt, idwt_stride, w, h %macro ADD_OBMC 2 ; void add_obmc(uint16_t *dst, uint8_t *src, int stride, uint8_t *obmc_weight, int yblen) -cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen +cglobal add_dirac_obmc%1_%2, 5,5,5, dst, src, stride, obmc, yblen pxor m4, m4 + movsxdifnidn strideq, strided .loop: %assign i 0 %rep %1 / mmsize @@ -227,7 +228,7 @@ cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen punpckhbw m1, m4 mova m2, [obmcq+i] mova m3, m2 - punpcklbw m2, m4 + punpcklbw m2, m4 punpckhbw m3, m4 pmullw m0, m2 pmullw m1, m3 @@ -247,9 +248,6 @@ cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen RET %endm -INIT_MMX -ADD_OBMC 8, mmx - INIT_XMM PUT_RECT sse2 ADD_RECT sse2 @@ -258,6 +256,25 @@ HPEL_FILTER sse2 ADD_OBMC 32, sse2 ADD_OBMC 16, sse2 +cglobal add_dirac_obmc8_sse2, 5,5,4, dst, src, stride, obmc, yblen + pxor m3, m3 + movsxdifnidn strideq, strided +.loop: + movh m0, [srcq] + punpcklbw m0, m3 + movh m1, [obmcq] + punpcklbw m1, m3 + pmullw m0, m1 + movu m1, [dstq] + paddw m0, m1 + movu [dstq], m0 + lea srcq, [srcq+strideq] + lea dstq, [dstq+2*strideq] + add obmcq, 32 + sub yblend, 1 + jg .loop + RET + INIT_XMM sse4 ; void dequant_subband_32(uint8_t *src, uint8_t *dst, ptrdiff_t stride, const int qf, const int qs, int tot_v, int tot_h) diff --git a/libavcodec/x86/diracdsp_init.c b/libavcodec/x86/diracdsp_init.c index f678759dc0..ef01ebdf2e 100644 --- a/libavcodec/x86/diracdsp_init.c +++ b/libavcodec/x86/diracdsp_init.c @@ -24,8 +24,7 @@ void ff_add_rect_clamped_sse2(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int); -void ff_add_dirac_obmc8_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); - +void ff_add_dirac_obmc8_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); void ff_add_dirac_obmc16_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); void ff_add_dirac_obmc32_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); @@ -57,11 +56,6 @@ void ff_dequant_subband_32_sse4(uint8_t *src, uint8_t *dst, ptrdiff_t stride, co } \ } -#define PIXFUNC(PFX, IDX, EXT) \ - /*MMXDISABLEDc->PFX ## _dirac_pixels_tab[0][IDX] = PFX ## _dirac_pixels8_ ## EXT;*/ \ - c->PFX ## _dirac_pixels_tab[1][IDX] = PFX ## _dirac_pixels16_ ## EXT; \ - c->PFX ## _dirac_pixels_tab[2][IDX] = PFX ## _dirac_pixels32_ ## EXT - #define DIRAC_PIXOP(OPNAME, EXT)\ static void OPNAME ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], \ int stride, int h) \ @@ -94,15 +88,12 @@ void ff_diracdsp_init_x86(DiracDSPContext* c) #if HAVE_X86ASM int mm_flags = av_get_cpu_flags(); - if (EXTERNAL_MMX(mm_flags)) { - c->add_dirac_obmc[0] = ff_add_dirac_obmc8_mmx; - } - if (EXTERNAL_SSE2(mm_flags)) { c->dirac_hpel_filter = dirac_hpel_filter_sse2; c->add_rect_clamped = ff_add_rect_clamped_sse2; c->put_signed_rect_clamped[0] = (void *)ff_put_signed_rect_clamped_sse2; + c->add_dirac_obmc[0] = ff_add_dirac_obmc8_sse2; c->add_dirac_obmc[1] = ff_add_dirac_obmc16_sse2; c->add_dirac_obmc[2] = ff_add_dirac_obmc32_sse2; @@ -116,5 +107,5 @@ void ff_diracdsp_init_x86(DiracDSPContext* c) c->dequant_subband[1] = ff_dequant_subband_32_sse4; c->put_signed_rect_clamped[1] = ff_put_signed_rect_clamped_10_sse4; } -#endif +#endif // HAVE_X86ASM } diff --git a/libavcodec/x86/fdctdsp_init.c b/libavcodec/x86/fdctdsp_init.c index 92a842433d..107912afc8 100644 --- a/libavcodec/x86/fdctdsp_init.c +++ b/libavcodec/x86/fdctdsp_init.c @@ -26,6 +26,7 @@ av_cold void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, unsigned high_bit_depth) { +#if HAVE_SSE2_INLINE int cpu_flags = av_get_cpu_flags(); const int dct_algo = avctx->dct_algo; @@ -35,4 +36,5 @@ av_cold void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, c->fdct = ff_fdct_sse2; } } +#endif } diff --git a/libavcodec/x86/fmtconvert.asm b/libavcodec/x86/fmtconvert.asm index e70df4662d..99c5efeab0 100644 --- a/libavcodec/x86/fmtconvert.asm +++ b/libavcodec/x86/fmtconvert.asm @@ -85,4 +85,3 @@ cglobal int32_to_float_fmul_array8, 5, 5, 5, c, dst, src, mul, len INIT_XMM sse2 INT32_TO_FLOAT_FMUL_ARRAY8 - diff --git a/libavcodec/x86/h26x/h2656_inter.asm b/libavcodec/x86/h26x/h2656_inter.asm index cbba0c1ea5..49a95d58fb 100644 --- a/libavcodec/x86/h26x/h2656_inter.asm +++ b/libavcodec/x86/h26x/h2656_inter.asm @@ -1126,7 +1126,6 @@ H2656PUT_8TAP 32, 8 H2656PUT_8TAP 16, 10 H2656PUT_8TAP 16, 12 -H2656PUT_8TAP_HV 32, 8 H2656PUT_8TAP_HV 16, 10 H2656PUT_8TAP_HV 16, 12 diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/h26x/h2656_sao.asm similarity index 77% rename from libavcodec/x86/hevc_sao.asm rename to libavcodec/x86/h26x/h2656_sao.asm index 8abb16150d..a80ee26178 100644 --- a/libavcodec/x86/hevc_sao.asm +++ b/libavcodec/x86/h26x/h2656_sao.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* SIMD optimized SAO functions for HEVC 8bit decoding +;* SIMD optimized SAO functions for HEVC/VVC 8bit decoding ;* ;* Copyright (c) 2013 Pierre-Edouard LEPERE ;* Copyright (c) 2014 James Almer @@ -36,7 +36,7 @@ SECTION .text ;SAO Band Filter ;****************************************************************************** -%macro HEVC_SAO_BAND_FILTER_INIT 0 +%macro H2656_SAO_BAND_FILTER_INIT 0 and leftq, 31 movd xm0, leftd add leftq, 1 @@ -88,7 +88,7 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height mov heightd, r7m %endmacro -%macro HEVC_SAO_BAND_FILTER_COMPUTE 2 +%macro H2656_SAO_BAND_FILTER_COMPUTE 2 psraw %1, %2, 3 %if ARCH_X86_64 pcmpeqw m10, %1, m0 @@ -119,48 +119,48 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height %endif ; ARCH %endmacro -;void ff_hevc_sao_band_filter__8_(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +;void ff_{hevc, vvc}_sao_band_filter__8_(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, ; int16_t *sao_offset_val, int sao_left_class, int width, int height); -%macro HEVC_SAO_BAND_FILTER 2 -cglobal hevc_sao_band_filter_%1_8, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left - HEVC_SAO_BAND_FILTER_INIT +%macro H2656_SAO_BAND_FILTER 3 +cglobal %1_sao_band_filter_%2_8, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left + H2656_SAO_BAND_FILTER_INIT align 16 .loop: -%if %1 == 8 +%if %2 == 8 movq m8, [srcq] punpcklbw m8, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 packuswb m8, m14 movq [dstq], m8 -%endif ; %1 == 8 +%endif ; %2 == 8 %assign i 0 -%rep %2 +%rep %3 mova m13, [srcq + i] punpcklbw m8, m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 punpckhbw m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m13 + H2656_SAO_BAND_FILTER_COMPUTE m9, m13 packuswb m8, m13 mova [dstq + i], m8 %assign i i+mmsize %endrep -%if %1 == 48 +%if %2 == 48 || %2 == 80 || %2 == 112 INIT_XMM cpuname mova m13, [srcq + i] punpcklbw m8, m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m8 + H2656_SAO_BAND_FILTER_COMPUTE m9, m8 punpckhbw m13, m14 - HEVC_SAO_BAND_FILTER_COMPUTE m9, m13 + H2656_SAO_BAND_FILTER_COMPUTE m9, m13 packuswb m8, m13 mova [dstq + i], m8 %if cpuflag(avx2) INIT_YMM cpuname %endif -%endif ; %1 == 48 +%endif ; %2 == 48 || %2 == 80 || %2 == 112 add dstq, dststrideq ; dst += dststride add srcq, srcstrideq ; src += srcstride @@ -169,39 +169,14 @@ INIT_YMM cpuname RET %endmacro - -%macro HEVC_SAO_BAND_FILTER_FUNCS 0 -HEVC_SAO_BAND_FILTER 8, 0 -HEVC_SAO_BAND_FILTER 16, 1 -HEVC_SAO_BAND_FILTER 32, 2 -HEVC_SAO_BAND_FILTER 48, 2 -HEVC_SAO_BAND_FILTER 64, 4 -%endmacro - -INIT_XMM sse2 -HEVC_SAO_BAND_FILTER_FUNCS -INIT_XMM avx -HEVC_SAO_BAND_FILTER_FUNCS - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 8, 0 -HEVC_SAO_BAND_FILTER 16, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 32, 1 -HEVC_SAO_BAND_FILTER 48, 1 -HEVC_SAO_BAND_FILTER 64, 2 -%endif - ;****************************************************************************** ;SAO Edge Filter ;****************************************************************************** -%define MAX_PB_SIZE 64 %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 +%macro H2656_SAO_EDGE_FILTER_INIT 0 %if WIN64 movsxd eoq, dword eom %elif ARCH_X86_64 @@ -220,7 +195,7 @@ HEVC_SAO_BAND_FILTER 64, 2 add b_strideq, tmpq %endmacro -%macro HEVC_SAO_EDGE_FILTER_COMPUTE 1 +%macro H2656_SAO_EDGE_FILTER_COMPUTE 1 pminub m4, m1, m2 pminub m5, m1, m3 pcmpeqb m2, m4 @@ -249,22 +224,22 @@ HEVC_SAO_BAND_FILTER 64, 2 %endif %endmacro -;void ff_hevc_sao_edge_filter__8_(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, +;void ff_{hevc, vvc}_sao_edge_filter__8_(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, ; int eo, int width, int height); -%macro HEVC_SAO_EDGE_FILTER 2-3 +%macro H2656_SAO_EDGE_FILTER 3-4 %if ARCH_X86_64 -cglobal hevc_sao_edge_filter_%1_8, 4, 9, 8, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp +cglobal %1_sao_edge_filter_%2_8, 4, 9, 8, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp %define tmp2q heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov heightd, r6m %else ; ARCH_X86_32 -cglobal hevc_sao_edge_filter_%1_8, 1, 6, 8, dst, src, dststride, a_stride, b_stride, height +cglobal %1_sao_edge_filter_%2_8, 1, 6, 8, dst, src, dststride, a_stride, b_stride, height %define eoq srcq %define tmpq heightq %define tmp2q dststrideq %define offsetq heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov srcq, srcm mov offsetq, r3m mov dststrideq, dststridem @@ -287,36 +262,36 @@ cglobal hevc_sao_edge_filter_%1_8, 1, 6, 8, dst, src, dststride, a_stride, b_str align 16 .loop: -%if %1 == 8 +%if %2 == 8 movq m1, [srcq] movq m2, [srcq + a_strideq] movq m3, [srcq + b_strideq] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 + H2656_SAO_EDGE_FILTER_COMPUTE %2 movq [dstq], m3 %endif %assign i 0 -%rep %2 +%rep %3 mova m1, [srcq + i] movu m2, [srcq + a_strideq + i] movu m3, [srcq + b_strideq + i] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 - mov%3 [dstq + i], m3 + H2656_SAO_EDGE_FILTER_COMPUTE %2 + mov%4 [dstq + i], m3 %assign i i+mmsize %endrep -%if %1 == 48 +%if %2 == 48 || %2 == 80 || %2 == 112 INIT_XMM cpuname mova m1, [srcq + i] movu m2, [srcq + a_strideq + i] movu m3, [srcq + b_strideq + i] - HEVC_SAO_EDGE_FILTER_COMPUTE %1 + H2656_SAO_EDGE_FILTER_COMPUTE %2 mova [dstq + i], m3 %if cpuflag(avx2) INIT_YMM cpuname %endif -%endif +%endif ; %2 == 48 || %2 == 80 || %2 == 112 add dstq, dststrideq add srcq, EDGE_SRCSTRIDE @@ -324,17 +299,3 @@ INIT_YMM cpuname jg .loop RET %endmacro - -INIT_XMM ssse3 -HEVC_SAO_EDGE_FILTER 8, 0 -HEVC_SAO_EDGE_FILTER 16, 1, a -HEVC_SAO_EDGE_FILTER 32, 2, a -HEVC_SAO_EDGE_FILTER 48, 2, a -HEVC_SAO_EDGE_FILTER 64, 4, a - -%if HAVE_AVX2_EXTERNAL -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 32, 1, a -HEVC_SAO_EDGE_FILTER 48, 1, u -HEVC_SAO_EDGE_FILTER 64, 2, a -%endif diff --git a/libavcodec/x86/hevc_sao_10bit.asm b/libavcodec/x86/h26x/h2656_sao_10bit.asm similarity index 75% rename from libavcodec/x86/hevc_sao_10bit.asm rename to libavcodec/x86/h26x/h2656_sao_10bit.asm index 0daa9c645c..052f2b1d16 100644 --- a/libavcodec/x86/hevc_sao_10bit.asm +++ b/libavcodec/x86/h26x/h2656_sao_10bit.asm @@ -1,5 +1,5 @@ ;****************************************************************************** -;* SIMD optimized SAO functions for HEVC 10/12bit decoding +;* SIMD optimized SAO functions for HEVC/VVC 10/12bit decoding ;* ;* Copyright (c) 2013 Pierre-Edouard LEPERE ;* Copyright (c) 2014 James Almer @@ -39,7 +39,7 @@ SECTION .text ;SAO Band Filter ;****************************************************************************** -%macro HEVC_SAO_BAND_FILTER_INIT 1 +%macro H2656_SAO_BAND_FILTER_INIT 1 and leftq, 31 movd xm0, leftd add leftq, 1 @@ -92,22 +92,22 @@ DEFINE_ARGS dst, src, dststride, srcstride, offset, height mov heightd, r7m %endmacro -;void ff_hevc_sao_band_filter___(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +;void ff_{hevc, vvc}_sao_band_filter___(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, ; int16_t *sao_offset_val, int sao_left_class, int width, int height); -%macro HEVC_SAO_BAND_FILTER 3 -cglobal hevc_sao_band_filter_%2_%1, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left - HEVC_SAO_BAND_FILTER_INIT %1 +%macro H2656_SAO_BAND_FILTER 4 +cglobal %1_sao_band_filter_%3_%2, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left + H2656_SAO_BAND_FILTER_INIT %2 align 16 .loop: %assign i 0 %assign j 0 -%rep %3 +%rep %4 %assign k 8+(j&1) %assign l 9-(j&1) mova m %+ k, [srcq + i] - psraw m %+ l, m %+ k, %1-5 + psraw m %+ l, m %+ k, %2-5 %if ARCH_X86_64 pcmpeqw m10, m %+ l, m0 pcmpeqw m11, m %+ l, m1 @@ -148,48 +148,10 @@ align 16 RET %endmacro -%macro HEVC_SAO_BAND_FILTER_FUNCS 0 -HEVC_SAO_BAND_FILTER 10, 8, 1 -HEVC_SAO_BAND_FILTER 10, 16, 2 -HEVC_SAO_BAND_FILTER 10, 32, 4 -HEVC_SAO_BAND_FILTER 10, 48, 6 -HEVC_SAO_BAND_FILTER 10, 64, 8 - -HEVC_SAO_BAND_FILTER 12, 8, 1 -HEVC_SAO_BAND_FILTER 12, 16, 2 -HEVC_SAO_BAND_FILTER 12, 32, 4 -HEVC_SAO_BAND_FILTER 12, 48, 6 -HEVC_SAO_BAND_FILTER 12, 64, 8 -%endmacro - -INIT_XMM sse2 -HEVC_SAO_BAND_FILTER_FUNCS -INIT_XMM avx -HEVC_SAO_BAND_FILTER_FUNCS - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 10, 8, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 10, 16, 1 -HEVC_SAO_BAND_FILTER 10, 32, 2 -HEVC_SAO_BAND_FILTER 10, 48, 3 -HEVC_SAO_BAND_FILTER 10, 64, 4 - -INIT_XMM avx2 -HEVC_SAO_BAND_FILTER 12, 8, 1 -INIT_YMM avx2 -HEVC_SAO_BAND_FILTER 12, 16, 1 -HEVC_SAO_BAND_FILTER 12, 32, 2 -HEVC_SAO_BAND_FILTER 12, 48, 3 -HEVC_SAO_BAND_FILTER 12, 64, 4 -%endif - ;****************************************************************************** ;SAO Edge Filter ;****************************************************************************** -%define MAX_PB_SIZE 64 %define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE @@ -202,7 +164,7 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 %endif %endmacro -%macro HEVC_SAO_EDGE_FILTER_INIT 0 +%macro H2656_SAO_EDGE_FILTER_INIT 0 %if WIN64 movsxd eoq, dword eom %elif ARCH_X86_64 @@ -221,19 +183,19 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 add b_strideq, tmpq %endmacro -;void ff_hevc_sao_edge_filter___(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, +;void ff_{hevc, vvc}_sao_edge_filter___(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, ; int eo, int width, int height); -%macro HEVC_SAO_EDGE_FILTER 3 +%macro H2656_SAO_EDGE_FILTER 4 %if ARCH_X86_64 -cglobal hevc_sao_edge_filter_%2_%1, 4, 9, 16, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp +cglobal %1_sao_edge_filter_%3_%2, 4, 9, 16, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp %define tmp2q heightq - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov heightd, r6m add a_strideq, a_strideq add b_strideq, b_strideq %else ; ARCH_X86_32 -cglobal hevc_sao_edge_filter_%2_%1, 1, 6, 8, 5*mmsize, dst, src, dststride, a_stride, b_stride, height +cglobal %1_sao_edge_filter_%3_%2, 1, 6, 8, 5*mmsize, dst, src, dststride, a_stride, b_stride, height %define eoq srcq %define tmpq heightq %define tmp2q dststrideq @@ -243,7 +205,7 @@ cglobal hevc_sao_edge_filter_%2_%1, 1, 6, 8, 5*mmsize, dst, src, dststride, a_st %define m10 m3 %define m11 m4 %define m12 m5 - HEVC_SAO_EDGE_FILTER_INIT + H2656_SAO_EDGE_FILTER_INIT mov srcq, srcm mov offsetq, r3m mov dststrideq, dststridem @@ -285,7 +247,7 @@ align 16 .loop: %assign i 0 -%rep %3 +%rep %4 mova m1, [srcq + i] movu m2, [srcq+a_strideq + i] movu m3, [srcq+b_strideq + i] @@ -326,7 +288,7 @@ align 16 paddw m2, m7 paddw m2, m1 paddw m2, m5 - CLIPW m2, m0, [pw_mask %+ %1] + CLIPW m2, m0, [pw_mask %+ %2] mova [dstq + i], m2 %assign i i+mmsize %endrep @@ -337,34 +299,3 @@ align 16 jg .loop RET %endmacro - -INIT_XMM sse2 -HEVC_SAO_EDGE_FILTER 10, 8, 1 -HEVC_SAO_EDGE_FILTER 10, 16, 2 -HEVC_SAO_EDGE_FILTER 10, 32, 4 -HEVC_SAO_EDGE_FILTER 10, 48, 6 -HEVC_SAO_EDGE_FILTER 10, 64, 8 - -HEVC_SAO_EDGE_FILTER 12, 8, 1 -HEVC_SAO_EDGE_FILTER 12, 16, 2 -HEVC_SAO_EDGE_FILTER 12, 32, 4 -HEVC_SAO_EDGE_FILTER 12, 48, 6 -HEVC_SAO_EDGE_FILTER 12, 64, 8 - -%if HAVE_AVX2_EXTERNAL -INIT_XMM avx2 -HEVC_SAO_EDGE_FILTER 10, 8, 1 -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 10, 16, 1 -HEVC_SAO_EDGE_FILTER 10, 32, 2 -HEVC_SAO_EDGE_FILTER 10, 48, 3 -HEVC_SAO_EDGE_FILTER 10, 64, 4 - -INIT_XMM avx2 -HEVC_SAO_EDGE_FILTER 12, 8, 1 -INIT_YMM avx2 -HEVC_SAO_EDGE_FILTER 12, 16, 1 -HEVC_SAO_EDGE_FILTER 12, 32, 2 -HEVC_SAO_EDGE_FILTER 12, 48, 3 -HEVC_SAO_EDGE_FILTER 12, 64, 4 -%endif diff --git a/libavcodec/x86/h26x/h2656dsp.c b/libavcodec/x86/h26x/h2656dsp.c index c402f9e21c..1d8ec1898d 100644 --- a/libavcodec/x86/h26x/h2656dsp.c +++ b/libavcodec/x86/h26x/h2656dsp.c @@ -80,9 +80,7 @@ mc_rep_funcs(8tap_hv, 8, 8, 16, sse4) #if HAVE_AVX2_EXTERNAL -#define MC_REP_FUNCS_AVX2(fname) \ - mc_rep_funcs(fname, 8, 32, 64, avx2) \ - mc_rep_funcs(fname, 8, 32,128, avx2) \ +#define MC_REP_FUNCS_AVX2_NO8(fname) \ mc_rep_funcs(fname,10, 16, 32, avx2) \ mc_rep_funcs(fname,10, 16, 64, avx2) \ mc_rep_funcs(fname,10, 16,128, avx2) \ @@ -90,12 +88,17 @@ mc_rep_funcs(8tap_hv, 8, 8, 16, sse4) mc_rep_funcs(fname,12, 16, 64, avx2) \ mc_rep_funcs(fname,12, 16,128, avx2) \ +#define MC_REP_FUNCS_AVX2(fname) \ + mc_rep_funcs(fname, 8, 32, 64, avx2) \ + mc_rep_funcs(fname, 8, 32,128, avx2) \ + MC_REP_FUNCS_AVX2_NO8(fname) + MC_REP_FUNCS_AVX2(pixels) MC_REP_FUNCS_AVX2(8tap_h) MC_REP_FUNCS_AVX2(8tap_v) -MC_REP_FUNCS_AVX2(8tap_hv) +MC_REP_FUNCS_AVX2_NO8(8tap_hv) MC_REP_FUNCS_AVX2(4tap_h) MC_REP_FUNCS_AVX2(4tap_v) -MC_REP_FUNCS_AVX2(4tap_hv) +MC_REP_FUNCS_AVX2_NO8(4tap_hv) #endif #endif diff --git a/libavcodec/x86/hevc/Makefile b/libavcodec/x86/hevc/Makefile new file mode 100644 index 0000000000..8f1c88c569 --- /dev/null +++ b/libavcodec/x86/hevc/Makefile @@ -0,0 +1,12 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/x86/hevc/%) $(CLEANSUFFIXES:%=libavcodec/x86/h26x/%) + +OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc/dsp_init.o \ + x86/h26x/h2656dsp.o +X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc/add_res.o \ + x86/hevc/deblock.o \ + x86/hevc/idct.o \ + x86/hevc/mc.o \ + x86/hevc/sao.o \ + x86/hevc/sao_10bit.o \ + x86/h26x/h2656_inter.o diff --git a/libavcodec/x86/hevc_add_res.asm b/libavcodec/x86/hevc/add_res.asm similarity index 100% rename from libavcodec/x86/hevc_add_res.asm rename to libavcodec/x86/hevc/add_res.asm diff --git a/libavcodec/x86/hevc_deblock.asm b/libavcodec/x86/hevc/deblock.asm similarity index 100% rename from libavcodec/x86/hevc_deblock.asm rename to libavcodec/x86/hevc/deblock.asm diff --git a/libavcodec/x86/hevc/dsp.h b/libavcodec/x86/hevc/dsp.h new file mode 100644 index 0000000000..03986b970a --- /dev/null +++ b/libavcodec/x86/hevc/dsp.h @@ -0,0 +1,189 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere + * + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_HEVC_DSP_H +#define AVCODEC_X86_HEVC_DSP_H + +#include +#include + +typedef void bi_pel_func(uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, + int height, intptr_t mx, intptr_t my, int width); + +#define BI_PEL_PROTOTYPE(name, W, D, opt) \ +bi_pel_func ff_hevc_put_bi_ ## name ## W ## _ ## D ## _##opt + +/////////////////////////////////////////////////////////////////////////////// +// MC functions +/////////////////////////////////////////////////////////////////////////////// + +#define WEIGHTING_PROTOTYPE(width, bitd, opt) \ +void ff_hevc_put_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, int height, int denom, int _wx, int _ox); \ +void ff_hevc_put_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, const int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1) + +#define WEIGHTING_PROTOTYPES(bitd, opt) \ + WEIGHTING_PROTOTYPE(4, bitd, opt); \ + WEIGHTING_PROTOTYPE(6, bitd, opt); \ + WEIGHTING_PROTOTYPE(8, bitd, opt); \ + WEIGHTING_PROTOTYPE(12, bitd, opt); \ + WEIGHTING_PROTOTYPE(16, bitd, opt); \ + WEIGHTING_PROTOTYPE(24, bitd, opt); \ + WEIGHTING_PROTOTYPE(32, bitd, opt); \ + WEIGHTING_PROTOTYPE(48, bitd, opt); \ + WEIGHTING_PROTOTYPE(64, bitd, opt) + + +/////////////////////////////////////////////////////////////////////////////// +// EPEL_PIXELS +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(pel_pixels, 4, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 4, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 4, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 6, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 10, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 8, 12, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 12, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 16, 8, sse4); +BI_PEL_PROTOTYPE(pel_pixels, 16, 10, avx2); +BI_PEL_PROTOTYPE(pel_pixels, 32, 8, avx2); + +/////////////////////////////////////////////////////////////////////////////// +// EPEL +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(epel_h, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_h, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_h, 12, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_h, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_h, 32, 8, avx2); + +BI_PEL_PROTOTYPE(epel_hv, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_hv, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_hv, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_hv, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_hv, 32, 8, avx2); + +BI_PEL_PROTOTYPE(epel_v, 4, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 4, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 4, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 6, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 10, sse4); +BI_PEL_PROTOTYPE(epel_v, 8, 12, sse4); +BI_PEL_PROTOTYPE(epel_v, 12, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 16, 8, sse4); +BI_PEL_PROTOTYPE(epel_v, 16, 10, avx2); +BI_PEL_PROTOTYPE(epel_v, 32, 8, avx2); + +/////////////////////////////////////////////////////////////////////////////// +// QPEL +/////////////////////////////////////////////////////////////////////////////// + +BI_PEL_PROTOTYPE(qpel_h, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_h, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_h, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_h, 12, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 16, 8, sse4); +BI_PEL_PROTOTYPE(qpel_h, 16, 10, avx2); +BI_PEL_PROTOTYPE(qpel_h, 32, 8, avx2); + +BI_PEL_PROTOTYPE(qpel_hv, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_hv, 16, 10, avx2); + +BI_PEL_PROTOTYPE(qpel_v, 4, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 4, 10, sse4); +BI_PEL_PROTOTYPE(qpel_v, 4, 12, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 10, sse4); +BI_PEL_PROTOTYPE(qpel_v, 8, 12, sse4); +BI_PEL_PROTOTYPE(qpel_v, 12, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 16, 8, sse4); +BI_PEL_PROTOTYPE(qpel_v, 16, 10, avx2); +BI_PEL_PROTOTYPE(qpel_v, 32, 8, avx2); + +WEIGHTING_PROTOTYPES(8, sse4); +WEIGHTING_PROTOTYPES(10, sse4); +WEIGHTING_PROTOTYPES(12, sse4); + +void ff_hevc_put_qpel_h4_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h16_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h32_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_h64_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_qpel_hv8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); + +/////////////////////////////////////////////////////////////////////////////// +// TRANSFORM_ADD +/////////////////////////////////////////////////////////////////////////////// + +void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_8_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_32_8_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_4_10_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_16_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); + +#endif // AVCODEC_X86_HEVC_DSP_H diff --git a/libavcodec/x86/hevcdsp_init.c b/libavcodec/x86/hevc/dsp_init.c similarity index 61% rename from libavcodec/x86/hevcdsp_init.c rename to libavcodec/x86/hevc/dsp_init.c index 2c0fca303e..ba921e7299 100644 --- a/libavcodec/x86/hevcdsp_init.c +++ b/libavcodec/x86/hevc/dsp_init.c @@ -27,7 +27,7 @@ #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/hevc/dsp.h" -#include "libavcodec/x86/hevcdsp.h" +#include "libavcodec/x86/hevc/dsp.h" #include "libavcodec/x86/h26x/h2656dsp.h" #define LFC_FUNC(DIR, DEPTH, OPT) \ @@ -92,15 +92,15 @@ IDCT_FUNCS(avx) const uint8_t *vf = ff_hevc_ ## f ## _filters[my]; #define FW_PUT(p, a, b, depth, opt) \ -void ff_hevc_put_hevc_ ## a ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ - int height, intptr_t mx, intptr_t my,int width) \ +static void hevc_put_ ## a ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ + int height, intptr_t mx, intptr_t my,int width) \ { \ DECL_HV_FILTER(p) \ ff_h2656_put_ ## b ## _ ## depth ## _##opt(dst, 2 * MAX_PB_SIZE, src, srcstride, height, hf, vf, width); \ } #define FW_PUT_UNI(p, a, b, depth, opt) \ -void ff_hevc_put_hevc_uni_ ## a ## _ ## depth ## _##opt(uint8_t *dst, ptrdiff_t dststride, \ +static void hevc_put_uni_ ## a ## _ ## depth ## _##opt(uint8_t *dst, ptrdiff_t dststride, \ const uint8_t *src, ptrdiff_t srcstride, \ int height, intptr_t mx, intptr_t my, int width) \ { \ @@ -190,36 +190,36 @@ FW_QPEL_HV(16, 10, avx2) #endif #define mc_rep_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *_dst, \ - const uint8_t *_src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##W##_##bitd##_##opt(int16_t *_dst, \ + const uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ int i; \ int16_t *dst; \ for (i = 0; i < W; i += step) { \ const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ dst = _dst + i; \ - ff_hevc_put_hevc_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ } \ } #define mc_rep_uni_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ int i; \ uint8_t *dst; \ for (i = 0; i < W; i += step) { \ const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ } \ } #define mc_rep_bi_func(name, bitd, step, W, opt) \ -void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const uint8_t *_src, \ - ptrdiff_t _srcstride, const int16_t *_src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const uint8_t *_src, \ + ptrdiff_t _srcstride, const int16_t *_src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ int i; \ uint8_t *dst; \ @@ -227,8 +227,8 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dst const uint8_t *src = _src + (i * ((bitd + 7) / 8)); \ const int16_t *src2 = _src2 + i; \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \ - height, mx, my, width); \ + ff_hevc_put_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ } \ } @@ -238,33 +238,33 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dst mc_rep_bi_func(name, bitd, step, W, opt) #define mc_rep_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *dst, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##W##_##bitd##_##opt(int16_t *dst, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \ - _srcstride, height, mx, my, width); \ + hevc_put_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \ + _srcstride, height, mx, my, width); \ } #define mc_rep_uni_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width);\ - ff_hevc_put_hevc_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ - src + (step1 * ((bitd + 7) / 8)), _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width); \ + hevc_put_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + height, mx, my, width); \ } #define mc_rep_bi_func2(name, bitd, step1, step2, W, opt) \ -void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\ - ff_hevc_put_hevc_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ - src + (step1 * ((bitd + 7) / 8)), _srcstride, \ - src2 + step1, height, mx, my, width); \ + ff_hevc_put_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\ + ff_hevc_put_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + src2 + step1, height, mx, my, width); \ } #define mc_rep_funcs2(name, bitd, step1, step2, W, opt) \ @@ -275,34 +275,34 @@ void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dsts #if ARCH_X86_64 && HAVE_SSE4_EXTERNAL #define mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_##name##width1##_10_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##width1##_10_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ \ { \ - ff_hevc_put_hevc_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \ + hevc_put_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \ } #define mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \ - height, mx, my, width); \ - ff_hevc_put_hevc_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2,\ - height, mx, my, width); \ + ff_hevc_put_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ + ff_hevc_put_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2, \ + height, mx, my, width); \ } #define mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ -void ff_hevc_put_hevc_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ - ff_hevc_put_hevc_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + hevc_put_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \ + height, mx, my, width); \ } #define mc_rep_mixs_10(name, width1, width2, width3, opt1, opt2, width4) \ @@ -311,34 +311,34 @@ mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) #define mc_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_##name##width1##_8_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void hevc_put_##name##width1##_8_##opt1(int16_t *dst, const uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ \ { \ - ff_hevc_put_hevc_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \ + hevc_put_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \ + hevc_put_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \ } #define mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ - ptrdiff_t _srcstride, const int16_t *src2, \ - int height, intptr_t mx, intptr_t my, int width) \ +static void ff_hevc_put_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \ + ptrdiff_t _srcstride, const int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ - src2, height, mx, my, width); \ - ff_hevc_put_hevc_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ - src2+width2, height, mx, my, width); \ + ff_hevc_put_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + src2, height, mx, my, width); \ + ff_hevc_put_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + src2+width2, height, mx, my, width); \ } #define mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ -void ff_hevc_put_hevc_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \ - const uint8_t *src, ptrdiff_t _srcstride, int height, \ - intptr_t mx, intptr_t my, int width) \ +static void hevc_put_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ { \ - ff_hevc_put_hevc_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ - height, mx, my, width); \ - ff_hevc_put_hevc_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ - height, mx, my, width); \ + hevc_put_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + hevc_put_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + height, mx, my, width); \ } #define mc_rep_mixs_8(name, width1, width2, width3, opt1, opt2) \ @@ -365,11 +365,11 @@ mc_rep_mixs_10(qpel_v , 24, 16, 8, avx2, sse4, 32) mc_rep_mixs_10(qpel_hv, 24, 16, 8, avx2, sse4, 32) +mc_rep_funcs(pel_pixels, 8, 32, 64, avx2) + mc_rep_uni_func(pel_pixels, 8, 64, 128, avx2)//used for 10bit mc_rep_uni_func(pel_pixels, 8, 32, 96, avx2) //used for 10bit -mc_rep_funcs(pel_pixels, 8, 32, 64, avx2) - mc_rep_func(pel_pixels, 10, 16, 32, avx2) mc_rep_func(pel_pixels, 10, 16, 48, avx2) mc_rep_func(pel_pixels, 10, 32, 64, avx2) @@ -536,16 +536,16 @@ mc_rep_funcs(qpel_hv,12, 8, 16, sse4) mc_rep_funcs(qpel_hv,12, 4, 12, sse4) #define mc_rep_uni_w(bitd, step, W, opt) \ -void ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ - int height, int denom, int _wx, int _ox) \ +void ff_hevc_put_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ + int height, int denom, int _wx, int _ox) \ { \ int i; \ uint8_t *dst; \ for (i = 0; i < W; i += step) { \ const int16_t *src = _src + i; \ dst= _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_uni_w##step##_##bitd##_##opt(dst, dststride, src, \ - height, denom, _wx, _ox); \ + ff_hevc_put_uni_w##step##_##bitd##_##opt(dst, dststride, src, \ + height, denom, _wx, _ox); \ } \ } @@ -571,9 +571,9 @@ mc_rep_uni_w(12, 8, 48, sse4) mc_rep_uni_w(12, 8, 64, sse4) #define mc_rep_bi_w(bitd, step, W, opt) \ -void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ - const int16_t *_src2, int height, \ - int denom, int _wx0, int _wx1, int _ox0, int _ox1) \ +void ff_hevc_put_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, const int16_t *_src, \ + const int16_t *_src2, int height, \ + int denom, int _wx0, int _wx1, int _ox0, int _ox1) \ { \ int i; \ uint8_t *dst; \ @@ -581,8 +581,8 @@ void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststrid const int16_t *src = _src + i; \ const int16_t *src2 = _src2 + i; \ dst = _dst + (i * ((bitd + 7) / 8)); \ - ff_hevc_put_hevc_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \ - height, denom, _wx0, _wx1, _ox0, _ox1); \ + ff_hevc_put_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ } \ } @@ -608,15 +608,15 @@ mc_rep_bi_w(12, 8, 48, sse4) mc_rep_bi_w(12, 8, 64, sse4) #define mc_uni_w_func(name, bitd, W, opt) \ -void ff_hevc_put_hevc_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, \ +static void hevc_put_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, \ int height, int denom, \ int _wx, int _ox, \ intptr_t mx, intptr_t my, int width) \ { \ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ - ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox);\ + hevc_put_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox); \ } #define mc_uni_w_funcs(name, bitd, opt) \ @@ -666,17 +666,17 @@ mc_uni_w_funcs(qpel_v, 12, sse4) mc_uni_w_funcs(qpel_hv, 12, sse4) #define mc_bi_w_func(name, bitd, W, opt) \ -void ff_hevc_put_hevc_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ - const uint8_t *_src, ptrdiff_t _srcstride, \ - const int16_t *_src2, \ +static void hevc_put_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + const uint8_t *_src, ptrdiff_t _srcstride, \ + const int16_t *_src2, \ int height, int denom, \ int _wx0, int _wx1, int _ox0, int _ox1, \ intptr_t mx, intptr_t my, int width) \ { \ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ - ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ - ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \ - height, denom, _wx0, _wx1, _ox0, _ox1); \ + hevc_put_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ } #define mc_bi_w_funcs(name, bitd, opt) \ @@ -783,6 +783,13 @@ SAO_EDGE_FILTER_FUNCS(12, avx2) c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_##bitd##_##opt; \ } while (0) +#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \ +dst [idx1][idx2][idx3] = hevc_put_ ## name ## _ ## D ## _##opt; \ +dst ## _bi [idx1][idx2][idx3] = ff_hevc_put_bi_ ## name ## _ ## D ## _##opt; \ +dst ## _uni [idx1][idx2][idx3] = hevc_put_uni_ ## name ## _ ## D ## _##opt; \ +dst ## _uni_w[idx1][idx2][idx3] = hevc_put_uni_w_ ## name ## _ ## D ## _##opt; \ +dst ## _bi_w [idx1][idx2][idx3] = hevc_put_bi_w_ ## name ## _ ## D ## _##opt + #define EPEL_LINKS(pointer, my, mx, fname, bitd, opt ) \ PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \ PEL_LINK(pointer, 2, my , mx , fname##6 , bitd, opt ); \ @@ -843,7 +850,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) } SAO_EDGE_INIT(8, ssse3); } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 8, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 8, sse4); @@ -855,6 +863,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 8, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 8, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_avx; @@ -878,94 +887,97 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_8_avx2; c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_8_avx2; } +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_avx2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_avx2; - if (ARCH_X86_64) { - c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; - c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; - c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; - c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; - c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; - c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; +#if ARCH_X86_64 + c->put_hevc_epel[7][0][0] = hevc_put_pel_pixels32_8_avx2; + c->put_hevc_epel[8][0][0] = hevc_put_pel_pixels48_8_avx2; + c->put_hevc_epel[9][0][0] = hevc_put_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_qpel[7][0][0] = hevc_put_pel_pixels32_8_avx2; + c->put_hevc_qpel[8][0][0] = hevc_put_pel_pixels48_8_avx2; + c->put_hevc_qpel[9][0][0] = hevc_put_pel_pixels64_8_avx2; - c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_epel_uni[7][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[8][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[9][0][0] = hevc_put_uni_pel_pixels64_8_avx2; - c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; - c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; - c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + c->put_hevc_qpel_uni[7][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = hevc_put_uni_pel_pixels64_8_avx2; - c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; - c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; - c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_8_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_8_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_8_avx2; - c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_8_avx2; - c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_8_avx2; - c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_8_avx2; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_8_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_8_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_8_avx2; - c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_8_avx2; - c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_8_avx2; + c->put_hevc_epel[7][0][1] = hevc_put_epel_h32_8_avx2; + c->put_hevc_epel[8][0][1] = hevc_put_epel_h48_8_avx2; + c->put_hevc_epel[9][0][1] = hevc_put_epel_h64_8_avx2; - c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_8_avx2; - c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_8_avx2; - c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_8_avx2; + c->put_hevc_epel_uni[7][0][1] = hevc_put_uni_epel_h32_8_avx2; + c->put_hevc_epel_uni[8][0][1] = hevc_put_uni_epel_h48_8_avx2; + c->put_hevc_epel_uni[9][0][1] = hevc_put_uni_epel_h64_8_avx2; - c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_8_avx2; - c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_8_avx2; - c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_8_avx2; + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_bi_epel_h32_8_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_bi_epel_h48_8_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_bi_epel_h64_8_avx2; - c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_8_avx2; - c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_8_avx2; - c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_8_avx2; + c->put_hevc_epel[7][1][0] = hevc_put_epel_v32_8_avx2; + c->put_hevc_epel[8][1][0] = hevc_put_epel_v48_8_avx2; + c->put_hevc_epel[9][1][0] = hevc_put_epel_v64_8_avx2; - c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_avx2; - c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_8_avx2; - c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_8_avx2; + c->put_hevc_epel_uni[7][1][0] = hevc_put_uni_epel_v32_8_avx2; + c->put_hevc_epel_uni[8][1][0] = hevc_put_uni_epel_v48_8_avx2; + c->put_hevc_epel_uni[9][1][0] = hevc_put_uni_epel_v64_8_avx2; - c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_8_avx2; - c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_8_avx2; - c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_8_avx2; + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_bi_epel_v32_8_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_bi_epel_v48_8_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_bi_epel_v64_8_avx2; - c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_8_avx2; - c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_8_avx2; - c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_8_avx2; + c->put_hevc_epel[7][1][1] = hevc_put_epel_hv32_8_avx2; + c->put_hevc_epel[8][1][1] = hevc_put_epel_hv48_8_avx2; + c->put_hevc_epel[9][1][1] = hevc_put_epel_hv64_8_avx2; - c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_8_avx2; - c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_8_avx2; - c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_8_avx2; + c->put_hevc_epel_uni[7][1][1] = hevc_put_uni_epel_hv32_8_avx2; + c->put_hevc_epel_uni[8][1][1] = hevc_put_uni_epel_hv48_8_avx2; + c->put_hevc_epel_uni[9][1][1] = hevc_put_uni_epel_hv64_8_avx2; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx2; - c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_avx2; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx2; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_bi_epel_hv32_8_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_bi_epel_hv48_8_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_bi_epel_hv64_8_avx2; - c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_8_avx2; - c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_8_avx2; - c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_8_avx2; + c->put_hevc_qpel[7][0][1] = hevc_put_qpel_h32_8_avx2; + c->put_hevc_qpel[8][0][1] = hevc_put_qpel_h48_8_avx2; + c->put_hevc_qpel[9][0][1] = hevc_put_qpel_h64_8_avx2; - c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_8_avx2; - c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_8_avx2; - c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_8_avx2; + c->put_hevc_qpel[7][1][0] = hevc_put_qpel_v32_8_avx2; + c->put_hevc_qpel[8][1][0] = hevc_put_qpel_v48_8_avx2; + c->put_hevc_qpel[9][1][0] = hevc_put_qpel_v64_8_avx2; - c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_8_avx2; - c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_8_avx2; - c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_8_avx2; + c->put_hevc_qpel_uni[7][0][1] = hevc_put_uni_qpel_h32_8_avx2; + c->put_hevc_qpel_uni[8][0][1] = hevc_put_uni_qpel_h48_8_avx2; + c->put_hevc_qpel_uni[9][0][1] = hevc_put_uni_qpel_h64_8_avx2; - c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_8_avx2; - c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_8_avx2; - c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_8_avx2; + c->put_hevc_qpel_uni[7][1][0] = hevc_put_uni_qpel_v32_8_avx2; + c->put_hevc_qpel_uni[8][1][0] = hevc_put_uni_qpel_v48_8_avx2; + c->put_hevc_qpel_uni[9][1][0] = hevc_put_uni_qpel_v64_8_avx2; + + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_bi_qpel_h32_8_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_bi_qpel_h48_8_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_bi_qpel_h64_8_avx2; + + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_bi_qpel_v32_8_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_bi_qpel_v48_8_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_bi_qpel_v64_8_avx2; +#endif /* ARCH_X86_64 */ - c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_8_avx2; - c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_8_avx2; - c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_8_avx2; - } SAO_BAND_INIT(8, avx2); c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_8_avx2; @@ -974,13 +986,14 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->add_residual[3] = ff_hevc_add_residual_32_8_avx2; } +#endif /* HAVE_AVX2_EXTERNAL */ if (EXTERNAL_AVX512ICL(cpu_flags) && ARCH_X86_64) { - c->put_hevc_qpel[1][0][1] = ff_hevc_put_hevc_qpel_h4_8_avx512icl; - c->put_hevc_qpel[3][0][1] = ff_hevc_put_hevc_qpel_h8_8_avx512icl; - c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_8_avx512icl; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx512icl; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx512icl; - c->put_hevc_qpel[3][1][1] = ff_hevc_put_hevc_qpel_hv8_8_avx512icl; + c->put_hevc_qpel[1][0][1] = ff_hevc_put_qpel_h4_8_avx512icl; + c->put_hevc_qpel[3][0][1] = ff_hevc_put_qpel_h8_8_avx512icl; + c->put_hevc_qpel[5][0][1] = ff_hevc_put_qpel_h16_8_avx512icl; + c->put_hevc_qpel[7][0][1] = ff_hevc_put_qpel_h32_8_avx512icl; + c->put_hevc_qpel[9][0][1] = ff_hevc_put_qpel_h64_8_avx512icl; + c->put_hevc_qpel[3][1][1] = ff_hevc_put_qpel_hv8_8_avx512icl; } } else if (bit_depth == 10) { if (EXTERNAL_MMXEXT(cpu_flags)) { @@ -1015,7 +1028,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_ssse3; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_ssse3; } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 10, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 10, sse4); EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 10, sse4); @@ -1026,6 +1040,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 10, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 10, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_avx; @@ -1045,159 +1060,163 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (EXTERNAL_AVX2(cpu_flags)) { c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_10_avx2; } +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_avx2; c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_avx2; - if (ARCH_X86_64) { - c->put_hevc_epel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; - c->put_hevc_epel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; - c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; - c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; - c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; - c->put_hevc_qpel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; - c->put_hevc_qpel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; - c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; - c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; - c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; +#if ARCH_X86_64 + c->put_hevc_epel[5][0][0] = hevc_put_pel_pixels16_10_avx2; + c->put_hevc_epel[6][0][0] = hevc_put_pel_pixels24_10_avx2; + c->put_hevc_epel[7][0][0] = hevc_put_pel_pixels32_10_avx2; + c->put_hevc_epel[8][0][0] = hevc_put_pel_pixels48_10_avx2; + c->put_hevc_epel[9][0][0] = hevc_put_pel_pixels64_10_avx2; - c->put_hevc_epel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_epel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; - c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; - c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + c->put_hevc_qpel[5][0][0] = hevc_put_pel_pixels16_10_avx2; + c->put_hevc_qpel[6][0][0] = hevc_put_pel_pixels24_10_avx2; + c->put_hevc_qpel[7][0][0] = hevc_put_pel_pixels32_10_avx2; + c->put_hevc_qpel[8][0][0] = hevc_put_pel_pixels48_10_avx2; + c->put_hevc_qpel[9][0][0] = hevc_put_pel_pixels64_10_avx2; - c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; - c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; - c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; - c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; - c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + c->put_hevc_epel_uni[5][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[6][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[7][0][0] = hevc_put_uni_pel_pixels64_8_avx2; + c->put_hevc_epel_uni[8][0][0] = hevc_put_uni_pel_pixels96_8_avx2; + c->put_hevc_epel_uni[9][0][0] = hevc_put_uni_pel_pixels128_8_avx2; - c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; - c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; - c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; - c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; - c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; - c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; - c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; - c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; - c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; - c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; + c->put_hevc_qpel_uni[5][0][0] = hevc_put_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[6][0][0] = hevc_put_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[7][0][0] = hevc_put_uni_pel_pixels64_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = hevc_put_uni_pel_pixels96_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = hevc_put_uni_pel_pixels128_8_avx2; - c->put_hevc_epel[5][0][1] = ff_hevc_put_hevc_epel_h16_10_avx2; - c->put_hevc_epel[6][0][1] = ff_hevc_put_hevc_epel_h24_10_avx2; - c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_10_avx2; - c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_10_avx2; - c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_10_avx2; + c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_bi_pel_pixels16_10_avx2; + c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_bi_pel_pixels24_10_avx2; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_10_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_10_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_10_avx2; + c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_bi_pel_pixels16_10_avx2; + c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_bi_pel_pixels24_10_avx2; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_bi_pel_pixels32_10_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_bi_pel_pixels48_10_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_bi_pel_pixels64_10_avx2; - c->put_hevc_epel_uni[5][0][1] = ff_hevc_put_hevc_uni_epel_h16_10_avx2; - c->put_hevc_epel_uni[6][0][1] = ff_hevc_put_hevc_uni_epel_h24_10_avx2; - c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_10_avx2; - c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_10_avx2; - c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_10_avx2; + c->put_hevc_epel[5][0][1] = hevc_put_epel_h16_10_avx2; + c->put_hevc_epel[6][0][1] = hevc_put_epel_h24_10_avx2; + c->put_hevc_epel[7][0][1] = hevc_put_epel_h32_10_avx2; + c->put_hevc_epel[8][0][1] = hevc_put_epel_h48_10_avx2; + c->put_hevc_epel[9][0][1] = hevc_put_epel_h64_10_avx2; - c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_hevc_bi_epel_h16_10_avx2; - c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_hevc_bi_epel_h24_10_avx2; - c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_10_avx2; - c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_10_avx2; - c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_10_avx2; + c->put_hevc_epel_uni[5][0][1] = hevc_put_uni_epel_h16_10_avx2; + c->put_hevc_epel_uni[6][0][1] = hevc_put_uni_epel_h24_10_avx2; + c->put_hevc_epel_uni[7][0][1] = hevc_put_uni_epel_h32_10_avx2; + c->put_hevc_epel_uni[8][0][1] = hevc_put_uni_epel_h48_10_avx2; + c->put_hevc_epel_uni[9][0][1] = hevc_put_uni_epel_h64_10_avx2; - c->put_hevc_epel[5][1][0] = ff_hevc_put_hevc_epel_v16_10_avx2; - c->put_hevc_epel[6][1][0] = ff_hevc_put_hevc_epel_v24_10_avx2; - c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_10_avx2; - c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_10_avx2; - c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_10_avx2; + c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_bi_epel_h16_10_avx2; + c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_bi_epel_h24_10_avx2; + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_bi_epel_h32_10_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_bi_epel_h48_10_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_bi_epel_h64_10_avx2; - c->put_hevc_epel_uni[5][1][0] = ff_hevc_put_hevc_uni_epel_v16_10_avx2; - c->put_hevc_epel_uni[6][1][0] = ff_hevc_put_hevc_uni_epel_v24_10_avx2; - c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_10_avx2; - c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_10_avx2; - c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_10_avx2; + c->put_hevc_epel[5][1][0] = hevc_put_epel_v16_10_avx2; + c->put_hevc_epel[6][1][0] = hevc_put_epel_v24_10_avx2; + c->put_hevc_epel[7][1][0] = hevc_put_epel_v32_10_avx2; + c->put_hevc_epel[8][1][0] = hevc_put_epel_v48_10_avx2; + c->put_hevc_epel[9][1][0] = hevc_put_epel_v64_10_avx2; - c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_hevc_bi_epel_v16_10_avx2; - c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_10_avx2; - c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_10_avx2; - c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_10_avx2; - c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_10_avx2; + c->put_hevc_epel_uni[5][1][0] = hevc_put_uni_epel_v16_10_avx2; + c->put_hevc_epel_uni[6][1][0] = hevc_put_uni_epel_v24_10_avx2; + c->put_hevc_epel_uni[7][1][0] = hevc_put_uni_epel_v32_10_avx2; + c->put_hevc_epel_uni[8][1][0] = hevc_put_uni_epel_v48_10_avx2; + c->put_hevc_epel_uni[9][1][0] = hevc_put_uni_epel_v64_10_avx2; - c->put_hevc_epel[5][1][1] = ff_hevc_put_hevc_epel_hv16_10_avx2; - c->put_hevc_epel[6][1][1] = ff_hevc_put_hevc_epel_hv24_10_avx2; - c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_10_avx2; - c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_10_avx2; - c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_10_avx2; + c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_bi_epel_v16_10_avx2; + c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_bi_epel_v24_10_avx2; + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_bi_epel_v32_10_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_bi_epel_v48_10_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_bi_epel_v64_10_avx2; - c->put_hevc_epel_uni[5][1][1] = ff_hevc_put_hevc_uni_epel_hv16_10_avx2; - c->put_hevc_epel_uni[6][1][1] = ff_hevc_put_hevc_uni_epel_hv24_10_avx2; - c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_10_avx2; - c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_10_avx2; - c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_10_avx2; + c->put_hevc_epel[5][1][1] = hevc_put_epel_hv16_10_avx2; + c->put_hevc_epel[6][1][1] = hevc_put_epel_hv24_10_avx2; + c->put_hevc_epel[7][1][1] = hevc_put_epel_hv32_10_avx2; + c->put_hevc_epel[8][1][1] = hevc_put_epel_hv48_10_avx2; + c->put_hevc_epel[9][1][1] = hevc_put_epel_hv64_10_avx2; - c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_10_avx2; - c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_10_avx2; - c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_10_avx2; - c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_10_avx2; - c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_10_avx2; + c->put_hevc_epel_uni[5][1][1] = hevc_put_uni_epel_hv16_10_avx2; + c->put_hevc_epel_uni[6][1][1] = hevc_put_uni_epel_hv24_10_avx2; + c->put_hevc_epel_uni[7][1][1] = hevc_put_uni_epel_hv32_10_avx2; + c->put_hevc_epel_uni[8][1][1] = hevc_put_uni_epel_hv48_10_avx2; + c->put_hevc_epel_uni[9][1][1] = hevc_put_uni_epel_hv64_10_avx2; - c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_10_avx2; - c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_10_avx2; - c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_10_avx2; - c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_10_avx2; - c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_10_avx2; + c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_bi_epel_hv16_10_avx2; + c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_bi_epel_hv24_10_avx2; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_bi_epel_hv32_10_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_bi_epel_hv48_10_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_bi_epel_hv64_10_avx2; - c->put_hevc_qpel_uni[5][0][1] = ff_hevc_put_hevc_uni_qpel_h16_10_avx2; - c->put_hevc_qpel_uni[6][0][1] = ff_hevc_put_hevc_uni_qpel_h24_10_avx2; - c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_10_avx2; - c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_10_avx2; - c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_10_avx2; + c->put_hevc_qpel[5][0][1] = hevc_put_qpel_h16_10_avx2; + c->put_hevc_qpel[6][0][1] = hevc_put_qpel_h24_10_avx2; + c->put_hevc_qpel[7][0][1] = hevc_put_qpel_h32_10_avx2; + c->put_hevc_qpel[8][0][1] = hevc_put_qpel_h48_10_avx2; + c->put_hevc_qpel[9][0][1] = hevc_put_qpel_h64_10_avx2; - c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_hevc_bi_qpel_h16_10_avx2; - c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_hevc_bi_qpel_h24_10_avx2; - c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_10_avx2; - c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_10_avx2; - c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_10_avx2; + c->put_hevc_qpel_uni[5][0][1] = hevc_put_uni_qpel_h16_10_avx2; + c->put_hevc_qpel_uni[6][0][1] = hevc_put_uni_qpel_h24_10_avx2; + c->put_hevc_qpel_uni[7][0][1] = hevc_put_uni_qpel_h32_10_avx2; + c->put_hevc_qpel_uni[8][0][1] = hevc_put_uni_qpel_h48_10_avx2; + c->put_hevc_qpel_uni[9][0][1] = hevc_put_uni_qpel_h64_10_avx2; - c->put_hevc_qpel[5][1][0] = ff_hevc_put_hevc_qpel_v16_10_avx2; - c->put_hevc_qpel[6][1][0] = ff_hevc_put_hevc_qpel_v24_10_avx2; - c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_10_avx2; - c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_10_avx2; - c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_10_avx2; + c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_bi_qpel_h16_10_avx2; + c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_bi_qpel_h24_10_avx2; + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_bi_qpel_h32_10_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_bi_qpel_h48_10_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_bi_qpel_h64_10_avx2; - c->put_hevc_qpel_uni[5][1][0] = ff_hevc_put_hevc_uni_qpel_v16_10_avx2; - c->put_hevc_qpel_uni[6][1][0] = ff_hevc_put_hevc_uni_qpel_v24_10_avx2; - c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_10_avx2; - c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_10_avx2; - c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_10_avx2; + c->put_hevc_qpel[5][1][0] = hevc_put_qpel_v16_10_avx2; + c->put_hevc_qpel[6][1][0] = hevc_put_qpel_v24_10_avx2; + c->put_hevc_qpel[7][1][0] = hevc_put_qpel_v32_10_avx2; + c->put_hevc_qpel[8][1][0] = hevc_put_qpel_v48_10_avx2; + c->put_hevc_qpel[9][1][0] = hevc_put_qpel_v64_10_avx2; - c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_hevc_bi_qpel_v16_10_avx2; - c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_hevc_bi_qpel_v24_10_avx2; - c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_10_avx2; - c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_10_avx2; - c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_10_avx2; + c->put_hevc_qpel_uni[5][1][0] = hevc_put_uni_qpel_v16_10_avx2; + c->put_hevc_qpel_uni[6][1][0] = hevc_put_uni_qpel_v24_10_avx2; + c->put_hevc_qpel_uni[7][1][0] = hevc_put_uni_qpel_v32_10_avx2; + c->put_hevc_qpel_uni[8][1][0] = hevc_put_uni_qpel_v48_10_avx2; + c->put_hevc_qpel_uni[9][1][0] = hevc_put_uni_qpel_v64_10_avx2; - c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_10_avx2; - c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_10_avx2; - c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_10_avx2; - c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_10_avx2; - c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_10_avx2; + c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_bi_qpel_v16_10_avx2; + c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_bi_qpel_v24_10_avx2; + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_bi_qpel_v32_10_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_bi_qpel_v48_10_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_bi_qpel_v64_10_avx2; - c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_uni_qpel_hv16_10_avx2; - c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_uni_qpel_hv24_10_avx2; - c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_uni_qpel_hv32_10_avx2; - c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_uni_qpel_hv48_10_avx2; - c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_uni_qpel_hv64_10_avx2; + c->put_hevc_qpel[5][1][1] = hevc_put_qpel_hv16_10_avx2; + c->put_hevc_qpel[6][1][1] = hevc_put_qpel_hv24_10_avx2; + c->put_hevc_qpel[7][1][1] = hevc_put_qpel_hv32_10_avx2; + c->put_hevc_qpel[8][1][1] = hevc_put_qpel_hv48_10_avx2; + c->put_hevc_qpel[9][1][1] = hevc_put_qpel_hv64_10_avx2; + + c->put_hevc_qpel_uni[5][1][1] = hevc_put_uni_qpel_hv16_10_avx2; + c->put_hevc_qpel_uni[6][1][1] = hevc_put_uni_qpel_hv24_10_avx2; + c->put_hevc_qpel_uni[7][1][1] = hevc_put_uni_qpel_hv32_10_avx2; + c->put_hevc_qpel_uni[8][1][1] = hevc_put_uni_qpel_hv48_10_avx2; + c->put_hevc_qpel_uni[9][1][1] = hevc_put_uni_qpel_hv64_10_avx2; + + c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_bi_qpel_hv16_10_avx2; + c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_bi_qpel_hv24_10_avx2; + c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_bi_qpel_hv32_10_avx2; + c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_bi_qpel_hv48_10_avx2; + c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_bi_qpel_hv64_10_avx2; +#endif /* ARCH_X86_64 */ - c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_hevc_bi_qpel_hv16_10_avx2; - c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_hevc_bi_qpel_hv24_10_avx2; - c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_hevc_bi_qpel_hv32_10_avx2; - c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_hevc_bi_qpel_hv48_10_avx2; - c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_hevc_bi_qpel_hv64_10_avx2; - } SAO_BAND_INIT(10, avx2); SAO_EDGE_INIT(10, avx2); c->add_residual[2] = ff_hevc_add_residual_16_10_avx2; c->add_residual[3] = ff_hevc_add_residual_32_10_avx2; } +#endif /* HAVE_AVX2_EXTERNAL */ } else if (bit_depth == 12) { if (EXTERNAL_MMXEXT(cpu_flags)) { c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_mmxext; @@ -1220,7 +1239,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_ssse3; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_ssse3; } - if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { +#if HAVE_SSE4_EXTERNAL && ARCH_X86_64 + if (EXTERNAL_SSE4(cpu_flags)) { EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 12, sse4); EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 12, sse4); EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 12, sse4); @@ -1231,6 +1251,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 12, sse4); QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 12, sse4); } +#endif if (EXTERNAL_AVX(cpu_flags)) { c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_avx; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_avx; diff --git a/libavcodec/x86/hevc_idct.asm b/libavcodec/x86/hevc/idct.asm similarity index 99% rename from libavcodec/x86/hevc_idct.asm rename to libavcodec/x86/hevc/idct.asm index ce41f33822..021e5dab14 100644 --- a/libavcodec/x86/hevc_idct.asm +++ b/libavcodec/x86/hevc/idct.asm @@ -25,7 +25,7 @@ SECTION_RODATA -pd_64: times 4 dd 64 +cextern pd_64 pd_2048: times 4 dd 2048 pd_512: times 4 dd 512 @@ -532,7 +532,7 @@ cglobal hevc_idct_8x8_%1, 1, 1, 8, coeffs ; %1, %2 - transform constants ; %3, %4 - regs with interleaved coeffs ; %5 - 1/0 SWAP or add -; %6, %7 - registers for intermidiate sums +; %6, %7 - registers for intermediate sums ; %8 - accumulator register %macro ADD_ROWS 8 pmaddwd %6, %3, %1 diff --git a/libavcodec/x86/hevc_mc.asm b/libavcodec/x86/hevc/mc.asm similarity index 95% rename from libavcodec/x86/hevc_mc.asm rename to libavcodec/x86/hevc/mc.asm index b3b589b271..550f7a0e23 100644 --- a/libavcodec/x86/hevc_mc.asm +++ b/libavcodec/x86/hevc/mc.asm @@ -716,7 +716,7 @@ SECTION .text ; ****************************** %macro HEVC_BI_PEL_PIXELS 2 -cglobal hevc_put_hevc_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstride, src2, height +cglobal hevc_put_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstride, src2, height pxor m2, m2 movdqa m5, [pw_bi_%2] .loop: @@ -748,7 +748,7 @@ cglobal hevc_put_hevc_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstrid %define XMM_REGS 8 %endif -cglobal hevc_put_hevc_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, mx, rfilter +cglobal hevc_put_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, mx, rfilter %assign %%stride ((%2 + 7)/8) movdqa m6, [pw_bi_%2] EPEL_FILTER %2, mx, m4, m5, rfilter @@ -771,7 +771,7 @@ cglobal hevc_put_hevc_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcst ; int height, int mx, int my, int width) ; ****************************** -cglobal hevc_put_hevc_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, r3src, my +cglobal hevc_put_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, r3src, my movifnidn myd, mym movdqa m6, [pw_bi_%2] sub srcq, srcstrideq @@ -800,7 +800,7 @@ cglobal hevc_put_hevc_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcst %macro HEVC_PUT_HEVC_EPEL_HV 2 -cglobal hevc_put_hevc_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src +cglobal hevc_put_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src %assign %%stride ((%2 + 7)/8) sub srcq, srcstrideq EPEL_HV_FILTER %2 @@ -882,7 +882,7 @@ cglobal hevc_put_hevc_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, %macro HEVC_PUT_HEVC_QPEL 2 -cglobal hevc_put_hevc_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, src2, height, mx, rfilter +cglobal hevc_put_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, src2, height, mx, rfilter movdqa m9, [pw_bi_%2] QPEL_FILTER %2, mx .loop: @@ -909,7 +909,7 @@ cglobal hevc_put_hevc_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, ; ****************************** -cglobal hevc_put_hevc_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter +cglobal hevc_put_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter movifnidn myd, mym movdqa m9, [pw_bi_%2] lea r3srcq, [srcstrideq*3] @@ -939,7 +939,7 @@ cglobal hevc_put_hevc_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, ; ****************************** %macro HEVC_PUT_HEVC_QPEL_HV 2 -cglobal hevc_put_hevc_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter +cglobal hevc_put_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter %if cpuflag(avx2) %assign %%shift 4 %else @@ -1025,11 +1025,11 @@ cglobal hevc_put_hevc_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride %macro WEIGHTING_FUNCS 2 %if WIN64 || ARCH_X86_32 -cglobal hevc_put_hevc_uni_w%1_%2, 4, 5, 7, dst, dststride, src, height, denom, wx, ox +cglobal hevc_put_uni_w%1_%2, 4, 5, 7, dst, dststride, src, height, denom, wx, ox mov r4d, denomm %define SHIFT r4d %else -cglobal hevc_put_hevc_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, wx, ox +cglobal hevc_put_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, wx, ox %define SHIFT denomd %endif lea SHIFT, [SHIFT+14-%2] ; shift = 14 - bitd + denom @@ -1090,7 +1090,7 @@ cglobal hevc_put_hevc_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, w jnz .loop ; height loop RET -cglobal hevc_put_hevc_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, denom, wx0, wx1, ox0, ox1 +cglobal hevc_put_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, denom, wx0, wx1, ox0, ox1 movifnidn r5d, denomm %if %1 <= 4 pxor m1, m1 @@ -1170,39 +1170,32 @@ cglobal hevc_put_hevc_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, de INIT_XMM sse4 ; adds ff_ and _sse4 to function name -WEIGHTING_FUNCS 2, 8 WEIGHTING_FUNCS 4, 8 WEIGHTING_FUNCS 6, 8 WEIGHTING_FUNCS 8, 8 -WEIGHTING_FUNCS 2, 10 WEIGHTING_FUNCS 4, 10 WEIGHTING_FUNCS 6, 10 WEIGHTING_FUNCS 8, 10 -WEIGHTING_FUNCS 2, 12 WEIGHTING_FUNCS 4, 12 WEIGHTING_FUNCS 6, 12 WEIGHTING_FUNCS 8, 12 -HEVC_BI_PEL_PIXELS 2, 8 HEVC_BI_PEL_PIXELS 4, 8 HEVC_BI_PEL_PIXELS 6, 8 HEVC_BI_PEL_PIXELS 8, 8 HEVC_BI_PEL_PIXELS 12, 8 HEVC_BI_PEL_PIXELS 16, 8 -HEVC_BI_PEL_PIXELS 2, 10 HEVC_BI_PEL_PIXELS 4, 10 HEVC_BI_PEL_PIXELS 6, 10 HEVC_BI_PEL_PIXELS 8, 10 -HEVC_BI_PEL_PIXELS 2, 12 HEVC_BI_PEL_PIXELS 4, 12 HEVC_BI_PEL_PIXELS 6, 12 HEVC_BI_PEL_PIXELS 8, 12 -HEVC_PUT_HEVC_EPEL 2, 8 HEVC_PUT_HEVC_EPEL 4, 8 HEVC_PUT_HEVC_EPEL 6, 8 HEVC_PUT_HEVC_EPEL 8, 8 @@ -1210,28 +1203,23 @@ HEVC_PUT_HEVC_EPEL 12, 8 HEVC_PUT_HEVC_EPEL 16, 8 -HEVC_PUT_HEVC_EPEL 2, 10 HEVC_PUT_HEVC_EPEL 4, 10 HEVC_PUT_HEVC_EPEL 6, 10 HEVC_PUT_HEVC_EPEL 8, 10 -HEVC_PUT_HEVC_EPEL 2, 12 HEVC_PUT_HEVC_EPEL 4, 12 HEVC_PUT_HEVC_EPEL 6, 12 HEVC_PUT_HEVC_EPEL 8, 12 -HEVC_PUT_HEVC_EPEL_HV 2, 8 HEVC_PUT_HEVC_EPEL_HV 4, 8 HEVC_PUT_HEVC_EPEL_HV 6, 8 HEVC_PUT_HEVC_EPEL_HV 8, 8 HEVC_PUT_HEVC_EPEL_HV 16, 8 -HEVC_PUT_HEVC_EPEL_HV 2, 10 HEVC_PUT_HEVC_EPEL_HV 4, 10 HEVC_PUT_HEVC_EPEL_HV 6, 10 HEVC_PUT_HEVC_EPEL_HV 8, 10 -HEVC_PUT_HEVC_EPEL_HV 2, 12 HEVC_PUT_HEVC_EPEL_HV 4, 12 HEVC_PUT_HEVC_EPEL_HV 6, 12 HEVC_PUT_HEVC_EPEL_HV 8, 12 @@ -1247,19 +1235,13 @@ HEVC_PUT_HEVC_QPEL 8, 10 HEVC_PUT_HEVC_QPEL 4, 12 HEVC_PUT_HEVC_QPEL 8, 12 -HEVC_PUT_HEVC_QPEL_HV 2, 8 HEVC_PUT_HEVC_QPEL_HV 4, 8 -HEVC_PUT_HEVC_QPEL_HV 6, 8 HEVC_PUT_HEVC_QPEL_HV 8, 8 -HEVC_PUT_HEVC_QPEL_HV 2, 10 HEVC_PUT_HEVC_QPEL_HV 4, 10 -HEVC_PUT_HEVC_QPEL_HV 6, 10 HEVC_PUT_HEVC_QPEL_HV 8, 10 -HEVC_PUT_HEVC_QPEL_HV 2, 12 HEVC_PUT_HEVC_QPEL_HV 4, 12 -HEVC_PUT_HEVC_QPEL_HV 6, 12 HEVC_PUT_HEVC_QPEL_HV 8, 12 %if HAVE_AVX2_EXTERNAL @@ -1329,7 +1311,7 @@ HEVC_PUT_HEVC_QPEL_HV 16, 10 %endmacro %macro HEVC_PUT_HEVC_QPEL_AVX512ICL 2 -cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp +cglobal hevc_put_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp QPEL_FILTER_H %1, mx, 0, 1, tmp QPEL_LOAD_SHUF 2, 3 .loop: @@ -1355,7 +1337,7 @@ cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 8, dst, src, srcstride, height, mx, tmp %endmacro %macro HEVC_PUT_HEVC_QPEL_HV_AVX512ICL 2 -cglobal hevc_put_hevc_qpel_hv%1_%2, 6, 7, 27, dst, src, srcstride, height, mx, my, tmp +cglobal hevc_put_qpel_hv%1_%2, 6, 7, 27, dst, src, srcstride, height, mx, my, tmp %assign %%shift 6 %assign %%extra 7 QPEL_FILTER_H %1, mx, 0, 1, tmp diff --git a/libavcodec/x86/hevc/sao.asm b/libavcodec/x86/hevc/sao.asm new file mode 100644 index 0000000000..c4f6db4cd5 --- /dev/null +++ b/libavcodec/x86/hevc/sao.asm @@ -0,0 +1,70 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for HEVC 8bit decoding +;* +;* Copyright (c) 2013 Pierre-Edouard LEPERE +;* Copyright (c) 2014 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%define MAX_PB_SIZE 64 +%include "libavcodec/x86/h26x/h2656_sao.asm" + +%macro HEVC_SAO_BAND_FILTER 2 + H2656_SAO_BAND_FILTER hevc, %1, %2 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 0 +HEVC_SAO_BAND_FILTER 8, 0 +HEVC_SAO_BAND_FILTER 16, 1 +HEVC_SAO_BAND_FILTER 32, 2 +HEVC_SAO_BAND_FILTER 48, 2 +HEVC_SAO_BAND_FILTER 64, 4 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +HEVC_SAO_BAND_FILTER_FUNCS + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +HEVC_SAO_BAND_FILTER 8, 0 +HEVC_SAO_BAND_FILTER 16, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER 32, 1 +HEVC_SAO_BAND_FILTER 48, 1 +HEVC_SAO_BAND_FILTER 64, 2 +%endif + +%macro HEVC_SAO_EDGE_FILTER 2-3 + H2656_SAO_EDGE_FILTER hevc, %{1:-1} +%endmacro + +INIT_XMM ssse3 +HEVC_SAO_EDGE_FILTER 8, 0 +HEVC_SAO_EDGE_FILTER 16, 1, a +HEVC_SAO_EDGE_FILTER 32, 2, a +HEVC_SAO_EDGE_FILTER 48, 2, a +HEVC_SAO_EDGE_FILTER 64, 4, a + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +HEVC_SAO_EDGE_FILTER 32, 1, a +HEVC_SAO_EDGE_FILTER 48, 1, u +HEVC_SAO_EDGE_FILTER 64, 2, a +%endif diff --git a/libavcodec/x86/hevc/sao_10bit.asm b/libavcodec/x86/hevc/sao_10bit.asm new file mode 100644 index 0000000000..0320efd758 --- /dev/null +++ b/libavcodec/x86/hevc/sao_10bit.asm @@ -0,0 +1,97 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for HEVC 10/12bit decoding +;* +;* Copyright (c) 2013 Pierre-Edouard LEPERE +;* Copyright (c) 2014 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%define MAX_PB_SIZE 64 +%include "libavcodec/x86/h26x/h2656_sao_10bit.asm" + +%macro HEVC_SAO_BAND_FILTER 3 + H2656_SAO_BAND_FILTER hevc, %1, %2, %3 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 1 + HEVC_SAO_BAND_FILTER %1, 8, 1 + HEVC_SAO_BAND_FILTER %1, 16, 2 + HEVC_SAO_BAND_FILTER %1, 32, 4 + HEVC_SAO_BAND_FILTER %1, 48, 6 + HEVC_SAO_BAND_FILTER %1, 64, 8 +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 0 + HEVC_SAO_BAND_FILTER_FUNCS 10 + HEVC_SAO_BAND_FILTER_FUNCS 12 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +HEVC_SAO_BAND_FILTER_FUNCS + +%if HAVE_AVX2_EXTERNAL + +%macro HEVC_SAO_BAND_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + HEVC_SAO_BAND_FILTER %1, 8, 1 + INIT_YMM avx2 + HEVC_SAO_BAND_FILTER %1, 16, 1 + HEVC_SAO_BAND_FILTER %1, 32, 2 + HEVC_SAO_BAND_FILTER %1, 48, 3 + HEVC_SAO_BAND_FILTER %1, 64, 4 +%endmacro + + HEVC_SAO_BAND_FILTER_FUNCS_AVX2 10 + HEVC_SAO_BAND_FILTER_FUNCS_AVX2 12 + +%endif + +%macro HEVC_SAO_EDGE_FILTER 3 + H2656_SAO_EDGE_FILTER hevc, %1, %2, %3 +%endmacro + +%macro HEVC_SAO_EDGE_FILTER_FUNCS 1 + HEVC_SAO_EDGE_FILTER %1, 8, 1 + HEVC_SAO_EDGE_FILTER %1, 16, 2 + HEVC_SAO_EDGE_FILTER %1, 32, 4 + HEVC_SAO_EDGE_FILTER %1, 48, 6 + HEVC_SAO_EDGE_FILTER %1, 64, 8 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_EDGE_FILTER_FUNCS 10 +HEVC_SAO_EDGE_FILTER_FUNCS 12 + +%if HAVE_AVX2_EXTERNAL + +%macro HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + HEVC_SAO_EDGE_FILTER %1, 8, 1 + INIT_YMM avx2 + HEVC_SAO_EDGE_FILTER %1, 16, 1 + HEVC_SAO_EDGE_FILTER %1, 32, 2 + HEVC_SAO_EDGE_FILTER %1, 48, 3 + HEVC_SAO_EDGE_FILTER %1, 64, 4 +%endmacro + +HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 10 +HEVC_SAO_EDGE_FILTER_FUNCS_AVX2 12 + +%endif diff --git a/libavcodec/x86/hevcdsp.h b/libavcodec/x86/hevcdsp.h deleted file mode 100644 index 037519fad4..0000000000 --- a/libavcodec/x86/hevcdsp.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * HEVC video decoder - * - * Copyright (C) 2012 - 2013 Guillaume Martres - * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere - * - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_X86_HEVCDSP_H -#define AVCODEC_X86_HEVCDSP_H - -#include -#include - - -#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \ -dst[idx1][idx2][idx3] = ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt; \ -dst ## _bi[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt; \ -dst ## _uni[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt; \ -dst ## _uni_w[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt; \ -dst ## _bi_w[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt - - -#define PEL_PROTOTYPE(name, D, opt) \ -void ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); \ -void ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width); \ -void ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, int denom, int wx0, int wx1, int ox0, int ox1, intptr_t mx, intptr_t my, int width) - - -/////////////////////////////////////////////////////////////////////////////// -// MC functions -/////////////////////////////////////////////////////////////////////////////// - -#define EPEL_PROTOTYPES(fname, bitd, opt) \ - PEL_PROTOTYPE(fname##4, bitd, opt); \ - PEL_PROTOTYPE(fname##6, bitd, opt); \ - PEL_PROTOTYPE(fname##8, bitd, opt); \ - PEL_PROTOTYPE(fname##12, bitd, opt); \ - PEL_PROTOTYPE(fname##16, bitd, opt); \ - PEL_PROTOTYPE(fname##24, bitd, opt); \ - PEL_PROTOTYPE(fname##32, bitd, opt); \ - PEL_PROTOTYPE(fname##48, bitd, opt); \ - PEL_PROTOTYPE(fname##64, bitd, opt) - -#define QPEL_PROTOTYPES(fname, bitd, opt) \ - PEL_PROTOTYPE(fname##4, bitd, opt); \ - PEL_PROTOTYPE(fname##8, bitd, opt); \ - PEL_PROTOTYPE(fname##12, bitd, opt); \ - PEL_PROTOTYPE(fname##16, bitd, opt); \ - PEL_PROTOTYPE(fname##24, bitd, opt); \ - PEL_PROTOTYPE(fname##32, bitd, opt); \ - PEL_PROTOTYPE(fname##48, bitd, opt); \ - PEL_PROTOTYPE(fname##64, bitd, opt) - -#define WEIGHTING_PROTOTYPE(width, bitd, opt) \ -void ff_hevc_put_hevc_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, int height, int denom, int _wx, int _ox); \ -void ff_hevc_put_hevc_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, const int16_t *_src, const int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1) - -#define WEIGHTING_PROTOTYPES(bitd, opt) \ - WEIGHTING_PROTOTYPE(2, bitd, opt); \ - WEIGHTING_PROTOTYPE(4, bitd, opt); \ - WEIGHTING_PROTOTYPE(6, bitd, opt); \ - WEIGHTING_PROTOTYPE(8, bitd, opt); \ - WEIGHTING_PROTOTYPE(12, bitd, opt); \ - WEIGHTING_PROTOTYPE(16, bitd, opt); \ - WEIGHTING_PROTOTYPE(24, bitd, opt); \ - WEIGHTING_PROTOTYPE(32, bitd, opt); \ - WEIGHTING_PROTOTYPE(48, bitd, opt); \ - WEIGHTING_PROTOTYPE(64, bitd, opt) - - -/////////////////////////////////////////////////////////////////////////////// -// QPEL_PIXELS EPEL_PIXELS -/////////////////////////////////////////////////////////////////////////////// -EPEL_PROTOTYPES(pel_pixels , 8, sse4); -EPEL_PROTOTYPES(pel_pixels , 10, sse4); -EPEL_PROTOTYPES(pel_pixels , 12, sse4); - -void ff_hevc_put_hevc_pel_pixels16_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels24_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels32_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels48_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels64_8_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); - -void ff_hevc_put_hevc_pel_pixels16_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels24_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels32_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels48_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_pel_pixels64_10_avx2(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); - - - -void ff_hevc_put_hevc_uni_pel_pixels32_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels48_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels64_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); -void ff_hevc_put_hevc_uni_pel_pixels96_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); //used for 10bit -void ff_hevc_put_hevc_uni_pel_pixels128_8_avx2(uint8_t *dst, ptrdiff_t dststride,const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);//used for 10bit - - -void ff_hevc_put_hevc_bi_pel_pixels16_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels24_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels32_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels48_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels64_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); - -void ff_hevc_put_hevc_bi_pel_pixels16_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels24_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels32_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels48_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_bi_pel_pixels64_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2, int height, intptr_t mx, intptr_t my, int width); - -/////////////////////////////////////////////////////////////////////////////// -// EPEL -/////////////////////////////////////////////////////////////////////////////// -EPEL_PROTOTYPES(epel_h , 8, sse4); -EPEL_PROTOTYPES(epel_h , 10, sse4); -EPEL_PROTOTYPES(epel_h , 12, sse4); - -EPEL_PROTOTYPES(epel_v , 8, sse4); -EPEL_PROTOTYPES(epel_v , 10, sse4); -EPEL_PROTOTYPES(epel_v , 12, sse4); - -EPEL_PROTOTYPES(epel_hv , 8, sse4); -EPEL_PROTOTYPES(epel_hv , 10, sse4); -EPEL_PROTOTYPES(epel_hv , 12, sse4); - -PEL_PROTOTYPE(epel_h16, 8, avx2); -PEL_PROTOTYPE(epel_h24, 8, avx2); -PEL_PROTOTYPE(epel_h32, 8, avx2); -PEL_PROTOTYPE(epel_h48, 8, avx2); -PEL_PROTOTYPE(epel_h64, 8, avx2); - -PEL_PROTOTYPE(epel_h16,10, avx2); -PEL_PROTOTYPE(epel_h24,10, avx2); -PEL_PROTOTYPE(epel_h32,10, avx2); -PEL_PROTOTYPE(epel_h48,10, avx2); -PEL_PROTOTYPE(epel_h64,10, avx2); - -PEL_PROTOTYPE(epel_v16, 8, avx2); -PEL_PROTOTYPE(epel_v24, 8, avx2); -PEL_PROTOTYPE(epel_v32, 8, avx2); -PEL_PROTOTYPE(epel_v48, 8, avx2); -PEL_PROTOTYPE(epel_v64, 8, avx2); - -PEL_PROTOTYPE(epel_v16,10, avx2); -PEL_PROTOTYPE(epel_v24,10, avx2); -PEL_PROTOTYPE(epel_v32,10, avx2); -PEL_PROTOTYPE(epel_v48,10, avx2); -PEL_PROTOTYPE(epel_v64,10, avx2); - -PEL_PROTOTYPE(epel_hv16, 8, avx2); -PEL_PROTOTYPE(epel_hv24, 8, avx2); -PEL_PROTOTYPE(epel_hv32, 8, avx2); -PEL_PROTOTYPE(epel_hv48, 8, avx2); -PEL_PROTOTYPE(epel_hv64, 8, avx2); - -PEL_PROTOTYPE(epel_hv16,10, avx2); -PEL_PROTOTYPE(epel_hv24,10, avx2); -PEL_PROTOTYPE(epel_hv32,10, avx2); -PEL_PROTOTYPE(epel_hv48,10, avx2); -PEL_PROTOTYPE(epel_hv64,10, avx2); - -/////////////////////////////////////////////////////////////////////////////// -// QPEL -/////////////////////////////////////////////////////////////////////////////// -QPEL_PROTOTYPES(qpel_h , 8, sse4); -QPEL_PROTOTYPES(qpel_h , 10, sse4); -QPEL_PROTOTYPES(qpel_h , 12, sse4); - -QPEL_PROTOTYPES(qpel_v, 8, sse4); -QPEL_PROTOTYPES(qpel_v, 10, sse4); -QPEL_PROTOTYPES(qpel_v, 12, sse4); - -QPEL_PROTOTYPES(qpel_hv, 8, sse4); -QPEL_PROTOTYPES(qpel_hv, 10, sse4); -QPEL_PROTOTYPES(qpel_hv, 12, sse4); - -PEL_PROTOTYPE(qpel_h16, 8, avx2); -PEL_PROTOTYPE(qpel_h24, 8, avx2); -PEL_PROTOTYPE(qpel_h32, 8, avx2); -PEL_PROTOTYPE(qpel_h48, 8, avx2); -PEL_PROTOTYPE(qpel_h64, 8, avx2); - -PEL_PROTOTYPE(qpel_h16,10, avx2); -PEL_PROTOTYPE(qpel_h24,10, avx2); -PEL_PROTOTYPE(qpel_h32,10, avx2); -PEL_PROTOTYPE(qpel_h48,10, avx2); -PEL_PROTOTYPE(qpel_h64,10, avx2); - -PEL_PROTOTYPE(qpel_v16, 8, avx2); -PEL_PROTOTYPE(qpel_v24, 8, avx2); -PEL_PROTOTYPE(qpel_v32, 8, avx2); -PEL_PROTOTYPE(qpel_v48, 8, avx2); -PEL_PROTOTYPE(qpel_v64, 8, avx2); - -PEL_PROTOTYPE(qpel_v16,10, avx2); -PEL_PROTOTYPE(qpel_v24,10, avx2); -PEL_PROTOTYPE(qpel_v32,10, avx2); -PEL_PROTOTYPE(qpel_v48,10, avx2); -PEL_PROTOTYPE(qpel_v64,10, avx2); - -PEL_PROTOTYPE(qpel_hv16, 8, avx2); -PEL_PROTOTYPE(qpel_hv24, 8, avx2); -PEL_PROTOTYPE(qpel_hv32, 8, avx2); -PEL_PROTOTYPE(qpel_hv48, 8, avx2); -PEL_PROTOTYPE(qpel_hv64, 8, avx2); - -PEL_PROTOTYPE(qpel_hv16,10, avx2); -PEL_PROTOTYPE(qpel_hv24,10, avx2); -PEL_PROTOTYPE(qpel_hv32,10, avx2); -PEL_PROTOTYPE(qpel_hv48,10, avx2); -PEL_PROTOTYPE(qpel_hv64,10, avx2); - -WEIGHTING_PROTOTYPES(8, sse4); -WEIGHTING_PROTOTYPES(10, sse4); -WEIGHTING_PROTOTYPES(12, sse4); - -void ff_hevc_put_hevc_qpel_h4_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h16_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h32_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_h64_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); -void ff_hevc_put_hevc_qpel_hv8_8_avx512icl(int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); - -/////////////////////////////////////////////////////////////////////////////// -// TRANSFORM_ADD -/////////////////////////////////////////////////////////////////////////////// - -void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_8_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_8_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_8_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_8_avx(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_32_8_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_4_10_mmxext(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_8_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_16_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_10_sse2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -void ff_hevc_add_residual_16_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); -void ff_hevc_add_residual_32_10_avx2(uint8_t *dst, const int16_t *res, ptrdiff_t stride); - -#endif // AVCODEC_X86_HEVCDSP_H diff --git a/libavcodec/x86/hpeldsp_init.c b/libavcodec/x86/hpeldsp_init.c index 4a0513d06d..6b2ad4494b 100644 --- a/libavcodec/x86/hpeldsp_init.c +++ b/libavcodec/x86/hpeldsp_init.c @@ -22,6 +22,9 @@ * MMX optimization by Nick Kurshev */ +#include +#include + #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/x86/cpu.h" @@ -74,19 +77,263 @@ void ff_avg_approx_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels, /* MMX no rounding */ #define DEF(x, y) x ## _no_rnd_ ## y ## _mmx #define SET_RND MOVQ_WONE -#define PAVGBP(a, b, c, d, e, f) PAVGBP_MMX_NO_RND(a, b, c, d, e, f) -#define PAVGB(a, b, c, e) PAVGB_MMX_NO_RND(a, b, c, e) #define STATIC static #include "rnd_template.c" -#include "hpeldsp_rnd_template.c" #undef DEF #undef SET_RND -#undef PAVGBP -#undef PAVGB #undef STATIC +// this routine is 'slightly' suboptimal but mostly unused +static void avg_no_rnd_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h) +{ + MOVQ_ZERO(mm7); + MOVQ_WONE(mm6); // =2 for rnd and =1 for no_rnd version + __asm__ volatile( + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm4 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + "add %3, %1 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddusw %%mm2, %%mm0 \n\t" + "paddusw %%mm3, %%mm1 \n\t" + "paddusw %%mm6, %%mm4 \n\t" + "paddusw %%mm6, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "psrlw $2, %%mm4 \n\t" + "psrlw $2, %%mm5 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "packuswb %%mm5, %%mm4 \n\t" + "pcmpeqd %%mm2, %%mm2 \n\t" + "paddb %%mm2, %%mm2 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm5, %%mm2) + "movq %%mm5, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 + "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq %%mm2, %%mm3 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm2, %%mm4 \n\t" + "paddusw %%mm3, %%mm5 \n\t" + "paddusw %%mm6, %%mm0 \n\t" + "paddusw %%mm6, %%mm1 \n\t" + "paddusw %%mm4, %%mm0 \n\t" + "paddusw %%mm5, %%mm1 \n\t" + "psrlw $2, %%mm0 \n\t" + "psrlw $2, %%mm1 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "pcmpeqd %%mm2, %%mm2 \n\t" + "paddb %%mm2, %%mm2 \n\t" + PAVGB_MMX(%%mm3, %%mm0, %%mm1, %%mm2) + "movq %%mm1, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "subl $2, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels) + :"D"(block), "r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +static void put_no_rnd_pixels8_x2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +static void put_no_rnd_pixels16_x2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%1, %3), %%mm2 \n\t" + "movq 9(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, 8(%2) \n\t" + "movq %%mm5, 8(%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%1, %3), %%mm2 \n\t" + "movq 9(%1, %3), %%mm3 \n\t" + PAVGBP_MMX_NO_RND(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, 8(%2) \n\t" + "movq %%mm5, 8(%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +static void put_no_rnd_pixels8_y2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + "movq (%1), %%mm0 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"),%%mm2\n\t" + PAVGBP_MMX_NO_RND(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"),%%mm0\n\t" + PAVGBP_MMX_NO_RND(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +static void avg_no_rnd_pixels16_x2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%2), %%mm3 \n\t" + PAVGB_MMX_NO_RND(%%mm0, %%mm1, %%mm2, %%mm6) + PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) + "movq %%mm0, (%2) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%2), %%mm3 \n\t" + PAVGB_MMX_NO_RND(%%mm0, %%mm1, %%mm2, %%mm6) + PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) + "movq %%mm0, 8(%2) \n\t" + "add %3, %1 \n\t" + "add %3, %2 \n\t" + "subl $1, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :"memory"); +} + +static void avg_no_rnd_pixels8_y2_mmx(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + "movq (%1), %%mm0 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" + PAVGBP_MMX_NO_RND(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) + "movq (%2), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm0, %%mm6) + "movq (%2, %3), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) + "movq %%mm0, (%2) \n\t" + "movq %%mm1, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + PAVGBP_MMX_NO_RND(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) + "movq (%2), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm2, %%mm6) + "movq (%2, %3), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) + "movq %%mm2, (%2) \n\t" + "movq %%mm1, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + #if HAVE_MMX CALL_2X_PIXELS(avg_no_rnd_pixels16_y2_mmx, avg_no_rnd_pixels8_y2_mmx, 8) CALL_2X_PIXELS(put_no_rnd_pixels16_y2_mmx, put_no_rnd_pixels8_y2_mmx, 8) @@ -101,7 +348,6 @@ CALL_2X_PIXELS(put_no_rnd_pixels16_xy2_mmx, put_no_rnd_pixels8_xy2_mmx, 8) #define SET_RND MOVQ_WTWO #define DEF(x, y) ff_ ## x ## _ ## y ## _mmx #define STATIC -#define NO_AVG #include "rnd_template.c" @@ -122,7 +368,6 @@ CALL_2X_PIXELS(put_pixels16_xy2_mmx, ff_put_pixels8_xy2_mmx, 8) CALL_2X_PIXELS(put_no_rnd_pixels16_x2 ## CPUEXT, ff_put_no_rnd_pixels8_x2 ## CPUEXT, 8) \ CALL_2X_PIXELS(put_pixels16_y2 ## CPUEXT, ff_put_pixels8_y2 ## CPUEXT, 8) \ CALL_2X_PIXELS(put_no_rnd_pixels16_y2 ## CPUEXT, ff_put_no_rnd_pixels8_y2 ## CPUEXT, 8) \ - CALL_2X_PIXELS(avg_pixels16 ## CPUEXT, ff_avg_pixels8 ## CPUEXT, 8) \ CALL_2X_PIXELS(avg_pixels16_x2 ## CPUEXT, ff_avg_pixels8_x2 ## CPUEXT, 8) \ CALL_2X_PIXELS(avg_pixels16_y2 ## CPUEXT, ff_avg_pixels8_y2 ## CPUEXT, 8) \ CALL_2X_PIXELS(avg_pixels16_xy2 ## CPUEXT, ff_avg_pixels8_xy2 ## CPUEXT, 8) \ @@ -170,7 +415,7 @@ static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags) c->put_pixels_tab[0][1] = ff_put_pixels16_x2_mmxext; c->put_pixels_tab[0][2] = put_pixels16_y2_mmxext; - c->avg_pixels_tab[0][0] = avg_pixels16_mmxext; + c->avg_pixels_tab[0][0] = ff_avg_pixels16_mmxext; c->avg_pixels_tab[0][1] = avg_pixels16_x2_mmxext; c->avg_pixels_tab[0][2] = avg_pixels16_y2_mmxext; c->avg_pixels_tab[0][3] = avg_pixels16_xy2_mmxext; diff --git a/libavcodec/x86/hpeldsp_rnd_template.c b/libavcodec/x86/hpeldsp_rnd_template.c deleted file mode 100644 index 2bff2d2766..0000000000 --- a/libavcodec/x86/hpeldsp_rnd_template.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SIMD-optimized halfpel functions are compiled twice for rnd/no_rnd - * Copyright (c) 2000, 2001 Fabrice Bellard - * Copyright (c) 2003-2004 Michael Niedermayer - * - * MMX optimization by Nick Kurshev - * mostly rewritten by Michael Niedermayer - * and improved by Zdenek Kabelac - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -// put_pixels -av_unused static void DEF(put, pixels8_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(put, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%1, %3), %%mm2 \n\t" - "movq 9(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, 8(%2) \n\t" - "movq %%mm5, 8(%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%1, %3), %%mm2 \n\t" - "movq 1(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%1, %3), %%mm2 \n\t" - "movq 9(%1, %3), %%mm3 \n\t" - PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) - "movq %%mm4, 8(%2) \n\t" - "movq %%mm5, 8(%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(put, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - "movq (%1), %%mm0 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"),%%mm2\n\t" - PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"),%%mm0\n\t" - PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) - "movq %%mm4, (%2) \n\t" - "movq %%mm5, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} - -av_unused static void DEF(avg, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm1 \n\t" - "movq (%2), %%mm3 \n\t" - PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) - PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) - "movq %%mm0, (%2) \n\t" - "movq 8(%1), %%mm0 \n\t" - "movq 9(%1), %%mm1 \n\t" - "movq 8(%2), %%mm3 \n\t" - PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) - PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) - "movq %%mm0, 8(%2) \n\t" - "add %3, %1 \n\t" - "add %3, %2 \n\t" - "subl $1, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :"memory"); -} - -av_unused static void DEF(avg, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) -{ - MOVQ_BFE(mm6); - __asm__ volatile( - "lea (%3, %3), %%"FF_REG_a" \n\t" - "movq (%1), %%mm0 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" - PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) - "movq (%2), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm0, %%mm6) - "movq (%2, %3), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) - "movq %%mm0, (%2) \n\t" - "movq %%mm1, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - - "movq (%1, %3), %%mm1 \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) - "movq (%2), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm2, %%mm6) - "movq (%2, %3), %%mm3 \n\t" - PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) - "movq %%mm2, (%2) \n\t" - "movq %%mm1, (%2, %3) \n\t" - "add %%"FF_REG_a", %1 \n\t" - "add %%"FF_REG_a", %2 \n\t" - - "subl $4, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels), "+D"(block) - :"r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} diff --git a/libavcodec/x86/lpc.asm b/libavcodec/x86/lpc.asm index a585c17ef5..a4f1ee91ec 100644 --- a/libavcodec/x86/lpc.asm +++ b/libavcodec/x86/lpc.asm @@ -257,7 +257,5 @@ cglobal lpc_apply_welch_window, 3, 5, 8, data, len, out, off1, off2 INIT_XMM sse2 APPLY_WELCH_FN -%if HAVE_AVX2_EXTERNAL INIT_YMM avx2 APPLY_WELCH_FN -%endif diff --git a/libavcodec/x86/me_cmp.asm b/libavcodec/x86/me_cmp.asm index 923eb8078b..a494cdeb64 100644 --- a/libavcodec/x86/me_cmp.asm +++ b/libavcodec/x86/me_cmp.asm @@ -214,7 +214,7 @@ hadamard8x8_diff %+ SUFFIX: hadamard8_16_wrapper %1, 3 %elif cpuflag(mmx) ALIGN 16 -; int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, const uint8_t *src1, +; int ff_hadamard8_diff_ ## cpu(MPVEncContext *s, const uint8_t *src1, ; const uint8_t *src2, ptrdiff_t stride, int h) ; r0 = void *s = unused, int h = unused (always 8) ; note how r1, r2 and r3 are not clobbered in this function, so 16x16 @@ -278,7 +278,7 @@ INIT_XMM ssse3 %define ABS_SUM_8x8 ABS_SUM_8x8_64 HADAMARD8_DIFF 9 -; int ff_sse*_*(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +; int ff_sse*_*(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ; ptrdiff_t line_size, int h) %macro SUM_SQUARED_ERRORS 1 @@ -466,7 +466,7 @@ HF_NOISE 8 HF_NOISE 16 ;--------------------------------------------------------------------------------------- -;int ff_sad_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;--------------------------------------------------------------------------------------- ;%1 = 8/16 %macro SAD 1 @@ -521,7 +521,7 @@ INIT_XMM sse2 SAD 16 ;------------------------------------------------------------------------------------------ -;int ff_sad_x2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_x2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------ ;%1 = 8/16 %macro SAD_X2 1 @@ -598,7 +598,7 @@ INIT_XMM sse2 SAD_X2 16 ;------------------------------------------------------------------------------------------ -;int ff_sad_y2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_y2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------ ;%1 = 8/16 %macro SAD_Y2 1 @@ -668,7 +668,7 @@ INIT_XMM sse2 SAD_Y2 16 ;------------------------------------------------------------------------------------------- -;int ff_sad_approx_xy2_(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); +;int ff_sad_approx_xy2_(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); ;------------------------------------------------------------------------------------------- ;%1 = 8/16 %macro SAD_APPROX_XY2 1 @@ -769,7 +769,7 @@ INIT_XMM sse2 SAD_APPROX_XY2 16 ;-------------------------------------------------------------------- -;int ff_vsad_intra(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +;int ff_vsad_intra(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ; ptrdiff_t line_size, int h); ;-------------------------------------------------------------------- ; %1 = 8/16 @@ -830,7 +830,7 @@ INIT_XMM sse2 VSAD_INTRA 16 ;--------------------------------------------------------------------- -;int ff_vsad_approx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +;int ff_vsad_approx(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ; ptrdiff_t line_size, int h); ;--------------------------------------------------------------------- ; %1 = 8/16 diff --git a/libavcodec/x86/me_cmp_init.c b/libavcodec/x86/me_cmp_init.c index 98b71b1894..45425f7109 100644 --- a/libavcodec/x86/me_cmp_init.c +++ b/libavcodec/x86/me_cmp_init.c @@ -28,59 +28,59 @@ #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/me_cmp.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" int ff_sum_abs_dctelem_sse2(const int16_t *block); int ff_sum_abs_dctelem_ssse3(const int16_t *block); -int ff_sse8_mmx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse8_mmx(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_mmx(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse16_mmx(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sse16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sse16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); int ff_hf_noise8_mmx(const uint8_t *pix1, ptrdiff_t stride, int h); int ff_hf_noise16_mmx(const uint8_t *pix1, ptrdiff_t stride, int h); -int ff_sad8_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_x2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_x2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_x2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_x2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_x2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_x2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_y2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_y2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_y2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_y2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_y2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_y2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad8_approx_xy2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad8_approx_xy2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_approx_xy2_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_approx_xy2_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_sad16_approx_xy2_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_sad16_approx_xy2_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad_intra8_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad_intra8_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad_intra16_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad_intra16_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad_intra16_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad_intra16_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad8_approx_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad8_approx_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad16_approx_mmxext(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad16_approx_mmxext(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -int ff_vsad16_approx_sse2(MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, +int ff_vsad16_approx_sse2(MPVEncContext *v, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h); -#define hadamard_func(cpu) \ - int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, const uint8_t *src1, \ +#define hadamard_func(cpu) \ + int ff_hadamard8_diff_ ## cpu(MPVEncContext *s, const uint8_t *src1, \ const uint8_t *src2, ptrdiff_t stride, int h); \ - int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, const uint8_t *src1, \ + int ff_hadamard8_diff16_ ## cpu(MPVEncContext *s, const uint8_t *src1, \ const uint8_t *src2, ptrdiff_t stride, int h); hadamard_func(mmxext) @@ -88,7 +88,7 @@ hadamard_func(sse2) hadamard_func(ssse3) #if HAVE_X86ASM -static int nsse16_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix2, +static int nsse16_mmx(MPVEncContext *c, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int score1, score2; @@ -101,12 +101,12 @@ static int nsse16_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix - ff_hf_noise16_mmx(pix2, stride, h) - ff_hf_noise8_mmx(pix2+8, stride, h); if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } -static int nsse8_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix2, +static int nsse8_mmx(MPVEncContext *c, const uint8_t *pix1, const uint8_t *pix2, ptrdiff_t stride, int h) { int score1 = ff_sse8_mmx(c, pix1, pix2, stride, h); @@ -114,7 +114,7 @@ static int nsse8_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix2 ff_hf_noise8_mmx(pix2, stride, h); if (c) - return score1 + FFABS(score2) * c->avctx->nsse_weight; + return score1 + FFABS(score2) * c->c.avctx->nsse_weight; else return score1 + FFABS(score2) * 8; } @@ -199,7 +199,7 @@ static inline int sum_mmx(void) } #define PIX_SADXY(suf) \ -static int sad8_xy2_ ## suf(MpegEncContext *v, const uint8_t *blk2, \ +static int sad8_xy2_ ## suf(MPVEncContext *v, const uint8_t *blk2, \ const uint8_t *blk1, ptrdiff_t stride, int h) \ { \ __asm__ volatile ( \ @@ -212,7 +212,7 @@ static int sad8_xy2_ ## suf(MpegEncContext *v, const uint8_t *blk2, \ return sum_ ## suf(); \ } \ \ -static int sad16_xy2_ ## suf(MpegEncContext *v, const uint8_t *blk2, \ +static int sad16_xy2_ ## suf(MPVEncContext *v, const uint8_t *blk2, \ const uint8_t *blk1, ptrdiff_t stride, int h) \ { \ __asm__ volatile ( \ diff --git a/libavcodec/x86/mpegvideo.c b/libavcodec/x86/mpegvideo.c index 9878607a81..8632acd412 100644 --- a/libavcodec/x86/mpegvideo.c +++ b/libavcodec/x86/mpegvideo.c @@ -20,12 +20,13 @@ */ #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/avcodec.h" #include "libavcodec/mpegvideo.h" #include "libavcodec/mpegvideodata.h" +#include "libavcodec/mpegvideo_unquantize.h" #if HAVE_MMX_INLINE @@ -449,7 +450,7 @@ __asm__ volatile( #endif /* HAVE_MMX_INLINE */ -av_cold void ff_mpv_common_init_x86(MpegEncContext *s) +av_cold void ff_mpv_unquantize_init_x86(MPVUnquantDSPContext *s, int bitexact) { #if HAVE_MMX_INLINE int cpu_flags = av_get_cpu_flags(); @@ -459,7 +460,7 @@ av_cold void ff_mpv_common_init_x86(MpegEncContext *s) s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_mmx; s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_mmx; s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_mmx; - if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) + if (!bitexact) s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_mmx; s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_mmx; } diff --git a/libavcodec/x86/mpegvideoenc.c b/libavcodec/x86/mpegvideoenc.c index 612e7ff758..eac9947590 100644 --- a/libavcodec/x86/mpegvideoenc.c +++ b/libavcodec/x86/mpegvideoenc.c @@ -25,7 +25,6 @@ #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" #include "libavcodec/avcodec.h" -#include "libavcodec/dct.h" #include "libavcodec/mpegvideoenc.h" /* not permutated inverse zigzag_direct + 1 for MMX quantizer */ @@ -43,26 +42,16 @@ DECLARE_ALIGNED(16, static const uint16_t, inv_zigzag_direct16)[64] = { #if HAVE_6REGS #if HAVE_SSE2_INLINE -#undef COMPILE_TEMPLATE_SSE2 -#undef COMPILE_TEMPLATE_SSSE3 -#define COMPILE_TEMPLATE_SSE2 1 #define COMPILE_TEMPLATE_SSSE3 0 -#undef RENAME -#undef RENAME_FDCT #define RENAME(a) a ## _sse2 -#define RENAME_FDCT(a) a ## _sse2 #include "mpegvideoenc_template.c" #endif /* HAVE_SSE2_INLINE */ #if HAVE_SSSE3_INLINE -#undef COMPILE_TEMPLATE_SSE2 #undef COMPILE_TEMPLATE_SSSE3 -#define COMPILE_TEMPLATE_SSE2 1 #define COMPILE_TEMPLATE_SSSE3 1 #undef RENAME -#undef RENAME_FDCT #define RENAME(a) a ## _ssse3 -#define RENAME_FDCT(a) a ## _sse2 #include "mpegvideoenc_template.c" #endif /* HAVE_SSSE3_INLINE */ @@ -70,8 +59,9 @@ DECLARE_ALIGNED(16, static const uint16_t, inv_zigzag_direct16)[64] = { #if HAVE_INLINE_ASM #if HAVE_SSE2_INLINE -static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){ - const int intra= s->mb_intra; +static void denoise_dct_sse2(MPVEncContext *const s, int16_t block[]) +{ + const int intra = s->c.mb_intra; int *sum= s->dct_error_sum[intra]; uint16_t *offset= s->dct_offset[intra]; @@ -128,9 +118,9 @@ static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){ #endif /* HAVE_SSE2_INLINE */ #endif /* HAVE_INLINE_ASM */ -av_cold void ff_dct_encode_init_x86(MpegEncContext *s) +av_cold void ff_dct_encode_init_x86(MPVEncContext *const s) { - const int dct_algo = s->avctx->dct_algo; + const int dct_algo = s->c.avctx->dct_algo; if (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX) { #if HAVE_MMX_INLINE diff --git a/libavcodec/x86/mpegvideoenc_template.c b/libavcodec/x86/mpegvideoenc_template.c index 4096d6391f..f0b95c1621 100644 --- a/libavcodec/x86/mpegvideoenc_template.c +++ b/libavcodec/x86/mpegvideoenc_template.c @@ -25,53 +25,27 @@ #include "libavutil/internal.h" #include "libavutil/mem_internal.h" #include "libavutil/x86/asm.h" +#include "libavcodec/mathops.h" #include "libavcodec/mpegutils.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideoenc.h" #include "fdct.h" -#undef MMREG_WIDTH -#undef MM -#undef MOVQ #undef SPREADW #undef PMAXW #undef PMAX #undef SAVE_SIGN #undef RESTORE_SIGN -#if COMPILE_TEMPLATE_SSE2 -#define MMREG_WIDTH "16" -#define MM "%%xmm" -#define MOVQ "movdqa" #define SPREADW(a) \ "pshuflw $0, "a", "a" \n\t"\ "punpcklwd "a", "a" \n\t" -#define PMAXW(a,b) "pmaxsw "a", "b" \n\t" #define PMAX(a,b) \ "movhlps "a", "b" \n\t"\ - PMAXW(b, a)\ + "pmaxsw "b", "a" \n\t"\ "pshuflw $0x0E, "a", "b" \n\t"\ - PMAXW(b, a)\ + "pmaxsw "b", "a" \n\t"\ "pshuflw $0x01, "a", "b" \n\t"\ - PMAXW(b, a) -#else -#define MMREG_WIDTH "8" -#define MM "%%mm" -#define MOVQ "movq" -#define SPREADW(a) \ - "punpcklwd "a", "a" \n\t"\ - "punpcklwd "a", "a" \n\t" -#define PMAXW(a,b) \ - "psubusw "a", "b" \n\t"\ - "paddw "a", "b" \n\t" -#define PMAX(a,b) \ - "movq "a", "b" \n\t"\ - "psrlq $32, "a" \n\t"\ - PMAXW(b, a)\ - "movq "a", "b" \n\t"\ - "psrlq $16, "a" \n\t"\ - PMAXW(b, a) - -#endif + "pmaxsw "b", "a" \n\t" #if COMPILE_TEMPLATE_SSSE3 #define SAVE_SIGN(a,b) \ @@ -90,7 +64,7 @@ "psubw "a", "b" \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) #endif -static int RENAME(dct_quantize)(MpegEncContext *s, +static int RENAME(dct_quantize)(MPVEncContext *const s, int16_t *block, int n, int qscale, int *overflow) { @@ -100,24 +74,24 @@ static int RENAME(dct_quantize)(MpegEncContext *s, LOCAL_ALIGNED_16(int16_t, temp_block, [64]); //s->fdct (block); - RENAME_FDCT(ff_fdct)(block); // cannot be anything else ... + ff_fdct_sse2(block); // cannot be anything else ... if(s->dct_error_sum) s->denoise_dct(s, block); - if (s->mb_intra) { + if (s->c.mb_intra) { int dummy; if (n < 4){ - q = s->y_dc_scale; + q = s->c.y_dc_scale; bias = s->q_intra_matrix16[qscale][1]; qmat = s->q_intra_matrix16[qscale][0]; }else{ - q = s->c_dc_scale; + q = s->c.c_dc_scale; bias = s->q_chroma_intra_matrix16[qscale][1]; qmat = s->q_chroma_intra_matrix16[qscale][0]; } /* note: block[0] is assumed to be positive */ - if (!s->h263_aic) { + if (!s->c.h263_aic) { __asm__ volatile ( "mul %%ecx \n\t" : "=d" (level), "=a"(dummy) @@ -136,35 +110,34 @@ static int RENAME(dct_quantize)(MpegEncContext *s, qmat = s->q_inter_matrix16[qscale][0]; } - if((s->out_format == FMT_H263 || s->out_format == FMT_H261) && s->mpeg_quant==0){ - + if ((s->c.out_format == FMT_H263 || s->c.out_format == FMT_H261) && !s->mpeg_quant) { __asm__ volatile( - "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 - SPREADW(MM"3") - "pxor "MM"7, "MM"7 \n\t" // 0 - "pxor "MM"4, "MM"4 \n\t" // 0 - MOVQ" (%2), "MM"5 \n\t" // qmat[0] - "pxor "MM"6, "MM"6 \n\t" - "psubw (%3), "MM"6 \n\t" // -bias[0] + "movd %%"FF_REG_a", %%xmm3 \n\t" // last_non_zero_p1 + SPREADW("%%xmm3") + "pxor %%xmm7, %%xmm7 \n\t" // 0 + "pxor %%xmm4, %%xmm4 \n\t" // 0 + "movdqa (%2), %%xmm5 \n\t" // qmat[0] + "pxor %%xmm6, %%xmm6 \n\t" + "psubw (%3), %%xmm6 \n\t" // -bias[0] "mov $-128, %%"FF_REG_a" \n\t" ".p2align 4 \n\t" "1: \n\t" - MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] - SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) - "psubusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] - "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16 - "por "MM"0, "MM"4 \n\t" - RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) - MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" - "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 - MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" - MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 - "pandn "MM"1, "MM"0 \n\t" - PMAXW(MM"0", MM"3") - "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" // block[i] + SAVE_SIGN("%%xmm1", "%%xmm0") // ABS(block[i]) + "psubusw %%xmm6, %%xmm0 \n\t" // ABS(block[i]) + bias[0] + "pmulhw %%xmm5, %%xmm0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16 + "por %%xmm0, %%xmm4 \n\t" + RESTORE_SIGN("%%xmm1", "%%xmm0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + "movdqa %%xmm0, (%5, %%"FF_REG_a") \n\t" + "pcmpeqw %%xmm7, %%xmm0 \n\t" // out==0 ? 0xFF : 0x00 + "movdqa (%4, %%"FF_REG_a"), %%xmm1 \n\t" + "movdqa %%xmm7, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn %%xmm1, %%xmm0 \n\t" + "pmaxsw %%xmm0, %%xmm3 \n\t" + "add $16, %%"FF_REG_a" \n\t" " js 1b \n\t" - PMAX(MM"3", MM"0") - "movd "MM"3, %%"FF_REG_a" \n\t" + PMAX("%%xmm3", "%%xmm0") + "movd %%xmm3, %%"FF_REG_a" \n\t" "movzbl %%al, %%eax \n\t" // last_non_zero_p1 : "+a" (last_non_zero_p1) : "r" (block+64), "r" (qmat), "r" (bias), @@ -174,31 +147,31 @@ static int RENAME(dct_quantize)(MpegEncContext *s, ); }else{ // FMT_H263 __asm__ volatile( - "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 - SPREADW(MM"3") - "pxor "MM"7, "MM"7 \n\t" // 0 - "pxor "MM"4, "MM"4 \n\t" // 0 + "movd %%"FF_REG_a", %%xmm3 \n\t" // last_non_zero_p1 + SPREADW("%%xmm3") + "pxor %%xmm7, %%xmm7 \n\t" // 0 + "pxor %%xmm4, %%xmm4 \n\t" // 0 "mov $-128, %%"FF_REG_a" \n\t" ".p2align 4 \n\t" "1: \n\t" - MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] - SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) - MOVQ" (%3, %%"FF_REG_a"), "MM"6 \n\t" // bias[0] - "paddusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] - MOVQ" (%2, %%"FF_REG_a"), "MM"5 \n\t" // qmat[i] - "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16 - "por "MM"0, "MM"4 \n\t" - RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) - MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" - "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 - MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" - MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 - "pandn "MM"1, "MM"0 \n\t" - PMAXW(MM"0", MM"3") - "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" // block[i] + SAVE_SIGN("%%xmm1", "%%xmm0") // ABS(block[i]) + "movdqa (%3, %%"FF_REG_a"), %%xmm6 \n\t" // bias[0] + "paddusw %%xmm6, %%xmm0 \n\t" // ABS(block[i]) + bias[0] + "movdqa (%2, %%"FF_REG_a"), %%xmm5 \n\t" // qmat[i] + "pmulhw %%xmm5, %%xmm0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16 + "por %%xmm0, %%xmm4 \n\t" + RESTORE_SIGN("%%xmm1", "%%xmm0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + "movdqa %%xmm0, (%5, %%"FF_REG_a") \n\t" + "pcmpeqw %%xmm7, %%xmm0 \n\t" // out==0 ? 0xFF : 0x00 + "movdqa (%4, %%"FF_REG_a"), %%xmm1 \n\t" + "movdqa %%xmm7, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn %%xmm1, %%xmm0 \n\t" + "pmaxsw %%xmm0, %%xmm3 \n\t" + "add $16, %%"FF_REG_a" \n\t" " js 1b \n\t" - PMAX(MM"3", MM"0") - "movd "MM"3, %%"FF_REG_a" \n\t" + PMAX("%%xmm3", "%%xmm0") + "movd %%xmm3, %%"FF_REG_a" \n\t" "movzbl %%al, %%eax \n\t" // last_non_zero_p1 : "+a" (last_non_zero_p1) : "r" (block+64), "r" (qmat+64), "r" (bias+64), @@ -208,23 +181,20 @@ static int RENAME(dct_quantize)(MpegEncContext *s, ); } __asm__ volatile( - "movd %1, "MM"1 \n\t" // max_qcoeff - SPREADW(MM"1") - "psubusw "MM"1, "MM"4 \n\t" - "packuswb "MM"4, "MM"4 \n\t" -#if COMPILE_TEMPLATE_SSE2 - "packsswb "MM"4, "MM"4 \n\t" -#endif - "movd "MM"4, %0 \n\t" // *overflow + "movd %1, %%xmm1 \n\t" // max_qcoeff + SPREADW("%%xmm1") + "psubusw %%xmm1, %%xmm4 \n\t" + "packuswb %%xmm4, %%xmm4 \n\t" + "packsswb %%xmm4, %%xmm4 \n\t" + "movd %%xmm4, %0 \n\t" // *overflow : "=g" (*overflow) : "g" (s->max_qcoeff) ); - if(s->mb_intra) block[0]= level; - else block[0]= temp_block[0]; + block[0] = s->c.mb_intra ? level : temp_block[0]; - av_assert2(ARCH_X86_32 || s->idsp.perm_type != FF_IDCT_PERM_SIMPLE); - if (ARCH_X86_32 && s->idsp.perm_type == FF_IDCT_PERM_SIMPLE) { + av_assert2(ARCH_X86_32 || s->c.idsp.perm_type != FF_IDCT_PERM_SIMPLE); + if (ARCH_X86_32 && s->c.idsp.perm_type == FF_IDCT_PERM_SIMPLE) { if(last_non_zero_p1 <= 1) goto end; block[0x08] = temp_block[0x01]; block[0x10] = temp_block[0x08]; block[0x20] = temp_block[0x10]; @@ -268,7 +238,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3E] = temp_block[0x3D]; block[0x27] = temp_block[0x36]; block[0x3D] = temp_block[0x2F]; block[0x2F] = temp_block[0x37]; block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - }else if(s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2){ + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_LIBMPEG2) { if(last_non_zero_p1 <= 1) goto end; block[0x04] = temp_block[0x01]; block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; @@ -312,7 +282,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3E] = temp_block[0x3D]; block[0x33] = temp_block[0x36]; block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; block[0x3B] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - } else if (s->idsp.perm_type == FF_IDCT_PERM_NONE) { + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_NONE) { if(last_non_zero_p1 <= 1) goto end; block[0x01] = temp_block[0x01]; block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; @@ -356,7 +326,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3D] = temp_block[0x3D]; block[0x36] = temp_block[0x36]; block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; block[0x3E] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; - } else if (s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE) { + } else if (s->c.idsp.perm_type == FF_IDCT_PERM_TRANSPOSE) { if(last_non_zero_p1 <= 1) goto end; block[0x08] = temp_block[0x01]; block[0x01] = temp_block[0x08]; block[0x02] = temp_block[0x10]; @@ -401,12 +371,12 @@ static int RENAME(dct_quantize)(MpegEncContext *s, block[0x3D] = temp_block[0x2F]; block[0x3E] = temp_block[0x37]; block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; } else { - av_log(s, AV_LOG_DEBUG, "s->idsp.perm_type: %d\n", - (int)s->idsp.perm_type); - av_assert0(s->idsp.perm_type == FF_IDCT_PERM_NONE || - s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2 || - s->idsp.perm_type == FF_IDCT_PERM_SIMPLE || - s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE); + av_log(s->c.avctx, AV_LOG_DEBUG, "s->c.idsp.perm_type: %d\n", + (int)s->c.idsp.perm_type); + av_assert0(s->c.idsp.perm_type == FF_IDCT_PERM_NONE || + s->c.idsp.perm_type == FF_IDCT_PERM_LIBMPEG2 || + s->c.idsp.perm_type == FF_IDCT_PERM_SIMPLE || + s->c.idsp.perm_type == FF_IDCT_PERM_TRANSPOSE); } end: return last_non_zero_p1 - 1; diff --git a/libavcodec/x86/mpegvideoencdsp.asm b/libavcodec/x86/mpegvideoencdsp.asm index c73b359c42..d12646ae54 100644 --- a/libavcodec/x86/mpegvideoencdsp.asm +++ b/libavcodec/x86/mpegvideoencdsp.asm @@ -104,4 +104,3 @@ cglobal pix_norm1, 2, 3, %1 INIT_XMM sse2 PIX_NORM1 6, 8 - diff --git a/libavcodec/x86/pixblockdsp_init.c b/libavcodec/x86/pixblockdsp_init.c index 51f2a0033a..f105775c2b 100644 --- a/libavcodec/x86/pixblockdsp_init.c +++ b/libavcodec/x86/pixblockdsp_init.c @@ -28,7 +28,6 @@ void ff_diff_pixels_sse2(int16_t *block, const uint8_t *s1, const uint8_t *s2, ptrdiff_t stride); av_cold void ff_pixblockdsp_init_x86(PixblockDSPContext *c, - AVCodecContext *avctx, unsigned high_bit_depth) { int cpu_flags = av_get_cpu_flags(); diff --git a/libavcodec/x86/rnd_template.c b/libavcodec/x86/rnd_template.c index b825eeba6e..4590aeddf0 100644 --- a/libavcodec/x86/rnd_template.c +++ b/libavcodec/x86/rnd_template.c @@ -96,82 +96,3 @@ av_unused STATIC void DEF(put, pixels8_xy2)(uint8_t *block, const uint8_t *pixel :"D"(block), "r"((x86_reg)line_size) :FF_REG_a, "memory"); } - -#ifndef NO_AVG -// avg_pixels -// this routine is 'slightly' suboptimal but mostly unused -av_unused STATIC void DEF(avg, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h) -{ - MOVQ_ZERO(mm7); - SET_RND(mm6); // =2 for rnd and =1 for no_rnd version - __asm__ volatile( - "movq (%1), %%mm0 \n\t" - "movq 1(%1), %%mm4 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" - "add %3, %1 \n\t" - ".p2align 3 \n\t" - "1: \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "punpcklbw %%mm7, %%mm0 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpckhbw %%mm7, %%mm1 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "paddusw %%mm2, %%mm0 \n\t" - "paddusw %%mm3, %%mm1 \n\t" - "paddusw %%mm6, %%mm4 \n\t" - "paddusw %%mm6, %%mm5 \n\t" - "paddusw %%mm0, %%mm4 \n\t" - "paddusw %%mm1, %%mm5 \n\t" - "psrlw $2, %%mm4 \n\t" - "psrlw $2, %%mm5 \n\t" - "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" - "packuswb %%mm5, %%mm4 \n\t" - "pcmpeqd %%mm2, %%mm2 \n\t" - "paddb %%mm2, %%mm2 \n\t" - PAVGB_MMX(%%mm3, %%mm4, %%mm5, %%mm2) - "movq %%mm5, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 - "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" - "movq %%mm2, %%mm3 \n\t" - "movq %%mm4, %%mm5 \n\t" - "punpcklbw %%mm7, %%mm2 \n\t" - "punpcklbw %%mm7, %%mm4 \n\t" - "punpckhbw %%mm7, %%mm3 \n\t" - "punpckhbw %%mm7, %%mm5 \n\t" - "paddusw %%mm2, %%mm4 \n\t" - "paddusw %%mm3, %%mm5 \n\t" - "paddusw %%mm6, %%mm0 \n\t" - "paddusw %%mm6, %%mm1 \n\t" - "paddusw %%mm4, %%mm0 \n\t" - "paddusw %%mm5, %%mm1 \n\t" - "psrlw $2, %%mm0 \n\t" - "psrlw $2, %%mm1 \n\t" - "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "pcmpeqd %%mm2, %%mm2 \n\t" - "paddb %%mm2, %%mm2 \n\t" - PAVGB_MMX(%%mm3, %%mm0, %%mm1, %%mm2) - "movq %%mm1, (%2, %%"FF_REG_a") \n\t" - "add %3, %%"FF_REG_a" \n\t" - - "subl $2, %0 \n\t" - "jnz 1b \n\t" - :"+g"(h), "+S"(pixels) - :"D"(block), "r"((x86_reg)line_size) - :FF_REG_a, "memory"); -} -#endif diff --git a/libavcodec/x86/vc1dsp.h b/libavcodec/x86/vc1dsp.h index fdd4de1813..9c16d73fd2 100644 --- a/libavcodec/x86/vc1dsp.h +++ b/libavcodec/x86/vc1dsp.h @@ -21,9 +21,14 @@ #ifndef AVCODEC_X86_VC1DSP_H #define AVCODEC_X86_VC1DSP_H +#include "libavutil/x86/asm.h" #include "libavcodec/vc1dsp.h" +#if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL + void ff_vc1dsp_init_mmx(VC1DSPContext *dsp); void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp); +#endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */ + #endif /* AVCODEC_X86_VC1DSP_H */ diff --git a/libavcodec/x86/vc1dsp_init.c b/libavcodec/x86/vc1dsp_init.c index 90b2f3624e..e8163f2886 100644 --- a/libavcodec/x86/vc1dsp_init.c +++ b/libavcodec/x86/vc1dsp_init.c @@ -102,6 +102,7 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) { int cpu_flags = av_get_cpu_flags(); +#if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL if (HAVE_6REGS && INLINE_MMX(cpu_flags)) if (EXTERNAL_MMX(cpu_flags)) ff_vc1dsp_init_mmx(dsp); @@ -109,6 +110,7 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) if (HAVE_6REGS && INLINE_MMXEXT(cpu_flags)) if (EXTERNAL_MMXEXT(cpu_flags)) ff_vc1dsp_init_mmxext(dsp); +#endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */ #define ASSIGN_LF4(EXT) \ dsp->vc1_v_loop_filter4 = ff_vc1_v_loop_filter4_ ## EXT; \ diff --git a/libavcodec/x86/videodsp.asm b/libavcodec/x86/videodsp.asm index 3cc07878d3..81ae2ec10c 100644 --- a/libavcodec/x86/videodsp.asm +++ b/libavcodec/x86/videodsp.asm @@ -123,54 +123,43 @@ hvar_fn ; - if (%2 & 8) fills 8 bytes into xmm$next ; - if (%2 & 4) fills 4 bytes into xmm$next ; - if (%2 & 3) fills 1, 2 or 4 bytes in eax -; on mmx, - fills mm0-7 for consecutive sets of 8 pixels -; - if (%2 & 4) fills 4 bytes into mm$next -; - if (%2 & 3) fills 1, 2 or 4 bytes in eax ; writing data out is in the same way %macro READ_NUM_BYTES 2 %assign %%off 0 ; offset in source buffer -%assign %%mmx_idx 0 ; mmx register index %assign %%xmm_idx 0 ; xmm register index %rep %2/mmsize -%if mmsize == 16 movu xmm %+ %%xmm_idx, [srcq+%%off] %assign %%xmm_idx %%xmm_idx+1 -%else ; mmx - movu mm %+ %%mmx_idx, [srcq+%%off] -%assign %%mmx_idx %%mmx_idx+1 -%endif %assign %%off %%off+mmsize %endrep ; %2/mmsize -%if mmsize == 16 %if (%2-%%off) >= 8 %if %2 > 16 && (%2-%%off) > 8 movu xmm %+ %%xmm_idx, [srcq+%2-16] %assign %%xmm_idx %%xmm_idx+1 %assign %%off %2 %else - movq mm %+ %%mmx_idx, [srcq+%%off] -%assign %%mmx_idx %%mmx_idx+1 + movq xmm %+ %%xmm_idx, [srcq+%%off] +%assign %%xmm_idx %%xmm_idx+1 %assign %%off %%off+8 %endif %endif ; (%2-%%off) >= 8 -%endif %if (%2-%%off) >= 4 %if %2 > 8 && (%2-%%off) > 4 - movq mm %+ %%mmx_idx, [srcq+%2-8] + movq xmm %+ %%xmm_idx, [srcq+%2-8] %assign %%off %2 %else - movd mm %+ %%mmx_idx, [srcq+%%off] + movd xmm %+ %%xmm_idx, [srcq+%%off] %assign %%off %%off+4 %endif -%assign %%mmx_idx %%mmx_idx+1 +%assign %%xmm_idx %%xmm_idx+1 %endif ; (%2-%%off) >= 4 %if (%2-%%off) >= 1 %if %2 >= 4 - movd mm %+ %%mmx_idx, [srcq+%2-4] + movd xmm %+ %%xmm_idx, [srcq+%2-4] %elif (%2-%%off) == 1 mov valb, [srcq+%2-1] %elif (%2-%%off) == 2 @@ -185,48 +174,40 @@ hvar_fn %macro WRITE_NUM_BYTES 2 %assign %%off 0 ; offset in destination buffer -%assign %%mmx_idx 0 ; mmx register index %assign %%xmm_idx 0 ; xmm register index %rep %2/mmsize -%if mmsize == 16 movu [dstq+%%off], xmm %+ %%xmm_idx %assign %%xmm_idx %%xmm_idx+1 -%else ; mmx - movu [dstq+%%off], mm %+ %%mmx_idx -%assign %%mmx_idx %%mmx_idx+1 -%endif %assign %%off %%off+mmsize %endrep ; %2/mmsize -%if mmsize == 16 %if (%2-%%off) >= 8 %if %2 > 16 && (%2-%%off) > 8 movu [dstq+%2-16], xmm %+ %%xmm_idx %assign %%xmm_idx %%xmm_idx+1 %assign %%off %2 %else - movq [dstq+%%off], mm %+ %%mmx_idx -%assign %%mmx_idx %%mmx_idx+1 + movq [dstq+%%off], xmm %+ %%xmm_idx +%assign %%xmm_idx %%xmm_idx+1 %assign %%off %%off+8 %endif %endif ; (%2-%%off) >= 8 -%endif %if (%2-%%off) >= 4 %if %2 > 8 && (%2-%%off) > 4 - movq [dstq+%2-8], mm %+ %%mmx_idx + movq [dstq+%2-8], xmm %+ %%xmm_idx %assign %%off %2 %else - movd [dstq+%%off], mm %+ %%mmx_idx + movd [dstq+%%off], xmm %+ %%xmm_idx %assign %%off %%off+4 %endif -%assign %%mmx_idx %%mmx_idx+1 +%assign %%xmm_idx %%xmm_idx+1 %endif ; (%2-%%off) >= 4 %if (%2-%%off) >= 1 %if %2 >= 4 - movd [dstq+%2-4], mm %+ %%mmx_idx + movd [dstq+%2-4], xmm %+ %%xmm_idx %elif (%2-%%off) == 1 mov [dstq+%2-1], valb %elif (%2-%%off) == 2 @@ -318,11 +299,8 @@ cglobal emu_edge_vfix %+ %%n, 1, 5, 1, dst, src, start_y, end_y, bh %endrep ; 1+%2-%1 %endmacro ; VERTICAL_EXTEND -INIT_MMX mmx -VERTICAL_EXTEND 1, 15 - -INIT_XMM sse -VERTICAL_EXTEND 16, 22 +INIT_XMM sse2 +VERTICAL_EXTEND 1, 22 ; left/right (horizontal) fast extend functions ; these are essentially identical to the vertical extend ones above, @@ -337,11 +315,7 @@ VERTICAL_EXTEND 16, 22 imul vald, 0x01010101 %if %1 >= 8 movd m0, vald -%if mmsize == 16 pshufd m0, m0, q0000 -%else - punpckldq m0, m0 -%endif ; mmsize == 16 %endif ; %1 > 16 %endif ; avx2 %endmacro ; READ_V_PIXEL @@ -356,7 +330,6 @@ VERTICAL_EXTEND 16, 22 %assign %%off %%off+mmsize %endrep ; %1/mmsize -%if mmsize == 16 %if %1-%%off >= 8 %if %1 > 16 && %1-%%off > 8 movu [%2+%1-16], m0 @@ -366,7 +339,6 @@ VERTICAL_EXTEND 16, 22 %assign %%off %%off+8 %endif %endif ; %1-%%off >= 8 -%endif ; mmsize == 16 %if %1-%%off >= 4 %if %1 > 8 && %1-%%off > 4 @@ -415,11 +387,8 @@ cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val %endrep ; 1+(%2-%1)/2 %endmacro ; H_EXTEND -INIT_MMX mmx -H_EXTEND 2, 14 - INIT_XMM sse2 -H_EXTEND 16, 22 +H_EXTEND 2, 22 %if HAVE_AVX2_EXTERNAL INIT_XMM avx2 diff --git a/libavcodec/x86/videodsp_init.c b/libavcodec/x86/videodsp_init.c index ae9db95624..602856de1e 100644 --- a/libavcodec/x86/videodsp_init.c +++ b/libavcodec/x86/videodsp_init.c @@ -37,37 +37,37 @@ typedef void emu_edge_vvar_func(uint8_t *dst, x86_reg dst_stride, x86_reg start_y, x86_reg end_y, x86_reg bh, x86_reg w); -extern emu_edge_vfix_func ff_emu_edge_vfix1_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix2_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix3_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix4_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix5_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix6_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix7_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix8_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix9_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix10_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix11_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix12_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix13_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix14_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix15_mmx; -extern emu_edge_vfix_func ff_emu_edge_vfix16_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix17_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix18_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix19_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix20_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix21_sse; -extern emu_edge_vfix_func ff_emu_edge_vfix22_sse; -static emu_edge_vfix_func * const vfixtbl_sse[22] = { - ff_emu_edge_vfix1_mmx, ff_emu_edge_vfix2_mmx, ff_emu_edge_vfix3_mmx, - ff_emu_edge_vfix4_mmx, ff_emu_edge_vfix5_mmx, ff_emu_edge_vfix6_mmx, - ff_emu_edge_vfix7_mmx, ff_emu_edge_vfix8_mmx, ff_emu_edge_vfix9_mmx, - ff_emu_edge_vfix10_mmx, ff_emu_edge_vfix11_mmx, ff_emu_edge_vfix12_mmx, - ff_emu_edge_vfix13_mmx, ff_emu_edge_vfix14_mmx, ff_emu_edge_vfix15_mmx, - ff_emu_edge_vfix16_sse, ff_emu_edge_vfix17_sse, ff_emu_edge_vfix18_sse, - ff_emu_edge_vfix19_sse, ff_emu_edge_vfix20_sse, ff_emu_edge_vfix21_sse, - ff_emu_edge_vfix22_sse +extern emu_edge_vfix_func ff_emu_edge_vfix1_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix2_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix3_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix4_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix5_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix6_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix7_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix8_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix9_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix10_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix11_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix12_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix13_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix14_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix15_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix16_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix17_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix18_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix19_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix20_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix21_sse2; +extern emu_edge_vfix_func ff_emu_edge_vfix22_sse2; +static emu_edge_vfix_func * const vfixtbl_sse2[22] = { + ff_emu_edge_vfix1_sse2, ff_emu_edge_vfix2_sse2, ff_emu_edge_vfix3_sse2, + ff_emu_edge_vfix4_sse2, ff_emu_edge_vfix5_sse2, ff_emu_edge_vfix6_sse2, + ff_emu_edge_vfix7_sse2, ff_emu_edge_vfix8_sse2, ff_emu_edge_vfix9_sse2, + ff_emu_edge_vfix10_sse2, ff_emu_edge_vfix11_sse2, ff_emu_edge_vfix12_sse2, + ff_emu_edge_vfix13_sse2, ff_emu_edge_vfix14_sse2, ff_emu_edge_vfix15_sse2, + ff_emu_edge_vfix16_sse2, ff_emu_edge_vfix17_sse2, ff_emu_edge_vfix18_sse2, + ff_emu_edge_vfix19_sse2, ff_emu_edge_vfix20_sse2, ff_emu_edge_vfix21_sse2, + ff_emu_edge_vfix22_sse2 }; extern emu_edge_vvar_func ff_emu_edge_vvar_sse; @@ -76,21 +76,21 @@ typedef void emu_edge_hfix_func(uint8_t *dst, x86_reg dst_stride, typedef void emu_edge_hvar_func(uint8_t *dst, x86_reg dst_stride, x86_reg start_x, x86_reg n_words, x86_reg bh); -extern emu_edge_hfix_func ff_emu_edge_hfix2_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix4_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix6_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix8_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix10_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix12_mmx; -extern emu_edge_hfix_func ff_emu_edge_hfix14_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix2_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix4_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix6_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix8_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix10_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix12_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix14_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix16_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix18_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix20_sse2; extern emu_edge_hfix_func ff_emu_edge_hfix22_sse2; static emu_edge_hfix_func * const hfixtbl_sse2[11] = { - ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, - ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx, - ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2, + ff_emu_edge_hfix2_sse2, ff_emu_edge_hfix4_sse2, ff_emu_edge_hfix6_sse2, + ff_emu_edge_hfix8_sse2, ff_emu_edge_hfix10_sse2, ff_emu_edge_hfix12_sse2, + ff_emu_edge_hfix14_sse2, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2, ff_emu_edge_hfix20_sse2, ff_emu_edge_hfix22_sse2 }; extern emu_edge_hvar_func ff_emu_edge_hvar_sse2; @@ -104,7 +104,7 @@ extern emu_edge_hfix_func ff_emu_edge_hfix18_avx2; extern emu_edge_hfix_func ff_emu_edge_hfix20_avx2; extern emu_edge_hfix_func ff_emu_edge_hfix22_avx2; static emu_edge_hfix_func * const hfixtbl_avx2[11] = { - ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, + ff_emu_edge_hfix2_sse2, ff_emu_edge_hfix4_sse2, ff_emu_edge_hfix6_sse2, ff_emu_edge_hfix8_avx2, ff_emu_edge_hfix10_avx2, ff_emu_edge_hfix12_avx2, ff_emu_edge_hfix14_avx2, ff_emu_edge_hfix16_avx2, ff_emu_edge_hfix18_avx2, ff_emu_edge_hfix20_avx2, ff_emu_edge_hfix22_avx2 @@ -196,7 +196,7 @@ static av_noinline void emulated_edge_mc_sse2(uint8_t *buf, const uint8_t *src, int h) { emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, - src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + src_x, src_y, w, h, vfixtbl_sse2, &ff_emu_edge_vvar_sse, hfixtbl_sse2, &ff_emu_edge_hvar_sse2); } @@ -209,7 +209,7 @@ static av_noinline void emulated_edge_mc_avx2(uint8_t *buf, const uint8_t *src, int h) { emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, - src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + src_x, src_y, w, h, vfixtbl_sse2, &ff_emu_edge_vvar_sse, hfixtbl_avx2, &ff_emu_edge_hvar_avx2); } #endif /* HAVE_AVX2_EXTERNAL */ diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c index 8d11dbc348..4373fa3f04 100644 --- a/libavcodec/x86/vp9dsp_init.c +++ b/libavcodec/x86/vp9dsp_init.c @@ -114,7 +114,9 @@ itxfm_func(idct, idct, 32, ssse3); itxfm_func(idct, idct, 32, avx); itxfm_func(iwht, iwht, 4, mmx); itxfm_funcs(16, avx2); +itxfm_funcs(16, avx512icl); itxfm_func(idct, idct, 32, avx2); +itxfm_func(idct, idct, 32, avx512icl); #undef itxfm_func #undef itxfm_funcs @@ -406,6 +408,19 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) init_ipred(32, avx2, tm, TM_VP8); } +#if ARCH_X86_64 + if (EXTERNAL_AVX512ICL(cpu_flags)) { + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx512icl; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx512icl; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx512icl; + } +#endif + #undef init_fpel #undef init_subpel1 #undef init_subpel2 diff --git a/libavcodec/x86/vp9dsp_init_16bpp_template.c b/libavcodec/x86/vp9dsp_init_16bpp_template.c index f93ea2468e..db775f7c1a 100644 --- a/libavcodec/x86/vp9dsp_init_16bpp_template.c +++ b/libavcodec/x86/vp9dsp_init_16bpp_template.c @@ -127,6 +127,8 @@ decl_itxfm_func(iwht, iwht, 4, BPC, mmxext); #if BPC == 10 decl_itxfm_func(idct, idct, 4, BPC, mmxext); decl_itxfm_funcs(4, BPC, ssse3); +decl_itxfm_funcs(16, BPC, avx512icl); +decl_itxfm_func(idct, idct, 32, BPC, avx512icl); #else decl_itxfm_func(idct, idct, 4, BPC, sse2); #endif @@ -233,6 +235,12 @@ av_cold void INIT_FUNC(VP9DSPContext *dsp, int bitexact) #endif } +#if ARCH_X86_64 && BPC == 10 + if (EXTERNAL_AVX512ICL(cpu_flags)) { + init_itx_funcs(TX_16X16, 16, BPC, avx512icl); + init_itx_func_one(TX_32X32, idct, idct, 32, BPC, avx512icl); + } +#endif #endif /* HAVE_X86ASM */ ff_vp9dsp_init_16bpp_x86(dsp); diff --git a/libavcodec/x86/vp9itxfm_16bpp_avx512.asm b/libavcodec/x86/vp9itxfm_16bpp_avx512.asm new file mode 100644 index 0000000000..1924233469 --- /dev/null +++ b/libavcodec/x86/vp9itxfm_16bpp_avx512.asm @@ -0,0 +1,1165 @@ +;****************************************************************************** +;* VP9 IDCT SIMD optimizations +;* +;* Copyright (C) 2025 Two Orioles, LLC +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 && HAVE_AVX512ICL_EXTERNAL + +SECTION_RODATA 64 + +; The following set of constants are ordered to form the +; qword shuffle mask { 0, 2, 4, 6, 1, 3, 5, 7 } +%define deintq_perm pd_5520 +pd_5520: dd 5520 +pd_9760: dd 9760 +pd_10394: dd 10394 +pd_15426: dd 15426 +pd_804: dd 804 +pd_2404: dd 2404 +pd_6270: dd 6270 +pd_9102: dd 9102 +pd_11585: dd 11585 +pd_12665: dd 12665 +pd_7723: dd 7723 +pd_14811: dd 14811 +pd_7005: dd 7005 +pd_14053: dd 14053 +pd_8423: dd 8423 +pd_13623: dd 13623 + +pixel_clip: times 2 dw 0x7c00 +pixel_clip6: dd 2031648 ; 32 + (pixel_clip << 6) +pd_532480: dd 532480 ; 8192 + (32 << 14) +pd_8192: dd 8192 + +pd_1606: dd 1606 +pd_3196: dd 3196 +pd_3981: dd 3981 +pd_4756: dd 4756 +pd_11003: dd 11003 +pd_12140: dd 12140 +pd_13160: dd 13160 +pd_14449: dd 14449 +pd_15137: dd 15137 +pd_15679: dd 15679 +pd_15893: dd 15893 +pd_16069: dd 16069 +pd_16207: dd 16207 +pd_16305: dd 16305 +pd_16364: dd 16364 + +SECTION .text + +%define o_base (deintq_perm+128) +%define o(x) (r5 - o_base + (x)) +%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX) + +; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12 +; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12 +; skip round/shift if rnd is not a number +%macro ITX_MULSUB_2D 8-9 0 ; dst/src[1-2], tmp[1-3], rnd, coef[1-2], inv_dst2 +%if %8 < 32 + pmulld m%4, m%1, m%8 + pmulld m%3, m%2, m%8 +%else + vpbroadcastd m%3, [o(pd_%8)] + pmulld m%4, m%1, m%3 + pmulld m%3, m%2 +%endif +%if %7 < 32 + pmulld m%1, m%7 + pmulld m%2, m%7 +%else + vpbroadcastd m%5, [o(pd_%7)] + pmulld m%1, m%5 + pmulld m%2, m%5 +%endif +%if %9 + psubd m%4, m%6, m%4 + psubd m%2, m%4, m%2 +%else +%ifnum %6 + paddd m%4, m%6 +%endif + paddd m%2, m%4 +%endif +%ifnum %6 + paddd m%1, m%6 +%endif + psubd m%1, m%3 +%ifnum %6 + psrad m%2, 14 + psrad m%1, 14 +%endif +%endmacro + +%macro WRAP_YMM 1+ + INIT_YMM cpuname + %1 + INIT_ZMM cpuname +%endmacro + +%macro TRANSPOSE_4D 5 ; in[1-4], tmp + punpckhdq m%5, m%3, m%4 ; c2 d2 c3 d3 + punpckldq m%3, m%4 ; c0 d0 c1 d1 + punpckhdq m%4, m%1, m%2 ; a2 b2 a3 b3 + punpckldq m%1, m%2 ; a0 b0 a1 b1 + punpckhqdq m%2, m%1, m%3 ; a1 b1 c1 d1 + punpcklqdq m%1, m%3 ; a0 b0 c0 d0 + punpcklqdq m%3, m%4, m%5 ; a2 b2 c2 d2 + punpckhqdq m%4, m%5 ; a3 b3 c3 d3 +%endmacro + +%macro TRANSPOSE_4DQ 5 ; in[1-4], tmp + vshufi32x4 m%5, m%3, m%4, q3232 ; c2 c3 d2 d3 + vinserti32x8 m%3, ym%4, 1 ; c0 c1 d0 d1 + vshufi32x4 m%4, m%1, m%2, q3232 ; a2 a3 b2 b3 + vinserti32x8 m%1, ym%2, 1 ; a0 a1 b0 b1 + vshufi32x4 m%2, m%1, m%3, q3131 ; a1 b1 c1 d1 + vshufi32x4 m%1, m%3, q2020 ; a0 b0 c0 d0 + vshufi32x4 m%3, m%4, m%5, q2020 ; a2 b2 c2 d2 + vshufi32x4 m%4, m%5, q3131 ; a3 b3 c3 d3 +%endmacro + +%macro INV_TXFM_FN 3-4 0 ; type1, type2, size, eob_offset +cglobal vp9_i%1_i%2_%3_add_10, 4, 5, 0, dst, stride, c, eob, tx2 + %define %%p1 m(vp9_i%1_%3_internal_10) + lea r5, [o_base] + ; Jump to the 1st txfm function if we're not taking the fast path, which + ; in turn performs an indirect jump to the 2nd txfm function. + lea tx2q, [m(vp9_i%2_%3_internal_10).pass2] +%ifidn %1_%2, dct_dct + dec eobd + jnz %%p1 +%else +%if %4 + add eobd, %4 +%endif + ; jump to the 1st txfm function unless it's located directly after this + times ((%%end - %%p1) >> 31) & 1 jmp %%p1 +ALIGN function_align +%%end: +%endif +%endmacro + +%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset + INV_TXFM_FN %1, %2, 16x16, %3 +%ifidn %1_%2, dct_dct + imul r6d, [cq], 11585 + vpbroadcastd ym3, [o(pixel_clip)] + mov [cq], r3d + add r6d, 8192 + sar r6d, 14 + imul r6d, 11585 + or r3d, 8 + add r6d, 532480 + sar r6d, 20 + vpbroadcastw ym2, r6d + paddsw ym2, ym3 +.dconly_loop: + paddsw ym0, ym2, [dstq+strideq*0] + paddsw ym1, ym2, [dstq+strideq*1] + psubusw ym0, ym3 + psubusw ym1, ym3 + mova [dstq+strideq*0], ym0 + mova [dstq+strideq*1], ym1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +%macro IDCT16_PART1 0 +%if mmsize == 64 +.main_part1_fast: +%endif + pmulld m15, m1, [o(pd_16305)] {bcstd} ; t15a + pmulld m1, [o(pd_1606)] {bcstd} ; t8a + pmulld m9, m7, [o(pd_10394)] {bcstd} ; t9a + pmulld m7, [o(pd_12665)] {bcstd} ; t14a + pmulld m11, m5, [o(pd_14449)] {bcstd} ; t13a + pmulld m5, [o(pd_7723)] {bcstd} ; t10a + pmulld m13, m3, [o(pd_4756)] {bcstd} ; t11a + pmulld m3, [o(pd_15679)] {bcstd} ; t12a + pmulld m10, m6, [o(pd_9102)] {bcstd} ; t5a + pmulld m6, [o(pd_13623)] {bcstd} ; t6a + pmulld m14, m2, [o(pd_16069)] {bcstd} ; t7a + pmulld m2, [o(pd_3196)] {bcstd} ; t4a + pmulld m12, m4, [o(pd_15137)] {bcstd} ; t3 + pmulld m4, [o(pd_6270)] {bcstd} ; t2 + pmulld m0, m21 + REPX {psubd x, m20, x}, m9, m13, m10 + paddd m0, m20 + mova m18, m0 +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main_part1b +.main_part1: + ITX_MULSUB_2D 1, 15, 16, 17, 18, _, 1606, 16305 ; t8a, t15a + ITX_MULSUB_2D 9, 7, 16, 17, 18, _, 12665, 10394 ; t9a, t14a + ITX_MULSUB_2D 5, 11, 16, 17, 18, _, 7723, 14449 ; t10a, t13a + ITX_MULSUB_2D 13, 3, 16, 17, 18, _, 15679, 4756 ; t11a, t12a + ITX_MULSUB_2D 10, 6, 16, 17, 18, _, 13623, 9102 ; t5a, t6a + ITX_MULSUB_2D 2, 14, 16, 17, 18, _, 3196, 16069 ; t4a, t7a + ITX_MULSUB_2D 4, 12, 16, 17, 18, _, 6270, 15137 ; t2, t3 + pmulld m0, m21 + pmulld m8, m21 + REPX {paddd x, m20}, m0, m9, m13, m10 + psubd m18, m0, m8 ; t1 + paddd m0, m8 ; t0 +%%main_part1b: +%endif + vpbroadcastd m19, [o(pd_15137)] + vpbroadcastd m16, [o(pd_6270)] + REPX {paddd x, m20}, m15, m7, m1, m11, m3, m5 + REPX {psrad x, 14 }, m15, m7, m1, m9, m11, m3, m5, m13 + paddd m17, m15, m7 ; t15 + psubd m15, m7 ; t14 + psubd m7, m3, m11 ; t13 + paddd m3, m11 ; t12 + psubd m11, m13, m5 ; t10 + paddd m5, m13 ; t11 + psubd m13, m1, m9 ; t9 + paddd m1, m9 ; t8 + ITX_MULSUB_2D 15, 13, 8, 9, _, 20, 16, 19 ; t9a, t14a + ITX_MULSUB_2D 7, 11, 8, 9, _, 20, 16, 19, 2 ; t13a, t10a + paddd m16, m1, m5 ; t8a + psubd m1, m5 ; t11a + paddd m8, m15, m11 ; t9 + psubd m15, m11 ; t10 + psubd m11, m17, m3 ; t12a + paddd m17, m3 ; t15a + psubd m9, m13, m7 ; t13 + paddd m13, m7 ; t14 + REPX {pmulld x, m21}, m11, m9, m1, m15 + REPX {paddd x, m20}, m2, m6, m14 + REPX {psrad x, 14 }, m10, m2, m6, m14 + psubd m3, m2, m10 ; t5a + paddd m10, m2 ; t4 + paddd m11, m20 + psubd m5, m11, m1 ; t11 + paddd m11, m1 ; t12 + psubd m1, m14, m6 ; t6a + paddd m14, m6 ; t7 + pmulld m1, m21 + pmulld m3, m21 + paddd m4, m20 + paddd m12, m20 + REPX {psrad x, 14 }, m4, m12, m0, m18 + paddd m9, m20 + paddd m2, m9, m15 ; t13a + psubd m9, m15 ; t10a + paddd m1, m20 + psubd m6, m1, m3 ; t5 + paddd m1, m3 ; t6 + REPX {psrad x, 14}, m6, m1, m11, m5, m2, m9 +%endmacro + +%macro IDCT16_PART2 0 + psubd m3, m0, m12 ; t3 + paddd m0, m12 ; t0 + psubd m12, m18, m4 ; t2 + paddd m18, m4 ; t1 + psubd m4, m3, m10 ; t4 + paddd m3, m10 ; t3 + psubd m10, m12, m6 ; t5 + paddd m12, m6 ; t2 + psubd m6, m18, m1 ; t6 + paddd m1, m18 ; t1 + psubd m7, m0, m14 ; t7 + paddd m0, m14 ; t0 + psubd m15, m0, m17 ; out15 + paddd m0, m17 ; out0 + psubd m14, m1, m13 ; out14 + paddd m1, m13 ; out1 + psubd m13, m12, m2 ; out13 + paddd m2, m12 ; out2 + psubd m12, m3, m11 ; out12 + paddd m3, m11 ; out3 + psubd m11, m4, m5 ; out11 + paddd m4, m5 ; out4 + paddd m5, m10, m9 ; out5 + psubd m10, m9 ; out10 + psubd m9, m6, m8 ; out9 + paddd m6, m8 ; out6 + psubd m8, m7, m16 ; out8 + paddd m7, m16 ; out7 +%endmacro + +INIT_ZMM avx512icl +INV_TXFM_16X16_FN dct, dct +INV_TXFM_16X16_FN dct, adst, 39-23-1 + +cglobal vp9_idct_16x16_internal_10, 0, 7, 22, dst, stride, c, eob, tx2 + mova m0, [cq+64* 0] + mova m1, [cq+64* 1] + mova m2, [cq+64* 2] + mova m3, [cq+64* 3] + mova m4, [cq+64* 4] + mova m5, [cq+64* 5] + mova m6, [cq+64* 6] + mova m7, [cq+64* 7] + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + sub eobd, 38 + jl .pass1_fast + mova m8, [cq+64* 8] + mova m9, [cq+64* 9] + mova m10, [cq+64*10] + mova m11, [cq+64*11] + mova m12, [cq+64*12] + mova m13, [cq+64*13] + mova m14, [cq+64*14] + mova m15, [cq+64*15] + call .main_part1 + call .main_part2 +.pass1_end: + TRANSPOSE_4DQ 0, 4, 8, 12, 16 + TRANSPOSE_4DQ 1, 5, 9, 13, 16 + TRANSPOSE_4DQ 2, 6, 10, 14, 16 + TRANSPOSE_4DQ 3, 7, 11, 15, 16 + TRANSPOSE_4D 8, 9, 10, 11, 16 + TRANSPOSE_4D 12, 13, 14, 15, 16 + mov r6d, 64*12 + jmp .pass1_transpose_end +.pass1_fast: + WRAP_YMM IDCT16_PART1 + WRAP_YMM IDCT16_PART2 +.pass1_fast_end: + vinserti32x8 m0, ym4, 1 + vinserti32x8 m8, ym12, 1 + vinserti32x8 m1, ym5, 1 + vinserti32x8 m9, ym13, 1 + vinserti32x8 m2, ym6, 1 + vinserti32x8 m10, ym14, 1 + vinserti32x8 m3, ym7, 1 + vinserti32x8 m11, ym15, 1 + vshufi32x4 m4, m0, m8, q3131 + vshufi32x4 m0, m8, q2020 + vshufi32x4 m5, m1, m9, q3131 + vshufi32x4 m1, m9, q2020 + vshufi32x4 m6, m2, m10, q3131 + vshufi32x4 m2, m10, q2020 + vshufi32x4 m7, m3, m11, q3131 + vshufi32x4 m3, m11, q2020 + mov r6d, 64*4 +.pass1_transpose_end: + pxor m16, m16 +.zero_loop: + mova [cq+r6+64*0], m16 + mova [cq+r6+64*1], m16 + mova [cq+r6+64*2], m16 + mova [cq+r6+64*3], m16 + sub r6d, 64*4 + jge .zero_loop + TRANSPOSE_4D 0, 1, 2, 3, 16 + TRANSPOSE_4D 4, 5, 6, 7, 16 + jmp tx2q +.pass2: + test eobd, eobd + jl .pass2_fast + call .main_part1 + jmp .pass2_end +.pass2_fast: + call .main_part1_fast +.pass2_end: + vpbroadcastd m3, [o(pixel_clip6)] + paddd m0, m3 + paddd m18, m3 + call .main_part2 + REPX {psrad x, 6}, m0, m1, m2, m3 + packssdw m0, m1 + lea r6, [strideq*3] + packssdw m1, m2, m3 + mova m2, [o(deintq_perm)] + vpbroadcastd m3, [o(pixel_clip)] + REPX {psrad x, 6}, m4, m5, m6, m7 + call .write_16x4 + packssdw m0, m4, m5 + packssdw m1, m6, m7 + REPX {psrad x, 6}, m8, m9, m10, m11 + call .write_16x4 + packssdw m0, m8, m9 + packssdw m1, m10, m11 +.pass2_end2: + REPX {psrad x, 6}, m12, m13, m14, m15 + call .write_16x4 + packssdw m0, m12, m13 + packssdw m1, m14, m15 + call .write_16x4 + RET +ALIGN function_align +.write_16x4: + mova ym16, [dstq+strideq*0] + vinserti32x8 m16, [dstq+strideq*1], 1 + mova ym17, [dstq+strideq*2] + vinserti32x8 m17, [dstq+r6 ], 1 + vpermq m0, m2, m0 + vpermq m1, m2, m1 + paddsw m16, m0 + paddsw m17, m1 + psubusw m16, m3 + psubusw m17, m3 + mova [dstq+strideq*0], ym16 + vextracti32x8 [dstq+strideq*1], m16, 1 + mova [dstq+strideq*2], ym17 + vextracti32x8 [dstq+r6 ], m17, 1 + lea dstq, [dstq+strideq*4] + ret +ALIGN function_align + IDCT16_PART1 + ret +ALIGN function_align +.main_part2: + IDCT16_PART2 + ret + +%macro IADST16_PART1 0 +%if mmsize == 64 +.main_part1_fast: +%endif + pmulld m15, m0, [o(pd_16364)] {bcstd} ; t1 + pmulld m0, [o(pd_804)] {bcstd} ; t0 + pmulld m13, m2, [o(pd_15893)] {bcstd} ; t3 + pmulld m2, [o(pd_3981)] {bcstd} ; t2 + pmulld m11, m4, [o(pd_14811)] {bcstd} ; t5 + pmulld m4, [o(pd_7005)] {bcstd} ; t4 + pmulld m9, m6, [o(pd_13160)] {bcstd} ; t7 + pmulld m6, [o(pd_9760)] {bcstd} ; t6 + pmulld m8, m7, [o(pd_11003)] {bcstd} ; t8 + pmulld m7, [o(pd_12140)] {bcstd} ; t9 + pmulld m10, m5, [o(pd_8423)] {bcstd} ; t10 + pmulld m5, [o(pd_14053)] {bcstd} ; t11 + pmulld m12, m3, [o(pd_5520)] {bcstd} ; t12 + pmulld m3, [o(pd_15426)] {bcstd} ; t13 + pmulld m14, m1, [o(pd_2404)] {bcstd} ; t14 + pmulld m1, [o(pd_16207)] {bcstd} ; t15 + REPX {psubd x, m20, x}, m15, m13, m11, m9 +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main_part1b +ALIGN function_align +.main_part1: + ITX_MULSUB_2D 15, 0, 16, 17, 18, _, 804, 16364 ; t1, t0 + ITX_MULSUB_2D 13, 2, 16, 17, 18, _, 3981, 15893 ; t3, t2 + ITX_MULSUB_2D 11, 4, 16, 17, 18, _, 7005, 14811 ; t5, t4 + ITX_MULSUB_2D 9, 6, 16, 17, 18, _, 9760, 13160 ; t7, t6 + ITX_MULSUB_2D 7, 8, 16, 17, 18, _, 12140, 11003 ; t9, t8 + ITX_MULSUB_2D 5, 10, 16, 17, 18, _, 14053, 8423 ; t11, t10 + ITX_MULSUB_2D 3, 12, 16, 17, 18, _, 15426, 5520 ; t13, t12 + ITX_MULSUB_2D 1, 14, 16, 17, 18, _, 16207, 2404 ; t15, t14 + REPX {paddd x, m20}, m15, m13, m11, m9 +%%main_part1b: +%endif + REPX {paddd x, m20}, m0, m2, m4, m6 + psubd m16, m2, m10 ; t10a + paddd m2, m10 ; t2a + psubd m10, m9, m1 ; t15a + paddd m9, m1 ; t7a + psubd m1, m13, m5 ; t11a + paddd m13, m5 ; t3a + psubd m5, m6, m14 ; t14a + paddd m6, m14 ; t6a + REPX {psrad x, 14}, m16, m10, m1, m5 + psubd m14, m0, m8 ; t8a + paddd m0, m8 ; t0a + psubd m8, m15, m7 ; t9a + paddd m15, m7 ; t1a + psubd m7, m4, m12 ; t12a + paddd m4, m12 ; t4a + paddd m12, m11, m3 ; t5a + psubd m11, m3 ; t13a + REPX {psrad x, 14}, m14, m8, m7, m11 + vpbroadcastd m19, [o(pd_9102)] + vpbroadcastd m18, [o(pd_13623)] + ITX_MULSUB_2D 16, 1, 3, 17, _, _, 18, 19 ; t11, t10 + ITX_MULSUB_2D 10, 5, 3, 17, _, _, 19, 18 ; t14, t15 + vpbroadcastd m19, [o(pd_16069)] + vpbroadcastd m18, [o(pd_3196)] + ITX_MULSUB_2D 14, 8, 3, 17, _, _, 18, 19 ; t9, t8 + ITX_MULSUB_2D 11, 7, 3, 17, _, _, 19, 18 ; t12, t13 + vpbroadcastd m19, [o(pd_6270)] + vpbroadcastd m18, [o(pd_15137)] + REPX {psrad x, 14}, m15, m12, m0, m4 + psubd m3, m15, m12 ; t5 + paddd m15, m12 ; t1 + psubd m12, m0, m4 ; t4 + paddd m0, m4 ; t0 + REPX {psrad x, 14}, m2, m6, m13, m9 + psubd m4, m2, m6 ; t6 + paddd m2, m6 ; t2 + psubd m6, m13, m9 ; t7 + paddd m9, m13 ; t3 + REPX {paddd x, m20}, m8, m14, m1, m16 + psubd m13, m8, m11 ; t12a + paddd m8, m11 ; t8a + psubd m11, m14, m7 ; t13a + paddd m14, m7 ; t9a + psubd m7, m1, m10 ; t14a + paddd m1, m10 ; t10a + psubd m10, m16, m5 ; t15a + paddd m16, m5 ; t11a + REPX {psrad x, 14}, m13, m11, m7, m10 + ITX_MULSUB_2D 12, 3, 5, 17, _, _, 19, 18 ; t5a, t4a + ITX_MULSUB_2D 6, 4, 5, 17, _, _, 18, 19 ; t6a, t7a + ITX_MULSUB_2D 13, 11, 5, 17, _, _, 19, 18 ; t13, t12 + ITX_MULSUB_2D 10, 7, 5, 17, _, _, 18, 19 ; t14, t15 + REPX {psrad x, 14}, m8, m1, m14, m16 + psubd m5, m8, m1 ; t10 + paddd m1, m8 ; -out1 + psubd m8, m15, m9 ; t3a + paddd m15, m9 ; -out15 + psubd m9, m14, m16 ; t11 + paddd m14, m16 ; out14 + psubd m16, m0, m2 ; t2a + paddd m0, m2 ; out0 + REPX {paddd x, m20}, m11, m13, m12, m3 + paddd m2, m11, m10 ; out2 + psubd m11, m10 ; t14a + psubd m10, m13, m7 ; t15a + paddd m13, m7 ; -out13 + psubd m7, m12, m4 ; t7 + paddd m12, m4 ; out12 + psubd m4, m3, m6 ; t6 + paddd m3, m6 ; -out3 + REPX {psrad x, 14}, m10, m7, m11, m4 + REPX {pmulld x, m21}, m9, m10, m7, m8, m5, m11, m4, m16 + REPX {psrad x, 14}, m2, m13, m12, m3 +%endmacro + +%macro IADST16_PART2 0 + paddd m9, m20 + psubd m10, m20, m10 + paddd m7, m20 + psubd m8, m20, m8 + paddd m6, m9, m5 ; out6 + psubd m9, m5 ; out9 + psubd m5, m10, m11 ; out5 + paddd m10, m11 ; out10 + psubd m11, m7, m4 ; out11 + paddd m4, m7 ; out4 + psubd m7, m8, m16 ; out7 + paddd m8, m16 ; out8 +%endmacro + +%macro IADST16_PASS1_END 0 + pxor m16, m16 + psubd m1, m16, m1 + psubd m3, m16, m3 + psubd m13, m16, m13 + psubd m15, m16, m15 + REPX {psrad x, 14}, m4, m5, m6, m7, m8, m9, m10, m11 +%endmacro + +INV_TXFM_16X16_FN adst, dct, 39-18 +INV_TXFM_16X16_FN adst, adst + +cglobal vp9_iadst_16x16_internal_10, 0, 7, 22, dst, stride, c, eob, tx2 + mova m0, [cq+64* 0] + mova m1, [cq+64* 1] + mova m2, [cq+64* 2] + mova m3, [cq+64* 3] + mova m4, [cq+64* 4] + mova m5, [cq+64* 5] + mova m6, [cq+64* 6] + mova m7, [cq+64* 7] + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + sub eobd, 39 + jl .pass1_fast + mova m8, [cq+64* 8] + mova m9, [cq+64* 9] + mova m10, [cq+64*10] + mova m11, [cq+64*11] + mova m12, [cq+64*12] + mova m13, [cq+64*13] + mova m14, [cq+64*14] + mova m15, [cq+64*15] + call .main_part1 + call .main_part2 + IADST16_PASS1_END + jmp m(vp9_idct_16x16_internal_10).pass1_end +.pass1_fast: + WRAP_YMM IADST16_PART1 + WRAP_YMM IADST16_PART2 + WRAP_YMM IADST16_PASS1_END + jmp m(vp9_idct_16x16_internal_10).pass1_fast_end +.pass2: + test eobd, eobd + jl .pass2_fast + call .main_part1 + jmp .pass2_end +.pass2_fast: + call .main_part1_fast +.pass2_end: + vpbroadcastd m20, [o(pd_532480)] + call .main_part2 + vpbroadcastd m16, [o(pixel_clip6)] + REPX {paddd x, m16}, m0, m2, m12, m14 + REPX {psubd x, m16, x}, m1, m3, m13, m15 + REPX {psrad x, 6}, m0, m1, m2, m3 + packssdw m0, m1 + lea r6, [strideq*3] + packssdw m1, m2, m3 + mova m2, [o(deintq_perm)] + vpbroadcastd m3, [o(pixel_clip)] + REPX {psrad x, 20}, m4, m5, m6, m7 + call m(vp9_idct_16x16_internal_10).write_16x4 + packssdw m0, m4, m5 + packssdw m1, m6, m7 + paddsw m0, m3 + paddsw m1, m3 + REPX {psrad x, 20}, m8, m9, m10, m11 + call m(vp9_idct_16x16_internal_10).write_16x4 + packssdw m0, m8, m9 + packssdw m1, m10, m11 + paddsw m0, m3 + paddsw m1, m3 + jmp m(vp9_idct_16x16_internal_10).pass2_end2 +ALIGN function_align + IADST16_PART1 + ret +ALIGN function_align +.main_part2: + IADST16_PART2 + ret + +cglobal vp9_idct_idct_32x32_add_10, 4, 7, 23, 64*64, dst, stride, c, eob +%undef cmp + lea r5, [o_base] + dec eobd + jnz .pass1 + imul r6d, [cq], 11585 + vpbroadcastd m3, [o(pixel_clip)] + mov [cq], r3d + add r6d, 8192 + sar r6d, 14 + imul r6d, 11585 + or r3d, 16 + add r6d, 532480 + sar r6d, 20 + vpbroadcastw m2, r6d + paddsw m2, m3 +.dconly_loop: + paddsw m0, m2, [dstq+strideq*0] + paddsw m1, m2, [dstq+strideq*1] + psubusw m0, m3 + psubusw m1, m3 + mova [dstq+strideq*0], m0 + mova [dstq+strideq*1], m1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +.pass1: + vpbroadcastd m20, [o(pd_8192)] + vpbroadcastd m21, [o(pd_11585)] + cmp eobd, 135 + jl .pass1_fast + add cq, 64 + lea r4, [rsp+64*8] + cmp eobd, 579 + jl .pass1_right_fast + mov r6d, 128*28 + call .pass1_main + jmp .pass1_right_end +.pass1_right_fast: ; bottomright quadrant is zero + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + call .main_fast + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + call m(vp9_idct_16x16_internal_10).main_part1_fast + mov r6d, 128*12 + call .pass1_main_end +.pass1_right_end: + mova [r4+64* 8], m0 + mova [r4+64* 9], m1 + mova [r4+64*10], m2 + mova [r4+64*11], m3 + mova [r4+64*12], m4 + mova [r4+64*13], m5 + mova [r4+64*14], m6 + mova [r4+64*15], m7 + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + sub cq, 64 + sub r4, 64*8 + mov r6d, 128*28 + call .pass1_main + mova m12, [r4+64*20] + mova m13, [r4+64*21] + mova m14, [r4+64*22] + mova m15, [r4+64*23] + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + mova m8, [r4+64*16] + mova m9, [r4+64*17] + mova m10, [r4+64*18] + mova m11, [r4+64*19] + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + call .main + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] + mova m8, [r4+64*24] + mova m9, [r4+64*25] + mova m10, [r4+64*26] + mova m11, [r4+64*27] + mova m12, [r4+64*28] + mova m13, [r4+64*29] + mova m14, [r4+64*30] + mova m15, [r4+64*31] + call m(vp9_idct_16x16_internal_10).main_part1 + call .pass2_main_left + mova m8, [r4+64* 8] + mova m9, [r4+64* 9] + mova m10, [r4+64*10] + mova m11, [r4+64*11] + mova m12, [r4+64*12] + mova m13, [r4+64*13] + mova m14, [r4+64*14] + mova m15, [r4+64*15] + TRANSPOSE_4DQ 8, 10, 12, 14, 16 + TRANSPOSE_4DQ 9, 11, 13, 15, 16 + call .main + call .pass2_main_right + mova m8, [r4+64*24] + mova m9, [r4+64*25] + mova m10, [r4+64*26] + mova m11, [r4+64*27] + mova m12, [r4+64*28] + mova m13, [r4+64*29] + mova m14, [r4+64*30] + mova m15, [r4+64*31] + TRANSPOSE_4DQ 8, 10, 12, 14, 16 + TRANSPOSE_4DQ 9, 11, 13, 15, 16 + call m(vp9_idct_16x16_internal_10).main_part1 + jmp .pass2_end +.pass1_fast: + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + mov r4, rsp + call .main_fast + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + call m(vp9_idct_16x16_internal_10).main_part1_fast + call m(vp9_idct_16x16_internal_10).main_part2 + mov r6d, 128*12 + call .pass1_main_end2 + mova [r4+64*16], m16 + mova [r4+64*17], m17 + mova [r4+64*18], m18 + mova [r4+64*19], m19 + mova [r4+64*20], m8 + mova [r4+64*21], m9 + mova [r4+64*22], m10 + mova [r4+64*23], m11 + call .main_fast + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] + call m(vp9_idct_16x16_internal_10).main_part1_fast + call .pass2_main_left + call .main_fast + call .pass2_main_right + call m(vp9_idct_16x16_internal_10).main_part1_fast +.pass2_end: + paddd m0, m22 + paddd m18, m22 + call m(vp9_idct_16x16_internal_10).main_part2 + mova m20, [o(deintq_perm)] + rorx r2, strideq, 59 ; strideq*32 + vpbroadcastd m21, [o(pixel_clip)] + add r2, dstq +%assign i 0 +%rep 16 + mova m16, [r4+64*(15-i)] + mova m17, [r4+64*(i-16)] + mova m18, [r4-64*(17+i)] + paddd m19, m %+ i, m16 + psubd m0, m %+ i, m16 + call .write_32x2 + %assign i i+1 +%endrep + RET +ALIGN function_align +.write_32x2: + paddd m16, m17, m18 + psubd m17, m18 + REPX {psrad x, 6}, m19, m16, m0, m17 + packssdw m16, m19 + packssdw m17, m0 + sub r2, strideq + vpermq m16, m20, m16 + vpermq m17, m20, m17 + paddsw m16, [dstq] + paddsw m17, [r2 ] + psubusw m16, m21 + psubusw m17, m21 + mova [dstq], m16 + mova [r2 ], m17 + add dstq, strideq + ret +ALIGN function_align +.pass1_main: + mova m0, [cq+128* 1] + mova m1, [cq+128* 3] + mova m2, [cq+128* 5] + mova m3, [cq+128* 7] + mova m4, [cq+128* 9] + mova m5, [cq+128*11] + mova m6, [cq+128*13] + mova m7, [cq+128*15] + mova m8, [cq+128*17] + mova m9, [cq+128*19] + mova m10, [cq+128*21] + mova m11, [cq+128*23] + mova m12, [cq+128*25] + mova m13, [cq+128*27] + mova m14, [cq+128*29] + mova m15, [cq+128*31] + call .main + mova m0, [cq+128* 0] + mova m1, [cq+128* 2] + mova m2, [cq+128* 4] + mova m3, [cq+128* 6] + mova m4, [cq+128* 8] + mova m5, [cq+128*10] + mova m6, [cq+128*12] + mova m7, [cq+128*14] + mova m8, [cq+128*16] + mova m9, [cq+128*18] + mova m10, [cq+128*20] + mova m11, [cq+128*22] + mova m12, [cq+128*24] + mova m13, [cq+128*26] + mova m14, [cq+128*28] + mova m15, [cq+128*30] + call m(vp9_idct_16x16_internal_10).main_part1 +.pass1_main_end: + call m(vp9_idct_16x16_internal_10).main_part2 +.pass1_main_end2: + pxor m16, m16 +.pass1_zero_loop: + mova [cq+r6+128*0], m16 + mova [cq+r6+128*1], m16 + mova [cq+r6+128*2], m16 + mova [cq+r6+128*3], m16 + sub r6d, 128*4 + jge .pass1_zero_loop + mova m16, [r4+64*15] + mova m19, [r4+64*14] + mova m22, [r4+64*13] + mova m17, [r4+64*12] + psubd m18, m0, m16 + paddd m16, m0 + paddd m0, m19, m1 + psubd m19, m1, m19 + paddd m1, m17, m3 + psubd m3, m17 + paddd m17, m2, m22 + psubd m2, m22 + TRANSPOSE_4D 3, 2, 19, 18, 22 ; 28 29 30 31 + TRANSPOSE_4D 16, 0, 17, 1, 22 ; 0 1 2 3 + mova [r4+64*54], m3 + mova [r4+64*55], m19 + mova [r4+64*38], m2 + mova [r4+64*39], m18 + mova m2, [r4+64*11] + mova m19, [r4+64*10] + mova m3, [r4+64* 9] + mova m22, [r4+64* 8] + paddd m18, m4, m2 + psubd m4, m2 + paddd m2, m5, m19 + psubd m5, m19 + paddd m19, m6, m3 + psubd m6, m3 + paddd m3, m7, m22 + psubd m7, m22 + TRANSPOSE_4D 7, 6, 5, 4, 22 ; 24 25 26 27 + TRANSPOSE_4D 18, 2, 19, 3, 22 ; 4 5 6 7 + mova [r4+64*52], m7 + mova [r4+64*53], m5 + mova [r4+64*36], m6 + mova [r4+64*37], m4 + mova m7, [r4+64* 7] + mova m4, [r4+64* 6] + mova m5, [r4+64* 5] + mova m22, [r4+64* 4] + psubd m6, m8, m7 + paddd m8, m7 + psubd m7, m9, m4 + paddd m4, m9 + paddd m9, m10, m5 + psubd m10, m5 + paddd m5, m11, m22 + psubd m11, m22 + TRANSPOSE_4D 11, 10, 7, 6, 22 ; 20 21 22 23 + TRANSPOSE_4D 8, 4, 9, 5, 22 ; 8 9 10 11 + mova [r4+64*50], m11 + mova [r4+64*51], m7 + mova [r4+64*34], m10 + mova [r4+64*35], m6 + mova m6, [r4+64* 3] + mova m11, [r4+64* 2] + mova m7, [r4+64* 1] + mova m22, [r4+64* 0] + paddd m10, m12, m6 + psubd m12, m6 + paddd m6, m13, m11 + psubd m13, m11 + paddd m11, m14, m7 + psubd m14, m7 + paddd m7, m15, m22 + psubd m15, m22 + TRANSPOSE_4D 15, 14, 13, 12, 22 ; 16 17 18 19 + TRANSPOSE_4D 10, 6, 11, 7, 22 ; 12 13 14 15 + mova [r4+64*48], m15 + mova [r4+64*49], m13 + mova [r4+64*32], m14 + mova [r4+64*33], m12 + TRANSPOSE_4DQ 0, 2, 4, 6, 22 + TRANSPOSE_4DQ 1, 3, 5, 7, 22 + TRANSPOSE_4DQ 16, 18, 8, 10, 22 + TRANSPOSE_4DQ 17, 19, 9, 11, 22 + ret +ALIGN function_align +.pass2_main_left: + vpbroadcastd m22, [o(pixel_clip6)] + paddd m0, m22 + paddd m18, m22 + call m(vp9_idct_16x16_internal_10).main_part2 + mova [r4+64*16], m0 + mova [r4+64*17], m1 + mova [r4+64*18], m2 + mova [r4+64*19], m3 + mova [r4+64*20], m4 + mova [r4+64*21], m5 + mova [r4+64*22], m6 + mova [r4+64*23], m7 + mova [r4+64*24], m8 + mova [r4+64*25], m9 + mova [r4+64*26], m10 + mova [r4+64*27], m11 + mova [r4+64*28], m12 + mova [r4+64*29], m13 + mova [r4+64*30], m14 + mova [r4+64*31], m15 + add r4, 64*32 + mova m0, [r4+64* 0] + mova m1, [r4+64* 1] + mova m2, [r4+64* 2] + mova m3, [r4+64* 3] + mova m4, [r4+64* 4] + mova m5, [r4+64* 5] + mova m6, [r4+64* 6] + mova m7, [r4+64* 7] + jmp .pass2_main_transpose +ALIGN function_align +.pass2_main_right: + mova m0, [r4+64*16] + mova m1, [r4+64*17] + mova m2, [r4+64*18] + mova m3, [r4+64*19] + mova m4, [r4+64*20] + mova m5, [r4+64*21] + mova m6, [r4+64*22] + mova m7, [r4+64*23] +.pass2_main_transpose: + TRANSPOSE_4DQ 0, 2, 4, 6, 8 + TRANSPOSE_4DQ 1, 3, 5, 7, 8 + ret +ALIGN function_align +.main_fast: + pmulld m15, m0, [o(pd_16364)] {1to16} ; t31a + pmulld m0, [o(pd_804)] {1to16} ; t16a + pmulld m8, m7, [o(pd_11003)] {1to16} ; t17a + pmulld m7, [o(pd_12140)] {1to16} ; t30a + pmulld m11, m4, [o(pd_14811)] {1to16} ; t29a + pmulld m4, [o(pd_7005)] {1to16} ; t18a + pmulld m12, m3, [o(pd_5520)] {1to16} ; t19a + pmulld m3, [o(pd_15426)] {1to16} ; t28a + pmulld m13, m2, [o(pd_15893)] {1to16} ; t27a + pmulld m2, [o(pd_3981)] {1to16} ; t20a + pmulld m10, m5, [o(pd_8423)] {1to16} ; t21a + pmulld m5, [o(pd_14053)] {1to16} ; t26a + pmulld m9, m6, [o(pd_13160)] {1to16} ; t25a + pmulld m6, [o(pd_9760)] {1to16} ; t22a + pmulld m14, m1, [o(pd_2404)] {1to16} ; t23a + pmulld m1, [o(pd_16207)] {1to16} ; t24a + REPX {psubd x, m20, x}, m8, m12, m10, m14 + jmp .main2 +ALIGN function_align +.main: + ITX_MULSUB_2D 0, 15, 16, 17, 18, _, 804, 16364 ; t16a, t31a + ITX_MULSUB_2D 8, 7, 16, 17, 18, _, 12140, 11003 ; t17a, t30a + ITX_MULSUB_2D 4, 11, 16, 17, 18, _, 7005, 14811 ; t18a, t29a + ITX_MULSUB_2D 12, 3, 16, 17, 18, _, 15426, 5520 ; t19a, t28a + ITX_MULSUB_2D 2, 13, 16, 17, 18, _, 3981, 15893 ; t20a, t27a + ITX_MULSUB_2D 10, 5, 16, 17, 18, _, 14053, 8423 ; t21a, t26a + ITX_MULSUB_2D 6, 9, 16, 17, 18, _, 9760, 13160 ; t22a, t25a + ITX_MULSUB_2D 14, 1, 16, 17, 18, _, 16207, 2404 ; t23a, t24a + REPX {paddd x, m20}, m8, m12, m10, m14 +.main2: + REPX {paddd x, m20}, m0, m15, m7, m4, m3, m11 + REPX {psrad x, 14 }, m8, m0, m15, m7, m12, m4, m3, m11 + psubd m16, m0, m8 ; t17 + paddd m0, m8 ; t16 + psubd m8, m15, m7 ; t30 + paddd m15, m7 ; t31 + paddd m7, m12, m4 ; t19 + psubd m12, m4 ; t18 + paddd m4, m3, m11 ; t28 + psubd m3, m11 ; t29 + REPX {paddd x, m20}, m2, m13, m5, m6, m1, m9 + REPX {psrad x, 14 }, m10, m2, m13, m5, m14, m6, m1, m9 + psubd m11, m2, m10 ; t21 + paddd m2, m10 ; t20 + psubd m10, m13, m5 ; t26 + paddd m13, m5 ; t27 + psubd m5, m14, m6 ; t22 + paddd m6, m14 ; t23 + psubd m14, m1, m9 ; t25 + paddd m9, m1 ; t24 + vpbroadcastd m19, [o(pd_16069)] + vpbroadcastd m18, [o(pd_3196)] + ITX_MULSUB_2D 8, 16, 1, 17, _, 20, 18, 19 ; t17a, t30a + ITX_MULSUB_2D 3, 12, 1, 17, _, 20, 18, 19, 1 ; t29a, t18a + vpbroadcastd m19, [o(pd_9102)] + vpbroadcastd m18, [o(pd_13623)] + ITX_MULSUB_2D 10, 11, 1, 17, _, 20, 18, 19 ; t21a, t26a + ITX_MULSUB_2D 14, 5, 1, 17, _, 20, 18, 19, 1 ; t25a, t22a + paddd m1, m6, m2 ; t23a + psubd m6, m2 ; t20a + psubd m2, m9, m13 ; t27a + paddd m9, m13 ; t24a + psubd m13, m15, m4 ; t28a + paddd m15, m4 ; t31a + psubd m4, m8, m12 ; t18 + paddd m8, m12 ; t17 + psubd m12, m0, m7 ; t19a + paddd m0, m7 ; t16a + psubd m7, m16, m3 ; t29 + paddd m3, m16 ; t30 + paddd m16, m5, m10 ; t22 + psubd m5, m10 ; t21 + psubd m10, m14, m11 ; t26 + paddd m14, m11 ; t25 + vpbroadcastd m19, [o(pd_15137)] + vpbroadcastd m18, [o(pd_6270)] + ITX_MULSUB_2D 13, 12, 11, 17, _, 20, 18, 19 ; t19, t28 + ITX_MULSUB_2D 2, 6, 11, 17, _, 20, 18, 19, 1 ; t27, t20 + ITX_MULSUB_2D 7, 4, 11, 17, _, 20, 18, 19 ; t18a, t29a + ITX_MULSUB_2D 10, 5, 11, 17, _, 20, 18, 19, 1 ; t26a, t21a + psubd m11, m0, m1 ; t23 + paddd m0, m1 ; t16 + paddd m1, m16, m8 ; t17a + psubd m16, m8, m16 ; t22a + psubd m8, m15, m9 ; t24 + paddd m15, m9 ; t31 + psubd m9, m3, m14 ; t25a + paddd m14, m3 ; t30a + paddd m3, m6, m13 ; t19a + psubd m6, m13, m6 ; t20a + paddd m13, m10, m4 ; t29 + psubd m10, m4, m10 ; t26 + psubd m4, m12, m2 ; t27a + paddd m12, m2 ; t28a + paddd m2, m7, m5 ; t18 + psubd m7, m5 ; t21 + REPX {pmulld x, m21}, m10, m8, m4, m9, m7, m11, m6, m16 + mova [r4+64* 0], m0 + mova [r4+64* 1], m1 + mova [r4+64* 2], m2 + mova [r4+64* 3], m3 + mova [r4+64*12], m12 + mova [r4+64*13], m13 + mova [r4+64*14], m14 + mova [r4+64*15], m15 + REPX {paddd x, m20}, m10, m8, m4, m9 + psubd m5, m10, m7 ; t21a + paddd m10, m7 ; t26a + psubd m7, m8, m11 ; t23a + paddd m8, m11 ; t24a + REPX {psrad x, 14 }, m5, m10, m7, m8 + paddd m11, m4, m6 ; t27 + psubd m4, m6 ; t20 + psubd m6, m9, m16 ; t22 + paddd m9, m16 ; t25 + REPX {psrad x, 14 }, m11, m4, m6, m9 + mova [r4+64* 4], m4 + mova [r4+64* 5], m5 + mova [r4+64* 6], m6 + mova [r4+64* 7], m7 + mova [r4+64* 8], m8 + mova [r4+64* 9], m9 + mova [r4+64*10], m10 + mova [r4+64*11], m11 + ret + +%endif diff --git a/libavcodec/x86/vp9itxfm_avx512.asm b/libavcodec/x86/vp9itxfm_avx512.asm new file mode 100644 index 0000000000..d51c50756d --- /dev/null +++ b/libavcodec/x86/vp9itxfm_avx512.asm @@ -0,0 +1,1629 @@ +;****************************************************************************** +;* VP9 IDCT SIMD optimizations +;* +;* Copyright (C) 2025 Two Orioles, LLC +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 && HAVE_AVX512ICL_EXTERNAL + +SECTION_RODATA 64 + +dup16_perm: db 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7 + db 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15 + db 16, 17, 16, 17, 18, 19, 18, 19, 20, 21, 20, 21, 22, 23, 22, 23 + db 24, 25, 24, 25, 26, 27, 26, 27, 28, 29, 28, 29, 30, 31, 30, 31 +itx_perm: dq 0x0000000820150440, 0x0000000231372604 + dq 0x0000000ca8041551, 0x00000006b9263715 + dq 0x00000001ec9d8c62, 0x0000000bfdbfae26 + dq 0x00000005648c9d73, 0x0000000f75aebf37 +deint_shuf: db 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 +int_shuf1: db 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15 +int_shuf2: db 8, 9, 0, 1, 10, 11, 2, 3, 12, 13, 4, 5, 14, 15, 6, 7 +pw_512: times 4 dw 512 +pw_m512: times 4 dw -512 +pw_15137_6270x2x4: times 4 dw 15137*2 + times 4 dw 6270*2 +pw_11585_m11585x2x4: times 4 dw 11585*2 +pw_m11585_11585x2x4: times 4 dw -11585*2 +pw_11585_11585x2: times 4 dw 11585*2 +int_mshift: db 142, 150, 0, 0, 174, 182, 0, 0 +pd_8192: dd 8192 +pw_804x2: times 2 dw 804*2 +pw_1606x2: times 2 dw 1606*2 +pw_3196x2: times 2 dw 3196*2 +pw_3981x2: times 2 dw 3981*2 +pw_6270x2: times 2 dw 6270*2 +pw_7005x2: times 2 dw 7005*2 +pw_7723x2: times 2 dw 7723*2 +pw_9760x2: times 2 dw 9760*2 +pw_12140x2: times 2 dw 12140*2 +pw_12665x2: times 2 dw 12665*2 +pw_13160x2: times 2 dw 13160*2 +pw_13623x2: times 2 dw 13623*2 +pw_14053x2: times 2 dw 14053*2 +pw_14449x2: times 2 dw 14449*2 +pw_14811x2: times 2 dw 14811*2 +pw_15137x2: times 2 dw 15137*2 +pw_15426x2: times 2 dw 15426*2 +pw_15679x2: times 2 dw 15679*2 +pw_15893x2: times 2 dw 15893*2 +pw_16069x2: times 2 dw 16069*2 +pw_16207x2: times 2 dw 16207*2 +pw_16305x2: times 2 dw 16305*2 +pw_16364x2: times 2 dw 16364*2 +pw_m2404x2: times 2 dw -2404*2 +pw_m4756x2: times 2 dw -4756*2 +pw_m5520x2: times 2 dw -5520*2 +pw_m8423x2: times 2 dw -8423*2 +pw_m9102x2: times 2 dw -9102*2 +pw_m10394x2: times 2 dw -10394*2 +pw_m11003x2: times 2 dw -11003*2 +pw_804_16364x2: dw 804*2, 16364*2 +pw_1606_16305x2: dw 1606*2, 16305*2 +pw_3196_16069x2: dw 3196*2, 16069*2 +pw_3981_15893x2: dw 3981*2, 15893*2 +pw_7005_14811x2: dw 7005*2, 14811*2 +pw_7723_14449x2: dw 7723*2, 14449*2 +pw_9760_13160x2: dw 9760*2, 13160*2 +pw_m2404_16207x2: dw -2404*2, 16207*2 +pw_m4756_15679x2: dw -4756*2, 15679*2 +pw_m5520_15426x2: dw -5520*2, 15426*2 +pw_m8423_14053x2: dw -8423*2, 14053*2 +pw_m9102_13623x2: dw -9102*2, 13623*2 +pw_m10394_12665x2: dw -10394*2, 12665*2 +pw_m11003_12140x2: dw -11003*2, 12140*2 + +%macro COEF_PAIR 2-3 0 +%if %3 & 4 +pw_%1_m%2: dw %1, -%2 +%else +pw_%1_%2: dw %1, %2 +%if %3 & 2 +pw_m%1_%2: dw -%1, %2 +%else +pw_m%2_%1: dw -%2, %1 +%endif +%endif +%if %3 & 1 +pw_m%1_m%2: dw -%1, -%2 +%endif +%endmacro + +COEF_PAIR 804, 16364 +COEF_PAIR 1606, 16305 +COEF_PAIR 3196, 16069, 1 +COEF_PAIR 3981, 15893 +COEF_PAIR 6270, 15137, 1 +COEF_PAIR 7005, 14811 +COEF_PAIR 7723, 14449 +COEF_PAIR 9102, 13623 +COEF_PAIR 9760, 13160 +COEF_PAIR 11585, 11585, 1 +COEF_PAIR 12140, 11003 +COEF_PAIR 12665, 10394 +COEF_PAIR 13623, 9102, 1 +COEF_PAIR 14053, 8423 +COEF_PAIR 15137, 6270 +COEF_PAIR 15426, 5520 +COEF_PAIR 15679, 4756 +COEF_PAIR 16069, 3196 +COEF_PAIR 16207, 2404 + +; ADST16-only: +COEF_PAIR 2404, 9760, 2 +COEF_PAIR 5520, 7005, 2 +COEF_PAIR 8423, 3981, 2 +COEF_PAIR 11003, 804, 2 +COEF_PAIR 12140, 16364, 5 +COEF_PAIR 14053, 15893, 5 +COEF_PAIR 15426, 14811, 5 +COEF_PAIR 16207, 13160, 5 +pw_11585_m11585: dw 11585, -11585 +pw_16069_m3196: dw 16069, -3196 +pw_9102_m13623: dw 9102, -13623 +pw_15137_m6270: dw 15137, -6270 +pw_6270_m15137: dw 6270, -15137 + +%define pw_11585x2 pw_11585_11585x2 +%define pw_m11585x2 pw_m11585_11585x2x4 + +SECTION .text + +%define o_base pw_512 + 128 +%define o(x) (r6 - (o_base) + (x)) +%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX) + +; flags: 1 = swap, 2 = interleave (l), 4 = interleave (t), 8 = no_pack, +; 16 = special_mul1, 32 = special_mul2, 64 = dst_in_tmp1 +%macro ITX_MUL2X_PACK 6-7 0 ; dst/src, tmp[1-2], rnd, coef[1-2], flags + mova m%2, m%4 +%if %7 & 16 + vpdpwssd m%2, m%1, [o(pw_%5)] {bcstd} + mova m%3, m%4 +%if %7 & 32 + vpdpwssd m%3, m%1, [o(pw_%6)] {bcstd} +%else + vpdpwssd m%3, m%1, m%6 +%endif +%elif %7 & 32 + vpdpwssd m%2, m%1, m%5 + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_%6)] {bcstd} +%elif %6 < 32 + vpdpwssd m%2, m%1, m%5 + mova m%3, m%4 + vpdpwssd m%3, m%1, m%6 +%elif %7 & 1 + vpdpwssd m%2, m%1, [o(pw_%5_%6)] {bcstd} + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_m%6_%5)] {bcstd} +%else + vpdpwssd m%2, m%1, [o(pw_m%6_%5)] {bcstd} + mova m%3, m%4 + vpdpwssd m%3, m%1, [o(pw_%5_%6)] {bcstd} +%endif +%if %7 & 2 + psrld m%2, 14 + pslld m%3, 2 + vpshrdd m%1, m%3, m%2, 16 +%elif %7 & 4 + ; compared to using shifts (as above) this has better throughput, + ; but worse latency and requires setting up the opmask/index + ; registers, so only use this method for the larger transforms +%if %7 & 64 + pslld m%2, 2 + vpmultishiftqb m%2{k7}, m13, m%3 +%else + pslld m%1, m%2, 2 + vpmultishiftqb m%1{k7}, m13, m%3 +%endif +%else + psrad m%2, 14 + psrad m%3, 14 +%if %7 & 8 == 0 + packssdw m%1, m%3, m%2 +%endif +%endif +%endmacro + +; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12 +; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12 +%macro ITX_MULSUB_2W 7 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2] + punpcklwd m%3, m%2, m%1 + punpckhwd m%2, m%1 +%if %7 < 32 + mova m%1, m%5 + vpdpwssd m%1, m%3, m%7 + mova m%4, m%5 + vpdpwssd m%4, m%2, m%7 +%else + mova m%1, m%5 + vpdpwssd m%1, m%3, [o(pw_m%7_%6)] {bcstd} + mova m%4, m%5 + vpdpwssd m%4, m%2, [o(pw_m%7_%6)] {bcstd} +%endif + psrad m%1, 14 + psrad m%4, 14 + packssdw m%1, m%4 + mova m%4, m%5 +%if %7 < 32 + vpdpwssd m%4, m%2, m%6 + mova m%2, m%5 + vpdpwssd m%2, m%3, m%6 +%else + vpdpwssd m%4, m%2, [o(pw_%6_%7)] {bcstd} + mova m%2, m%5 + vpdpwssd m%2, m%3, [o(pw_%6_%7)] {bcstd} +%endif + psrad m%4, 14 + psrad m%2, 14 + packssdw m%2, m%4 +%endmacro + +; flags: 1 = swap, 2 = invert2, 4 = invert1 +%macro ADST_MULSUB_4W 10-11 0 ; dst1/src1, src2, dst2, tmp[1-2], rnd, coef[1-4], flags + mova m%3, m%6 +%if %11 & 1 + vpdpwssd m%3, m%1, [o(pw_m%8_%7)] {bcstd} +%else + vpdpwssd m%3, m%1, [o(pw_%7_%8)] {bcstd} +%endif +%if %11 & 4 + vpbroadcastd m%4, [o(pw_m%9_%10)] +%elif %11 & 2 + vpbroadcastd m%4, [o(pw_%9_m%10)] +%elif %11 & 1 + vpbroadcastd m%4, [o(pw_%10_%9)] +%else + vpbroadcastd m%4, [o(pw_%9_%10)] +%endif + pmaddwd m%4, m%2 + mova m%5, m%6 +%if %11 & 4 + vpdpwssd m%5, m%1, [o(pw_%8_m%7)] {bcstd} +%elif %11 & 1 + vpdpwssd m%5, m%1, [o(pw_%7_%8)] {bcstd} +%else + vpdpwssd m%5, m%1, [o(pw_m%8_%7)] {bcstd} +%endif +%if %11 & 2 + vpbroadcastd m%1, [o(pw_%10_%9)] +%elif %11 & 1 + vpbroadcastd m%1, [o(pw_%9_m%10)] +%else + vpbroadcastd m%1, [o(pw_m%10_%9)] +%endif + pmaddwd m%2, m%1 + paddd m%1, m%3, m%4 + psubd m%3, m%4 + paddd m%4, m%5, m%2 + psubd m%5, m%2 + pslld m%1, 2 + pslld m%3, 2 + vpmultishiftqb m%1{k7}, m13, m%4 + vpmultishiftqb m%3{k7}, m13, m%5 +%endmacro + +%macro WRAP_YMM 1+ + INIT_YMM cpuname + %1 + INIT_ZMM cpuname +%endmacro + +%macro INV_TXFM_FN 3-4 0 ; type1, type2, size, eob_offset +cglobal vp9_i%1_i%2_%3_add, 4, 5, 0, dst, stride, c, eob, tx2 + %undef cmp + %define %%p1 m(vp9_i%1_%3_internal) + lea r6, [o_base] + ; Jump to the 1st txfm function if we're not taking the fast path, which + ; in turn performs an indirect jump to the 2nd txfm function. + lea tx2q, [m(vp9_i%2_%3_internal).pass2] +%ifidn %1_%2, dct_dct + cmp eobd, 1 + jne %%p1 +%else +%if %4 + add eobd, %4 +%endif + ; jump to the 1st txfm function unless it's located directly after this + times ((%%end - %%p1) >> 31) & 1 jmp %%p1 +ALIGN function_align +%%end: +%endif +%endmacro + +%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset + INV_TXFM_FN %1, %2, 16x16, %3 +%ifidn %1_%2, dct_dct + movd xmm0, [o(pw_11585x2)] + pmulhrsw xmm3, xmm0, [cq] + pxor ym2, ym2 + pmulhrsw xmm3, xmm0 + pmulhrsw xmm3, [o(pw_512)] + mova [cq], xm2 + add r3d, 7 + vpbroadcastw ym3, xmm3 +.dconly_loop: + mova xm1, [dstq+strideq*0] + vinserti32x4 ym1, [dstq+strideq*1], 1 + punpcklbw ym0, ym1, ym2 + punpckhbw ym1, ym2 + paddw ym0, ym3 + paddw ym1, ym3 + packuswb ym0, ym1 + mova [dstq+strideq*0], xm0 + vextracti32x4 [dstq+strideq*1], ym0, 1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +%endif +%endmacro + +%macro IDCT16_MAIN 0-1 0 ; idct32 +%if mmsize == 64 && %1 == 0 +.main_fast: +%endif + vpbroadcastd m2, [o(pw_1606_16305x2)] + vpbroadcastd m4, [o(pw_m10394_12665x2)] + vpbroadcastd m11, [o(pw_7723_14449x2)] + vpbroadcastd m12, [o(pw_m4756_15679x2)] + pmulhrsw m8, m2 ; t8a t15a + vpbroadcastd m2, [o(pw_3196_16069x2)] + pmulhrsw m0, m4 ; t9a t14a + vpbroadcastd m4, [o(pw_m9102_13623x2)] + pmulhrsw m5, m11 ; t10a t13a + vpbroadcastd m11, [o(pw_11585_11585x2)] + pmulhrsw m1, m12 ; t11a t12a + vbroadcasti32x4 m12, [o(pw_15137_6270x2x4)] + pmulhrsw m7, m2 ; t4a t7a + pmulhrsw m3, m4 ; t5a t6a + pmulhrsw m9, m11 ; t0 t1 + pmulhrsw m6, m12 ; t3 t2 +%if mmsize == 64 && %1 == 0 + jmp %%main2 +ALIGN function_align +.main: + punpckhwd m8, m7, m0 ; dct16 in15 in1 + punpcklwd m9, m4, m0 ; dct4 in2 in0 + punpckhwd m0, m3, m4 ; dct16 in7 in9 + punpcklwd m7, m1 ; dct8 in7 in1 + punpckhwd m1, m6 ; dct16 in3 in13 + punpcklwd m3, m5 ; dct8 in3 in5 + punpckhwd m5, m2 ; dct16 in11 in5 + punpcklwd m6, m2 ; dct4 in3 in1 + ITX_MUL2X_PACK 8, 2, 4, 10, 1606, 16305, 5 ; t8a t15a + ITX_MUL2X_PACK 0, 2, 4, 10, 12665, 10394, 5 ; t9a t14a + ITX_MUL2X_PACK 5, 2, 4, 10, 7723, 14449, 5 ; t10a t13a + ITX_MUL2X_PACK 1, 2, 4, 10, 15679, 4756, 5 ; t11a t12a + ITX_MUL2X_PACK 7, 2, 4, 10, 3196, 16069, 5 ; t4a t7a + ITX_MUL2X_PACK 3, 2, 4, 10, 13623, 9102, 5 ; t5a t6a + ITX_MUL2X_PACK 9, 2, 4, 10, 11585, 11585 ; t0 t1 + ITX_MUL2X_PACK 6, 2, 4, 10, 6270, 15137 ; t3 t2 +%%main2: +%endif + psubw m2, m8, m0 ; t9 t14 + paddw m8, m0 ; t8 t15 + psubw m4, m1, m5 ; t10 t13 + paddw m1, m5 ; t11 t12 + ITX_MUL2X_PACK 2, 0, 5, 10, 6270, 15137, (1|%1*4) ; t9a t14a + ITX_MUL2X_PACK 4, 0, 5, 10, m15137, 6270, (1|%1*4) ; t10a t13a + vbroadcasti32x4 m5, [o(deint_shuf)] + psubw m0, m8, m1 ; t11a t12a + paddw m8, m1 ; t8a t15a + psubw m1, m7, m3 ; t5a t6a + paddw m7, m3 ; t4 t7 + pshufb m8, m5 + pshufb m7, m5 + paddw m3, m2, m4 ; t9 t14 + psubw m2, m4 ; t10 t13 +%if %1 + vpbroadcastd m12, [o(pw_11585_11585)] + vpbroadcastd m11, [o(pw_m11585_11585)] + pshufb m3, m5 + ITX_MUL2X_PACK 1, 4, 5, 10, 12, 11 ; t5 t6 + ITX_MUL2X_PACK 0, 4, 5, 10, 11, 12, 8 ; t11 t12 + ITX_MUL2X_PACK 2, 0, 11, 10, 11, 12, 8 ; t10a t13a + packssdw m5, m11 ; t12 t13a + packssdw m4, m0 ; t11 t10a +%else + pshufb m0, m5 + ITX_MUL2X_PACK 1, 4, 5, 10, 11585_11585, m11585_11585, 48 ; t5 t6 + vpbroadcastd m11, [o(pw_11585x2)] + punpckhqdq m5, m0, m2 ; t12a t13 + punpcklqdq m0, m2 ; t11a t10 + psubw m4, m5, m0 + paddw m5, m0 + pmulhrsw m4, m11 ; t11 t10a + pmulhrsw m5, m11 ; t12 t13a +%endif + punpckhqdq m2, m7, m1 ; t7 t6 + punpcklqdq m7, m1 ; t4 t5 + psubw m1, m9, m6 ; t3 t2 + paddw m9, m6 ; t0 t1 + punpckhqdq m0, m8, m3 ; t15a t14 + punpcklqdq m8, m3 ; t8a t9 + psubw m3, m9, m2 ; t7 t6 + paddw m9, m2 ; t0 t1 + psubw m2, m1, m7 ; t4 t5 + paddw m1, m7 ; t3 t2 + psubw m7, m9, m0 ; out15 out14 + paddw m0, m9 ; out0 out1 + psubw m6, m1, m5 ; out12 out13 + paddw m1, m5 ; out3 out2 + psubw m5, m2, m4 ; out11 out10 + paddw m2, m4 ; out4 out5 + psubw m4, m3, m8 ; out8 out9 + paddw m3, m8 ; out7 out6 +%endmacro + +INIT_ZMM avx512icl +INV_TXFM_16X16_FN dct, dct +INV_TXFM_16X16_FN dct, adst, 39-23 + +cglobal vp9_idct_16x16_internal, 0, 5, 16, dst, stride, c, eob, tx2 + mova m15, [o(itx_perm)] + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + vpcmpub k7, m13, m10, 6 + sub eobd, 39 + jl .pass1_fast + vpermq m0, m15, [cq+64*0] + vpermq m1, m15, [cq+64*1] + vpermq m2, m15, [cq+64*2] + vpermq m3, m15, [cq+64*3] + vpermq m4, m15, [cq+64*4] + vpermq m5, m15, [cq+64*5] + vpermq m6, m15, [cq+64*6] + vpermq m7, m15, [cq+64*7] + call .main + vbroadcasti32x4 m12, [o(int_shuf1)] + vbroadcasti32x4 m11, [o(int_shuf2)] + pshufb m0, m12 + pshufb m8, m1, m11 + pshufb m2, m12 + pshufb m9, m3, m11 + pshufb m4, m12 + pshufb m14, m5, m11 + pshufb m6, m12 + pshufb m11, m7, m11 + punpckhdq m1, m0, m8 + punpckldq m0, m8 + punpckhdq m3, m2, m9 + punpckldq m2, m9 + punpckhdq m5, m4, m14 + punpckldq m4, m14 + punpckhdq m7, m6, m11 + punpckldq m6, m11 +.pass1_end: + vshufi32x4 m8, m4, m6, q3232 + vinserti32x8 m4, ym6, 1 + vshufi32x4 m6, m0, m2, q3232 + vinserti32x8 m0, ym2, 1 + vshufi32x4 m9, m5, m7, q3232 + vinserti32x8 m5, ym7, 1 + vshufi32x4 m7, m1, m3, q3232 + vinserti32x8 m1, ym3, 1 + vshufi32x4 m2, m0, m4, q3131 ; 4 5 + vshufi32x4 m0, m4, q2020 ; 0 1 + vshufi32x4 m4, m6, m8, q2020 ; 8 9 + vshufi32x4 m6, m8, q3131 ; 12 13 + vshufi32x4 m3, m1, m5, q3131 ; 6 7 + vshufi32x4 m1, m5, q2020 ; 2 3 + vshufi32x4 m5, m7, m9, q2020 ; 10 11 + vshufi32x4 m7, m9, q3131 ; 14 1 + jmp tx2q +.pass1_fast: + mova ym3, [o(dup16_perm)] + vbroadcasti32x4 ym9, [cq+32*0] + vbroadcasti32x4 ym6, [cq+32*4] + vpermb ym8, ym3, [cq+32*1] + vpermb ym0, ym3, [cq+32*7] + vpermb ym5, ym3, [cq+32*5] + vpermb ym1, ym3, [cq+32*3] + vpermb ym7, ym3, [cq+32*2] + vpermb ym3, ym3, [cq+32*6] + shufpd ym9, ym9, 0x0c + shufpd ym6, ym6, 0x0c + WRAP_YMM IDCT16_MAIN + vbroadcasti32x4 m8, [o(int_shuf1)] + vbroadcasti32x4 m9, [o(int_shuf2)] + vinserti32x8 m0, ym2, 1 ; 0 1 | 4 5 + vinserti32x8 m4, ym6, 1 ; 8 9 | 12 13 + vinserti32x8 m1, ym3, 1 ; 3 2 | 7 6 + vinserti32x8 m5, ym7, 1 ; 11 10 | 15 14 + vshufi32x4 m2, m0, m4, q3131 + vshufi32x4 m0, m4, q2020 + vshufi32x4 m4, m1, m5, q2020 + vshufi32x4 m1, m5, q3131 + pshufb m2, m8 + pshufb m0, m8 + pshufb m4, m9 + pshufb m1, m9 + punpckhdq m3, m2, m1 ; 6-7 + punpckldq m2, m1 ; 4-5 + punpckhdq m1, m0, m4 ; 2-3 + punpckldq m0, m4 ; 0-1 + jmp tx2q +.pass2: + test eobd, eobd + jl .pass2_fast + call .main + jmp .pass2_end +.pass2_fast: + punpcklqdq m9, m0, m0 + punpckhwd m8, m0, m0 + punpcklwd m7, m1, m1 + punpckhwd m1, m1 + punpcklqdq m6, m2, m2 + punpckhwd m5, m2, m2 + punpckhwd m0, m3, m3 + punpcklwd m3, m3 + call .main_fast +.pass2_end: + psrldq m8, m15, 1 + psrlq m12, m15, 12 + psrldq m9, m15, 2 + psrlq m13, m15, 20 + mova m10, m8 + vpermi2q m8, m0, m2 ; 0 1 4 5 + vpermt2q m0, m12, m2 + mova m11, m9 + vpermi2q m9, m1, m3 ; 2 3 6 7 + vpermt2q m1, m13, m3 + vpbroadcastd m2, [o(pw_512)] + vpermi2q m10, m4, m6 ; 8 9 12 13 + vpermt2q m4, m12, m6 + vpermi2q m11, m5, m7 ; 10 11 14 15 + vpermt2q m5, m13, m7 + REPX {pmulhrsw x, m2}, m0, m1, m4, m5, m8, m9, m10, m11 +.pass2_end2: + lea r3, [strideq*3] + lea r4, [dstq+strideq*4] + lea r5, [dstq+strideq*8] + lea r6, [r4 +strideq*8] + mova xm3, [dstq+strideq*0] + mova xm6, [dstq+strideq*2] + vinserti32x4 ym3, [dstq+strideq*1], 1 + vinserti32x4 ym6, [dstq+r3 ], 1 + vinserti32x4 m3, [r4+strideq*0], 2 + vinserti32x4 m6, [r4+strideq*2], 2 + vinserti32x4 m3, [r4+strideq*1], 3 + vinserti32x4 m6, [r4+r3 ], 3 + mova xm12, [r5+strideq*0] + mova xm13, [r5+strideq*2] + vinserti32x4 ym12, [r5+strideq*1], 1 + vinserti32x4 ym13, [r5+r3 ], 1 + vinserti32x4 m12, [r6+strideq*0], 2 + vinserti32x4 m13, [r6+strideq*2], 2 + vinserti32x4 m12, [r6+strideq*1], 3 + vinserti32x4 m13, [r6+r3 ], 3 + pxor m7, m7 + REPX {mova [cq+64*x], m7}, 0, 1, 2, 3, 4, 5, 6, 7 + punpcklbw m2, m3, m7 + punpckhbw m3, m7 + paddw m0, m2 + paddw m8, m3 + packuswb m0, m8 + punpcklbw m2, m6, m7 + punpckhbw m6, m7 + paddw m1, m2 + paddw m9, m6 + packuswb m1, m9 + punpcklbw m2, m12, m7 + punpckhbw m12, m7 + paddw m2, m4 + paddw m10, m12 + packuswb m2, m10 + punpcklbw m3, m13, m7 + punpckhbw m13, m7 + paddw m3, m5 + paddw m11, m13 + packuswb m3, m11 + mova [dstq+strideq*0], xm0 + vextracti32x4 [dstq+strideq*1], ym0, 1 + mova [dstq+strideq*2], xm1 + vextracti32x4 [dstq+r3 ], ym1, 1 + vextracti32x4 [r4+strideq*0], m0, 2 + vextracti32x4 [r4+strideq*1], m0, 3 + vextracti32x4 [r4+strideq*2], m1, 2 + vextracti32x4 [r4+r3 ], m1, 3 + mova [r5+strideq*0], xm2 + vextracti32x4 [r5+strideq*1], ym2, 1 + mova [r5+strideq*2], xm3 + vextracti32x4 [r5+r3 ], ym3, 1 + vextracti32x4 [r6+strideq*0], m2, 2 + vextracti32x4 [r6+strideq*1], m2, 3 + vextracti32x4 [r6+strideq*2], m3, 2 + vextracti32x4 [r6+r3 ], m3, 3 + RET +ALIGN function_align + IDCT16_MAIN + ret + +%macro IADST16_MAIN 0 +%if mmsize == 64 +.main_fast: +%endif + punpcklwd m4, m3, m0 ; in7 in0 + punpcklwd m11, m1, m2 ; in3 in4 + punpckhwd m9, m2, m1 ; in5 in2 + punpckhwd m7, m0, m3 ; in1 in6 + ITX_MUL2X_PACK 4, 0, 6, 10, 11003_804, 12140_m16364, 116 ; t1a t0a + ITX_MUL2X_PACK 4, 5, 6, 10, m11003_804, m12140_m16364, 52 ; t9a t8a + ITX_MUL2X_PACK 11, 2, 6, 10, 5520_7005, 15426_m14811, 116 ; t5a t4a + ITX_MUL2X_PACK 11, 5, 6, 10, m5520_7005, m15426_m14811, 52 ; t13a t12a + ITX_MUL2X_PACK 9, 1, 6, 10, 8423_3981, 14053_m15893, 116 ; t3a t2a + ITX_MUL2X_PACK 9, 5, 6, 10, m8423_3981, m14053_m15893, 52 ; t11a t10a + ITX_MUL2X_PACK 7, 3, 6, 10, 2404_9760, 16207_m13160, 116 ; t7a t6a + ITX_MUL2X_PACK 7, 5, 6, 10, m2404_9760, m16207_m13160, 52 ; t15a t14a +%if mmsize == 64 ; for the ymm variant we only ever use the fast path + jmp %%main2 +ALIGN function_align +.main: + punpckhwd m8, m7, m0 ; in14 in1 + punpcklwd m0, m7 ; in0 in15 + punpcklwd m7, m6, m1 ; in12 in3 + punpckhwd m1, m6 ; in2 in13 + punpckhwd m6, m5, m2 ; in10 in5 + punpcklwd m2, m5 ; in4 in11 + punpcklwd m5, m4, m3 ; in8 in7 + punpckhwd m3, m4 ; in6 in9 + ADST_MULSUB_4W 0, 5, 4, 9, 11, 10, 804, 16364, 12140, 11003 ; t1a t0a, t9a t8a + ADST_MULSUB_4W 2, 7, 11, 5, 9, 10, 7005, 14811, 15426, 5520 ; t5a t4a, t13a t12a + ADST_MULSUB_4W 1, 6, 9, 5, 7, 10, 3981, 15893, 14053, 8423 ; t3a t2a, t11a t10a + ADST_MULSUB_4W 3, 8, 7, 5, 6, 10, 9760, 13160, 16207, 2404 ; t7a t6a, t15a t14a +%%main2: +%endif + psubw m5, m1, m3 ; t7 t6 + paddw m6, m1, m3 ; t3 t2 + psubw m1, m0, m2 ; t5 t4 + paddw m2, m0 ; t1 t0 + ADST_MULSUB_4W 4, 11, 8, 3, 0, 10, 3196, 16069, 16069, 3196, 1 ; t8a t9a, t12a t13a + ADST_MULSUB_4W 9, 7, 0, 3, 11, 10, 13623, 9102, 9102, 13623, 1 ; t10a t11a, t14a t15a + ADST_MULSUB_4W 1, 5, 11, 3, 7, 10, 6270, 15137, 15137, 6270, 2 ; out12 -out3, t7 t6 + psubw m3, m2, m6 ; t3a t2a + paddw m2, m6 ; -out15 out0 + ADST_MULSUB_4W 8, 0, 5, 6, 7, 10, 15137, 6270, 6270, 15137, 6 ; -out13 out2, t15a t14 + vbroadcasti32x4 m12, [o(deint_shuf)] + paddw m0, m4, m9 ; -out1 out14 + psubw m4, m9 ; t10 t11 + pshufb m2, m12 + pshufb m1, m12 + pshufb m8, m12 + pshufb m0, m12 + punpcklqdq m6, m1, m8 ; out12 -out13 + shufps m7, m0, m2, q1032 ; out14 -out15 +%endmacro + +%macro IADST16_PASS1_END 0 + shufps m0, m2, m0, q1032 ; out0 -out1 + punpckhqdq m1, m8, m1 ; out2 -out3 + mova m2, m10 + vpdpwssd m2, m5, [o(pw_m11585_m11585)] {bcstd} ; out5 + mova m8, m10 + vpdpwssd m8, m11, [o(pw_11585_11585)] {bcstd} ; out4 + mova m9, m10 + vpdpwssd m9, m5, [o(pw_m11585_11585)] {bcstd} ; out10 + mova m5, m10 + vpdpwssd m5, m11, [o(pw_11585_m11585)] {bcstd} ; out11 + mova m11, m10 + vpdpwssd m11, m3, [o(pw_m11585_m11585)] {bcstd} ; out7 + mova m14, m10 + vpdpwssd m14, m4, [o(pw_11585_11585)] {bcstd} ; out6 + mova m12, m10 + vpdpwssd m12, m3, [o(pw_m11585_11585)] {bcstd} ; out8 + mova m3, m10 + vpdpwssd m3, m4, [o(pw_m11585_11585)] {bcstd} ; out9 +%endmacro + +INV_TXFM_16X16_FN adst, dct, 39-18 +INV_TXFM_16X16_FN adst, adst + +cglobal vp9_iadst_16x16_internal, 0, 5, 16, dst, stride, c, eob, tx2 + mova m15, [o(itx_perm)] + psrlq m7, m15, 4 + vpermq m0, m15, [cq+64*0] ; 0 1 + vpermq m1, m7, [cq+64*1] ; 3 2 + vpermq m2, m15, [cq+64*2] ; 4 5 + vpermq m3, m7, [cq+64*3] ; 7 6 + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + vpcmpub k7, m13, m10, 6 + sub eobd, 39 + jl .pass1_fast + vpermq m4, m15, [cq+64*4] ; 8 9 + vpermq m5, m7, [cq+64*5] ; 11 10 + vpermq m6, m15, [cq+64*6] ; 12 13 + vpermq m7, m7, [cq+64*7] ; 15 14 + call .main + IADST16_PASS1_END + REPX {psrad x, 14}, m2, m8, m9, m5, m11, m14, m12, m3 + packssdw m2, m8, m2 ; out4 out5 + packssdw m5, m9, m5 ; out10 out11 + packssdw m4, m12, m3 ; out8 out9 + packssdw m3, m14, m11 ; out6 out7 + pxor m9, m9 + punpckhwd m8, m0, m1 + punpcklwd m0, m1 + psubw m8, m9, m8 + punpckhwd m1, m0, m8 + punpcklwd m0, m8 + punpckhwd m8, m2, m3 + punpcklwd m2, m3 + punpckhwd m3, m2, m8 + punpcklwd m2, m8 + punpckhwd m8, m4, m5 + punpcklwd m4, m5 + punpckhwd m5, m4, m8 + punpcklwd m4, m8 + punpckhwd m8, m6, m7 + punpcklwd m6, m7 + psubw m8, m9, m8 + punpckhwd m7, m6, m8 + punpcklwd m6, m8 + jmp m(vp9_idct_16x16_internal).pass1_end +.pass1_fast: + WRAP_YMM IADST16_MAIN + WRAP_YMM IADST16_PASS1_END + vinserti32x8 m0, ym6, 1 + vinserti32x8 m1, ym7, 1 + vinserti32x8 m8, ym12, 1 + vinserti32x8 m2, ym3, 1 + vinserti32x8 m14, ym9, 1 + vinserti32x8 m11, ym5, 1 + pslld m14, 2 + pslld m11, 2 + punpckhwd m4, m0, m1 + punpcklwd m0, m1 + vpmultishiftqb m14{k7}, m13, m8 + vpmultishiftqb m11{k7}, m13, m2 + psrlq m1, m15, 24 + pxor m2, m2 + psubw m2, m4 + punpckhwd m3, m0, m2 + punpcklwd m0, m2 + psrlq m2, m15, 28 + punpckhwd m4, m14, m11 + punpcklwd m14, m11 + mova m5, m2 + vpermi2q m2, m0, m14 + vpermt2q m0, m1, m14 + vpermi2q m1, m3, m4 + vpermt2q m3, m5, m4 + jmp tx2q +.pass2: + pshufd m1, m1, q1032 + pshufd m3, m3, q1032 + test eobd, eobd + jl .pass2_fast + pshufd m5, m5, q1032 + pshufd m7, m7, q1032 + call .main + jmp .pass2_end +.pass2_fast: + call .main_fast +.pass2_end: + vbroadcasti32x4 m9, [o(pw_11585_m11585x2x4)] + vbroadcasti32x4 m10, [o(pw_m11585_11585x2x4)] + punpckhqdq m1, m8 ; -out3 out2 + shufps m0, m2, q3210 ; -out1 out0 + pshufb m2, m11, m12 + pshufb m5, m12 + pshufb m3, m12 + pshufb m4, m12 + vbroadcasti32x4 m11, [o(pw_512)] + vpbroadcastd m12, [o(pw_512)] + punpcklqdq m8, m5, m2 ; t15a t7 + punpckhqdq m5, m2 ; t14a t6 + shufps m2, m3, m4, q1032 ; t2a t10 + shufps m3, m4, q3210 ; t3a t11 + psubsw m4, m2, m3 + paddsw m3, m2 + paddsw m2, m5, m8 + psubsw m5, m8 + pmulhrsw m4, m9 ; out8 out9 + pmulhrsw m3, m10 ; out7 out6 + pmulhrsw m2, m10 ; out5 out4 + pmulhrsw m5, m9 ; out10 out11 + pmulhrsw m6, m11 + pmulhrsw m7, m11 + pshufd m11, m11, q1032 + pmulhrsw m0, m11 + pmulhrsw m1, m11 + REPX {pmulhrsw x, m12}, m2, m3, m4, m5 + psrldq m8, m15, 2 + psrlq m12, m15, 20 + psrldq m10, m15, 1 + psrlq m13, m15, 12 + mova m9, m8 + vpermi2q m8, m0, m2 ; 0 1 4 5 + vpermt2q m0, m12, m2 + vpermi2q m9, m1, m3 ; 2 3 6 7 + vpermt2q m1, m12, m3 + mova m11, m10 + vpermi2q m10, m4, m6 ; 8 9 12 13 + vpermt2q m4, m13, m6 + vpermi2q m11, m5, m7 ; 10 11 14 15 + vpermt2q m5, m13, m7 + jmp m(vp9_idct_16x16_internal).pass2_end2 +ALIGN function_align + IADST16_MAIN + ret + +%macro IDCT_32x32_END 4 ; src, mem, stride[1-2] + pmovzxbw m10, [dstq+%3] + pmovzxbw m11, [r3 +%4] +%if %2 < 8 + paddw m8, m%2, m%1 + psubw m9, m%2, m%1 +%else + mova m9, [rsp+64*(%2-8)] + paddw m8, m9, m%1 + psubw m9, m%1 +%endif + pmulhrsw m8, m12 + pmulhrsw m9, m12 + paddw m8, m10 + paddw m9, m11 + packuswb m8, m9 + vpermq m8, m13, m8 + mova [dstq+%3], ym8 + vextracti32x8 [r3 +%4], m8, 1 +%if %2 == 3 || %2 == 7 || %2 == 11 + add dstq, r5 + sub r3, r5 +%endif +%endmacro + +cglobal vp9_idct_idct_32x32_add, 4, 7, 0, dst, stride, c, eob +%undef cmp + lea r6, [o_base] + cmp eobd, 1 + jne .pass1 + movd xmm0, [o(pw_11585x2)] + pmulhrsw xmm3, xmm0, [cq] + pxor m2, m2 + pmulhrsw xmm3, xmm0 + pmulhrsw xmm3, [o(pw_512)] + movd [cq], xm2 + add r3d, 15 + vpbroadcastw m3, xmm3 +.dconly_loop: + mova ym1, [dstq+strideq*0] + vinserti32x8 m1, [dstq+strideq*1], 1 + punpcklbw m0, m1, m2 + punpckhbw m1, m2 + paddw m0, m3 + paddw m1, m3 + packuswb m0, m1 + mova [dstq+strideq*0], ym0 + vextracti32x8 [dstq+strideq*1], m0, 1 + lea dstq, [dstq+strideq*2] + dec r3d + jg .dconly_loop + RET +.pass1: + PROLOGUE 0, 7, 30, 64*16, dst, stride, c, eob + sub eobd, 135 + jl .fast + mova m0, [cq+64* 0] + mova m14, [cq+64* 2] + mova m1, [cq+64* 4] + mova m15, [cq+64* 6] + mova m2, [cq+64* 8] + mova m16, [cq+64*10] + mova m3, [cq+64*12] + mova m17, [cq+64*14] + mova m4, [cq+64*16] + mova m18, [cq+64*18] + mova m5, [cq+64*20] + mova m19, [cq+64*22] + mova m6, [cq+64*24] + mova m20, [cq+64*26] + mova m7, [cq+64*28] + mova m21, [cq+64*30] + call .idct16 + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + mova m22, [cq+64* 1] + mova m23, [cq+64* 3] + mova m24, [cq+64* 5] + mova m25, [cq+64* 7] + mova m26, [cq+64* 9] + mova m27, [cq+64*11] + mova m28, [cq+64*13] + mova m29, [cq+64*15] + mova m14, [cq+64*17] + mova m15, [cq+64*19] + mova m16, [cq+64*21] + mova m17, [cq+64*23] + mova m18, [cq+64*25] + mova m19, [cq+64*27] + mova m20, [cq+64*29] + mova m21, [cq+64*31] + call .main + psubw m13, m0, m29 ; 31 + paddw m0, m29 ; 0 + psubw m29, m1, m28 ; 30 + paddw m1, m28 ; 1 + psubw m28, m2, m27 ; 29 + paddw m2, m27 ; 2 + psubw m27, m3, m26 ; 28 + paddw m3, m26 ; 3 + psubw m26, m4, m25 ; 27 + paddw m4, m25 ; 4 + psubw m25, m5, m24 ; 26 + paddw m5, m24 ; 5 + psubw m24, m6, m23 ; 25 + paddw m6, m23 ; 6 + psubw m23, m7, m22 ; 24 + paddw m7, m22 ; 7 + punpckhwd m8, m0, m1 ; a4 b4 a5 b5 a6 b6 a7 b7 + punpcklwd m0, m1 ; a0 b0 a1 b1 a2 b2 a3 b3 + punpckhwd m1, m2, m3 ; c4 d4 c5 d5 c6 d6 c7 d7 + punpcklwd m2, m3 ; c0 d0 c1 d1 c2 d2 c3 d3 + punpckhwd m22, m4, m5 ; e4 f4 e5 f5 e6 f6 e7 f7 + punpcklwd m4, m5 ; e0 f0 e1 f1 e2 f2 e3 f3 + punpckhwd m5, m6, m7 ; g4 h4 g5 h5 g6 h6 g7 h7 + punpcklwd m6, m7 ; g0 h0 g1 h1 g2 h2 g3 h3 + punpckhwd m3, m23, m24 + punpcklwd m23, m24 + punpckhwd m24, m25, m26 + punpcklwd m25, m26 + punpckhwd m26, m27, m28 + punpcklwd m27, m28 + punpckhwd m28, m29, m13 + punpcklwd m29, m13 + punpckhdq m7, m0, m2 ; a2 b2 c2 d2 a3 b3 c3 d3 + punpckldq m0, m2 ; a0 b0 c0 d0 a1 b1 c1 d1 + punpckhdq m2, m4, m6 ; e2 f2 g2 h2 e3 f3 g3 h3 + punpckldq m4, m6 ; e0 f0 g0 h0 e1 f1 g1 h1 + punpckhdq m6, m8, m1 ; a6 b6 c6 d6 a7 b7 c7 d7 + punpckldq m8, m1 ; a4 b4 c4 d4 a5 b5 c5 d5 + punpckhdq m1, m22, m5 ; e6 f6 g6 h6 e7 f7 g7 h7 + punpckldq m22, m5 ; e4 f4 g4 h5 e5 f5 g5 h5 + punpckhdq m13, m23, m25 + punpckldq m23, m25 + punpckhdq m25, m27, m29 + punpckldq m27, m29 + punpckhdq m9, m3, m24 + punpckldq m3, m24 + punpckhdq m24, m26, m28 + punpckldq m26, m28 + punpcklqdq m5, m23, m27 ; d00 d08 d16 d24 + punpckhqdq m23, m27 ; d01 d09 d17 d25 + punpckhqdq m27, m13, m25 ; d03 d11 d19 d27 + punpcklqdq m13, m25 ; d02 d10 d18 d26 + punpckhqdq m25, m3, m26 ; d05 d13 d21 d29 + punpcklqdq m3, m26 ; d04 d12 d20 d28 + punpckhqdq m26, m9, m24 ; d07 d15 d23 d31 + punpcklqdq m9, m24 ; d06 d14 d22 d30 + mova [rsp+64*12], m23 + mova [rsp+64*13], m27 + mova [rsp+64*14], m25 + mova [rsp+64*15], m26 + punpckhqdq m24, m8, m22 ; a05 a13 a21 a29 + punpcklqdq m8, m22 ; a04 a12 a20 a28 + punpckhqdq m22, m0, m4 ; a01 a09 a17 a25 + punpcklqdq m0, m4 ; a00 a08 a16 a24 + punpckhqdq m23, m7, m2 ; a03 a11 a19 a27 + punpcklqdq m7, m2 ; a02 a10 a18 a26 + punpckhqdq m25, m6, m1 ; a07 a15 a23 a31 + punpcklqdq m6, m1 ; a06 a14 a22 a30 + mova m2, [rsp+64*0] + mova m11, [rsp+64*1] + mova m12, [rsp+64*2] + mova m29, [rsp+64*3] + mova m27, [rsp+64*4] + mova m26, [rsp+64*5] + mova m4, [rsp+64*6] + mova m28, [rsp+64*7] + psubw m1, m2, m21 ; 23 + paddw m2, m21 ; 8 + psubw m21, m11, m20 ; 22 + paddw m11, m20 ; 9 + psubw m20, m12, m19 ; 21 + paddw m12, m19 ; 10 + psubw m19, m29, m18 ; 20 + paddw m29, m18 ; 11 + psubw m18, m27, m17 ; 19 + paddw m27, m17 ; 12 + psubw m17, m26, m16 ; 18 + paddw m26, m16 ; 13 + paddw m16, m4, m15 ; 14 + psubw m4, m15 ; 17 + mova m15, m6 + psubw m6, m28, m14 ; 16 + paddw m28, m14 ; 15 + mova m14, m7 + punpcklwd m7, m6, m4 + punpckhwd m6, m4 + punpckhwd m4, m17, m18 + punpcklwd m17, m18 + punpckhwd m18, m19, m20 + punpcklwd m19, m20 + punpckhwd m20, m21, m1 + punpcklwd m21, m1 + punpckhwd m1, m2, m11 ; i4 j4 i5 j5 i6 j6 i7 j7 + punpcklwd m2, m11 ; i0 j1 i1 j1 i2 j2 i3 j3 + punpckhwd m11, m12, m29 ; k4 l4 k5 l5 k6 l6 k7 l7 + punpcklwd m12, m29 ; k0 l0 k1 l1 k2 l2 k3 l3 + punpckhwd m29, m27, m26 ; m4 n4 m5 n5 m6 n6 m7 n7 + punpcklwd m27, m26 ; m0 n0 m1 n1 m2 n2 m3 n3 + punpckhwd m26, m16, m28 ; o4 p4 o5 p5 o6 p6 o7 p7 + punpcklwd m16, m28 ; o0 p0 o1 p1 o2 p2 o3 p3 + punpckhdq m28, m2, m12 ; i2 j2 k2 l2 i3 j3 k3 l3 + punpckldq m2, m12 ; i0 j0 k0 l0 i1 j1 k1 l1 + punpckhdq m12, m27, m16 ; m2 n2 o2 p2 m3 n3 o3 p3 + punpckldq m27, m16 ; m0 n0 o0 p0 m1 n1 o1 p1 + punpckhdq m16, m1, m11 ; i6 j6 k6 l6 i7 j7 k7 l7 + punpckldq m1, m11 ; i4 j4 k4 l4 i5 j5 k5 l5 + punpckhdq m11, m29, m26 ; m6 n6 o6 p6 m7 n7 o7 p7 + punpckldq m29, m26 ; m4 n4 o4 p4 m5 n5 o5 p5 + punpckhdq m26, m19, m21 + punpckldq m19, m21 + punpckhdq m21, m6, m4 + punpckldq m6, m4 + punpckhdq m4, m18, m20 + punpckldq m18, m20 + punpckhdq m20, m7, m17 + punpckldq m7, m17 + punpcklqdq m17, m28, m12 ; b02 b10 b18 b26 + punpckhqdq m28, m12 ; b03 b11 b19 b27 + punpckhqdq m12, m2, m27 ; b01 b09 b17 b25 + punpcklqdq m2, m27 ; b00 b08 b16 b24 + punpckhqdq m27, m1, m29 ; b05 b13 b21 b29 + punpcklqdq m1, m29 ; b04 b12 b20 b28 + punpckhqdq m29, m16, m11 ; b07 b15 b23 b31 + punpcklqdq m16, m11 ; b06 b14 b22 b30 + mova [rsp+64* 8], m12 + mova [rsp+64* 9], m28 + mova [rsp+64*10], m27 + mova [rsp+64*11], m29 + punpckhqdq m27, m20, m26 ; c03 c11 c19 c27 + punpcklqdq m20, m26 ; c02 c10 c18 c26 + punpckhqdq m26, m7, m19 ; c01 c09 c17 c25 + punpcklqdq m7, m19 ; c00 c08 c16 c24 + punpckhqdq m28, m6, m18 ; c05 c13 c21 c29 + punpcklqdq m6, m18 ; c04 c12 c20 c28 + punpckhqdq m29, m21, m4 ; c07 c15 c23 c31 + punpcklqdq m21, m4 ; c06 c14 c22 c30 + mov r3d, 64*28 + pxor m4, m4 +.zero_loop: + mova [cq+r3+64*0], m4 + mova [cq+r3+64*1], m4 + mova [cq+r3+64*2], m4 + mova [cq+r3+64*3], m4 + sub r3d, 64*4 + jge .zero_loop + vshufi32x4 m4, m0, m2, q3232 ; a16 a24 b16 b24 + vinserti32x8 m0, ym2, 1 ; a00 a08 b00 b08 + vshufi32x4 m2, m7, m5, q3232 ; c16 c24 d16 d24 + vinserti32x8 m7, ym5, 1 ; c00 c08 d00 d08 + vshufi32x4 m5, m8, m1, q3232 ; a20 a28 b20 b28 + vinserti32x8 m1, m8, ym1, 1 ; a04 a12 b04 b12 + vshufi32x4 m8, m6, m3, q3232 ; c20 c28 d20 d28 + vinserti32x8 m6, ym3, 1 ; c04 c12 d04 d12 + vshufi32x4 m3, m1, m6, q3131 ; 12 + vshufi32x4 m1, m6, q2020 ; 4 + vshufi32x4 m6, m4, m2, q3131 ; 24 + vshufi32x4 m4, m2, q2020 ; 16 + vshufi32x4 m2, m0, m7, q3131 ; 8 + vshufi32x4 m0, m7, q2020 ; 0 + vshufi32x4 m7, m5, m8, q3131 ; 28 + vshufi32x4 m5, m8, q2020 ; 20 + vshufi32x4 m18, m14, m17, q3232 ; a18 a26 b18 b26 + vinserti32x8 m14, ym17, 1 ; a02 a10 b02 b10 + vshufi32x4 m17, m20, m13, q3232 ; c18 c26 d18 d26 + vinserti32x8 m20, ym13, 1 ; c02 c10 d02 d10 + vshufi32x4 m13, m21, m9, q3232 ; c22 c30 d22 d30 + vinserti32x8 m21, ym9, 1 ; c06 c14 d06 d14 + vshufi32x4 m19, m15, m16, q3232 ; a22 a30 b22 b30 + vinserti32x8 m15, ym16, 1 ; a06 a14 b06 b14 + vshufi32x4 m16, m14, m20, q3131 ; 10 + vshufi32x4 m14, m20, q2020 ; 2 + vshufi32x4 m20, m18, m17, q3131 ; 26 + vshufi32x4 m18, m17, q2020 ; 18 + vshufi32x4 m17, m15, m21, q3131 ; 14 + vshufi32x4 m15, m21, q2020 ; 6 + vshufi32x4 m21, m19, m13, q3131 ; 30 + vshufi32x4 m19, m13, q2020 ; 22 + call .idct16 + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + mova m15, [rsp+64* 8] + mova m16, [rsp+64* 9] + mova m17, [rsp+64*10] + mova m19, [rsp+64*11] + mova m20, [rsp+64*12] + mova m21, [rsp+64*13] + mova m13, [rsp+64*14] + mova m18, [rsp+64*15] + vshufi32x4 m14, m22, m15, q3232 ; a17 a25 b17 b25 + vinserti32x8 m22, ym15, 1 ; a01 a09 b01 b09 + vshufi32x4 m15, m23, m16, q3232 ; a19 a27 b19 b27 + vinserti32x8 m23, ym16, 1 ; a03 a11 b03 b11 + vshufi32x4 m16, m24, m17, q3232 ; a21 a29 b21 b29 + vinserti32x8 m24, ym17, 1 ; a05 a13 b05 b13 + vshufi32x4 m17, m25, m19, q3232 ; a23 a31 b23 b31 + vinserti32x8 m25, ym19, 1 ; a07 a15 b07 b15 + vinserti32x8 m8, m26, ym20, 1 ; c01 c09 d01 d09 + vshufi32x4 m26, m20, q3232 ; c17 c25 d17 d25 + vinserti32x8 m9, m27, ym21, 1 ; c03 c11 d03 d11 + vshufi32x4 m27, m21, q3232 ; c19 c27 d19 d27 + vinserti32x8 m11, m28, ym13, 1 ; c05 c13 d05 d13 + vshufi32x4 m28, m13, q3232 ; c21 c29 d21 d29 + vinserti32x8 m12, m29, ym18, 1 ; c07 c15 d07 d15 + vshufi32x4 m29, m18, q3232 ; c23 c31 d23 d31 + vshufi32x4 m18, m14, m26, q3131 ; 25 + vshufi32x4 m14, m26, q2020 ; 17 + vshufi32x4 m19, m15, m27, q3131 ; 27 + vshufi32x4 m15, m27, q2020 ; 19 + vshufi32x4 m20, m16, m28, q3131 ; 29 + vshufi32x4 m16, m28, q2020 ; 21 + vshufi32x4 m21, m17, m29, q3131 ; 31 + vshufi32x4 m17, m29, q2020 ; 23 + vshufi32x4 m26, m22, m8, q3131 ; 9 + vshufi32x4 m22, m8, q2020 ; 1 + vshufi32x4 m27, m23, m9, q3131 ; 11 + vshufi32x4 m23, m9, q2020 ; 3 + vshufi32x4 m28, m24, m11, q3131 ; 13 + vshufi32x4 m24, m11, q2020 ; 5 + vshufi32x4 m29, m25, m12, q3131 ; 15 + vshufi32x4 m25, m12, q2020 ; 7 + call .main + jmp .end +.fast: + mova m14, [o(dup16_perm)] + pmovzxbw m9, [cq+64*0] + pmovzxbw m6, [cq+64*8] + vpermb m8, m14, [cq+64* 2] + vpermb m0, m14, [cq+64*14] + vpermb m5, m14, [cq+64*10] + vpermb m1, m14, [cq+64* 6] + vpermb m7, m14, [cq+64* 4] + vpermb m3, m14, [cq+64*12] + vpbroadcastd m10, [o(pd_8192)] + vpbroadcastq m13, [o(int_mshift)] + packuswb m9, m9 + packuswb m6, m6 + vpcmpub k7, m13, m10, 6 + IDCT16_MAIN 1 + vpermb m21, m14, [cq+64* 1] + vpermb m17, m14, [cq+64*15] + vpermb m20, m14, [cq+64* 9] + vpermb m15, m14, [cq+64* 7] + vpermb m18, m14, [cq+64* 5] + vpermb m16, m14, [cq+64*11] + vpermb m19, m14, [cq+64*13] + vpermb m14, m14, [cq+64* 3] + call .main_packed_fast + punpcklwd m8, m0, m2 + punpckhwd m0, m2 + punpcklwd m2, m1, m3 + punpckhwd m1, m3 + punpcklwd m3, m4, m6 + punpckhwd m4, m6 + punpcklwd m6, m5, m7 + punpckhwd m5, m7 + punpcklwd m7, m14, m16 + punpckhwd m14, m16 + punpcklwd m16, m15, m17 + punpckhwd m15, m17 + punpcklwd m17, m19, m21 + punpckhwd m19, m21 + punpckhwd m21, m18, m20 + punpcklwd m18, m20 + punpcklwd m20, m8, m1 + punpckhwd m8, m1 + punpcklwd m1, m0, m2 + punpckhwd m0, m2 + punpcklwd m2, m3, m5 + punpckhwd m3, m5 + punpcklwd m5, m4, m6 + punpckhwd m4, m6 + punpcklwd m6, m7, m15 + punpckhwd m7, m15 + punpcklwd m15, m14, m16 + punpckhwd m14, m16 + punpckhwd m16, m18, m19 + punpcklwd m18, m19 + punpcklwd m19, m21, m17 + punpckhwd m21, m17 + punpcklwd m17, m8, m0 ; a2 a6 aa ae + punpckhwd m8, m0 ; a3 a7 ab af + punpcklwd m0, m20, m1 ; a0 a4 a8 ac + punpckhwd m20, m1 ; a1 a5 a9 ad + punpcklwd m1, m2, m5 ; b0 b4 b8 bc + punpckhwd m2, m5 ; b1 b5 b9 bd + punpcklwd m5, m3, m4 ; b2 b6 ba be + punpckhwd m3, m4 ; b3 b7 bb bf + punpcklwd m4, m6, m15 ; c0 c4 c8 cc + punpckhwd m6, m15 ; c1 c5 c9 cd + punpcklwd m15, m7, m14 ; c2 c6 ca ce + punpckhwd m7, m14 ; c3 c7 cb cf + punpcklwd m14, m18, m19 ; d0 d4 d8 dc + punpckhwd m18, m19 ; d1 d5 d9 dd + punpcklwd m9, m16, m21 ; d2 d6 da de + punpckhwd m16, m21 ; d3 d7 db df + mov r3d, 64*12 + pxor ym21, ym21 +.fast_zero_loop: + mova [cq+r3+64*0], ym21 + mova [cq+r3+64*1], ym21 + mova [cq+r3+64*2], ym21 + mova [cq+r3+64*3], ym21 + sub r3d, 64*4 + jge .fast_zero_loop + vshufi32x4 m21, m0, m1, q3232 ; a8 ac b8 bc + vinserti32x8 m0, ym1, 1 ; a0 a4 b0 b4 + vinserti32x8 m1, m17, ym5, 1 ; a2 a6 b2 b6 + vshufi32x4 m5, m17, m5, q3232 ; aa ae ba be + vinserti32x8 m17, m8, ym3, 1 ; a3 a7 b3 b7 + vshufi32x4 m19, m8, m3, q3232 ; ab af bb bf + vinserti32x8 m3, m4, ym14, 1 ; c0 c4 d0 d4 + vshufi32x4 m4, m14, q3232 ; c8 cc d8 dc + vinserti32x8 m14, m20, ym2, 1 ; a1 a5 b1 b5 + vshufi32x4 m20, m2, q3232 ; a9 ad b9 bd + vinserti32x8 m2, m6, ym18, 1 ; c1 c5 d1 d5 + vshufi32x4 m6, m18, q3232 ; c9 cd d9 dd + vinserti32x8 m18, m15, ym9, 1 ; c2 c6 d2 d6 + vshufi32x4 m15, m9, q3232 ; ca ce da de + vinserti32x8 m9, m7, ym16, 1 ; c3 c7 d3 d7 + vshufi32x4 m7, m16, q3232 ; cb cf db df + vshufi32x4 m22, m14, m2, q2020 ; 1 + vshufi32x4 m24, m14, m2, q3131 ; 5 + vshufi32x4 m23, m17, m9, q2020 ; 3 + vshufi32x4 m25, m17, m9, q3131 ; 7 + vshufi32x4 m16, m5, m15, q2020 ; 10 + vshufi32x4 m17, m5, m15, q3131 ; 14 + vshufi32x4 m14, m1, m18, q2020 ; 2 + vshufi32x4 m15, m1, m18, q3131 ; 6 + vshufi32x4 m1, m0, m3, q3131 ; 4 + vshufi32x4 m0, m3, q2020 ; 0 + vshufi32x4 m3, m21, m4, q3131 ; 12 + vshufi32x4 m2, m21, m4, q2020 ; 8 + vshufi32x4 m26, m20, m6, q2020 ; 9 + vshufi32x4 m28, m20, m6, q3131 ; 13 + vshufi32x4 m27, m19, m7, q2020 ; 11 + vshufi32x4 m29, m19, m7, q3131 ; 15 + call .idct16_fast + mova [rsp+64*0], m14 + mova [rsp+64*1], m15 + mova [rsp+64*2], m16 + mova [rsp+64*3], m17 + mova [rsp+64*4], m18 + mova [rsp+64*5], m19 + mova [rsp+64*6], m20 + mova [rsp+64*7], m21 + call .main_fast +.end: + lea r4, [strideq*3] + vpbroadcastd m12, [o(pw_512)] + movshdup m13, [o(itx_perm)] + lea r3, [dstq+r4*8] + lea r5, [strideq+r4] ; stride*4 + add r3, r5 ; dst+stride*28 + IDCT_32x32_END 29, 0, strideq*0, r4 + IDCT_32x32_END 28, 1, strideq*1, strideq*2 + IDCT_32x32_END 27, 2, strideq*2, strideq*1 + IDCT_32x32_END 26, 3, r4 , strideq*0 + IDCT_32x32_END 25, 4, strideq*0, r4 + IDCT_32x32_END 24, 5, strideq*1, strideq*2 + IDCT_32x32_END 23, 6, strideq*2, strideq*1 + IDCT_32x32_END 22, 7, r4 , strideq*0 + IDCT_32x32_END 21, 8, strideq*0, r4 + IDCT_32x32_END 20, 9, strideq*1, strideq*2 + IDCT_32x32_END 19, 10, strideq*2, strideq*1 + IDCT_32x32_END 18, 11, r4 , strideq*0 + IDCT_32x32_END 17, 12, strideq*0, r4 + IDCT_32x32_END 16, 13, strideq*1, strideq*2 + IDCT_32x32_END 15, 14, strideq*2, strideq*1 + IDCT_32x32_END 14, 15, r4 , strideq*0 + RET +ALIGN function_align +.idct16_fast: + vpbroadcastd m21, [o(pw_16305x2)] + vpbroadcastd m8, [o(pw_1606x2)] + vpbroadcastd m18, [o(pw_m10394x2)] + vpbroadcastd m9, [o(pw_12665x2)] + pmulhrsw m21, m14 ; t15a + vpbroadcastd m19, [o(pw_14449x2)] + pmulhrsw m14, m8 ; t8a + vpbroadcastd m8, [o(pw_7723x2)] + pmulhrsw m18, m17 ; t9a + vpbroadcastd m20, [o(pw_m4756x2)] + pmulhrsw m17, m9 ; t14a + vpbroadcastd m9, [o(pw_15679x2)] + pmulhrsw m19, m16 ; t13a + vpbroadcastd m5, [o(pw_m9102x2)] + pmulhrsw m16, m8 ; t10a + vpbroadcastd m8, [o(pw_13623x2)] + pmulhrsw m20, m15 ; t11a + vpbroadcastd m7, [o(pw_16069x2)] + pmulhrsw m15, m9 ; t12a + vpbroadcastd m9, [o(pw_3196x2)] + pmulhrsw m5, m3 ; t5a + vpbroadcastd m6, [o(pw_15137x2)] + pmulhrsw m3, m8 ; t6a + vpbroadcastd m8, [o(pw_6270x2)] + pmulhrsw m7, m1 ; t7a + vpbroadcastd m4, [o(pw_11585x2)] + pmulhrsw m1, m9 ; t4 + vpbroadcastd m10, [o(pd_8192)] + pmulhrsw m6, m2 ; t3 + pmulhrsw m2, m8 ; t2 + pmulhrsw m4, m0 ; t0 + mova m0, m4 ; t1 + jmp .idct16b +ALIGN function_align +.idct16: + vpbroadcastd m10, [o(pd_8192)] + ITX_MULSUB_2W 14, 21, 8, 9, 10, 1606, 16305 ; t8a, t15a + ITX_MULSUB_2W 18, 17, 8, 9, 10, 12665, 10394 ; t9a, t14a + ITX_MULSUB_2W 16, 19, 8, 9, 10, 7723, 14449 ; t10a, t13a + ITX_MULSUB_2W 20, 15, 8, 9, 10, 15679, 4756 ; t11a, t12 + ITX_MULSUB_2W 5, 3, 8, 9, 10, 13623, 9102 ; t5a, t6a + ITX_MULSUB_2W 1, 7, 8, 9, 10, 3196, 16069 ; t4a, t7a + ITX_MULSUB_2W 2, 6, 8, 9, 10, 6270, 15137 ; t2, t3 + ITX_MULSUB_2W 0, 4, 8, 9, 10, 11585, 11585 ; t1, t0 +.idct16b: + paddw m8, m20, m16 ; t11 + psubw m20, m16 ; t10 + paddw m16, m15, m19 ; t12 + psubw m15, m19 ; t13 + psubw m19, m14, m18 ; t9 + paddw m14, m18 ; t8 + psubw m18, m21, m17 ; t14 + paddw m21, m17 ; t15 + vpbroadcastd m11, [o(pw_6270_15137)] + vpbroadcastd m12, [o(pw_m15137_6270)] + ITX_MULSUB_2W 18, 19, 9, 17, 10, 11, 12 ; t9a, t14a + vpbroadcastd m11, [o(pw_m6270_m15137)] + ITX_MULSUB_2W 15, 20, 9, 17, 10, 12, 11 ; t10a, t13a + vpbroadcastd m11, [o(pw_11585_11585)] + vpbroadcastd m12, [o(pw_m11585_11585)] + paddw m9, m7, m3 ; t7 + psubw m3, m7, m3 ; t6a + paddw m7, m1, m5 ; t4 + psubw m1, m5 ; t5a + psubw m17, m14, m8 ; t11a + paddw m8, m14 ; t8a + paddw m14, m18, m15 ; t9 + psubw m18, m15 ; t10 + psubw m15, m19, m20 ; t13 + paddw m19, m20 ; t14 + paddw m20, m21, m16 ; t15a + psubw m16, m21, m16 ; t12a + ITX_MULSUB_2W 3, 1, 5, 21, 10, 11, 12 ; t5, t6 + ITX_MULSUB_2W 15, 18, 5, 21, 10, 11, 12 ; t10a, t13a + ITX_MULSUB_2W 16, 17, 5, 21, 10, 11, 12 ; t11, t12 + psubw m5, m0, m2 ; t2 + paddw m2, m0 ; t1 + paddw m0, m4, m6 ; t0 + psubw m4, m6 ; t3 + psubw m6, m2, m1 ; t6 + paddw m1, m2 ; t1 + paddw m2, m5, m3 ; t2 + psubw m5, m3 ; t5 + paddw m3, m4, m7 ; t3 + psubw m4, m7 ; t4 + psubw m7, m0, m9 ; t7 + paddw m0, m9 ; t0 + psubw m21, m0, m20 ; out15 + paddw m0, m20 ; out0 + psubw m20, m1, m19 ; out14 + paddw m1, m19 ; out1 + psubw m19, m2, m18 ; out13 + paddw m2, m18 ; out2 + psubw m18, m3, m17 ; out12 + paddw m3, m17 ; out3 + psubw m17, m4, m16 ; out11 + paddw m4, m16 ; out4 + psubw m16, m5, m15 ; out10 + paddw m5, m15 ; out5 + psubw m15, m6, m14 ; out9 + paddw m6, m14 ; out6 + psubw m14, m7, m8 ; out8 + paddw m7, m8 ; out7 + ret +ALIGN function_align +.main_fast: + vpbroadcastd m21, [o(pw_16364x2)] + vpbroadcastd m8, [o(pw_804x2)] + vpbroadcastd m14, [o(pw_m11003x2)] + vpbroadcastd m9, [o(pw_12140x2)] + pmulhrsw m21, m22 ; t31a + vpbroadcastd m17, [o(pw_14811x2)] + pmulhrsw m22, m8 ; t16a + vpbroadcastd m8, [o(pw_7005x2)] + pmulhrsw m14, m29 ; t30a + vpbroadcastd m18, [o(pw_m5520x2)] + pmulhrsw m29, m9 ; t17a + vpbroadcastd m9, [o(pw_15426x2)] + pmulhrsw m17, m26 ; t29a + vpbroadcastd m19, [o(pw_15893x2)] + pmulhrsw m26, m8 ; t18a + vpbroadcastd m8, [o(pw_3981x2)] + pmulhrsw m18, m25 ; t19a + vpbroadcastd m16, [o(pw_m8423x2)] + pmulhrsw m25, m9 ; t28a + vpbroadcastd m9, [o(pw_14053x2)] + pmulhrsw m19, m24 ; t27a + vpbroadcastd m15, [o(pw_13160x2)] + pmulhrsw m24, m8 ; t20a + vpbroadcastd m8, [o(pw_9760x2)] + pmulhrsw m16, m27 ; t21a + vpbroadcastd m20, [o(pw_m2404x2)] + pmulhrsw m27, m9 ; t26a + vpbroadcastd m9, [o(pw_16207x2)] + pmulhrsw m15, m28 ; t25a + pmulhrsw m28, m8 ; t22a + pmulhrsw m20, m23 ; t23a + pmulhrsw m23, m9 ; t24a + jmp .main2 +ALIGN function_align +.main: + ITX_MULSUB_2W 22, 21, 8, 9, 10, 804, 16364 ; t16a, t31a + ITX_MULSUB_2W 14, 29, 8, 9, 10, 12140, 11003 ; t17a, t30a + ITX_MULSUB_2W 26, 17, 8, 9, 10, 7005, 14811 ; t18a, t29a + ITX_MULSUB_2W 18, 25, 8, 9, 10, 15426, 5520 ; t19a, t28a + ITX_MULSUB_2W 24, 19, 8, 9, 10, 3981, 15893 ; t20a, t27a + ITX_MULSUB_2W 16, 27, 8, 9, 10, 14053, 8423 ; t21a, t26a + ITX_MULSUB_2W 28, 15, 8, 9, 10, 9760, 13160 ; t22a, t25a + ITX_MULSUB_2W 20, 23, 8, 9, 10, 16207, 2404 ; t23a, t24a +.main2: + psubw m8, m22, m14 ; t17 + paddw m22, m14 ; t16 + paddw m14, m18, m26 ; t19 + psubw m18, m26 ; t18 + psubw m26, m24, m16 ; t21 + paddw m24, m16 ; t20 + psubw m16, m20, m28 ; t22 + paddw m28, m20 ; t23 + psubw m20, m23, m15 ; t25 + paddw m23, m15 ; t24 + psubw m15, m21, m29 ; t30 + paddw m21, m29 ; t31 + psubw m29, m19, m27 ; t26 + paddw m19, m27 ; t27 + paddw m27, m25, m17 ; t28 + psubw m25, m17 ; t29 + ITX_MULSUB_2W 15, 8, 9, 17, 10, 3196, 16069 ; t17a, t30a + ITX_MULSUB_2W 25, 18, 9, 17, 10, m16069, 3196 ; t18a, t29a + ITX_MULSUB_2W 29, 26, 9, 17, 10, 13623, 9102 ; t21a, t26a + ITX_MULSUB_2W 20, 16, 9, 17, 10, m9102, 13623 ; t22a, t25a + psubw m17, m21, m27 ; t28a + paddw m21, m27 ; t31a + psubw m27, m15, m25 ; t18 + paddw m15, m25 ; t17 + psubw m25, m20, m29 ; t21 + paddw m20, m29 ; t22 + psubw m29, m8, m18 ; t29 + paddw m8, m18 ; t30 + psubw m18, m22, m14 ; t19a + paddw m22, m14 ; t16a + psubw m14, m28, m24 ; t20a + paddw m24, m28 ; t23a + paddw m28, m16, m26 ; t25 + psubw m16, m26 ; t26 + psubw m26, m23, m19 ; t27a + paddw m23, m19 ; t24a + vpbroadcastd m12, [o(pw_m15137_6270)] + vpbroadcastd m11, [o(pw_6270_15137)] + ITX_MULSUB_2W 29, 27, 9, 19, 10, 11, 12 ; t18a, t29a + ITX_MULSUB_2W 17, 18, 9, 19, 10, 11, 12 ; t19, t28 + vpbroadcastd m11, [o(pw_m6270_m15137)] + ITX_MULSUB_2W 16, 25, 9, 19, 10, 12, 11 ; t21a, t26a + ITX_MULSUB_2W 26, 14, 9, 19, 10, 12, 11 ; t20, t27 + vpbroadcastd m12, [o(pw_m11585_11585)] + vpbroadcastd m11, [o(pw_11585_11585)] + psubw m19, m27, m25 ; t26 + paddw m27, m25 ; t29 + psubw m25, m17, m26 ; t20a + paddw m17, m26 ; t19a + paddw m26, m18, m14 ; t28a + psubw m18, m14 ; t27a + paddw m14, m22, m24 ; t16 + psubw m22, m24 ; t23 + psubw m24, m29, m16 ; t21 + paddw m16, m29 ; t18 + paddw m29, m21, m23 ; t31 + psubw m21, m23 ; t24 + psubw m23, m15, m20 ; t22a + paddw m15, m20 ; t17a + psubw m20, m8, m28 ; t25a + paddw m28, m8 ; t30a + ITX_MULSUB_2W 18, 25, 8, 9, 10, 11, 12 ; t20, t27 + ITX_MULSUB_2W 19, 24, 8, 9, 10, 11, 12 ; t21a, t26a + ITX_MULSUB_2W 21, 22, 8, 9, 10, 11, 12 ; t23a, t24a + ITX_MULSUB_2W 20, 23, 8, 9, 10, 11, 12 ; t22, t25 + ret +ALIGN function_align +.main_packed_fast: + vpbroadcastd m8, [o(pw_804_16364x2)] + vpbroadcastd m9, [o(pw_m11003_12140x2)] + vpbroadcastd m11, [o(pw_7005_14811x2)] + vpbroadcastd m12, [o(pw_m5520_15426x2)] + pmulhrsw m21, m8 ; t16a, t31a + vpbroadcastd m8, [o(pw_3981_15893x2)] + pmulhrsw m17, m9 ; t17a, t30a + vpbroadcastd m9, [o(pw_m8423_14053x2)] + pmulhrsw m20, m11 ; t18a, t29a + vpbroadcastd m11, [o(pw_9760_13160x2)] + pmulhrsw m15, m12 ; t19a, t28a + vpbroadcastd m12, [o(pw_m2404_16207x2)] + pmulhrsw m18, m8 ; t20a, t27a + pmulhrsw m16, m9 ; t21a, t26a + pmulhrsw m19, m11 ; t22a, t25a + pmulhrsw m14, m12 ; t23a, t24a + psubw m8, m21, m17 ; t17 t30 + paddw m21, m17 ; t16 t31 + psubw m17, m15, m20 ; t18 t29 + paddw m20, m15 ; t19 t28 + psubw m15, m18, m16 ; t21 t26 + paddw m18, m16 ; t20 t27 + psubw m16, m14, m19 ; t22 t25 + paddw m14, m19 ; t23 t24 + ITX_MUL2X_PACK 8, 9, 19, 10, 3196, 16069, 5 ; t17a t30a + ITX_MUL2X_PACK 17, 9, 19, 10, m16069, 3196, 5 ; t18a t29a + ITX_MUL2X_PACK 15, 9, 19, 10, 13623, 9102, 5 ; t21a t26a + ITX_MUL2X_PACK 16, 9, 19, 10, m9102, 13623, 5 ; t22a t25a + vpbroadcastd m11, [o(pw_m15137_6270)] + psubw m19, m21, m20 ; t19a t28a + paddw m21, m20 ; t16a t31a + psubw m20, m14, m18 ; t20a t27a + paddw m14, m18 ; t23a t24a + psubw m18, m8, m17 ; t18 t29 + paddw m8, m17 ; t17 t30 + psubw m17, m16, m15 ; t21 t26 + paddw m15, m16 ; t22 t25 + ITX_MUL2X_PACK 18, 9, 16, 10, 6270_15137, 11, 20 ; t18a t29a + ITX_MUL2X_PACK 19, 9, 16, 10, 6270_15137, 11, 20 ; t19 t28 + ITX_MUL2X_PACK 20, 9, 16, 10, 11, m6270_m15137, 36 ; t20 t27 + ITX_MUL2X_PACK 17, 9, 16, 10, 11, m6270_m15137, 36 ; t21a t26a + vbroadcasti32x4 m9, [o(deint_shuf)] + psubw m16, m21, m14 ; t23 t24 + paddw m14, m21 ; t16 t31 + psubw m21, m8, m15 ; t22a t25a + paddw m15, m8 ; t17a t30a + psubw m8, m18, m17 ; t21 t26 + paddw m18, m17 ; t18 t29 + paddw m17, m19, m20 ; t19a t28a + psubw m19, m20 ; t20a t27a + vpbroadcastd m11, [o(pw_m11585_11585)] + vpbroadcastd m12, [o(pw_11585_11585)] + REPX {pshufb x, m9}, m14, m15, m18, m17 + mova m9, m10 + vpdpwssd m9, m16, m11 + mova m20, m10 + vpdpwssd m20, m21, m11 + psrad m9, 14 + psrad m20, 14 + packssdw m9, m20 ; t23a t22 + mova m20, m10 + vpdpwssd m20, m16, m12 + mova m16, m10 + vpdpwssd m16, m21, m12 + psrad m20, 14 + psrad m16, 14 + packssdw m16, m20, m16 ; t24a t25 + ITX_MUL2X_PACK 8, 21, 20, 10, 11, 12, 8 ; t21a t26a + ITX_MUL2X_PACK 19, 8, 11, 10, 11, 12, 8 ; t20 t27 + packssdw m11, m20 ; t27 t26a + packssdw m8, m21 ; t20 t21a + punpcklqdq m20, m14, m15 ; t16 t17a + punpckhqdq m14, m15 ; t31 t30a + punpckhqdq m15, m17, m18 ; t28a t29 + punpcklqdq m17, m18 ; t19a t18 + psubw m21, m0, m14 ; out31 out30 + paddw m0, m14 ; out0 out1 + psubw m14, m7, m20 ; out16 out17 + paddw m7, m20 ; out15 out14 + psubw m20, m1, m15 ; out28 out29 + paddw m1, m15 ; out3 out2 + psubw m15, m6, m17 ; out19 out18 + paddw m6, m17 ; out12 out13 + psubw m17, m4, m9 ; out23 out22 + paddw m4, m9 ; out8 out9 + psubw m18, m3, m16 ; out24 out25 + paddw m3, m16 ; out7 out6 + psubw m16, m5, m8 ; out20 out21 + paddw m5, m8 ; out11 out10 + psubw m19, m2, m11 ; out27 out26 + paddw m2, m11 ; out4 out5 + ret + +%endif diff --git a/libavcodec/x86/vp9mc_16bpp.asm b/libavcodec/x86/vp9mc_16bpp.asm index 9a462eaf80..d86a89ccba 100644 --- a/libavcodec/x86/vp9mc_16bpp.asm +++ b/libavcodec/x86/vp9mc_16bpp.asm @@ -24,8 +24,7 @@ SECTION_RODATA 32 -pd_64: times 8 dd 64 - +cextern pd_64 cextern pw_1023 cextern pw_4095 diff --git a/libavcodec/x86/vvc/Makefile b/libavcodec/x86/vvc/Makefile index aa59aa59cf..c426b156c1 100644 --- a/libavcodec/x86/vvc/Makefile +++ b/libavcodec/x86/vvc/Makefile @@ -1,11 +1,13 @@ clean:: $(RM) $(CLEANSUFFIXES:%=libavcodec/x86/vvc/%) $(CLEANSUFFIXES:%=libavcodec/x86/h26x/%) -OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvcdsp_init.o \ +OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/dsp_init.o \ x86/h26x/h2656dsp.o -X86ASM-OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvc_alf.o \ - x86/vvc/vvc_dmvr.o \ - x86/vvc/vvc_mc.o \ - x86/vvc/vvc_of.o \ - x86/vvc/vvc_sad.o \ +X86ASM-OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/alf.o \ + x86/vvc/dmvr.o \ + x86/vvc/mc.o \ + x86/vvc/of.o \ + x86/vvc/sad.o \ + x86/vvc/sao.o \ + x86/vvc/sao_10bit.o \ x86/h26x/h2656_inter.o diff --git a/libavcodec/x86/vvc/vvc_alf.asm b/libavcodec/x86/vvc/alf.asm similarity index 99% rename from libavcodec/x86/vvc/vvc_alf.asm rename to libavcodec/x86/vvc/alf.asm index f69a69f05f..ccb236294a 100644 --- a/libavcodec/x86/vvc/vvc_alf.asm +++ b/libavcodec/x86/vvc/alf.asm @@ -44,8 +44,8 @@ CLASSIFY_SHUFFE: times 2 db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, TRANSPOSE_PERMUTE: dd 0, 1, 4, 5, 2, 3, 6, 7 ARG_VAR_SHUFFE: times 2 db 0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4 +cextern pd_64 dd448: times 8 dd 512 - 64 -dw64: times 8 dd 64 dd2: times 8 dd 2 dw3: times 8 dd 3 dw5: times 8 dd 5 @@ -287,8 +287,8 @@ SECTION .text ; output: m0, m1 ; temp: s0q...s1q %macro FILTER_VB 1 - vpbroadcastd m0, [dw64] - vpbroadcastd m1, [dw64] + vpbroadcastd m0, [pd_64] + vpbroadcastd m1, [pd_64] GET_SRCS %1 %if LUMA diff --git a/libavcodec/x86/vvc/vvc_dmvr.asm b/libavcodec/x86/vvc/dmvr.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_dmvr.asm rename to libavcodec/x86/vvc/dmvr.asm diff --git a/libavcodec/x86/vvc/vvcdsp_init.c b/libavcodec/x86/vvc/dsp_init.c similarity index 78% rename from libavcodec/x86/vvc/vvcdsp_init.c rename to libavcodec/x86/vvc/dsp_init.c index f3e2e3a27b..cbcfa40a66 100644 --- a/libavcodec/x86/vvc/vvcdsp_init.c +++ b/libavcodec/x86/vvc/dsp_init.c @@ -30,38 +30,7 @@ #include "libavcodec/vvc/dsp.h" #include "libavcodec/x86/h26x/h2656dsp.h" -#define PUT_PROTOTYPE(name, depth, opt) \ -void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, const int8_t *hf, const int8_t *vf, int width); - -#define PUT_PROTOTYPES(name, bitd, opt) \ - PUT_PROTOTYPE(name##2, bitd, opt) \ - PUT_PROTOTYPE(name##4, bitd, opt) \ - PUT_PROTOTYPE(name##8, bitd, opt) \ - PUT_PROTOTYPE(name##12, bitd, opt) \ - PUT_PROTOTYPE(name##16, bitd, opt) \ - PUT_PROTOTYPE(name##24, bitd, opt) \ - PUT_PROTOTYPE(name##32, bitd, opt) \ - PUT_PROTOTYPE(name##48, bitd, opt) \ - PUT_PROTOTYPE(name##64, bitd, opt) \ - PUT_PROTOTYPE(name##128, bitd, opt) - -#define PUT_BPC_PROTOTYPES(name, opt) \ - PUT_PROTOTYPES(name, 8, opt) \ - PUT_PROTOTYPES(name, 10, opt) \ - PUT_PROTOTYPES(name, 12, opt) - -#define PUT_TAP_PROTOTYPES(n, opt) \ - PUT_BPC_PROTOTYPES(n##tap_h, opt) \ - PUT_BPC_PROTOTYPES(n##tap_v, opt) \ - PUT_BPC_PROTOTYPES(n##tap_hv, opt) - -PUT_BPC_PROTOTYPES(pixels, sse4) -PUT_BPC_PROTOTYPES(pixels, avx2) - -PUT_TAP_PROTOTYPES(4, sse4) -PUT_TAP_PROTOTYPES(8, sse4) -PUT_TAP_PROTOTYPES(4, avx2) -PUT_TAP_PROTOTYPES(8, avx2) +#if ARCH_X86_64 #define bf(fn, bd, opt) fn##_##bd##_##opt #define BF(fn, bpc, opt) fn##_##bpc##bpc_##opt @@ -73,21 +42,9 @@ void BF(ff_vvc_w_avg, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, intptr_t width, intptr_t height, \ intptr_t denom, intptr_t w0, intptr_t w1, intptr_t o0, intptr_t o1, intptr_t pixel_max); -#define AVG_PROTOTYPES(bd, opt) \ -void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height); \ -void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int width, int height, \ - int denom, int w0, int w1, int o0, int o1); - AVG_BPC_PROTOTYPES( 8, avx2) AVG_BPC_PROTOTYPES(16, avx2) -AVG_PROTOTYPES( 8, avx2) -AVG_PROTOTYPES(10, avx2) -AVG_PROTOTYPES(12, avx2) - - #define DMVR_PROTOTYPES(bd, opt) \ void ff_vvc_dmvr_##bd##_##opt(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, \ int height, intptr_t mx, intptr_t my, int width); \ @@ -102,19 +59,24 @@ DMVR_PROTOTYPES( 8, avx2) DMVR_PROTOTYPES(10, avx2) DMVR_PROTOTYPES(12, avx2) -void ff_vvc_apply_bdof_avx2(uint8_t *dst, ptrdiff_t dst_stride, \ - const int16_t *src0, const int16_t *src1, int w, int h, int pixel_max); \ +#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +void ff_vvc_apply_bdof_avx2(uint8_t *dst, ptrdiff_t dst_stride, + const int16_t *src0, const int16_t *src1, + int w, int h, int pixel_max); -#define OF_PROTOTYPES(bd, opt) \ -static void ff_vvc_apply_bdof_##bd##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ +#define OF_FUNC(bd, opt) \ +static void vvc_apply_bdof_##bd##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ const int16_t *src0, const int16_t *src1, int w, int h) \ { \ ff_vvc_apply_bdof##_##opt(dst, dst_stride, src0, src1, w, h, (1 << bd) - 1); \ } \ -OF_PROTOTYPES( 8, avx2) -OF_PROTOTYPES(10, avx2) -OF_PROTOTYPES(12, avx2) +OF_FUNC( 8, avx2) +OF_FUNC(10, avx2) +OF_FUNC(12, avx2) + +#define OF_INIT(bd) c->inter.apply_bdof = vvc_apply_bdof_##bd##_avx2 +#endif #define ALF_BPC_PROTOTYPES(bpc, opt) \ void BF(ff_vvc_alf_filter_luma, bpc, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ @@ -128,30 +90,18 @@ void BF(ff_vvc_alf_classify_grad, bpc, opt)(int *gradient_sum, void BF(ff_vvc_alf_classify, bpc, opt)(int *class_idx, int *transpose_idx, const int *gradient_sum, \ intptr_t width, intptr_t height, intptr_t vb_pos, intptr_t bit_depth); \ -#define ALF_PROTOTYPES(bpc, bd, opt) \ -void bf(ff_vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos); \ -void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ - int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos); \ -void bf(ff_vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ - const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, int *gradient_tmp); \ - ALF_BPC_PROTOTYPES(8, avx2) ALF_BPC_PROTOTYPES(16, avx2) -ALF_PROTOTYPES(8, 8, avx2) -ALF_PROTOTYPES(16, 10, avx2) -ALF_PROTOTYPES(16, 12, avx2) - #if ARCH_X86_64 -#if HAVE_SSE4_EXTERNAL #define FW_PUT(name, depth, opt) \ -void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ +static void vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ int height, const int8_t *hf, const int8_t *vf, int width) \ { \ ff_h2656_put_## name ## _ ## depth ## _##opt(dst, 2 * MAX_PB_SIZE, src, srcstride, height, hf, vf, width); \ } +#if HAVE_SSE4_EXTERNAL #define FW_PUT_TAP(fname, bitd, opt ) \ FW_PUT(fname##4, bitd, opt ) \ FW_PUT(fname##8, bitd, opt ) \ @@ -221,12 +171,12 @@ FW_PUT_16BPC_AVX2(10) FW_PUT_16BPC_AVX2(12) #define AVG_FUNCS(bpc, bd, opt) \ -void bf(ff_vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ +static void bf(vvc_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ const int16_t *src0, const int16_t *src1, int width, int height) \ { \ BF(ff_vvc_avg, bpc, opt)(dst, dst_stride, src0, src1, width, height, (1 << bd) - 1); \ } \ -void bf(ff_vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ +static void bf(vvc_w_avg, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \ const int16_t *src0, const int16_t *src1, int width, int height, \ int denom, int w0, int w1, int o0, int o1) \ { \ @@ -239,20 +189,20 @@ AVG_FUNCS(16, 10, avx2) AVG_FUNCS(16, 12, avx2) #define ALF_FUNCS(bpc, bd, opt) \ -void bf(ff_vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ +static void bf(vvc_alf_filter_luma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos) \ { \ const int param_stride = (width >> 2) * ALF_NUM_COEFF_LUMA; \ BF(ff_vvc_alf_filter_luma, bpc, opt)(dst, dst_stride, src, src_stride, width, height, \ filter, clip, param_stride, vb_pos, (1 << bd) - 1); \ } \ -void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ +static void bf(vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, \ int width, int height, const int16_t *filter, const int16_t *clip, const int vb_pos) \ { \ BF(ff_vvc_alf_filter_chroma, bpc, opt)(dst, dst_stride, src, src_stride, width, height, \ filter, clip, 0, vb_pos,(1 << bd) - 1); \ } \ -void bf(ff_vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ +static void bf(vvc_alf_classify, bd, opt)(int *class_idx, int *transpose_idx, \ const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, int *gradient_tmp) \ { \ BF(ff_vvc_alf_classify_grad, bpc, opt)(gradient_tmp, src, src_stride, width, height, vb_pos); \ @@ -265,8 +215,58 @@ ALF_FUNCS(16, 12, avx2) #endif +#define SAO_FILTER_FUNC(wd, bitd, opt) \ +void ff_vvc_sao_band_filter_##wd##_##bitd##_##opt(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + const int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_vvc_sao_edge_filter_##wd##_##bitd##_##opt(uint8_t *_dst, const uint8_t *_src, ptrdiff_t stride_dst, \ + const int16_t *sao_offset_val, int eo, int width, int height); \ + +#define SAO_FILTER_FUNCS(bitd, opt) \ + SAO_FILTER_FUNC(8, bitd, opt) \ + SAO_FILTER_FUNC(16, bitd, opt) \ + SAO_FILTER_FUNC(32, bitd, opt) \ + SAO_FILTER_FUNC(48, bitd, opt) \ + SAO_FILTER_FUNC(64, bitd, opt) \ + SAO_FILTER_FUNC(80, bitd, opt) \ + SAO_FILTER_FUNC(96, bitd, opt) \ + SAO_FILTER_FUNC(112, bitd, opt) \ + SAO_FILTER_FUNC(128, bitd, opt) \ + +SAO_FILTER_FUNCS(8, avx2) +SAO_FILTER_FUNCS(10, avx2) +SAO_FILTER_FUNCS(12, avx2) + +#define SAO_FILTER_INIT(type, bitd, opt) do { \ + c->sao.type##_filter[0] = ff_vvc_sao_##type##_filter_8_##bitd##_##opt; \ + c->sao.type##_filter[1] = ff_vvc_sao_##type##_filter_16_##bitd##_##opt; \ + c->sao.type##_filter[2] = ff_vvc_sao_##type##_filter_32_##bitd##_##opt; \ + c->sao.type##_filter[3] = ff_vvc_sao_##type##_filter_48_##bitd##_##opt; \ + c->sao.type##_filter[4] = ff_vvc_sao_##type##_filter_64_##bitd##_##opt; \ + c->sao.type##_filter[5] = ff_vvc_sao_##type##_filter_80_##bitd##_##opt; \ + c->sao.type##_filter[6] = ff_vvc_sao_##type##_filter_96_##bitd##_##opt; \ + c->sao.type##_filter[7] = ff_vvc_sao_##type##_filter_112_##bitd##_##opt; \ + c->sao.type##_filter[8] = ff_vvc_sao_##type##_filter_128_##bitd##_##opt; \ +} while (0) + +#define SAO_INIT(bitd, opt) do { \ + SAO_FILTER_INIT(band, bitd, opt); \ + SAO_FILTER_INIT(edge, bitd, opt); \ +} while (0) + +#define AVG_INIT(bd, opt) do { \ + c->inter.avg = bf(vvc_avg, bd, opt); \ + c->inter.w_avg = bf(vvc_w_avg, bd, opt); \ +} while (0) + +#define DMVR_INIT(bd) do { \ + c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_avx2; \ + c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_avx2; \ + c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_avx2; \ + c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_avx2; \ +} while (0) + #define PEL_LINK(dst, C, W, idx1, idx2, name, D, opt) \ - dst[C][W][idx1][idx2] = ff_vvc_put_## name ## _ ## D ## _##opt; \ + dst[C][W][idx1][idx2] = vvc_put_## name ## _ ## D ## _##opt; \ dst ## _uni[C][W][idx1][idx2] = ff_h2656_put_uni_ ## name ## _ ## D ## _##opt; \ #define MC_TAP_LINKS(pointer, C, my, mx, fname, bitd, opt ) \ @@ -330,32 +330,20 @@ ALF_FUNCS(16, 12, avx2) MC_TAP_LINKS_16BPC_AVX2(LUMA, 8, bd); \ MC_TAP_LINKS_16BPC_AVX2(CHROMA, 4, bd); -#define AVG_INIT(bd, opt) do { \ - c->inter.avg = bf(ff_vvc_avg, bd, opt); \ - c->inter.w_avg = bf(ff_vvc_w_avg, bd, opt); \ -} while (0) - -#define DMVR_INIT(bd) do { \ - c->inter.dmvr[0][0] = ff_vvc_dmvr_##bd##_avx2; \ - c->inter.dmvr[0][1] = ff_vvc_dmvr_h_##bd##_avx2; \ - c->inter.dmvr[1][0] = ff_vvc_dmvr_v_##bd##_avx2; \ - c->inter.dmvr[1][1] = ff_vvc_dmvr_hv_##bd##_avx2; \ -} while (0) - -#define OF_INIT(bd) do { \ - c->inter.apply_bdof = ff_vvc_apply_bdof_##bd##_avx2; \ -} while (0) - -#define ALF_INIT(bd) do { \ - c->alf.filter[LUMA] = ff_vvc_alf_filter_luma_##bd##_avx2; \ - c->alf.filter[CHROMA] = ff_vvc_alf_filter_chroma_##bd##_avx2; \ - c->alf.classify = ff_vvc_alf_classify_##bd##_avx2; \ -} while (0) - int ff_vvc_sad_avx2(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); #define SAD_INIT() c->inter.sad = ff_vvc_sad_avx2 + +#define ALF_INIT(bd) do { \ + c->alf.filter[LUMA] = vvc_alf_filter_luma_##bd##_avx2; \ + c->alf.filter[CHROMA] = vvc_alf_filter_chroma_##bd##_avx2; \ + c->alf.classify = vvc_alf_classify_##bd##_avx2; \ +} while (0) + #endif + +#endif // ARCH_X86_64 + void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) { #if ARCH_X86_64 @@ -363,45 +351,69 @@ void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) switch (bd) { case 8: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(8); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(8); + // inter AVG_INIT(8, avx2); + DMVR_INIT(8); MC_LINKS_AVX2(8); OF_INIT(8); - DMVR_INIT(8); SAD_INIT(); + + // filter + ALF_INIT(8); + SAO_INIT(8, avx2); } +#endif break; case 10: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(10); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(10); + // inter AVG_INIT(10, avx2); + DMVR_INIT(10); MC_LINKS_AVX2(10); MC_LINKS_16BPC_AVX2(10); OF_INIT(10); - DMVR_INIT(10); SAD_INIT(); + + // filter + ALF_INIT(10); + SAO_INIT(10, avx2); } +#endif break; case 12: +#if HAVE_SSE4_EXTERNAL if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(12); } +#endif +#if HAVE_AVX2_EXTERNAL if (EXTERNAL_AVX2_FAST(cpu_flags)) { - ALF_INIT(12); + // inter AVG_INIT(12, avx2); + DMVR_INIT(12); MC_LINKS_AVX2(12); MC_LINKS_16BPC_AVX2(12); OF_INIT(12); - DMVR_INIT(12); SAD_INIT(); + + // filter + ALF_INIT(12); + SAO_INIT(12, avx2); } +#endif break; default: break; diff --git a/libavcodec/x86/vvc/vvc_mc.asm b/libavcodec/x86/vvc/mc.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_mc.asm rename to libavcodec/x86/vvc/mc.asm diff --git a/libavcodec/x86/vvc/vvc_of.asm b/libavcodec/x86/vvc/of.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_of.asm rename to libavcodec/x86/vvc/of.asm diff --git a/libavcodec/x86/vvc/vvc_sad.asm b/libavcodec/x86/vvc/sad.asm similarity index 100% rename from libavcodec/x86/vvc/vvc_sad.asm rename to libavcodec/x86/vvc/sad.asm diff --git a/libavcodec/x86/vvc/sao.asm b/libavcodec/x86/vvc/sao.asm new file mode 100644 index 0000000000..5f7d7e5358 --- /dev/null +++ b/libavcodec/x86/vvc/sao.asm @@ -0,0 +1,73 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for VVC 8bit decoding +;* +;* Copyright (c) 2024 Shaun Loo +;* Copyright (c) 2024 Nuo Mi +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General 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 MAX_PB_SIZE 128 +%include "libavcodec/x86/h26x/h2656_sao.asm" + +%macro VVC_SAO_BAND_FILTER 2 + H2656_SAO_BAND_FILTER vvc, %1, %2 +%endmacro + +%macro VVC_SAO_BAND_FILTER_FUNCS 0 +VVC_SAO_BAND_FILTER 8, 0 +VVC_SAO_BAND_FILTER 16, 1 +VVC_SAO_BAND_FILTER 32, 2 +VVC_SAO_BAND_FILTER 48, 2 +VVC_SAO_BAND_FILTER 64, 4 +VVC_SAO_BAND_FILTER 80, 4 +VVC_SAO_BAND_FILTER 96, 6 +VVC_SAO_BAND_FILTER 112, 6 +VVC_SAO_BAND_FILTER 128, 8 +%endmacro + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +VVC_SAO_BAND_FILTER 8, 0 +VVC_SAO_BAND_FILTER 16, 1 +INIT_YMM avx2 +VVC_SAO_BAND_FILTER 32, 1 +VVC_SAO_BAND_FILTER 48, 1 +VVC_SAO_BAND_FILTER 64, 2 +VVC_SAO_BAND_FILTER 80, 2 +VVC_SAO_BAND_FILTER 96, 3 +VVC_SAO_BAND_FILTER 112, 3 +VVC_SAO_BAND_FILTER 128, 4 +%endif + +%macro VVC_SAO_EDGE_FILTER 2-3 + H2656_SAO_EDGE_FILTER vvc, %{1:-1} +%endmacro + +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +VVC_SAO_EDGE_FILTER 8, 0 +VVC_SAO_EDGE_FILTER 16, 1, a +INIT_YMM avx2 +VVC_SAO_EDGE_FILTER 32, 1, a +VVC_SAO_EDGE_FILTER 48, 1, u +VVC_SAO_EDGE_FILTER 64, 2, a +VVC_SAO_EDGE_FILTER 80, 2, u +VVC_SAO_EDGE_FILTER 96, 3, a +VVC_SAO_EDGE_FILTER 112, 3, u +VVC_SAO_EDGE_FILTER 128, 4, a +%endif diff --git a/libavcodec/x86/vvc/sao_10bit.asm b/libavcodec/x86/vvc/sao_10bit.asm new file mode 100644 index 0000000000..b7d3d08008 --- /dev/null +++ b/libavcodec/x86/vvc/sao_10bit.asm @@ -0,0 +1,113 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for VVC 10/12bit decoding +;* +;* Copyright (c) 2024 Shaun Loo +;* Copyright (c) 2024 Nuo Mi +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General 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 MAX_PB_SIZE 128 +%include "libavcodec/x86/h26x/h2656_sao_10bit.asm" + +%macro VVC_SAO_BAND_FILTER 3 + H2656_SAO_BAND_FILTER vvc, %1, %2, %3 +%endmacro + +%macro VVC_SAO_BAND_FILTER_FUNCS 1 + VVC_SAO_BAND_FILTER %1, 8, 1 + VVC_SAO_BAND_FILTER %1, 16, 2 + VVC_SAO_BAND_FILTER %1, 32, 4 + VVC_SAO_BAND_FILTER %1, 48, 6 + VVC_SAO_BAND_FILTER %1, 64, 8 + VVC_SAO_BAND_FILTER %1, 80, 10 + VVC_SAO_BAND_FILTER %1, 96, 12 + VVC_SAO_BAND_FILTER %1, 112, 14 + VVC_SAO_BAND_FILTER %1, 128, 16 +%endmacro + +%macro VVC_SAO_BAND_FILTER_FUNCS 0 + VVC_SAO_BAND_FILTER_FUNCS 10 + VVC_SAO_BAND_FILTER_FUNCS 12 +%endmacro + +INIT_XMM sse2 +VVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +VVC_SAO_BAND_FILTER_FUNCS + +%if HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_BAND_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + VVC_SAO_BAND_FILTER %1, 8, 1 + INIT_YMM avx2 + VVC_SAO_BAND_FILTER %1, 16, 1 + VVC_SAO_BAND_FILTER %1, 32, 2 + VVC_SAO_BAND_FILTER %1, 48, 3 + VVC_SAO_BAND_FILTER %1, 64, 4 + VVC_SAO_BAND_FILTER %1, 80, 5 + VVC_SAO_BAND_FILTER %1, 96, 6 + VVC_SAO_BAND_FILTER %1, 112, 7 + VVC_SAO_BAND_FILTER %1, 128, 8 +%endmacro + +VVC_SAO_BAND_FILTER_FUNCS_AVX2 10 +VVC_SAO_BAND_FILTER_FUNCS_AVX2 12 + +%endif ; HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_EDGE_FILTER 3 + H2656_SAO_EDGE_FILTER vvc, %1, %2, %3 +%endmacro + +%macro VVC_SAO_EDGE_FILTER_FUNCS 1 + VVC_SAO_EDGE_FILTER %1, 8, 1 + VVC_SAO_EDGE_FILTER %1, 16, 2 + VVC_SAO_EDGE_FILTER %1, 32, 4 + VVC_SAO_EDGE_FILTER %1, 48, 6 + VVC_SAO_EDGE_FILTER %1, 64, 8 + VVC_SAO_EDGE_FILTER %1, 80, 10 + VVC_SAO_EDGE_FILTER %1, 96, 12 + VVC_SAO_EDGE_FILTER %1, 112, 14 + VVC_SAO_EDGE_FILTER %1, 128, 16 +%endmacro + +INIT_XMM sse2 +VVC_SAO_EDGE_FILTER_FUNCS 10 +VVC_SAO_EDGE_FILTER_FUNCS 12 + +%if HAVE_AVX2_EXTERNAL + +%macro VVC_SAO_EDGE_FILTER_FUNCS_AVX2 1 + INIT_XMM avx2 + VVC_SAO_EDGE_FILTER %1, 8, 1 + INIT_YMM avx2 + VVC_SAO_EDGE_FILTER %1, 16, 1 + VVC_SAO_EDGE_FILTER %1, 32, 2 + VVC_SAO_EDGE_FILTER %1, 48, 3 + VVC_SAO_EDGE_FILTER %1, 64, 4 + VVC_SAO_EDGE_FILTER %1, 80, 5 + VVC_SAO_EDGE_FILTER %1, 96, 6 + VVC_SAO_EDGE_FILTER %1, 112, 7 + VVC_SAO_EDGE_FILTER %1, 128, 8 +%endmacro + +VVC_SAO_EDGE_FILTER_FUNCS_AVX2 10 +VVC_SAO_EDGE_FILTER_FUNCS_AVX2 12 + +%endif ; HAVE_AVX2_EXTERNAL diff --git a/libavcodec/x86/xvididct_init.c b/libavcodec/x86/xvididct_init.c index fda34cc638..c6c87b0c90 100644 --- a/libavcodec/x86/xvididct_init.c +++ b/libavcodec/x86/xvididct_init.c @@ -25,17 +25,11 @@ #include "xvididct.h" -av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) +av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c) { #if HAVE_X86ASM int cpu_flags = av_get_cpu_flags(); - if (high_bit_depth || - !(avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID)) - return; - if (EXTERNAL_SSE2(cpu_flags)) { c->idct_put = ff_xvid_idct_put_sse2; c->idct_add = ff_xvid_idct_add_sse2; diff --git a/libavcodec/xbmenc.c b/libavcodec/xbmenc.c index 5231d4691d..8454fefe5d 100644 --- a/libavcodec/xbmenc.c +++ b/libavcodec/xbmenc.c @@ -93,6 +93,5 @@ const FFCodec ff_xbm_encoder = { .p.id = AV_CODEC_ID_XBM, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(xbm_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/xfaceenc.c b/libavcodec/xfaceenc.c index 4998d42ea5..640ef02df5 100644 --- a/libavcodec/xfaceenc.c +++ b/libavcodec/xfaceenc.c @@ -217,7 +217,7 @@ const FFCodec ff_xface_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_XFACE, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_MONOWHITE), .priv_data_size = sizeof(XFaceContext), FF_CODEC_ENCODE_CB(xface_encode_frame), }; diff --git a/libavcodec/xvididct.c b/libavcodec/xvididct.c index 01072d80ab..317e4e82cd 100644 --- a/libavcodec/xvididct.c +++ b/libavcodec/xvididct.c @@ -32,7 +32,6 @@ #include "config.h" #include "libavutil/attributes.h" -#include "avcodec.h" #include "idctdsp.h" #include "xvididct.h" @@ -330,27 +329,16 @@ static void xvid_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) ff_add_pixels_clamped_c(block, dest, line_size); } -av_cold void ff_xvid_idct_init(IDCTDSPContext *c, AVCodecContext *avctx) +av_cold void ff_xvid_idct_init(IDCTDSPContext *c) { - const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8; - - if (high_bit_depth || avctx->lowres || - !(avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_XVID)) - return; - - if (avctx->idct_algo == FF_IDCT_XVID) { - c->idct_put = xvid_idct_put; - c->idct_add = xvid_idct_add; - c->idct = ff_xvid_idct; - c->perm_type = FF_IDCT_PERM_NONE; - } + c->idct_put = xvid_idct_put; + c->idct_add = xvid_idct_add; + c->idct = ff_xvid_idct; + c->perm_type = FF_IDCT_PERM_NONE; #if ARCH_X86 - ff_xvid_idct_init_x86(c, avctx, high_bit_depth); + ff_xvid_idct_init_x86(c); #elif ARCH_MIPS - ff_xvid_idct_init_mips(c, avctx, high_bit_depth); + ff_xvid_idct_init_mips(c); #endif - - ff_init_scantable_permutation(c->idct_permutation, c->perm_type); } diff --git a/libavcodec/xvididct.h b/libavcodec/xvididct.h index e0bc1a2b91..496071a034 100644 --- a/libavcodec/xvididct.h +++ b/libavcodec/xvididct.h @@ -21,16 +21,13 @@ #include -#include "avcodec.h" #include "idctdsp.h" void ff_xvid_idct(int16_t *const in); -void ff_xvid_idct_init(IDCTDSPContext *c, AVCodecContext *avctx); +void ff_xvid_idct_init(IDCTDSPContext *c); -void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); -void ff_xvid_idct_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth); +void ff_xvid_idct_init_x86(IDCTDSPContext *c); +void ff_xvid_idct_init_mips(IDCTDSPContext *c); #endif /* AVCODEC_XVIDIDCT_H */ diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c index 40bee20109..1d8b7d9002 100644 --- a/libavcodec/xwdenc.c +++ b/libavcodec/xwdenc.c @@ -219,26 +219,12 @@ const FFCodec ff_xwd_encoder = { .p.id = AV_CODEC_ID_XWD, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, FF_CODEC_ENCODE_CB(xwd_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGRA, - AV_PIX_FMT_RGBA, - AV_PIX_FMT_ARGB, - AV_PIX_FMT_ABGR, - AV_PIX_FMT_RGB24, - AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGB565BE, - AV_PIX_FMT_RGB565LE, - AV_PIX_FMT_BGR565BE, - AV_PIX_FMT_BGR565LE, - AV_PIX_FMT_RGB555BE, - AV_PIX_FMT_RGB555LE, - AV_PIX_FMT_BGR555BE, - AV_PIX_FMT_BGR555LE, - AV_PIX_FMT_RGB8, - AV_PIX_FMT_BGR8, - AV_PIX_FMT_RGB4_BYTE, - AV_PIX_FMT_BGR4_BYTE, - AV_PIX_FMT_PAL8, - AV_PIX_FMT_GRAY8, - AV_PIX_FMT_MONOWHITE, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_BGRA, AV_PIX_FMT_RGBA, AV_PIX_FMT_ARGB, + AV_PIX_FMT_ABGR, AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGB565BE, AV_PIX_FMT_RGB565LE, AV_PIX_FMT_BGR565BE, + AV_PIX_FMT_BGR565LE, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_BGR555BE, AV_PIX_FMT_BGR555LE, + AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, + AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, + AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8, AV_PIX_FMT_MONOWHITE), }; diff --git a/libavcodec/y41penc.c b/libavcodec/y41penc.c index e86769da66..b0044b35ef 100644 --- a/libavcodec/y41penc.c +++ b/libavcodec/y41penc.c @@ -85,6 +85,5 @@ const FFCodec ff_y41p_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .init = y41p_encode_init, FF_CODEC_ENCODE_CB(y41p_encode_frame), - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV411P), }; diff --git a/libavcodec/yop.c b/libavcodec/yop.c index 77b8d6e055..225bc71f5d 100644 --- a/libavcodec/yop.c +++ b/libavcodec/yop.c @@ -232,12 +232,6 @@ static int yop_decode_frame(AVCodecContext *avctx, AVFrame *rframe, (palette[i + firstcolor] >> 6) & 0x30303; } -#if FF_API_PALETTE_HAS_CHANGED -FF_DISABLE_DEPRECATION_WARNINGS - frame->palette_has_changed = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - for (y = 0; y < avctx->height; y += 2) { for (x = 0; x < avctx->width; x += 2) { if (s->srcptr - avpkt->data >= avpkt->size) { diff --git a/libavcodec/yuv4enc.c b/libavcodec/yuv4enc.c index 2a9d3442ca..093038142f 100644 --- a/libavcodec/yuv4enc.c +++ b/libavcodec/yuv4enc.c @@ -76,6 +76,6 @@ const FFCodec ff_yuv4_encoder = { .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_YUV4, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, - .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + CODEC_PIXFMTS(AV_PIX_FMT_YUV420P), FF_CODEC_ENCODE_CB(yuv4_encode_frame), }; diff --git a/libavcodec/zmbvenc.c b/libavcodec/zmbvenc.c index 04889b97d2..17eb3caa2b 100644 --- a/libavcodec/zmbvenc.c +++ b/libavcodec/zmbvenc.c @@ -410,6 +410,17 @@ static av_cold int encode_init(AVCodecContext *avctx) return ff_deflate_init(&c->zstream, lvl, avctx); } +static const enum AVPixelFormat zmbv_pixfmts_list[] = { + AV_PIX_FMT_PAL8, + AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_RGB565LE, +#ifdef ZMBV_ENABLE_24BPP + AV_PIX_FMT_BGR24, +#endif + AV_PIX_FMT_BGR0, + AV_PIX_FMT_NONE +}; + const FFCodec ff_zmbv_encoder = { .p.name = "zmbv", CODEC_LONG_NAME("Zip Motion Blocks Video"), @@ -420,13 +431,6 @@ const FFCodec ff_zmbv_encoder = { .init = encode_init, FF_CODEC_ENCODE_CB(encode_frame), .close = encode_end, - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, - AV_PIX_FMT_RGB555LE, - AV_PIX_FMT_RGB565LE, -#ifdef ZMBV_ENABLE_24BPP - AV_PIX_FMT_BGR24, -#endif //ZMBV_ENABLE_24BPP - AV_PIX_FMT_BGR0, - AV_PIX_FMT_NONE }, + CODEC_PIXFMTS_ARRAY(zmbv_pixfmts_list), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavdevice/Makefile b/libavdevice/Makefile index c30449201d..a226368d16 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -18,7 +18,6 @@ OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o OBJS-$(CONFIG_ANDROID_CAMERA_INDEV) += android_camera.o OBJS-$(CONFIG_AUDIOTOOLBOX_OUTDEV) += audiotoolbox.o OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o -OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_CACA_OUTDEV) += caca.o OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o @@ -35,14 +34,12 @@ OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o OBJS-$(CONFIG_KMSGRAB_INDEV) += kmsgrab.o OBJS-$(CONFIG_LAVFI_INDEV) += lavfi.o OBJS-$(CONFIG_OPENAL_INDEV) += openal-dec.o -OBJS-$(CONFIG_OPENGL_OUTDEV) += opengl_enc.o OBJS-$(CONFIG_OSS_INDEV) += oss_dec.o oss.o OBJS-$(CONFIG_OSS_OUTDEV) += oss_enc.o oss.o OBJS-$(CONFIG_PULSE_INDEV) += pulse_audio_dec.o \ pulse_audio_common.o timefilter.o OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \ pulse_audio_common.o -OBJS-$(CONFIG_SDL2_OUTDEV) += sdl2.o OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index 9b9a9146c7..573595f416 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -20,8 +20,8 @@ #include "libavutil/attributes.h" #include "libavutil/attributes_internal.h" +#include "libavformat/avformat_internal.h" #include "libavformat/demux.h" -#include "libavformat/internal.h" #include "libavformat/mux.h" #include "avdevice.h" @@ -32,7 +32,6 @@ extern const FFOutputFormat ff_alsa_muxer; extern const FFInputFormat ff_android_camera_demuxer; extern const FFOutputFormat ff_audiotoolbox_muxer; extern const FFInputFormat ff_avfoundation_demuxer; -extern const FFInputFormat ff_bktr_demuxer; extern const FFOutputFormat ff_caca_muxer; extern const FFInputFormat ff_decklink_demuxer; extern const FFOutputFormat ff_decklink_muxer; @@ -45,12 +44,10 @@ extern const FFInputFormat ff_jack_demuxer; extern const FFInputFormat ff_kmsgrab_demuxer; extern const FFInputFormat ff_lavfi_demuxer; extern const FFInputFormat ff_openal_demuxer; -extern const FFOutputFormat ff_opengl_muxer; extern const FFInputFormat ff_oss_demuxer; extern const FFOutputFormat ff_oss_muxer; extern const FFInputFormat ff_pulse_demuxer; extern const FFOutputFormat ff_pulse_muxer; -extern const FFOutputFormat ff_sdl2_muxer; extern const FFInputFormat ff_sndio_demuxer; extern const FFOutputFormat ff_sndio_muxer; extern const FFInputFormat ff_v4l2_demuxer; diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c index d62ccc09c6..cfdb28ff49 100644 --- a/libavdevice/alsa.c +++ b/libavdevice/alsa.c @@ -127,7 +127,8 @@ switch(format) {\ case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\ } -static av_cold int find_reorder_func(AlsaData *s, int codec_id, AVChannelLayout *layout, int out) +static av_cold int find_reorder_func(AlsaData *s, int codec_id, + const AVChannelLayout *layout, int out) { int format; @@ -172,10 +173,9 @@ static av_cold int find_reorder_func(AlsaData *s, int codec_id, AVChannelLayout av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id) + const AVChannelLayout *layout, enum AVCodecID *codec_id) { AlsaData *s = ctx->priv_data; - AVChannelLayout *layout = &ctx->streams[0]->codecpar->ch_layout; const char *audio_device; int res, flags = 0; snd_pcm_format_t format; @@ -193,7 +193,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); return AVERROR(ENOSYS); } - s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; + s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * layout->nb_channels; if (ctx->flags & AVFMT_FLAG_NONBLOCK) { flags = SND_PCM_NONBLOCK; @@ -240,10 +240,10 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, goto fail; } - res = snd_pcm_hw_params_set_channels(h, hw_params, channels); + res = snd_pcm_hw_params_set_channels(h, hw_params, layout->nb_channels); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", - channels, snd_strerror(res)); + layout->nb_channels, snd_strerror(res)); goto fail; } @@ -277,7 +277,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, snd_pcm_hw_params_free(hw_params); - if (channels > 2 && layout->order != AV_CHANNEL_ORDER_UNSPEC) { + if (layout->nb_channels > 2 && layout->order != AV_CHANNEL_ORDER_UNSPEC) { if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) { char name[128]; av_channel_layout_describe(layout, name, sizeof(name)); diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h index 07783c983a..d3dfa478c5 100644 --- a/libavdevice/alsa.h +++ b/libavdevice/alsa.h @@ -35,6 +35,7 @@ #include "libavutil/log.h" #include "timefilter.h" #include "avdevice.h" +#include "version.h" /* XXX: we make the assumption that the soundcard accepts this format */ /* XXX: find better solution with "preinit" method, needed also in @@ -51,7 +52,10 @@ typedef struct AlsaData { int frame_size; ///< bytes per sample * channels int period_size; ///< preferred size for reads and writes, in frames int sample_rate; ///< sample rate set by user +#if FF_API_ALSA_CHANNELS int channels; ///< number of channels set by user +#endif + AVChannelLayout ch_layout; ///< Channel layout set by user int last_period; TimeFilter *timefilter; void (*reorder_func)(const void *, void *, int); @@ -68,7 +72,7 @@ typedef struct AlsaData { * @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK * @param sample_rate in: requested sample rate; * out: actually selected sample rate - * @param channels number of channels + * @param layout channel layout * @param codec_id in: requested AVCodecID or AV_CODEC_ID_NONE; * out: actually selected AVCodecID, changed only if * AV_CODEC_ID_NONE was requested @@ -78,7 +82,7 @@ typedef struct AlsaData { av_warn_unused_result int ff_alsa_open(AVFormatContext *s, snd_pcm_stream_t mode, unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id); + const AVChannelLayout *layout, enum AVCodecID *codec_id); /** * Close the ALSA PCM. diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c index 018afaef08..63409a7785 100644 --- a/libavdevice/alsa_dec.c +++ b/libavdevice/alsa_dec.c @@ -73,7 +73,14 @@ static av_cold int audio_read_header(AVFormatContext *s1) } codec_id = s1->audio_codec_id; - ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels, +#if FF_API_ALSA_CHANNELS + if (s->channels > 0) { + av_channel_layout_uninit(&s->ch_layout); + s->ch_layout.nb_channels = s->channels; + } +#endif + + ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, &s->ch_layout, &codec_id); if (ret < 0) { return AVERROR(EIO); @@ -83,20 +90,24 @@ static av_cold int audio_read_header(AVFormatContext *s1) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = codec_id; st->codecpar->sample_rate = s->sample_rate; - st->codecpar->ch_layout.nb_channels = s->channels; + ret = av_channel_layout_copy(&st->codecpar->ch_layout, &s->ch_layout); + if (ret < 0) + goto fail; st->codecpar->frame_size = s->frame_size; avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ /* microseconds instead of seconds, MHz instead of Hz */ s->timefilter = ff_timefilter_new(1000000.0 / s->sample_rate, s->period_size, 1.5E-6); - if (!s->timefilter) + if (!s->timefilter) { + ret = AVERROR(EIO); goto fail; + } return 0; fail: snd_pcm_close(s->h); - return AVERROR(EIO); + return ret; } static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) @@ -146,7 +157,10 @@ static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_li static const AVOption options[] = { { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, +#if FF_API_ALSA_CHANNELS + { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_DEPRECATED }, +#endif + { "ch_layout", "", offsetof(AlsaData, ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = "2C"}, INT_MIN, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/libavdevice/alsa_enc.c b/libavdevice/alsa_enc.c index 0b4c7834f7..971cff688c 100644 --- a/libavdevice/alsa_enc.c +++ b/libavdevice/alsa_enc.c @@ -66,7 +66,7 @@ static av_cold int audio_write_header(AVFormatContext *s1) sample_rate = st->codecpar->sample_rate; codec_id = st->codecpar->codec_id; res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, - st->codecpar->ch_layout.nb_channels, &codec_id); + &st->codecpar->ch_layout, &codec_id); if (sample_rate != st->codecpar->sample_rate) { av_log(s1, AV_LOG_ERROR, "sample rate %d not available, nearest is %d\n", diff --git a/libavdevice/android_camera.c b/libavdevice/android_camera.c index 5de44e6d86..8433286296 100644 --- a/libavdevice/android_camera.c +++ b/libavdevice/android_camera.c @@ -421,7 +421,7 @@ static void image_available(void *context, AImageReader *reader) } } - pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 32); + pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 1); AImage_getTimestamp(image, &image_timestamp); AImage_getPlaneRowStride(image, 0, &image_linestrides[0]); @@ -460,7 +460,7 @@ static void image_available(void *context, AImageReader *reader) 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); + ctx->width, ctx->height, 1); ret = av_thread_message_queue_send(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK); diff --git a/libavdevice/audiotoolbox.m b/libavdevice/audiotoolbox.m index 7d95c34593..32ab151851 100644 --- a/libavdevice/audiotoolbox.m +++ b/libavdevice/audiotoolbox.m @@ -247,7 +247,7 @@ static int at_write_packet(AVFormatContext *avctx, AVPacket *pkt) // will be unlocked by queue callback pthread_mutex_lock(&ctx->buffer_lock[ctx->cur_buf]); - // (re-)allocate the buffer if not existant or of different size + // (re-)allocate the buffer if not existent or of different size if (!ctx->buffer[ctx->cur_buf] || ctx->buffer[ctx->cur_buf]->mAudioDataBytesCapacity != pkt->size) { err = AudioQueueAllocateBuffer(ctx->queue, pkt->size, &ctx->buffer[ctx->cur_buf]); if (check_status(avctx, &err, "AudioQueueAllocateBuffer")) { diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h index 887fd5e3c8..10ffaf4c5f 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -372,7 +372,7 @@ void avdevice_free_list_devices(AVDeviceInfoList **device_list); * List devices. * * Returns available device names and their parameters. - * These are convinient wrappers for avdevice_list_devices(). + * These are convenient wrappers for avdevice_list_devices(). * Device context is allocated and deallocated internally. * * @param device device format. May be NULL if device name is set. diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index c5a09c6563..ebec1ac4f2 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -150,7 +150,7 @@ static void unlock_frames(AVFContext* ctx) pthread_mutex_unlock(&ctx->frame_lock); } -/** FrameReciever class - delegate for AVCaptureSession +/** FrameReceiver class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject { @@ -242,7 +242,7 @@ static void unlock_frames(AVFContext* ctx) @end -/** AudioReciever class - delegate for AVCaptureSession +/** AudioReceiver class - delegate for AVCaptureSession */ @interface AVFAudioReceiver : NSObject { @@ -632,7 +632,6 @@ static int get_video_config(AVFormatContext *s) { AVFContext *ctx = (AVFContext*)s->priv_data; CVImageBufferRef image_buffer; - CMBlockBufferRef block_buffer; CGSize image_buffer_size; AVStream* stream = avformat_new_stream(s, NULL); @@ -652,7 +651,6 @@ static int get_video_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); - block_buffer = CMSampleBufferGetDataBuffer(ctx->current_frame); if (image_buffer) { image_buffer_size = CVImageBufferGetEncodedSize(image_buffer); @@ -816,8 +814,10 @@ static NSArray* getDevicesWithMediaType(AVMediaType mediaType) { mediaType:mediaType position:AVCaptureDevicePositionUnspecified]; return [captureDeviceDiscoverySession devices]; -#else +#elif TARGET_OS_OSX return [AVCaptureDevice devicesWithMediaType:mediaType]; +#else + return nil; #endif } diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c deleted file mode 100644 index eed75a9a92..0000000000 --- a/libavdevice/bktr.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * *BSD video grab interface - * Copyright (c) 2002 Steve O'Hara-Smith - * based on - * Linux video grab interface - * Copyright (c) 2000, 2001 Fabrice Bellard - * and - * simple_grab.c Copyright (c) 1999 Roger Hardiman - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavformat/demux.h" -#include "libavformat/internal.h" -#include "libavutil/file_open.h" -#include "libavutil/internal.h" -#include "libavutil/log.h" -#include "libavutil/mem.h" -#include "libavutil/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/time.h" -#if HAVE_DEV_BKTR_IOCTL_METEOR_H && HAVE_DEV_BKTR_IOCTL_BT848_H -# include -# include -#elif HAVE_MACHINE_IOCTL_METEOR_H && HAVE_MACHINE_IOCTL_BT848_H -# include -# include -#elif HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H && HAVE_DEV_VIDEO_BKTR_IOCTL_BT848_H -# include -# include -#elif HAVE_DEV_IC_BT8XX_H -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include "avdevice.h" - -typedef struct VideoData { - AVClass *class; - int video_fd; - int tuner_fd; - int width, height; - uint64_t per_frame; - int standard; - char *framerate; /**< Set by a private option. */ -} VideoData; - - -#define PAL 1 -#define PALBDGHI 1 -#define NTSC 2 -#define NTSCM 2 -#define SECAM 3 -#define PALN 4 -#define PALM 5 -#define NTSCJ 6 - -/* PAL is 768 x 576. NTSC is 640 x 480 */ -#define PAL_HEIGHT 576 -#define SECAM_HEIGHT 576 -#define NTSC_HEIGHT 480 - -#ifndef VIDEO_FORMAT -#define VIDEO_FORMAT NTSC -#endif - -static const int bktr_dev[] = { METEOR_DEV0, METEOR_DEV1, METEOR_DEV2, - METEOR_DEV3, METEOR_DEV_SVIDEO }; - -uint8_t *video_buf; -size_t video_buf_size; -uint64_t last_frame_time; -volatile sig_atomic_t nsignals; - - -static void catchsignal(int signal) -{ - nsignals++; - return; -} - -static av_cold int bktr_init(const char *video_device, int width, int height, - int format, int *video_fd, int *tuner_fd, int idev, double frequency) -{ - struct meteor_geomet geo; - int h_max; - long ioctl_frequency; - char *arg; - int c; - struct sigaction act, old; - int ret; - char errbuf[128]; - - if (idev < 0 || idev > 4) - { - arg = getenv ("BKTR_DEV"); - if (arg) - idev = atoi (arg); - if (idev < 0 || idev > 4) - idev = 1; - } - - if (format < 1 || format > 6) - { - arg = getenv ("BKTR_FORMAT"); - if (arg) - format = atoi (arg); - if (format < 1 || format > 6) - format = VIDEO_FORMAT; - } - - if (frequency <= 0) - { - arg = getenv ("BKTR_FREQUENCY"); - if (arg) - frequency = atof (arg); - if (frequency <= 0) - frequency = 0.0; - } - - memset(&act, 0, sizeof(act)); - sigemptyset(&act.sa_mask); - act.sa_handler = catchsignal; - sigaction(SIGUSR1, &act, &old); - - *tuner_fd = avpriv_open("/dev/tuner0", O_RDONLY); - if (*tuner_fd < 0) - av_log(NULL, AV_LOG_ERROR, "Warning. Tuner not opened, continuing: %s\n", strerror(errno)); - - *video_fd = avpriv_open(video_device, O_RDONLY); - if (*video_fd < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "%s: %s\n", video_device, errbuf); - return ret; - } - - geo.rows = height; - geo.columns = width; - geo.frames = 1; - geo.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12; - - switch (format) { - case PAL: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - case PALN: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALN; break; - case PALM: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALM; break; - case SECAM: h_max = SECAM_HEIGHT; c = BT848_IFORM_F_SECAM; break; - case NTSC: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCM; break; - case NTSCJ: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCJ; break; - default: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - } - - if (height <= h_max / 2) - geo.oformat |= METEOR_GEO_EVEN_ONLY; - - if (ioctl(*video_fd, METEORSETGEO, &geo) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "METEORSETGEO: %s\n", errbuf); - return ret; - } - - if (ioctl(*video_fd, BT848SFMT, &c) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "BT848SFMT: %s\n", errbuf); - return ret; - } - - c = bktr_dev[idev]; - if (ioctl(*video_fd, METEORSINPUT, &c) < 0) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "METEORSINPUT: %s\n", errbuf); - return ret; - } - - video_buf_size = width * height * 12 / 8; - - video_buf = (uint8_t *)mmap((caddr_t)0, video_buf_size, - PROT_READ, MAP_SHARED, *video_fd, (off_t)0); - if (video_buf == MAP_FAILED) { - ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(NULL, AV_LOG_ERROR, "mmap: %s\n", errbuf); - return ret; - } - - if (frequency != 0.0) { - ioctl_frequency = (unsigned long)(frequency*16); - if (ioctl(*tuner_fd, TVTUNER_SETFREQ, &ioctl_frequency) < 0) - av_log(NULL, AV_LOG_ERROR, "TVTUNER_SETFREQ: %s\n", strerror(errno)); - } - - c = AUDIO_UNMUTE; - if (ioctl(*tuner_fd, BT848_SAUDIO, &c) < 0) - av_log(NULL, AV_LOG_ERROR, "TVTUNER_SAUDIO: %s\n", strerror(errno)); - - c = METEOR_CAP_CONTINOUS; - ioctl(*video_fd, METEORCAPTUR, &c); - - c = SIGUSR1; - ioctl(*video_fd, METEORSSIGNAL, &c); - - return 0; -} - -static void bktr_getframe(uint64_t per_frame) -{ - uint64_t curtime; - - curtime = av_gettime_relative(); - if (!last_frame_time - || ((last_frame_time + per_frame) > curtime)) { - if (!usleep(last_frame_time + per_frame + per_frame / 8 - curtime)) { - if (!nsignals) - av_log(NULL, AV_LOG_INFO, - "SLEPT NO signals - %d microseconds late\n", - (int)(av_gettime_relative() - last_frame_time - per_frame)); - } - } - nsignals = 0; - last_frame_time = curtime; -} - - -/* note: we support only one picture read at a time */ -static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - VideoData *s = s1->priv_data; - - if (av_new_packet(pkt, video_buf_size) < 0) - return AVERROR(EIO); - - bktr_getframe(s->per_frame); - - pkt->pts = av_gettime(); - memcpy(pkt->data, video_buf, video_buf_size); - - return video_buf_size; -} - -static int grab_read_header(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - AVStream *st; - AVRational framerate; - int ret = 0; - - av_log(s1, AV_LOG_WARNING, "bktr input is deprecated and will be removed. " - "Please contact the developers if you are interested in maintaining it.\n"); - - if (!s->framerate) - switch (s->standard) { - case PAL: s->framerate = av_strdup("pal"); break; - case NTSC: s->framerate = av_strdup("ntsc"); break; - case SECAM: s->framerate = av_strdup("25"); break; - default: - av_log(s1, AV_LOG_ERROR, "Unknown standard.\n"); - ret = AVERROR(EINVAL); - goto out; - } - if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) { - av_log(s1, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", s->framerate); - goto out; - } - - st = avformat_new_stream(s1, NULL); - if (!st) { - ret = AVERROR(ENOMEM); - goto out; - } - avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in use */ - - s->per_frame = ((uint64_t)1000000 * framerate.den) / framerate.num; - - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->codecpar->format = AV_PIX_FMT_YUV420P; - st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - st->codecpar->width = s->width; - st->codecpar->height = s->height; - st->avg_frame_rate = framerate; - - 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; - } - - nsignals = 0; - last_frame_time = 0; - -out: - return ret; -} - -static int grab_read_close(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - int c; - - c = METEOR_CAP_STOP_CONT; - ioctl(s->video_fd, METEORCAPTUR, &c); - close(s->video_fd); - - c = AUDIO_MUTE; - ioctl(s->tuner_fd, BT848_SAUDIO, &c); - close(s->tuner_fd); - - munmap((caddr_t)video_buf, video_buf_size); - - return 0; -} - -#define OFFSET(x) offsetof(VideoData, x) -#define DEC AV_OPT_FLAG_DECODING_PARAM -static const AVOption options[] = { - { "standard", "", offsetof(VideoData, standard), AV_OPT_TYPE_INT, {.i64 = VIDEO_FORMAT}, PAL, NTSCJ, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = PAL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "NTSC", "", 0, AV_OPT_TYPE_CONST, {.i64 = NTSC}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "SECAM", "", 0, AV_OPT_TYPE_CONST, {.i64 = SECAM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PALN", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALN}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "PALM", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "NTSCJ", "", 0, AV_OPT_TYPE_CONST, {.i64 = NTSCJ}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, .unit = "standard" }, - { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "vga"}, 0, 0, DEC }, - { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, - { NULL }, -}; - -static const AVClass bktr_class = { - .class_name = "BKTR grab indev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, -}; - -const FFInputFormat ff_bktr_demuxer = { - .p.name = "bktr", - .p.long_name = NULL_IF_CONFIG_SMALL("video grab"), - .p.flags = AVFMT_NOFILE, - .p.priv_class = &bktr_class, - .priv_data_size = sizeof(VideoData), - .read_header = grab_read_header, - .read_packet = grab_read_packet, - .read_close = grab_read_close, -}; diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 54d698bc12..418701e4e0 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -1098,6 +1098,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) } if (!ctx->draw_bars && ctx->signal_loss_action != SIGNAL_LOSS_NONE) { av_log(avctx, AV_LOG_ERROR, "options draw_bars and signal_loss_action are mutually exclusive\n"); + av_freep(&ctx); return AVERROR(EINVAL); } ctx->audio_depth = cctx->audio_depth; @@ -1113,7 +1114,8 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; default: av_log(avctx, AV_LOG_ERROR, "Value of channels option must be one of 2, 8 or 16\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto error; } /* Check audio bit depth option for valid values: 16 or 32 */ @@ -1123,18 +1125,20 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; default: av_log(avctx, AV_LOG_ERROR, "Value for audio bit depth option must be either 16 or 32\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto error; } /* List available devices. */ if (ctx->list_devices) { ff_decklink_list_devices_legacy(avctx, 1, 0); - return AVERROR_EXIT; + ret = AVERROR_EXIT; + goto error; } ret = ff_decklink_init_device(avctx, avctx->url); if (ret < 0) - return ret; + goto error; /* Get input device. */ if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { @@ -1335,6 +1339,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) error: ff_decklink_cleanup(avctx); + av_freep(&cctx->ctx); return ret; } diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index 84db151577..6e97304850 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -985,8 +985,8 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, } } else { WAVEFORMATEX *fx; - AUDIO_STREAM_CONFIG_CAPS *acaps = caps; #if DSHOWDEBUG + AUDIO_STREAM_CONFIG_CAPS *acaps = caps; ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) { diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c index ce10d61f8a..548183d633 100644 --- a/libavdevice/lavfi.c +++ b/libavdevice/lavfi.c @@ -249,18 +249,24 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL, }; - ret = avfilter_graph_create_filter(&sink, abuffersink, - inout->name, NULL, - NULL, lavfi->graph); - if (ret >= 0) - ret = av_opt_set_bin(sink, "sample_fmts", (const uint8_t*)sample_fmts, - sizeof(sample_fmts), AV_OPT_SEARCH_CHILDREN); + sink = avfilter_graph_alloc_filter(lavfi->graph, abuffersink, inout->name); + if (!sink) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = av_opt_set_bin(sink, "sample_fmts", (const uint8_t*)sample_fmts, + sizeof(sample_fmts), AV_OPT_SEARCH_CHILDREN); if (ret < 0) goto end; ret = av_opt_set_int(sink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN); if (ret < 0) goto end; + + ret = avfilter_init_dict(sink, NULL); + if (ret < 0) + goto end; } else { av_log(avctx, AV_LOG_ERROR, "Output '%s' is not a video or audio output, not yet supported\n", inout->name); @@ -347,11 +353,6 @@ static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame, memcpy(lavfi->subcc_packet.data, sd->data, sd->size); lavfi->subcc_packet.stream_index = stream_idx; lavfi->subcc_packet.pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - lavfi->subcc_packet.pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif return 0; } @@ -460,11 +461,6 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) pkt->stream_index = stream_idx; pkt->pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - pkt->pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif av_frame_free(&frame_to_free); diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c deleted file mode 100644 index 93d3959880..0000000000 --- a/libavdevice/opengl_enc.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright (c) 2014 Lukasz Marek - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -//TODO: support for more formats -//TODO: support for more systems. -//TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread. - -#include -#include -#include -#include - -#include "config.h" - -#if HAVE_WINDOWS_H -#include -#endif -#if HAVE_OPENGL_GL3_H -#include -#elif HAVE_ES2_GL_H -#include -#else -#include -#include -#endif -#if HAVE_GLXGETPROCADDRESS -#include -#endif - -#if CONFIG_SDL2 -#include -#endif - -#include "libavutil/common.h" -#include "libavutil/frame.h" -#include "libavutil/mem.h" -#include "libavutil/pixdesc.h" -#include "libavutil/log.h" -#include "libavutil/opt.h" -#include "libavutil/avassert.h" -#include "libavformat/avformat.h" -#include "libavformat/internal.h" -#include "libavformat/mux.h" -#include "libavdevice/avdevice.h" -#include "opengl_enc_shaders.h" - -#ifndef APIENTRY -#define APIENTRY -#endif - -/* FF_GL_RED_COMPONENT is used for planar pixel types. - * Only red component is sampled in shaders. - * On some platforms GL_RED is not available and GL_LUMINANCE have to be used, - * but since OpenGL 3.0 GL_LUMINANCE is deprecated. - * GL_RED produces RGBA = value, 0, 0, 1. - * GL_LUMINANCE produces RGBA = value, value, value, 1. - * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */ -#if defined(GL_RED) -#define FF_GL_RED_COMPONENT GL_RED -#elif defined(GL_LUMINANCE) -#define FF_GL_RED_COMPONENT GL_LUMINANCE -#else -#define FF_GL_RED_COMPONENT 0x1903; //GL_RED -#endif - -/* Constants not defined for iOS */ -#define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define FF_GL_UNPACK_ROW_LENGTH 0x0CF2 - -/* MinGW exposes only OpenGL 1.1 API */ -#define FF_GL_ARRAY_BUFFER 0x8892 -#define FF_GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define FF_GL_STATIC_DRAW 0x88E4 -#define FF_GL_FRAGMENT_SHADER 0x8B30 -#define FF_GL_VERTEX_SHADER 0x8B31 -#define FF_GL_COMPILE_STATUS 0x8B81 -#define FF_GL_LINK_STATUS 0x8B82 -#define FF_GL_INFO_LOG_LENGTH 0x8B84 -typedef void (APIENTRY *FF_PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRY *FF_PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef void (APIENTRY *FF_PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRY *FF_PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid *data, GLenum usage); -typedef void (APIENTRY *FF_PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef GLint (APIENTRY *FF_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char *name); -typedef void (APIENTRY *FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRY *FF_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t pointer); -typedef GLint (APIENTRY *FF_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name); -typedef void (APIENTRY *FF_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRY *FF_PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRY *FF_PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef GLuint (APIENTRY *FF_PFNGLCREATEPROGRAMPROC) (void); -typedef void (APIENTRY *FF_PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRY *FF_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRY *FF_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog); -typedef void (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef void (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length); -typedef void (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog); - -typedef struct FFOpenGLFunctions { - FF_PFNGLACTIVETEXTUREPROC glActiveTexture; //Require GL ARB multitexture - FF_PFNGLGENBUFFERSPROC glGenBuffers; //Require GL_ARB_vertex_buffer_object - FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers; //Require GL_ARB_vertex_buffer_object - FF_PFNGLBUFFERDATAPROC glBufferData; //Require GL_ARB_vertex_buffer_object - FF_PFNGLBINDBUFFERPROC glBindBuffer; //Require GL_ARB_vertex_buffer_object - FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; //Require GL_ARB_vertex_shader - FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; //Require GL_ARB_vertex_shader - FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; //Require GL_ARB_vertex_shader - FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORM1FPROC glUniform1f; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORM1IPROC glUniform1i; //Require GL_ARB_shader_objects - FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; //Require GL_ARB_shader_objects - FF_PFNGLCREATEPROGRAMPROC glCreateProgram; //Require GL_ARB_shader_objects - FF_PFNGLDELETEPROGRAMPROC glDeleteProgram; //Require GL_ARB_shader_objects - FF_PFNGLUSEPROGRAMPROC glUseProgram; //Require GL_ARB_shader_objects - FF_PFNGLLINKPROGRAMPROC glLinkProgram; //Require GL_ARB_shader_objects - FF_PFNGLGETPROGRAMIVPROC glGetProgramiv; //Require GL_ARB_shader_objects - FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; //Require GL_ARB_shader_objects - FF_PFNGLATTACHSHADERPROC glAttachShader; //Require GL_ARB_shader_objects - FF_PFNGLCREATESHADERPROC glCreateShader; //Require GL_ARB_shader_objects - FF_PFNGLDELETESHADERPROC glDeleteShader; //Require GL_ARB_shader_objects - FF_PFNGLCOMPILESHADERPROC glCompileShader; //Require GL_ARB_shader_objects - FF_PFNGLSHADERSOURCEPROC glShaderSource; //Require GL_ARB_shader_objects - FF_PFNGLGETSHADERIVPROC glGetShaderiv; //Require GL_ARB_shader_objects - FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; //Require GL_ARB_shader_objects -} FFOpenGLFunctions; - -#define OPENGL_ERROR_CHECK(ctx) \ -{\ - GLenum err_code; \ - if ((err_code = glGetError()) != GL_NO_ERROR) { \ - av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __func__, __LINE__, err_code); \ - goto fail; \ - } \ -}\ - -typedef struct OpenGLVertexInfo -{ - float x, y, z; ///texture_name); - opengl->texture_name[0] = opengl->texture_name[1] = - opengl->texture_name[2] = opengl->texture_name[3] = 0; - if (opengl->glprocs.glUseProgram) - opengl->glprocs.glUseProgram(0); - if (opengl->glprocs.glDeleteProgram) { - opengl->glprocs.glDeleteProgram(opengl->program); - opengl->program = 0; - } - if (opengl->glprocs.glDeleteShader) { - opengl->glprocs.glDeleteShader(opengl->vertex_shader); - opengl->glprocs.glDeleteShader(opengl->fragment_shader); - opengl->vertex_shader = opengl->fragment_shader = 0; - } - if (opengl->glprocs.glBindBuffer) { - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0); - } - if (opengl->glprocs.glDeleteBuffers) { - opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer); - opengl->vertex_buffer = opengl->index_buffer = 0; - } -} - -static int opengl_resize(AVFormatContext *h, int width, int height) -{ - int ret = 0; - OpenGLContext *opengl = h->priv_data; - opengl->window_width = width; - opengl->window_height = height; - if (opengl->inited) { - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - goto end; - } - if ((ret = opengl_prepare_vertex(h)) < 0) - goto end; - ret = opengl_draw(h, NULL, 1, 0); - } - end: - return ret; -} - -static int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size) -{ - OpenGLContext *opengl = h->priv_data; - switch(type) { - case AV_APP_TO_DEV_WINDOW_SIZE: - if (data) { - AVDeviceRect *message = data; - return opengl_resize(h, message->width, message->height); - } - return AVERROR(EINVAL); - case AV_APP_TO_DEV_WINDOW_REPAINT: - return opengl_resize(h, opengl->window_width, opengl->window_height); - } - return AVERROR(ENOSYS); -} - -#if CONFIG_SDL2 -static int opengl_sdl_process_events(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVDeviceRect message; - SDL_Event event; - SDL_PumpEvents(); - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) { - switch (event.type) { - case SDL_QUIT: - return AVERROR(EIO); - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - case SDLK_q: - return AVERROR(EIO); - } - return 0; - case SDL_WINDOWEVENT: - switch(event.window.event) { - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height); - return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect)); - default: - break; - } - } - } - return 0; -} - -static int av_cold opengl_sdl_create_window(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVDeviceRect message; - if (SDL_Init(SDL_INIT_VIDEO)) { - av_log(opengl, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - opengl->window = SDL_CreateWindow(opengl->window_title, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - opengl->window_width, opengl->window_height, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); - if (!opengl->window) { - av_log(opengl, AV_LOG_ERROR, "Unable to create default window: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - opengl->glcontext = SDL_GL_CreateContext(opengl->window); - if (!opengl->glcontext) { - av_log(opengl, AV_LOG_ERROR, "Unable to create OpenGL context on default window: %s\n", SDL_GetError()); - return AVERROR_EXTERNAL; - } - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - av_log(opengl, AV_LOG_INFO, "SDL driver: '%s'.\n", SDL_GetCurrentVideoDriver()); - SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height); - return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect)); -} - -static int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#define LOAD_OPENGL_FUN(name, type) \ - procs->name = (type)SDL_GL_GetProcAddress(#name); \ - if (!procs->name) { \ - av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \ - return AVERROR(ENOSYS); \ - } - - LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC) - LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC) - LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC) - LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC) - LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC) - LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC) - LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC) - LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC) - LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC) - LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC) - LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC) - LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC) - LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC) - LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC) - LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC) - LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC) - LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC) - LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC) - LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC) - LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC) - LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC) - LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC) - LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC) - LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) - LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC) - - return 0; - -#undef LOAD_OPENGL_FUN -} -#endif /* CONFIG_SDL2 */ - -#if defined(__APPLE__) -static int av_cold opengl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#if CONFIG_SDL2 - if (!opengl->no_window) - return opengl_sdl_load_procedures(opengl); -#endif - - procs->glActiveTexture = glActiveTexture; - procs->glGenBuffers = glGenBuffers; - procs->glDeleteBuffers = glDeleteBuffers; - procs->glBufferData = glBufferData; - procs->glBindBuffer = glBindBuffer; - procs->glGetAttribLocation = glGetAttribLocation; - procs->glGetUniformLocation = glGetUniformLocation; - procs->glUniform1f = glUniform1f; - procs->glUniform1i = glUniform1i; - procs->glUniformMatrix4fv = glUniformMatrix4fv; - procs->glCreateProgram = glCreateProgram; - procs->glDeleteProgram = glDeleteProgram; - procs->glUseProgram = glUseProgram; - procs->glLinkProgram = glLinkProgram; - procs->glGetProgramiv = glGetProgramiv; - procs->glGetProgramInfoLog = glGetProgramInfoLog; - procs->glAttachShader = glAttachShader; - procs->glCreateShader = glCreateShader; - procs->glDeleteShader = glDeleteShader; - procs->glCompileShader = glCompileShader; - procs->glShaderSource = glShaderSource; - procs->glGetShaderiv = glGetShaderiv; - procs->glGetShaderInfoLog = glGetShaderInfoLog; - procs->glEnableVertexAttribArray = glEnableVertexAttribArray; - procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer; - return 0; -} -#else -static int av_cold opengl_load_procedures(OpenGLContext *opengl) -{ - FFOpenGLFunctions *procs = &opengl->glprocs; - -#if HAVE_GLXGETPROCADDRESS -#define SelectedGetProcAddress glXGetProcAddress -#elif HAVE_WGLGETPROCADDRESS -#define SelectedGetProcAddress wglGetProcAddress -#endif - -#define LOAD_OPENGL_FUN(name, type) \ - procs->name = (type)SelectedGetProcAddress(#name); \ - if (!procs->name) { \ - av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \ - return AVERROR(ENOSYS); \ - } - -#if CONFIG_SDL2 - if (!opengl->no_window) - return opengl_sdl_load_procedures(opengl); -#endif - - LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC) - LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC) - LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC) - LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC) - LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC) - LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC) - LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC) - LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC) - LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC) - LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC) - LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC) - LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC) - LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC) - LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC) - LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC) - LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC) - LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC) - LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC) - LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC) - LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC) - LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC) - LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC) - LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC) - LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) - LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC) - - return 0; - -#undef SelectedGetProcAddress -#undef LOAD_OPENGL_FUN -} -#endif - -static void opengl_make_identity(float matrix[16]) -{ - memset(matrix, 0, 16 * sizeof(float)); - matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f; -} - -static void opengl_make_ortho(float matrix[16], float left, float right, - float bottom, float top, float nearZ, float farZ) -{ - float ral = right + left; - float rsl = right - left; - float tab = top + bottom; - float tsb = top - bottom; - float fan = farZ + nearZ; - float fsn = farZ - nearZ; - - memset(matrix, 0, 16 * sizeof(float)); - matrix[0] = 2.0f / rsl; - matrix[5] = 2.0f / tsb; - matrix[10] = -2.0f / fsn; - matrix[12] = -ral / rsl; - matrix[13] = -tab / tsb; - matrix[14] = -fan / fsn; - matrix[15] = 1.0f; -} - -static av_cold int opengl_read_limits(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - static const struct{ - const char *extension; - int major; - int minor; - } required_extensions[] = { - { "GL_ARB_multitexture", 1, 3 }, - { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object - { "GL_ARB_vertex_shader", 2, 0 }, - { "GL_ARB_fragment_shader", 2, 0 }, - { "GL_ARB_shader_objects", 2, 0 }, - { NULL, 0, 0 } - }; - int i, major, minor; - const char *extensions, *version; - - version = glGetString(GL_VERSION); - extensions = glGetString(GL_EXTENSIONS); - if (!version || !extensions) { - av_log(h, AV_LOG_ERROR, "No OpenGL context initialized for the current thread\n"); - return AVERROR(ENOSYS); - } - - av_log(h, AV_LOG_DEBUG, "OpenGL version: %s\n", version); - if (sscanf(version, "%d.%d", &major, &minor) != 2) - return AVERROR(ENOSYS); - - for (i = 0; required_extensions[i].extension; i++) { - if (major < required_extensions[i].major && - (major == required_extensions[i].major && minor < required_extensions[i].minor) && - !strstr(extensions, required_extensions[i].extension)) { - av_log(h, AV_LOG_ERROR, "Required extension %s is not supported.\n", - required_extensions[i].extension); - av_log(h, AV_LOG_DEBUG, "Supported extensions are: %s\n", extensions); - return AVERROR(ENOSYS); - } - } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &opengl->max_texture_size); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &opengl->max_viewport_width); - opengl->non_pow_2_textures = major >= 2 || strstr(extensions, "GL_ARB_texture_non_power_of_two"); -#if defined(GL_ES_VERSION_2_0) - opengl->unpack_subimage = !!strstr(extensions, "GL_EXT_unpack_subimage"); -#else - opengl->unpack_subimage = 1; -#endif - - av_log(h, AV_LOG_DEBUG, "Non Power of 2 textures support: %s\n", opengl->non_pow_2_textures ? "Yes" : "No"); - av_log(h, AV_LOG_DEBUG, "Unpack Subimage extension support: %s\n", opengl->unpack_subimage ? "Yes" : "No"); - av_log(h, AV_LOG_DEBUG, "Max texture size: %dx%d\n", opengl->max_texture_size, opengl->max_texture_size); - av_log(h, AV_LOG_DEBUG, "Max viewport size: %dx%d\n", - opengl->max_viewport_width, opengl->max_viewport_height); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) { - if (opengl_format_desc[i].fixel_format == format) - return *opengl_format_desc[i].fragment_shader; - } - return NULL; -} - -static int opengl_type_size(GLenum type) -{ - switch(type) { - case GL_UNSIGNED_SHORT: - case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_SHORT_5_6_5: - return 2; - case GL_UNSIGNED_BYTE: - case FF_GL_UNSIGNED_BYTE_3_3_2: - case FF_GL_UNSIGNED_BYTE_2_3_3_REV: - default: - break; - } - return 1; -} - -static av_cold void opengl_get_texture_params(OpenGLContext *opengl) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) { - if (opengl_format_desc[i].fixel_format == opengl->pix_fmt) { - opengl->format = opengl_format_desc[i].format; - opengl->type = opengl_format_desc[i].type; - break; - } - } -} - -static void opengl_compute_display_area(AVFormatContext *s) -{ - AVRational sar, dar; /* sample and display aspect ratios */ - OpenGLContext *opengl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *par = st->codecpar; - - /* compute overlay width and height from the codec context information */ - sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 }; - dar = av_mul_q(sar, (AVRational){ par->width, par->height }); - - /* we suppose the screen has a 1/1 sample aspect ratio */ - /* fit in the window */ - if (av_cmp_q(dar, (AVRational){ opengl->window_width, opengl->window_height }) > 0) { - /* fit in width */ - opengl->picture_width = opengl->window_width; - opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num); - } else { - /* fit in height */ - opengl->picture_height = opengl->window_height; - opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den); - } -} - -static av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height, - int *out_width, int *out_height) -{ - if (opengl->non_pow_2_textures) { - *out_width = in_width; - *out_height = in_height; - } else { - int max = FFMIN(FFMAX(in_width, in_height), opengl->max_texture_size); - unsigned power_of_2 = 1; - while (power_of_2 < max) - power_of_2 *= 2; - *out_height = power_of_2; - *out_width = power_of_2; - av_log(opengl, AV_LOG_DEBUG, "Texture size calculated from %dx%d into %dx%d\n", - in_width, in_height, *out_width, *out_height); - } -} - -static av_cold void opengl_fill_color_map(OpenGLContext *opengl) -{ - const AVPixFmtDescriptor *desc; - int shift; - enum AVPixelFormat pix_fmt = opengl->pix_fmt; - - /* We need order of components, not exact position, some minor HACKs here */ - if (pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR555 || - pix_fmt == AV_PIX_FMT_BGR8 || pix_fmt == AV_PIX_FMT_RGB8) - pix_fmt = AV_PIX_FMT_RGB24; - else if (pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_RGB555) - pix_fmt = AV_PIX_FMT_BGR24; - - desc = av_pix_fmt_desc_get(pix_fmt); - if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) - return; - -#define FILL_COMPONENT(i) { \ - shift = (desc->comp[i].depth - 1) >> 3; \ - opengl->color_map[(i << 2) + (desc->comp[i].offset >> shift)] = 1.0; \ - } - - memset(opengl->color_map, 0, sizeof(opengl->color_map)); - FILL_COMPONENT(0); - FILL_COMPONENT(1); - FILL_COMPONENT(2); - if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) - FILL_COMPONENT(3); - -#undef FILL_COMPONENT -} - -static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source) -{ - GLuint shader = opengl->glprocs.glCreateShader(type); - GLint result; - if (!shader) { - av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n"); - return 0; - } - opengl->glprocs.glShaderSource(shader, 1, &source, NULL); - opengl->glprocs.glCompileShader(shader); - - opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result); - if (!result) { - char *log; - opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result); - if (result) { - if ((log = av_malloc(result))) { - opengl->glprocs.glGetShaderInfoLog(shader, result, NULL, log); - av_log(opengl, AV_LOG_ERROR, "Compile error: %s\n", log); - av_free(log); - } - } - goto fail; - } - OPENGL_ERROR_CHECK(opengl); - return shader; - fail: - opengl->glprocs.glDeleteShader(shader); - return 0; -} - -static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt) -{ - GLint result; - const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt); - - if (!fragment_shader_code) { - av_log(opengl, AV_LOG_ERROR, "Provided pixel format '%s' is not supported\n", - av_get_pix_fmt_name(pix_fmt)); - return AVERROR(EINVAL); - } - - opengl->vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER, - FF_OPENGL_VERTEX_SHADER); - if (!opengl->vertex_shader) { - av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n"); - goto fail; - } - opengl->fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER, - fragment_shader_code); - if (!opengl->fragment_shader) { - av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n"); - goto fail; - } - - opengl->program = opengl->glprocs.glCreateProgram(); - if (!opengl->program) - goto fail; - - opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader); - opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader); - opengl->glprocs.glLinkProgram(opengl->program); - - opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result); - if (!result) { - char *log; - opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result); - if (result) { - log = av_malloc(result); - if (!log) - goto fail; - opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log); - av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log); - av_free(log); - } - goto fail; - } - - opengl->position_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_position"); - opengl->texture_coords_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_textureCoords"); - opengl->projection_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_projectionMatrix"); - opengl->model_view_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_modelViewMatrix"); - opengl->color_map_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_colorMap"); - opengl->texture_location[0] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture0"); - opengl->texture_location[1] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture1"); - opengl->texture_location[2] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture2"); - opengl->texture_location[3] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture3"); - opengl->chroma_div_w_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_w"); - opengl->chroma_div_h_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_h"); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - opengl->glprocs.glDeleteShader(opengl->vertex_shader); - opengl->glprocs.glDeleteShader(opengl->fragment_shader); - opengl->glprocs.glDeleteProgram(opengl->program); - opengl->fragment_shader = opengl->vertex_shader = opengl->program = 0; - return AVERROR_EXTERNAL; -} - -static av_cold int opengl_configure_texture(OpenGLContext *opengl, GLuint texture, - GLsizei width, GLsizei height) -{ - if (texture) { - int new_width, new_height; - opengl_get_texture_size(opengl, width, height, &new_width, &new_height); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, opengl->format, new_width, new_height, 0, - opengl->format, opengl->type, NULL); - OPENGL_ERROR_CHECK(NULL); - } - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static av_cold int opengl_prepare_vertex(AVFormatContext *s) -{ - OpenGLContext *opengl = s->priv_data; - int tex_w, tex_h; - - if (opengl->window_width > opengl->max_viewport_width || opengl->window_height > opengl->max_viewport_height) { - opengl->window_width = FFMIN(opengl->window_width, opengl->max_viewport_width); - opengl->window_height = FFMIN(opengl->window_height, opengl->max_viewport_height); - av_log(opengl, AV_LOG_WARNING, "Too big viewport requested, limited to %dx%d", opengl->window_width, opengl->window_height); - } - glViewport(0, 0, opengl->window_width, opengl->window_height); - opengl_make_ortho(opengl->projection_matrix, - - (float)opengl->window_width / 2.0f, (float)opengl->window_width / 2.0f, - - (float)opengl->window_height / 2.0f, (float)opengl->window_height / 2.0f, - 1.0f, -1.0f); - opengl_make_identity(opengl->model_view_matrix); - - opengl_compute_display_area(s); - - opengl->vertex[0].z = opengl->vertex[1].z = opengl->vertex[2].z = opengl->vertex[3].z = 0.0f; - opengl->vertex[0].x = opengl->vertex[1].x = - (float)opengl->picture_width / 2.0f; - opengl->vertex[2].x = opengl->vertex[3].x = (float)opengl->picture_width / 2.0f; - opengl->vertex[1].y = opengl->vertex[2].y = - (float)opengl->picture_height / 2.0f; - opengl->vertex[0].y = opengl->vertex[3].y = (float)opengl->picture_height / 2.0f; - - opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h); - - opengl->vertex[0].s0 = 0.0f; - opengl->vertex[0].t0 = 0.0f; - opengl->vertex[1].s0 = 0.0f; - opengl->vertex[1].t0 = (float)opengl->height / (float)tex_h; - opengl->vertex[2].s0 = (float)opengl->width / (float)tex_w; - opengl->vertex[2].t0 = (float)opengl->height / (float)tex_h; - opengl->vertex[3].s0 = (float)opengl->width / (float)tex_w; - opengl->vertex[3].t0 = 0.0f; - - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer); - opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW); - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0); - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static int opengl_prepare(OpenGLContext *opengl) -{ - int i; - opengl->glprocs.glUseProgram(opengl->program); - opengl->glprocs.glUniformMatrix4fv(opengl->projection_matrix_location, 1, GL_FALSE, opengl->projection_matrix); - opengl->glprocs.glUniformMatrix4fv(opengl->model_view_matrix_location, 1, GL_FALSE, opengl->model_view_matrix); - for (i = 0; i < 4; i++) - if (opengl->texture_location[i] != -1) { - opengl->glprocs.glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, opengl->texture_name[i]); - opengl->glprocs.glUniform1i(opengl->texture_location[i], i); - } - if (opengl->color_map_location != -1) - opengl->glprocs.glUniformMatrix4fv(opengl->color_map_location, 1, GL_FALSE, opengl->color_map); - if (opengl->chroma_div_h_location != -1) - opengl->glprocs.glUniform1f(opengl->chroma_div_h_location, opengl->chroma_div_h); - if (opengl->chroma_div_w_location != -1) - opengl->glprocs.glUniform1f(opengl->chroma_div_w_location, opengl->chroma_div_w); - - OPENGL_ERROR_CHECK(opengl); - return 0; - fail: - return AVERROR_EXTERNAL; -} - -static int opengl_create_window(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - int ret; - - if (!opengl->no_window) { -#if CONFIG_SDL2 - if ((ret = opengl_sdl_create_window(h)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n"); - return ret; - } -#else - av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n"); - return AVERROR(ENOSYS); -#endif - } else { - AVDeviceRect message; - message.x = message.y = 0; - message.width = opengl->window_width; - message.height = opengl->window_height; - if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER, - &message , sizeof(message))) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n"); - return ret; - } - if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - return ret; - } - } - return 0; -} - -static int opengl_release_window(AVFormatContext *h) -{ - int ret; - OpenGLContext *opengl = h->priv_data; - if (!opengl->no_window) { -#if CONFIG_SDL2 - SDL_GL_DeleteContext(opengl->glcontext); - SDL_DestroyWindow(opengl->window); - SDL_Quit(); -#endif - } else if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n"); - return ret; - } - return 0; -} - -static av_cold int opengl_write_trailer(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - - if (opengl->no_window && - avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0) - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - - opengl_deinit_context(opengl); - opengl_release_window(h); - - return 0; -} - -static av_cold int opengl_init_context(OpenGLContext *opengl) -{ - int i, ret; - const AVPixFmtDescriptor *desc; - - if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0) - goto fail; - - desc = av_pix_fmt_desc_get(opengl->pix_fmt); - av_assert0(desc->nb_components > 0 && desc->nb_components <= 4); - glGenTextures(desc->nb_components, opengl->texture_name); - - opengl->glprocs.glGenBuffers(2, &opengl->index_buffer); - if (!opengl->index_buffer || !opengl->vertex_buffer) { - av_log(opengl, AV_LOG_ERROR, "Buffer generation failed.\n"); - ret = AVERROR_EXTERNAL; - goto fail; - } - - opengl_configure_texture(opengl, opengl->texture_name[0], opengl->width, opengl->height); - if (desc->nb_components > 1) { - int has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA; - int num_planes = desc->nb_components - (has_alpha ? 1 : 0); - if (opengl->non_pow_2_textures) { - opengl->chroma_div_w = 1.0f; - opengl->chroma_div_h = 1.0f; - } else { - opengl->chroma_div_w = 1 << desc->log2_chroma_w; - opengl->chroma_div_h = 1 << desc->log2_chroma_h; - } - for (i = 1; i < num_planes; i++) - if (opengl->non_pow_2_textures) - opengl_configure_texture(opengl, opengl->texture_name[i], - AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w), - AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h)); - else - opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height); - if (has_alpha) - opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height); - } - - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); - opengl->glprocs.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER, sizeof(g_index), g_index, FF_GL_STATIC_DRAW); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f, - (float)opengl->background[2] / 255.0f, 1.0f); - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - return 0; - fail: - return ret; -} - -static av_cold int opengl_write_header(AVFormatContext *h) -{ - OpenGLContext *opengl = h->priv_data; - AVCodecParameters *par = h->streams[0]->codecpar; - AVStream *st; - int ret; - - if (!opengl->warned) { - av_log(opengl, AV_LOG_WARNING, - "The opengl output device is deprecated due to being fundamentally incompatible with libavformat API. " - "For monitoring purposes in ffmpeg you can output to a file or use pipes and a video player.\n" - "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" - ); - opengl->warned = 1; - } - - if (h->nb_streams != 1 || - par->codec_type != AVMEDIA_TYPE_VIDEO || - (par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME && par->codec_id != AV_CODEC_ID_RAWVIDEO)) { - av_log(opengl, AV_LOG_ERROR, "Only a single raw or wrapped avframe video stream is supported.\n"); - return AVERROR(EINVAL); - } - st = h->streams[0]; - opengl->width = st->codecpar->width; - opengl->height = st->codecpar->height; - opengl->pix_fmt = st->codecpar->format; - if (!opengl->window_width) - opengl->window_width = opengl->width; - if (!opengl->window_height) - opengl->window_height = opengl->height; - - if (!opengl->window_title && !opengl->no_window) - opengl->window_title = av_strdup(h->url); - - if ((ret = opengl_create_window(h))) - goto fail; - - if ((ret = opengl_read_limits(h)) < 0) - goto fail; - - if (opengl->width > opengl->max_texture_size || opengl->height > opengl->max_texture_size) { - av_log(opengl, AV_LOG_ERROR, "Too big picture %dx%d, max supported size is %dx%d\n", - opengl->width, opengl->height, opengl->max_texture_size, opengl->max_texture_size); - ret = AVERROR(EINVAL); - goto fail; - } - - if ((ret = opengl_load_procedures(opengl)) < 0) - goto fail; - - opengl_fill_color_map(opengl); - opengl_get_texture_params(opengl); - - if ((ret = opengl_init_context(opengl)) < 0) - goto fail; - - if ((ret = opengl_prepare_vertex(h)) < 0) - goto fail; - - glClear(GL_COLOR_BUFFER_BIT); - -#if CONFIG_SDL2 - if (!opengl->no_window) - SDL_GL_SwapWindow(opengl->window); -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n"); - goto fail; - } - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - opengl->inited = 1; - return 0; - - fail: - opengl_write_trailer(h); - return ret; -} - -static uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index, - const AVPixFmtDescriptor *desc) -{ - uint8_t *data = pkt->data; - int wordsize = opengl_type_size(opengl->type); - int width_chroma = AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w); - int height_chroma = AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h); - int plane = desc->comp[comp_index].plane; - - switch(plane) { - case 0: - break; - case 1: - data += opengl->width * opengl->height * wordsize; - break; - case 2: - data += opengl->width * opengl->height * wordsize; - data += width_chroma * height_chroma * wordsize; - break; - case 3: - data += opengl->width * opengl->height * wordsize; - data += 2 * width_chroma * height_chroma * wordsize; - break; - default: - return NULL; - } - return data; -} - -#define LOAD_TEXTURE_DATA(comp_index, sub) \ -{ \ - int width = sub ? AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \ - int height = sub ? AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \ - uint8_t *data; \ - int plane = desc->comp[comp_index].plane; \ - \ - glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \ - if (!is_pkt) { \ - GLint length = ((AVFrame *)input)->linesize[plane]; \ - int bytes_per_pixel = opengl_type_size(opengl->type); \ - if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \ - bytes_per_pixel *= desc->nb_components; \ - data = ((AVFrame *)input)->data[plane]; \ - if (!(length % bytes_per_pixel) && \ - (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \ - length /= bytes_per_pixel; \ - if (length != width) \ - glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \ - opengl->format, opengl->type, data); \ - if (length != width) \ - glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \ - } else { \ - int h; \ - for (h = 0; h < height; h++) { \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \ - opengl->format, opengl->type, data); \ - data += length; \ - } \ - } \ - } else { \ - data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \ - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \ - opengl->format, opengl->type, data); \ - } \ -} - -static int opengl_draw(AVFormatContext *h, void *input, int repaint, int is_pkt) -{ - OpenGLContext *opengl = h->priv_data; - enum AVPixelFormat pix_fmt = h->streams[0]->codecpar->format; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - int ret; - -#if CONFIG_SDL2 - /* At this point, opengl->glcontext implies opengl->glcontext */ - if (opengl->glcontext) - SDL_GL_MakeCurrent(opengl->window, opengl->glcontext); - - if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0) - goto fail; -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n"); - goto fail; - } - - glClear(GL_COLOR_BUFFER_BIT); - - if (!repaint) { - if (is_pkt) - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - LOAD_TEXTURE_DATA(0, 0) - if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) { - LOAD_TEXTURE_DATA(1, 1) - LOAD_TEXTURE_DATA(2, 1) - if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) - LOAD_TEXTURE_DATA(3, 0) - } - } - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - - if ((ret = opengl_prepare(opengl)) < 0) - goto fail; - - opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer); - opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); - opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0); - opengl->glprocs.glEnableVertexAttribArray(opengl->position_attrib); - opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12); - opengl->glprocs.glEnableVertexAttribArray(opengl->texture_coords_attrib); - - glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0); - - ret = AVERROR_EXTERNAL; - OPENGL_ERROR_CHECK(opengl); - -#if CONFIG_SDL2 - if (!opengl->no_window) - SDL_GL_SwapWindow(opengl->window); -#endif - if (opengl->no_window && - (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) { - av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n"); - goto fail; - } - - return 0; - fail: - return ret; -} - -static int opengl_write_packet(AVFormatContext *h, AVPacket *pkt) -{ - AVCodecParameters *par = h->streams[0]->codecpar; - if (par->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { - AVFrame *frame = (AVFrame *)pkt->data; - return opengl_draw(h, frame, 0, 0); - } else { - return opengl_draw(h, pkt, 0, 1); - } -} - -static int opengl_write_frame(AVFormatContext *h, int stream_index, - AVFrame **frame, unsigned flags) -{ - if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) - return 0; - return opengl_draw(h, *frame, 0, 0); -} - -#define OFFSET(x) offsetof(OpenGLContext, x) -#define ENC AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { - { "background", "set background color", OFFSET(background), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, ENC }, - { "no_window", "disable default window", OFFSET(no_window), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, ENC }, - { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, ENC }, - { "window_size", "set window size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, ENC }, - { NULL } -}; - -static const AVClass opengl_class = { - .class_name = "opengl outdev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT, -}; - -const FFOutputFormat ff_opengl_muxer = { - .p.name = "opengl", - .p.long_name = NULL_IF_CONFIG_SMALL("OpenGL output"), - .p.audio_codec = AV_CODEC_ID_NONE, - .p.video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, - .p.flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS, - .p.priv_class = &opengl_class, - .priv_data_size = sizeof(OpenGLContext), - .write_header = opengl_write_header, - .write_packet = opengl_write_packet, - .write_uncoded_frame = opengl_write_frame, - .write_trailer = opengl_write_trailer, - .control_message = opengl_control_message, -}; diff --git a/libavdevice/opengl_enc_shaders.h b/libavdevice/opengl_enc_shaders.h deleted file mode 100644 index 67ee0ae7b4..0000000000 --- a/libavdevice/opengl_enc_shaders.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2014 Lukasz Marek - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVDEVICE_OPENGL_ENC_SHADERS_H -#define AVDEVICE_OPENGL_ENC_SHADERS_H - -#include "libavutil/pixfmt.h" - -static const char * const FF_OPENGL_VERTEX_SHADER = - "uniform mat4 u_projectionMatrix;" - "uniform mat4 u_modelViewMatrix;" - - "attribute vec4 a_position;" - "attribute vec2 a_textureCoords;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_Position = u_projectionMatrix * (a_position * u_modelViewMatrix);" - "texture_coordinate = a_textureCoords;" - "}"; - -/** - * Fragment shader for packet RGBA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform mat4 u_colorMap;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = texture2D(u_texture0, texture_coordinate) * u_colorMap;" - "}"; - -/** - * Fragment shader for packet RGB formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform mat4 u_colorMap;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4((texture2D(u_texture0, texture_coordinate) * u_colorMap).rgb, 1.0);" - "}"; - -/** - * Fragment shader for planar RGBA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform sampler2D u_texture3;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r," - "texture2D(u_texture1, texture_coordinate).r," - "texture2D(u_texture2, texture_coordinate).r," - "texture2D(u_texture3, texture_coordinate).r);" - "}"; - -/** - * Fragment shader for planar RGB formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r," - "texture2D(u_texture1, texture_coordinate).r," - "texture2D(u_texture2, texture_coordinate).r," - "1.0);" - "}"; - -/** - * Fragment shader for planar YUV formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform float u_chroma_div_w;" - "uniform float u_chroma_div_h;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "vec3 yuv;" - - "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;" - "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - - "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643," - "0.0, -0.39173, 2.0170," - "1.5958, -0.81290, 0.0) * yuv, 1.0), 0.0, 1.0);" - - "}"; - -/** - * Fragment shader for planar YUVA formats. - */ -static const char * const FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "uniform sampler2D u_texture1;" - "uniform sampler2D u_texture2;" - "uniform sampler2D u_texture3;" - "uniform float u_chroma_div_w;" - "uniform float u_chroma_div_h;" - - "varying vec2 texture_coordinate;" - - "void main()" - "{" - "vec3 yuv;" - - "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;" - "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;" - - "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643," - "0.0, -0.39173, 2.0170," - "1.5958, -0.81290, 0.0) * yuv, texture2D(u_texture3, texture_coordinate).r), 0.0, 1.0);" - "}"; - -static const char * const FF_OPENGL_FRAGMENT_SHADER_GRAY = -#if defined(GL_ES_VERSION_2_0) - "precision mediump float;" -#endif - "uniform sampler2D u_texture0;" - "varying vec2 texture_coordinate;" - "void main()" - "{" - "float c = texture2D(u_texture0, texture_coordinate).r;" - "gl_FragColor = vec4(c, c, c, 1.0);" - "}"; - -#endif /* AVDEVICE_OPENGL_ENC_SHADERS_H */ diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c index 80136d1e20..d1652bf8d7 100644 --- a/libavdevice/pulse_audio_enc.c +++ b/libavdevice/pulse_audio_enc.c @@ -796,11 +796,7 @@ const FFOutputFormat ff_pulse_muxer = { .get_output_timestamp = pulse_get_output_timestamp, .get_device_list = pulse_get_device_list, .control_message = pulse_control_message, -#if FF_API_ALLOW_FLUSH - .p.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH, -#else .p.flags = AVFMT_NOFILE, -#endif .p.priv_class = &pulse_muxer_class, .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH, }; diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c deleted file mode 100644 index 491c8dafe8..0000000000 --- a/libavdevice/sdl2.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) 2016 Josh de Kock - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * libSDL2 output device - */ - -#include -#include - -#include "libavutil/imgutils.h" -#include "libavutil/mem.h" -#include "libavutil/opt.h" -#include "libavutil/pixdesc.h" -#include "libavformat/mux.h" - -typedef struct { - AVClass *class; - SDL_Window *window; - SDL_Renderer *renderer; - char *window_title; - int window_width, window_height; /**< size of the window */ - int window_x, window_y; /**< position of the window */ - int window_fullscreen; - int window_borderless; - int enable_quit_action; - - SDL_Texture *texture; - int texture_fmt; - SDL_Rect texture_rect; - - int inited; - int warned; -} SDLContext; - -static const struct sdl_texture_format_entry { - enum AVPixelFormat format; int texture_fmt; -} sdl_texture_format_map[] = { - /* - * Not implemented in FFmpeg, but leaving here for completeness. - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA4444 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB1555 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA5551 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR1555 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA5551 }, - * { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB2101010 }, - */ - { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 }, - { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 }, - { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 }, - { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 }, - { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 }, - { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 }, - { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 }, - { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 }, - { AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_RGB888 }, - { AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_BGR888 }, -#if HAVE_BIGENDIAN - { AV_PIX_FMT_RGB0, SDL_PIXELFORMAT_RGBX8888 }, - { AV_PIX_FMT_BGR0, SDL_PIXELFORMAT_BGRX8888 }, -#else - { AV_PIX_FMT_0BGR, SDL_PIXELFORMAT_RGBX8888 }, - { AV_PIX_FMT_0RGB, SDL_PIXELFORMAT_BGRX8888 }, -#endif - { AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888 }, - { AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888 }, - { AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888 }, - { AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888 }, - { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, - { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, - { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY }, - { AV_PIX_FMT_NONE, 0 }, -}; - -static void compute_texture_rect(AVFormatContext *s) -{ - AVRational sar, dar; /* sample and display aspect ratios */ - SDLContext *sdl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *codecpar = st->codecpar; - SDL_Rect *texture_rect = &sdl->texture_rect; - - /* compute texture width and height from the codec context information */ - sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 }; - dar = av_mul_q(sar, (AVRational){ codecpar->width, codecpar->height }); - - /* we suppose the screen has a 1/1 sample aspect ratio */ - if (sdl->window_width && sdl->window_height) { - /* fit in the window */ - if (av_cmp_q(dar, (AVRational){ sdl->window_width, sdl->window_height }) > 0) { - /* fit in width */ - texture_rect->w = sdl->window_width; - texture_rect->h = av_rescale(texture_rect->w, dar.den, dar.num); - } else { - /* fit in height */ - texture_rect->h = sdl->window_height; - texture_rect->w = av_rescale(texture_rect->h, dar.num, dar.den); - } - } else { - if (sar.num > sar.den) { - texture_rect->w = codecpar->width; - texture_rect->h = av_rescale(texture_rect->w, dar.den, dar.num); - } else { - texture_rect->h = codecpar->height; - texture_rect->w = av_rescale(texture_rect->h, dar.num, dar.den); - } - sdl->window_width = texture_rect->w; - sdl->window_height = texture_rect->h; - } - - texture_rect->x = (sdl->window_width - texture_rect->w) / 2; - texture_rect->y = (sdl->window_height - texture_rect->h) / 2; -} - -static int sdl2_write_trailer(AVFormatContext *s) -{ - SDLContext *sdl = s->priv_data; - - if (sdl->texture) - SDL_DestroyTexture(sdl->texture); - sdl->texture = NULL; - - if (sdl->renderer) - SDL_DestroyRenderer(sdl->renderer); - sdl->renderer = NULL; - - if (sdl->window) - SDL_DestroyWindow(sdl->window); - sdl->window = NULL; - - if (!sdl->inited) - SDL_Quit(); - - return 0; -} - -static int sdl2_write_header(AVFormatContext *s) -{ - SDLContext *sdl = s->priv_data; - AVStream *st = s->streams[0]; - AVCodecParameters *codecpar = st->codecpar; - int i, ret = 0; - int flags = 0; - - if (!sdl->warned) { - av_log(sdl, AV_LOG_WARNING, - "The sdl output device is deprecated due to being fundamentally incompatible with libavformat API. " - "For monitoring purposes in ffmpeg you can output to a file or use pipes and a video player.\n" - "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" - ); - sdl->warned = 1; - } - - if (!sdl->window_title) - sdl->window_title = av_strdup(s->url); - - if (SDL_WasInit(SDL_INIT_VIDEO)) { - av_log(s, AV_LOG_WARNING, - "SDL video subsystem was already inited, you could have multiple SDL outputs. This may cause unknown behaviour.\n"); - sdl->inited = 1; - } - - if ( s->nb_streams > 1 - || codecpar->codec_type != AVMEDIA_TYPE_VIDEO - || codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) { - av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n"); - goto fail; - } - - for (i = 0; sdl_texture_format_map[i].format != AV_PIX_FMT_NONE; i++) { - if (sdl_texture_format_map[i].format == codecpar->format) { - sdl->texture_fmt = sdl_texture_format_map[i].texture_fmt; - break; - } - } - - if (!sdl->texture_fmt) { - av_log(s, AV_LOG_ERROR, - "Unsupported pixel format '%s'.\n", - av_get_pix_fmt_name(codecpar->format)); - goto fail; - } - - /* resize texture to width and height from the codec context information */ - flags = SDL_WINDOW_HIDDEN | - (sdl->window_fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | - (sdl->window_borderless ? SDL_WINDOW_BORDERLESS : SDL_WINDOW_RESIZABLE); - - /* initialization */ - if (!sdl->inited){ - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError()); - goto fail; - } - } - - compute_texture_rect(s); - - if (SDL_CreateWindowAndRenderer(sdl->window_width, sdl->window_height, - flags, &sdl->window, &sdl->renderer) != 0){ - av_log(sdl, AV_LOG_ERROR, "Couldn't create window and renderer: %s\n", SDL_GetError()); - goto fail; - } - - SDL_SetWindowTitle(sdl->window, sdl->window_title); - SDL_SetWindowPosition(sdl->window, sdl->window_x, sdl->window_y); - SDL_ShowWindow(sdl->window); - - sdl->texture = SDL_CreateTexture(sdl->renderer, sdl->texture_fmt, SDL_TEXTUREACCESS_STREAMING, - codecpar->width, codecpar->height); - - if (!sdl->texture) { - av_log(sdl, AV_LOG_ERROR, "Unable to set create mode: %s\n", SDL_GetError()); - goto fail; - } - - av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d\n", - codecpar->width, codecpar->height, av_get_pix_fmt_name(codecpar->format), - sdl->window_width, sdl->window_height); - - sdl->inited = 1; - - return 0; -fail: - sdl2_write_trailer(s); - return ret; -} - -static int sdl2_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - int ret, quit = 0; - SDLContext *sdl = s->priv_data; - AVCodecParameters *codecpar = s->streams[0]->codecpar; - uint8_t *data[4]; - int linesize[4]; - - SDL_Event event; - if (SDL_PollEvent(&event)){ - switch (event.type) { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - case SDLK_q: - quit = 1; - break; - default: - break; - } - break; - case SDL_QUIT: - quit = 1; - break; - case SDL_WINDOWEVENT: - switch(event.window.event){ - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - sdl->window_width = event.window.data1; - sdl->window_height = event.window.data2; - compute_texture_rect(s); - break; - default: - break; - } - break; - default: - break; - } - } - - if (quit && sdl->enable_quit_action) { - sdl2_write_trailer(s); - return AVERROR(EIO); - } - - av_image_fill_arrays(data, linesize, pkt->data, codecpar->format, codecpar->width, codecpar->height, 1); - switch (sdl->texture_fmt) { - /* case SDL_PIXELFORMAT_ARGB4444: - * case SDL_PIXELFORMAT_RGBA4444: - * case SDL_PIXELFORMAT_ABGR4444: - * case SDL_PIXELFORMAT_BGRA4444: - * case SDL_PIXELFORMAT_ARGB1555: - * case SDL_PIXELFORMAT_RGBA5551: - * case SDL_PIXELFORMAT_ABGR1555: - * case SDL_PIXELFORMAT_BGRA5551: - * case SDL_PIXELFORMAT_ARGB2101010: - */ - case SDL_PIXELFORMAT_IYUV: - case SDL_PIXELFORMAT_YUY2: - case SDL_PIXELFORMAT_UYVY: - ret = SDL_UpdateYUVTexture(sdl->texture, NULL, - data[0], linesize[0], - data[1], linesize[1], - data[2], linesize[2]); - break; - case SDL_PIXELFORMAT_RGB332: - case SDL_PIXELFORMAT_RGB444: - case SDL_PIXELFORMAT_RGB555: - case SDL_PIXELFORMAT_BGR555: - case SDL_PIXELFORMAT_RGB565: - case SDL_PIXELFORMAT_BGR565: - case SDL_PIXELFORMAT_RGB24: - case SDL_PIXELFORMAT_BGR24: - case SDL_PIXELFORMAT_RGB888: - case SDL_PIXELFORMAT_RGBX8888: - case SDL_PIXELFORMAT_BGR888: - case SDL_PIXELFORMAT_BGRX8888: - case SDL_PIXELFORMAT_ARGB8888: - case SDL_PIXELFORMAT_RGBA8888: - case SDL_PIXELFORMAT_ABGR8888: - case SDL_PIXELFORMAT_BGRA8888: - ret = SDL_UpdateTexture(sdl->texture, NULL, data[0], linesize[0]); - break; - default: - av_log(NULL, AV_LOG_FATAL, "Unsupported pixel format\n"); - ret = -1; - break; - } - SDL_RenderClear(sdl->renderer); - SDL_RenderCopy(sdl->renderer, sdl->texture, NULL, &sdl->texture_rect); - SDL_RenderPresent(sdl->renderer); - return ret; -} - -#define OFFSET(x) offsetof(SDLContext,x) - -static const AVOption options[] = { - { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_size", "set SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_x", "set SDL window x position", OFFSET(window_x), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_y", "set SDL window y position", OFFSET(window_y), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_borderless", "set SDL window border off", OFFSET(window_borderless), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "window_enable_quit", "set if quit action is available", OFFSET(enable_quit_action), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { NULL }, -}; - -static const AVClass sdl2_class = { - .class_name = "sdl2 outdev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT, -}; - -const FFOutputFormat ff_sdl2_muxer = { - .p.name = "sdl,sdl2", - .p.long_name = NULL_IF_CONFIG_SMALL("SDL2 output device"), - .priv_data_size = sizeof(SDLContext), - .p.audio_codec = AV_CODEC_ID_NONE, - .p.video_codec = AV_CODEC_ID_RAWVIDEO, - .write_header = sdl2_write_header, - .write_packet = sdl2_write_packet, - .write_trailer = sdl2_write_trailer, - .p.flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS, - .p.priv_class = &sdl2_class, -}; diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 0ae6872338..c38ecbb378 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -111,7 +111,7 @@ struct video_data { int (*open_f)(const char *file, int oflag, ...); int (*close_f)(int fd); int (*dup_f)(int fd); -#if HAVE_POSIX_IOCTL +#if HAVE_IOCTL_POSIX int (*ioctl_f)(int fd, int request, ...); #else int (*ioctl_f)(int fd, unsigned long int request, ...); diff --git a/libavdevice/version.h b/libavdevice/version.h index 7608a8602c..5cd01a1672 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVDEVICE_VERSION_MINOR 3 +#define LIBAVDEVICE_VERSION_MINOR 2 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ diff --git a/libavdevice/version_major.h b/libavdevice/version_major.h index f16abb6909..191511cdcc 100644 --- a/libavdevice/version_major.h +++ b/libavdevice/version_major.h @@ -25,7 +25,7 @@ * Libavdevice version macros */ -#define LIBAVDEVICE_VERSION_MAJOR 61 +#define LIBAVDEVICE_VERSION_MAJOR 62 /** * FF_API_* defines may be placed below to indicate public API that will be @@ -33,11 +33,6 @@ * the public API and may change, break or disappear at any time. */ -// reminder to remove the bktr device on next major bump -#define FF_API_BKTR_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) -// reminder to remove the opengl device on next major bump -#define FF_API_OPENGL_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) -// reminder to remove the sdl2 device on next major bump -#define FF_API_SDL2_DEVICE (LIBAVDEVICE_VERSION_MAJOR < 62) +#define FF_API_ALSA_CHANNELS (LIBAVDEVICE_VERSION_MAJOR < 63) #endif /* AVDEVICE_VERSION_MAJOR_H */ diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c index c736ec0cbc..d0b2c6e0b5 100644 --- a/libavdevice/xcbgrab.c +++ b/libavdevice/xcbgrab.c @@ -830,7 +830,7 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s) *display_name = 0; if(sscanf(s->url, "+%d,%d", &c->x, &c->y) != 2) { if (*s->url) - av_log(s, AV_LOG_WARNING, "Ambigous URL: %s\n", s->url); + av_log(s, AV_LOG_WARNING, "Ambiguous URL: %s\n", s->url); } } diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 91487afb21..07fb4c3d6c 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -24,6 +24,9 @@ OBJS = allfilters.o \ version.o \ video.o \ +include $(SRC_PATH)/libavfilter/dnn/Makefile +include $(SRC_PATH)/libavfilter/vulkan/Makefile + OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o OBJS-$(HAVE_THREADS) += pthread.o @@ -31,7 +34,6 @@ OBJS-$(HAVE_THREADS) += pthread.o OBJS-$(CONFIG_QSVVPP) += qsvvpp.o OBJS-$(CONFIG_SCENE_SAD) += scene_sad.o OBJS-$(CONFIG_DNN) += dnn_filter_common.o -include $(SRC_PATH)/libavfilter/dnn/Makefile # audio filters OBJS-$(CONFIG_AAP_FILTER) += af_aap.o @@ -186,6 +188,8 @@ OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o +OBJS-$(CONFIG_WHISPER_FILTER) += af_whisper.o + OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o # video filters @@ -206,6 +210,7 @@ OBJS-$(CONFIG_BILATERAL_FILTER) += vf_bilateral.o OBJS-$(CONFIG_BILATERAL_CUDA_FILTER) += vf_bilateral_cuda.o vf_bilateral_cuda.ptx.o OBJS-$(CONFIG_BITPLANENOISE_FILTER) += vf_bitplanenoise.o OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o +OBJS-$(CONFIG_BLACKDETECT_VULKAN_FILTER) += vf_blackdetect_vulkan.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o framesync.o OBJS-$(CONFIG_BLEND_VULKAN_FILTER) += vf_blend_vulkan.o framesync.o vulkan.o vulkan_filter.o @@ -234,6 +239,7 @@ OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o OBJS-$(CONFIG_COLORCONTRAST_FILTER) += vf_colorcontrast.o OBJS-$(CONFIG_COLORCORRECT_FILTER) += vf_colorcorrect.o +OBJS-$(CONFIG_COLORDETECT_FILTER) += vf_colordetect.o OBJS-$(CONFIG_COLORIZE_FILTER) += vf_colorize.o OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ @@ -356,6 +362,7 @@ OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.o +OBJS-$(CONFIG_INTERLACE_VULKAN_FILTER) += vf_interlace_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o OBJS-$(CONFIG_KIRSCH_FILTER) += vf_convolution.o @@ -394,6 +401,7 @@ OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o framesync.o OBJS-$(CONFIG_MONOCHROME_FILTER) += vf_monochrome.o OBJS-$(CONFIG_MORPHO_FILTER) += vf_morpho.o framesync.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o +OBJS-$(CONFIG_MSAD_FILTER) += vf_identity.o framesync.o OBJS-$(CONFIG_MULTIPLY_FILTER) += vf_multiply.o framesync.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_negate.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o @@ -417,6 +425,7 @@ OBJS-$(CONFIG_OVERLAY_VAAPI_FILTER) += vf_overlay_vaapi.o framesync.o v OBJS-$(CONFIG_OVERLAY_VULKAN_FILTER) += vf_overlay_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o +OBJS-$(CONFIG_PAD_CUDA_FILTER) += vf_pad_cuda.o vf_pad_cuda.ptx.o cuda/load_helper.o OBJS-$(CONFIG_PAD_OPENCL_FILTER) += vf_pad_opencl.o opencl.o opencl/pad.o OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o palette.o OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o framesync.o palette.o @@ -427,7 +436,6 @@ OBJS-$(CONFIG_PHOTOSENSITIVITY_FILTER) += vf_photosensitivity.o OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o OBJS-$(CONFIG_PIXELIZE_FILTER) += vf_pixelize.o OBJS-$(CONFIG_PIXSCOPE_FILTER) += vf_datascope.o -OBJS-$(CONFIG_PP_FILTER) += vf_pp.o qp_table.o OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o qp_table.o OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o @@ -436,7 +444,7 @@ OBJS-$(CONFIG_PREWITT_OPENCL_FILTER) += vf_convolution_opencl.o opencl.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_PSNR_FILTER) += vf_psnr.o framesync.o psnr.o OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o OBJS-$(CONFIG_QP_FILTER) += vf_qp.o OBJS-$(CONFIG_QUIRC_FILTER) += vf_quirc.o @@ -458,6 +466,7 @@ OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale_eval.o framesync.o +OBJS-$(CONFIG_SCALE_D3D11_FILTER) += vf_scale_d3d11.o scale_eval.o OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o scale_eval.o \ vf_scale_cuda.ptx.o cuda/load_helper.o OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale_eval.o @@ -468,6 +477,7 @@ OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vf_scale_vulkan.o vulkan.o vulka OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale_eval.o framesync.o OBJS-$(CONFIG_SCALE2REF_NPP_FILTER) += vf_scale_npp.o scale_eval.o OBJS-$(CONFIG_SCDET_FILTER) += vf_scdet.o +OBJS-$(CONFIG_SCDET_VULKAN_FILTER) += vf_scdet_vulkan.o OBJS-$(CONFIG_SCHARR_FILTER) += vf_convolution.o OBJS-$(CONFIG_SCROLL_FILTER) += vf_scroll.o OBJS-$(CONFIG_SEGMENT_FILTER) += f_segment.o @@ -501,6 +511,7 @@ OBJS-$(CONFIG_SITI_FILTER) += vf_siti.o OBJS-$(CONFIG_SPLIT_FILTER) += split.o OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o qp_table.o OBJS-$(CONFIG_SR_FILTER) += vf_sr.o +OBJS-$(CONFIG_SR_AMF_FILTER) += vf_sr_amf.o scale_eval.o vf_amf_common.o OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o framesync.o OBJS-$(CONFIG_SSIM360_FILTER) += vf_ssim360.o framesync.o OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o @@ -554,6 +565,7 @@ OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransfo OBJS-$(CONFIG_VIF_FILTER) += vf_vif.o framesync.o OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o +OBJS-$(CONFIG_VPP_AMF_FILTER) += vf_vpp_amf.o scale_eval.o vf_amf_common.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 @@ -565,7 +577,7 @@ OBJS-$(CONFIG_XFADE_FILTER) += vf_xfade.o OBJS-$(CONFIG_XFADE_OPENCL_FILTER) += vf_xfade_opencl.o opencl.o opencl/xfade.o OBJS-$(CONFIG_XFADE_VULKAN_FILTER) += vf_xfade_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_XMEDIAN_FILTER) += vf_xmedian.o framesync.o -OBJS-$(CONFIG_XPSNR_FILTER) += vf_xpsnr.o framesync.o +OBJS-$(CONFIG_XPSNR_FILTER) += vf_xpsnr.o framesync.o psnr.o OBJS-$(CONFIG_XSTACK_FILTER) += vf_stack.o framesync.o OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o yadif_common.o OBJS-$(CONFIG_YADIF_CUDA_FILTER) += vf_yadif_cuda.o vf_yadif_cuda.ptx.o \ @@ -658,12 +670,11 @@ SHLIBOBJS-$(HAVE_GNU_WINDRES) += avfilterres.o SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h +SKIPHEADERS-$(CONFIG_AMF) += vf_amf_common.h SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h stack_internal.h SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h stack_internal.h -SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h -SKIPHEADERS-$(CONFIG_LIBSHADERC) += vulkan_spirv.h -SKIPHEADERS-$(CONFIG_LIBGLSLANG) += vulkan_spirv.h +SKIPHEADERS-$(CONFIG_VULKAN) += vulkan_filter.h TOOLS = graph2dot TESTPROGS = drawutils filtfmts formats integral @@ -680,9 +691,3 @@ OPENCL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/opencl/*.cl)) libavfilter/opencl/%.c: TAG = OPENCL libavfilter/opencl/%.c: $(SRC_PATH)/libavfilter/opencl/%.cl $(M)$(SRC_PATH)/tools/source2c $< $@ - -VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/vulkan/*.comp)) -.SECONDARY: $(VULKAN:.comp=.c) -libavfilter/vulkan/%.c: TAG = OPENCL -libavfilter/vulkan/%.c: $(SRC_PATH)/libavfilter/vulkan/%.comp - $(M)$(SRC_PATH)/tools/source2c $< $@ diff --git a/libavfilter/aarch64/vf_bwdif_init_aarch64.c b/libavfilter/aarch64/vf_bwdif_init_aarch64.c index 74530ed5b7..efcb31efff 100644 --- a/libavfilter/aarch64/vf_bwdif_init_aarch64.c +++ b/libavfilter/aarch64/vf_bwdif_init_aarch64.c @@ -122,4 +122,3 @@ ff_bwdif_init_aarch64(BWDIFDSPContext *s, int bit_depth) s->filter_edge = filter_edge_helper; s->filter_line3 = filter_line3_helper; } - diff --git a/libavfilter/aarch64/vf_bwdif_neon.S b/libavfilter/aarch64/vf_bwdif_neon.S index bf268b12f8..d078f6f6f1 100644 --- a/libavfilter/aarch64/vf_bwdif_neon.S +++ b/libavfilter/aarch64/vf_bwdif_neon.S @@ -148,7 +148,7 @@ // static const uint16_t coef_hf[3] = { 5570, 3801, 1016 }; // static const uint16_t coef_sp[2] = { 5077, 981 }; -const coeffs, align=4 // align 4 means align on 2^4 boundry +const coeffs, align=4 // align 4 means align on 2^4 boundary .hword 4309 * 4, 213 * 4 // lf[0]*4 = v0.h[0] .hword 5570, 3801, 1016, -3801 // hf[0] = v0.h[2], -hf[1] = v0.h[5] .hword 5077, 981 // sp[0] = v0.h[6] diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c index 0e7ba8df80..03ecb4e5bb 100644 --- a/libavfilter/aeval.c +++ b/libavfilter/aeval.c @@ -114,9 +114,10 @@ static int parse_channel_expressions(AVFilterContext *ctx, if (!args1) return AVERROR(ENOMEM); - if (!eval->exprs) { + if (!eval->exprs || !*eval->exprs) { av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto end; } if (!strcmp(ctx->filter->name, "aeval")) { @@ -320,17 +321,16 @@ static const AVFilterPad aevalsrc_outputs[] = { }, }; -const AVFilter ff_asrc_aevalsrc = { - .name = "aevalsrc", - .description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."), +const FFFilter ff_asrc_aevalsrc = { + .p.name = "aevalsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."), + .p.priv_class = &aevalsrc_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(EvalContext), - .inputs = NULL, FILTER_OUTPUTS(aevalsrc_outputs), FILTER_QUERY_FUNC2(query_formats), - .priv_class = &aevalsrc_class, }; #endif /* CONFIG_AEVALSRC_FILTER */ @@ -462,17 +462,17 @@ static const AVFilterPad aeval_outputs[] = { }, }; -const AVFilter ff_af_aeval = { - .name = "aeval", - .description = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."), +const FFFilter ff_af_aeval = { + .p.name = "aeval", + .p.description = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."), + .p.priv_class = &aeval_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .init = init, .uninit = uninit, .priv_size = sizeof(EvalContext), FILTER_INPUTS(aeval_inputs), FILTER_OUTPUTS(aeval_outputs), FILTER_QUERY_FUNC2(aeval_query_formats), - .priv_class = &aeval_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AEVAL_FILTER */ diff --git a/libavfilter/af_aap.c b/libavfilter/af_aap.c index 05608d7fbb..8d3209a1ef 100644 --- a/libavfilter/af_aap.c +++ b/libavfilter/af_aap.c @@ -315,18 +315,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_aap = { - .name = "aap", - .description = NULL_IF_CONFIG_SMALL("Apply Affine Projection algorithm to first audio stream."), +const FFFilter ff_af_aap = { + .p.name = "aap", + .p.description = NULL_IF_CONFIG_SMALL("Apply Affine Projection algorithm to first audio stream."), + .p.priv_class = &aap_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioAPContext), - .priv_class = &aap_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c index e520b1b66b..b99a65b2f6 100644 --- a/libavfilter/af_acontrast.c +++ b/libavfilter/af_acontrast.c @@ -169,11 +169,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_acontrast = { - .name = "acontrast", - .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), +const FFFilter ff_af_acontrast = { + .p.name = "acontrast", + .p.description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), + .p.priv_class = &acontrast_class, .priv_size = sizeof(AudioContrastContext), - .priv_class = &acontrast_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, diff --git a/libavfilter/af_acopy.c b/libavfilter/af_acopy.c index 9d06e2d4b4..e886a2ce2b 100644 --- a/libavfilter/af_acopy.c +++ b/libavfilter/af_acopy.c @@ -53,10 +53,10 @@ static const AVFilterPad acopy_inputs[] = { }, }; -const AVFilter ff_af_acopy = { - .name = "acopy", - .description = NULL_IF_CONFIG_SMALL("Copy the input audio unchanged to the output."), - .flags = AVFILTER_FLAG_METADATA_ONLY, +const FFFilter ff_af_acopy = { + .p.name = "acopy", + .p.description = NULL_IF_CONFIG_SMALL("Copy the input audio unchanged to the output."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(acopy_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c index 3fd5c1d246..e24bf9eb73 100644 --- a/libavfilter/af_acrossover.c +++ b/libavfilter/af_acrossover.c @@ -588,15 +588,7 @@ static int activate(AVFilterContext *ctx) return 0; } - for (int i = 0; i < ctx->nb_outputs; i++) { - if (ff_outlink_get_status(ctx->outputs[i])) - continue; - - if (ff_outlink_frame_wanted(ctx->outputs[i])) { - ff_inlink_request_frame(inlink); - return 0; - } - } + FF_FILTER_FORWARD_WANTED_ANY(ctx, inlink); return FFERROR_NOT_READY; } @@ -617,17 +609,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_acrossover = { - .name = "acrossover", - .description = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."), +const FFFilter ff_af_acrossover = { + .p.name = "acrossover", + .p.description = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."), + .p.priv_class = &acrossover_class, + .p.outputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioCrossoverContext), - .priv_class = &acrossover_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_acrusher.c b/libavfilter/af_acrusher.c index f064f5b04e..3ec38269d0 100644 --- a/libavfilter/af_acrusher.c +++ b/libavfilter/af_acrusher.c @@ -326,15 +326,15 @@ static const AVFilterPad avfilter_af_acrusher_inputs[] = { }, }; -const AVFilter ff_af_acrusher = { - .name = "acrusher", - .description = NULL_IF_CONFIG_SMALL("Reduce audio bit resolution."), +const FFFilter ff_af_acrusher = { + .p.name = "acrusher", + .p.description = NULL_IF_CONFIG_SMALL("Reduce audio bit resolution."), + .p.priv_class = &acrusher_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ACrusherContext), - .priv_class = &acrusher_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_acrusher_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c index 819ad2ab5c..043435b186 100644 --- a/libavfilter/af_adeclick.c +++ b/libavfilter/af_adeclick.c @@ -778,18 +778,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adeclick = { - .name = "adeclick", - .description = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."), +const FFFilter ff_af_adeclick = { + .p.name = "adeclick", + .p.description = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."), + .p.priv_class = &adeclick_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDeclickContext), - .priv_class = &adeclick_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; static const AVOption adeclip_options[] = { @@ -814,16 +814,16 @@ static const AVOption adeclip_options[] = { AVFILTER_DEFINE_CLASS(adeclip); -const AVFilter ff_af_adeclip = { - .name = "adeclip", - .description = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."), +const FFFilter ff_af_adeclip = { + .p.name = "adeclip", + .p.description = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."), + .p.priv_class = &adeclip_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDeclickContext), - .priv_class = &adeclip_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adecorrelate.c b/libavfilter/af_adecorrelate.c index 5cde9e7e18..8991bf2077 100644 --- a/libavfilter/af_adecorrelate.c +++ b/libavfilter/af_adecorrelate.c @@ -231,15 +231,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adecorrelate = { - .name = "adecorrelate", - .description = NULL_IF_CONFIG_SMALL("Apply decorrelation to input audio."), +const FFFilter ff_af_adecorrelate = { + .p.name = "adecorrelate", + .p.description = NULL_IF_CONFIG_SMALL("Apply decorrelation to input audio."), + .p.priv_class = &adecorrelate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ADecorrelateContext), - .priv_class = &adecorrelate_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index ab2d660446..c0d076fe64 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -465,17 +465,17 @@ static const AVFilterPad adelay_inputs[] = { }, }; -const AVFilter ff_af_adelay = { - .name = "adelay", - .description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."), +const FFFilter ff_af_adelay = { + .p.name = "adelay", + .p.description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."), + .p.priv_class = &adelay_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDelayContext), - .priv_class = &adelay_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(adelay_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_adenorm.c b/libavfilter/af_adenorm.c index 7dc3c0f735..0d61eed1dd 100644 --- a/libavfilter/af_adenorm.c +++ b/libavfilter/af_adenorm.c @@ -262,15 +262,15 @@ static const AVOption adenorm_options[] = { AVFILTER_DEFINE_CLASS(adenorm); -const AVFilter ff_af_adenorm = { - .name = "adenorm", - .description = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."), +const FFFilter ff_af_adenorm = { + .p.name = "adenorm", + .p.description = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."), + .p.priv_class = &adenorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ADenormContext), FILTER_INPUTS(adenorm_inputs), FILTER_OUTPUTS(adenorm_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .priv_class = &adenorm_class, .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c index 1254aa9457..7ac730836a 100644 --- a/libavfilter/af_aderivative.c +++ b/libavfilter/af_aderivative.c @@ -160,27 +160,27 @@ static const AVOption aderivative_options[] = { AVFILTER_DEFINE_CLASS_EXT(aderivative, "aderivative/aintegral", aderivative_options); -const AVFilter ff_af_aderivative = { - .name = "aderivative", - .description = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."), +const FFFilter ff_af_aderivative = { + .p.name = "aderivative", + .p.description = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."), + .p.priv_class = &aderivative_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ADerivativeContext), - .priv_class = &aderivative_class, .uninit = uninit, FILTER_INPUTS(aderivative_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; -const AVFilter ff_af_aintegral = { - .name = "aintegral", - .description = NULL_IF_CONFIG_SMALL("Compute integral of input audio."), +const FFFilter ff_af_aintegral = { + .p.name = "aintegral", + .p.description = NULL_IF_CONFIG_SMALL("Compute integral of input audio."), + .p.priv_class = &aderivative_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ADerivativeContext), - .priv_class = &aderivative_class, .uninit = uninit, FILTER_INPUTS(aderivative_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_adrc.c b/libavfilter/af_adrc.c index 7410b99ed3..9e3becdf2e 100644 --- a/libavfilter/af_adrc.c +++ b/libavfilter/af_adrc.c @@ -486,17 +486,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adrc = { - .name = "adrc", - .description = NULL_IF_CONFIG_SMALL("Audio Spectral Dynamic Range Controller."), +const FFFilter ff_af_adrc = { + .p.name = "adrc", + .p.description = NULL_IF_CONFIG_SMALL("Audio Spectral Dynamic Range Controller."), + .p.priv_class = &adrc_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioDRCContext), - .priv_class = &adrc_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .activate = activate, .process_command = process_command, }; diff --git a/libavfilter/af_adynamicequalizer.c b/libavfilter/af_adynamicequalizer.c index ba03faff60..6043623f46 100644 --- a/libavfilter/af_adynamicequalizer.c +++ b/libavfilter/af_adynamicequalizer.c @@ -273,16 +273,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adynamicequalizer = { - .name = "adynamicequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply Dynamic Equalization of input audio."), +const FFFilter ff_af_adynamicequalizer = { + .p.name = "adynamicequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply Dynamic Equalization of input audio."), + .p.priv_class = &adynamicequalizer_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioDynamicEqualizerContext), - .priv_class = &adynamicequalizer_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_adynamicsmooth.c b/libavfilter/af_adynamicsmooth.c index a0276616ca..aa729c9c16 100644 --- a/libavfilter/af_adynamicsmooth.c +++ b/libavfilter/af_adynamicsmooth.c @@ -121,15 +121,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_adynamicsmooth = { - .name = "adynamicsmooth", - .description = NULL_IF_CONFIG_SMALL("Apply Dynamic Smoothing of input audio."), +const FFFilter ff_af_adynamicsmooth = { + .p.name = "adynamicsmooth", + .p.description = NULL_IF_CONFIG_SMALL("Apply Dynamic Smoothing of input audio."), + .p.priv_class = &adynamicsmooth_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDynamicSmoothContext), - .priv_class = &adynamicsmooth_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index b1c656e034..ff316eaa67 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -336,11 +336,11 @@ static const AVFilterPad aecho_outputs[] = { }, }; -const AVFilter ff_af_aecho = { - .name = "aecho", - .description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."), +const FFFilter ff_af_aecho = { + .p.name = "aecho", + .p.description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."), + .p.priv_class = &aecho_class, .priv_size = sizeof(AudioEchoContext), - .priv_class = &aecho_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c index 4bde916717..d35111f89f 100644 --- a/libavfilter/af_aemphasis.c +++ b/libavfilter/af_aemphasis.c @@ -361,16 +361,16 @@ static const AVFilterPad avfilter_af_aemphasis_inputs[] = { }, }; -const AVFilter ff_af_aemphasis = { - .name = "aemphasis", - .description = NULL_IF_CONFIG_SMALL("Audio emphasis."), +const FFFilter ff_af_aemphasis = { + .p.name = "aemphasis", + .p.description = NULL_IF_CONFIG_SMALL("Audio emphasis."), + .p.priv_class = &aemphasis_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioEmphasisContext), - .priv_class = &aemphasis_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_aemphasis_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aexciter.c b/libavfilter/af_aexciter.c index 3fe7ce799b..188693716c 100644 --- a/libavfilter/af_aexciter.c +++ b/libavfilter/af_aexciter.c @@ -265,15 +265,15 @@ static const AVFilterPad avfilter_af_aexciter_inputs[] = { }, }; -const AVFilter ff_af_aexciter = { - .name = "aexciter", - .description = NULL_IF_CONFIG_SMALL("Enhance high frequency part of audio."), +const FFFilter ff_af_aexciter = { + .p.name = "aexciter", + .p.description = NULL_IF_CONFIG_SMALL("Enhance high frequency part of audio."), + .p.priv_class = &aexciter_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AExciterContext), - .priv_class = &aexciter_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_aexciter_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 7cc5182d1a..d4ea1a7bab 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -25,6 +25,7 @@ #include "config_components.h" +#include "libavutil/avassert.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" @@ -41,9 +42,8 @@ typedef struct AudioFadeContext { double silence; double unity; int overlap; - int status[2]; - int passthrough; int64_t pts; + int xfade_status; void (*fade_samples)(uint8_t **dst, uint8_t * const *src, int nb_samples, int channels, int direction, @@ -433,17 +433,17 @@ static const AVFilterPad avfilter_af_afade_outputs[] = { }, }; -const AVFilter ff_af_afade = { - .name = "afade", - .description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), +const FFFilter ff_af_afade = { + .p.name = "afade", + .p.description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), + .p.priv_class = &afade_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioFadeContext), .init = init, FILTER_INPUTS(avfilter_af_afade_inputs), FILTER_OUTPUTS(avfilter_af_afade_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), - .priv_class = &afade_class, .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AFADE_FILTER */ @@ -540,141 +540,155 @@ CROSSFADE(flt, float) CROSSFADE(s16, int16_t) CROSSFADE(s32, int32_t) -static int check_input(AVFilterLink *inlink) +static int pass_frame(AVFilterLink *inlink, AVFilterLink *outlink, int64_t *pts) { - const int queued_samples = ff_inlink_queued_samples(inlink); + AVFrame *in; + int ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + av_assert1(ret); + in->pts = *pts; + *pts += av_rescale_q(in->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + return ff_filter_frame(outlink, in); +} - return ff_inlink_check_available_samples(inlink, queued_samples + 1) == 1; +static int pass_samples(AVFilterLink *inlink, AVFilterLink *outlink, unsigned nb_samples, int64_t *pts) +{ + AVFrame *in; + int ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); + if (ret < 0) + return ret; + av_assert1(ret); + in->pts = *pts; + *pts += av_rescale_q(in->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + return ff_filter_frame(outlink, in); +} + +static int pass_crossfade(AVFilterContext *ctx) +{ + AudioFadeContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out, *cf[2] = { NULL }; + int ret; + + if (s->overlap) { + out = ff_get_audio_buffer(outlink, s->nb_samples); + 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); + return ret; + } + + 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, out->ch_layout.nb_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); + 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); + 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); + return ret; + } + + s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples, + outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve, 0., 1.); + 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) + return ret; + + 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; + } + + s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, + outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2, 0., 1.); + out->pts = s->pts; + s->pts += av_rescale_q(s->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + av_frame_free(&cf[1]); + return ff_filter_frame(outlink, out); + } } static int activate(AVFilterContext *ctx) { AudioFadeContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - AVFrame *in = NULL, *out, *cf[2] = { NULL }; - int ret = 0, nb_samples, status; - int64_t pts; FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); - if (s->passthrough && s->status[0]) { - ret = ff_inlink_consume_frame(ctx->inputs[1], &in); - if (ret > 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 (ret < 0) { - return ret; - } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) { - ff_outlink_set_status(outlink, status, pts); - return 0; - } else if (!ret) { - if (ff_outlink_frame_wanted(outlink)) { - ff_inlink_request_frame(ctx->inputs[1]); - return 0; - } + // Read first input until EOF + if (s->xfade_status == 0) { + int queued_samples = ff_inlink_queued_samples(ctx->inputs[0]); + if (queued_samples > s->nb_samples) { + AVFrame *frame = ff_inlink_peek_frame(ctx->inputs[0], 0); + if (queued_samples - s->nb_samples >= frame->nb_samples) + return pass_frame(ctx->inputs[0], outlink, &s->pts); } - } - - nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); - if (nb_samples > s->nb_samples) { - nb_samples -= s->nb_samples; - s->passthrough = 1; - ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in); - if (ret < 0) - return ret; - 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 (s->status[0] && nb_samples >= s->nb_samples && - ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { - if (s->overlap) { - out = ff_get_audio_buffer(outlink, s->nb_samples); - 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); - return ret; - } - - 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, out->ch_layout.nb_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); - s->passthrough = 1; - av_frame_free(&cf[0]); - av_frame_free(&cf[1]); - return ff_filter_frame(outlink, out); + if (ff_outlink_get_status(ctx->inputs[0])) { + if (queued_samples > s->nb_samples) + return pass_samples(ctx->inputs[0], outlink, queued_samples - s->nb_samples, &s->pts); + s->xfade_status = 1; } else { - out = ff_get_audio_buffer(outlink, s->nb_samples); - 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); - return ret; - } - - s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples, - outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve, 0., 1.); - 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) - return ret; - - 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; - } - - s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, - outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2, 0., 1.); - out->pts = s->pts; - s->pts += av_rescale_q(s->nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - s->passthrough = 1; - av_frame_free(&cf[1]); - return ff_filter_frame(outlink, out); + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[0]); } - } else if (ff_outlink_frame_wanted(outlink)) { - if (!s->status[0] && check_input(ctx->inputs[0])) - s->status[0] = AVERROR_EOF; - s->passthrough = !s->status[0]; - if (check_input(ctx->inputs[1])) { - s->status[1] = AVERROR_EOF; - ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE); - return 0; + } + // Read second input until enough data is ready or EOF + if (s->xfade_status == 1) { + if (ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples || ff_outlink_get_status(ctx->inputs[1])) { + s->xfade_status = 2; + } else { + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); } - if (!s->status[0]) - ff_inlink_request_frame(ctx->inputs[0]); - else - ff_inlink_request_frame(ctx->inputs[1]); - return 0; + } + // Do crossfade + if (s->xfade_status == 2) { + s->xfade_status = 3; + // TODO: Do some partial crossfade if not all inputs have enough duration? + if (ff_inlink_queued_samples(ctx->inputs[0]) >= s->nb_samples && + ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) + return pass_crossfade(ctx); + } + // Read second input until EOF + if (s->xfade_status == 3) { + if (ff_inlink_queued_frames(ctx->inputs[1])) + return pass_frame(ctx->inputs[1], outlink, &s->pts); + FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink); + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); } - return ret; + return FFERROR_NOT_READY; } static int acrossfade_config_output(AVFilterLink *outlink) @@ -700,26 +714,14 @@ static int acrossfade_config_output(AVFilterLink *outlink) return 0; } -static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) -{ - AVFilterContext *ctx = inlink->dst; - AudioFadeContext *s = ctx->priv; - - return s->passthrough ? - ff_null_get_audio_buffer (inlink, nb_samples) : - ff_default_get_audio_buffer(inlink, nb_samples); -} - static const AVFilterPad avfilter_af_acrossfade_inputs[] = { { .name = "crossfade0", .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, }, { .name = "crossfade1", .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, }, }; @@ -731,12 +733,12 @@ static const AVFilterPad avfilter_af_acrossfade_outputs[] = { }, }; -const AVFilter ff_af_acrossfade = { - .name = "acrossfade", - .description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), +const FFFilter ff_af_acrossfade = { + .p.name = "acrossfade", + .p.description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), + .p.priv_class = &acrossfade_class, .priv_size = sizeof(AudioFadeContext), .activate = activate, - .priv_class = &acrossfade_class, FILTER_INPUTS(avfilter_af_acrossfade_inputs), FILTER_OUTPUTS(avfilter_af_acrossfade_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c index fd6b2b2685..e97dfe1f0d 100644 --- a/libavfilter/af_afftdn.c +++ b/libavfilter/af_afftdn.c @@ -379,7 +379,7 @@ static void process_frame(AVFilterContext *ctx, noisy_data[i] = mag = hypot(fft_data_dbl[i].re, fft_data_dbl[i].im); break; default: - av_assert2(0); + av_assert0(0); } power = mag * mag; @@ -541,8 +541,9 @@ static void set_band_parameters(AudioFFTDeNoiseContext *s, dnch->noise_band_auto_var[i] = dnch->max_var * exp((process_get_band_noise(s, dnch, i) - 2.0) * C); } -static void read_custom_noise(AudioFFTDeNoiseContext *s, int ch) +static void read_custom_noise(AVFilterContext *ctx, int ch) { + AudioFFTDeNoiseContext *s = ctx->priv; DeNoiseChannel *dnch = &s->dnch[ch]; char *custom_noise_str, *p, *arg, *saveptr = NULL; double band_noise[NB_PROFILE_BANDS] = { 0.f }; @@ -565,7 +566,7 @@ static void read_custom_noise(AudioFFTDeNoiseContext *s, int ch) ret = av_sscanf(arg, "%f", &noise); if (ret != 1) { - av_log(s, AV_LOG_ERROR, "Custom band noise must be float.\n"); + av_log(ctx, AV_LOG_ERROR, "Custom band noise must be float.\n"); break; } @@ -735,7 +736,7 @@ static int config_input(AVFilterLink *inlink) dnch->band_noise[i] = get_band_noise(s, i, 1.0, 500.0, 1.0E10); break; case CUSTOM_NOISE: - read_custom_noise(s, ch); + read_custom_noise(ctx, ch); break; default: return AVERROR_BUG; @@ -1009,10 +1010,11 @@ static void finish_sample_noise(AudioFFTDeNoiseContext *s, } } -static void set_noise_profile(AudioFFTDeNoiseContext *s, +static void set_noise_profile(AVFilterContext *ctx, DeNoiseChannel *dnch, double *sample_noise) { + AudioFFTDeNoiseContext *s = ctx->priv; double new_band_noise[NB_PROFILE_BANDS]; double temp[NB_PROFILE_BANDS]; double sum = 0.0; @@ -1036,13 +1038,13 @@ static void set_noise_profile(AudioFFTDeNoiseContext *s, reduce_mean(temp); - av_log(s, AV_LOG_INFO, "bn="); + av_log(ctx, AV_LOG_INFO, "bn="); for (int m = 0; m < NB_PROFILE_BANDS; m++) { new_band_noise[m] = temp[m]; new_band_noise[m] = av_clipd(new_band_noise[m], -24.0, 24.0); - av_log(s, AV_LOG_INFO, "%f ", new_band_noise[m]); + av_log(ctx, AV_LOG_INFO, "%f ", new_band_noise[m]); } - av_log(s, AV_LOG_INFO, "\n"); + av_log(ctx, AV_LOG_INFO, "\n"); memcpy(dnch->band_noise, new_band_noise, sizeof(new_band_noise)); } @@ -1182,7 +1184,7 @@ static int output_frame(AVFilterLink *inlink, AVFrame *in) if (s->sample_noise_blocks <= 0) break; finish_sample_noise(s, dnch, sample_noise); - set_noise_profile(s, dnch, sample_noise); + set_noise_profile(ctx, dnch, sample_noise); set_parameters(s, dnch, 1, 1); } s->sample_noise = 0; @@ -1363,17 +1365,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afftdn = { - .name = "afftdn", - .description = NULL_IF_CONFIG_SMALL("Denoise audio samples using FFT."), +const FFFilter ff_af_afftdn = { + .p.name = "afftdn", + .p.description = NULL_IF_CONFIG_SMALL("Denoise audio samples using FFT."), + .p.priv_class = &afftdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFFTDeNoiseContext), - .priv_class = &afftdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 98b09e666d..08cdcae2f7 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -439,16 +439,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afftfilt = { - .name = "afftfilt", - .description = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."), +const FFFilter ff_af_afftfilt = { + .p.name = "afftfilt", + .p.description = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."), + .p.priv_class = &afftfilt_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFFTFiltContext), - .priv_class = &afftfilt_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index c641893d4a..aff837d9bf 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -777,18 +777,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_afir = { - .name = "afir", - .description = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in additional stream(s)."), +const FFFilter ff_af_afir = { + .p.name = "afir", + .p.description = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in additional stream(s)."), + .p.priv_class = &afir_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFIRContext), - .priv_class = &afir_class, FILTER_QUERY_FUNC2(query_formats), FILTER_OUTPUTS(outputs), .init = init, .activate = activate, .uninit = uninit, .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c index a7d05a9ce8..2806eac963 100644 --- a/libavfilter/af_aformat.c +++ b/libavfilter/af_aformat.c @@ -132,13 +132,13 @@ static int query_formats(const AVFilterContext *ctx, return 0; } -const AVFilter ff_af_aformat = { - .name = "aformat", - .description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), +const FFFilter ff_af_aformat = { + .p.name = "aformat", + .p.description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), + .p.priv_class = &aformat_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .init = init, .priv_size = sizeof(AFormatContext), - .priv_class = &aformat_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_afreqshift.c b/libavfilter/af_afreqshift.c index fa93eed995..68969f2fdd 100644 --- a/libavfilter/af_afreqshift.c +++ b/libavfilter/af_afreqshift.c @@ -366,18 +366,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_afreqshift = { - .name = "afreqshift", - .description = NULL_IF_CONFIG_SMALL("Apply frequency shifting to input audio."), +const FFFilter ff_af_afreqshift = { + .p.name = "afreqshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply frequency shifting to input audio."), + .p.priv_class = &afreqshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFreqShift), - .priv_class = &afreqshift_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption aphaseshift_options[] = { @@ -389,16 +389,16 @@ static const AVOption aphaseshift_options[] = { AVFILTER_DEFINE_CLASS(aphaseshift); -const AVFilter ff_af_aphaseshift = { - .name = "aphaseshift", - .description = NULL_IF_CONFIG_SMALL("Apply phase shifting to input audio."), +const FFFilter ff_af_aphaseshift = { + .p.name = "aphaseshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply phase shifting to input audio."), + .p.priv_class = &aphaseshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AFreqShift), - .priv_class = &aphaseshift_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c index fb172f26cc..12a2c751c5 100644 --- a/libavfilter/af_afwtdn.c +++ b/libavfilter/af_afwtdn.c @@ -1301,17 +1301,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_afwtdn = { - .name = "afwtdn", - .description = NULL_IF_CONFIG_SMALL("Denoise audio stream using Wavelets."), +const FFFilter ff_af_afwtdn = { + .p.name = "afwtdn", + .p.description = NULL_IF_CONFIG_SMALL("Denoise audio stream using Wavelets."), + .p.priv_class = &afwtdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioFWTDNContext), - .priv_class = &afwtdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index 09655b7f82..3f8a7b3202 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -228,16 +228,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_agate = { - .name = "agate", - .description = NULL_IF_CONFIG_SMALL("Audio gate."), - .priv_class = &agate_sidechaingate_class, +const FFFilter ff_af_agate = { + .p.name = "agate", + .p.description = NULL_IF_CONFIG_SMALL("Audio gate."), + .p.priv_class = &agate_sidechaingate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioGateContext), FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; #endif /* CONFIG_AGATE_FILTER */ @@ -378,10 +378,11 @@ static const AVFilterPad sidechaingate_outputs[] = { }, }; -const AVFilter ff_af_sidechaingate = { - .name = "sidechaingate", - .description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), - .priv_class = &agate_sidechaingate_class, +const FFFilter ff_af_sidechaingate = { + .p.name = "sidechaingate", + .p.description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), + .p.priv_class = &agate_sidechaingate_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioGateContext), .activate = activate, .uninit = uninit, @@ -389,6 +390,5 @@ const AVFilter ff_af_sidechaingate = { FILTER_OUTPUTS(sidechaingate_outputs), FILTER_QUERY_FUNC2(scquery_formats), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; #endif /* CONFIG_SIDECHAINGATE_FILTER */ diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index dfeeb34c9b..f18b6e9286 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -1038,7 +1038,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color int font_height; int i; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (i = 0; txt[i]; i++) { int char_y, mask; @@ -1560,15 +1560,15 @@ static const AVOption aiir_options[] = { AVFILTER_DEFINE_CLASS(aiir); -const AVFilter ff_af_aiir = { - .name = "aiir", - .description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), +const FFFilter ff_af_aiir = { + .p.name = "aiir", + .p.description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), + .p.priv_class = &aiir_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioIIRContext), - .priv_class = &aiir_class, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c index a08616f69c..61ea7beb6f 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -421,16 +421,16 @@ static const AVFilterPad alimiter_outputs[] = { }, }; -const AVFilter ff_af_alimiter = { - .name = "alimiter", - .description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), +const FFFilter ff_af_alimiter = { + .p.name = "alimiter", + .p.description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), + .p.priv_class = &alimiter_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(AudioLimiterContext), - .priv_class = &alimiter_class, .init = init, .uninit = uninit, FILTER_INPUTS(alimiter_inputs), FILTER_OUTPUTS(alimiter_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c index 16507299b5..bb82128a84 100644 --- a/libavfilter/af_amerge.c +++ b/libavfilter/af_amerge.c @@ -341,17 +341,17 @@ static const AVFilterPad amerge_outputs[] = { }, }; -const AVFilter ff_af_amerge = { - .name = "amerge", - .description = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into " +const FFFilter ff_af_amerge = { + .p.name = "amerge", + .p.description = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into " "a single multi-channel stream."), + .p.inputs = NULL, + .p.priv_class = &amerge_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(AMergeContext), .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(amerge_outputs), FILTER_QUERY_FUNC(query_formats), - .priv_class = &amerge_class, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index bc97200926..082d69b97f 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -616,18 +616,18 @@ static const AVFilterPad avfilter_af_amix_outputs[] = { }, }; -const AVFilter ff_af_amix = { - .name = "amix", - .description = NULL_IF_CONFIG_SMALL("Audio mixing."), +const FFFilter ff_af_amix = { + .p.name = "amix", + .p.description = NULL_IF_CONFIG_SMALL("Audio mixing."), + .p.priv_class = &amix_class, + .p.inputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(MixContext), - .priv_class = &amix_class, .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(avfilter_af_amix_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c index 5090098c1b..6b6d3e0a57 100644 --- a/libavfilter/af_amultiply.c +++ b/libavfilter/af_amultiply.c @@ -169,9 +169,9 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_amultiply = { - .name = "amultiply", - .description = NULL_IF_CONFIG_SMALL("Multiply two audio streams."), +const FFFilter ff_af_amultiply = { + .p.name = "amultiply", + .p.description = NULL_IF_CONFIG_SMALL("Multiply two audio streams."), .priv_size = sizeof(AudioMultiplyContext), .init = init, .uninit = uninit, diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c index 26e9c3cdd7..26df4f7e32 100644 --- a/libavfilter/af_anequalizer.c +++ b/libavfilter/af_anequalizer.c @@ -752,18 +752,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_anequalizer = { - .name = "anequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply high-order audio parametric multi band equalizer."), +const FFFilter ff_af_anequalizer = { + .p.name = "anequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply high-order audio parametric multi band equalizer."), + .p.priv_class = &anequalizer_class, + .p.outputs = NULL, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNEqualizerContext), - .priv_class = &anequalizer_class, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_anlmdn.c b/libavfilter/af_anlmdn.c index f8e4f92c47..b1944fb2d7 100644 --- a/libavfilter/af_anlmdn.c +++ b/libavfilter/af_anlmdn.c @@ -349,17 +349,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_anlmdn = { - .name = "anlmdn", - .description = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Non-Local Means."), +const FFFilter ff_af_anlmdn = { + .p.name = "anlmdn", + .p.description = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Non-Local Means."), + .p.priv_class = &anlmdn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMeansContext), - .priv_class = &anlmdn_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_anlms.c b/libavfilter/af_anlms.c index 4e83a0501d..b03dd6da2a 100644 --- a/libavfilter/af_anlms.c +++ b/libavfilter/af_anlms.c @@ -251,34 +251,34 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_anlms = { - .name = "anlms", - .description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."), +const FFFilter ff_af_anlms = { + .p.name = "anlms", + .p.description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."), + .p.priv_class = &anlms_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMSContext), - .priv_class = &anlms_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; -const AVFilter ff_af_anlmf = { - .name = "anlmf", - .description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Fourth algorithm to first audio stream."), +const FFFilter ff_af_anlmf = { + .p.name = "anlmf", + .p.description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Fourth algorithm to first audio stream."), + .p.priv_class = &anlms_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioNLMSContext), - .priv_class = &anlms_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c index d7645fd0ec..6df598261a 100644 --- a/libavfilter/af_anull.c +++ b/libavfilter/af_anull.c @@ -27,10 +27,10 @@ #include "filters.h" #include "libavutil/internal.h" -const AVFilter ff_af_anull = { - .name = "anull", - .description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."), - .flags = AVFILTER_FLAG_METADATA_ONLY, +const FFFilter ff_af_anull = { + .p.name = "anull", + .p.description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c index 6cdfd15972..cc214f7cc8 100644 --- a/libavfilter/af_apad.c +++ b/libavfilter/af_apad.c @@ -194,14 +194,14 @@ static const AVFilterPad apad_outputs[] = { }, }; -const AVFilter ff_af_apad = { - .name = "apad", - .description = NULL_IF_CONFIG_SMALL("Pad audio with silence."), +const FFFilter ff_af_apad = { + .p.name = "apad", + .p.description = NULL_IF_CONFIG_SMALL("Pad audio with silence."), + .p.priv_class = &apad_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .init = init, .activate = activate, .priv_size = sizeof(APadContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(apad_outputs), - .priv_class = &apad_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index b070f4d2a6..8d7f624827 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -256,9 +256,10 @@ static const AVFilterPad aphaser_outputs[] = { }, }; -const AVFilter ff_af_aphaser = { - .name = "aphaser", - .description = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."), +const FFFilter ff_af_aphaser = { + .p.name = "aphaser", + .p.description = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."), + .p.priv_class = &aphaser_class, .priv_size = sizeof(AudioPhaserContext), .init = init, .uninit = uninit, @@ -268,5 +269,4 @@ const AVFilter ff_af_aphaser = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), - .priv_class = &aphaser_class, }; diff --git a/libavfilter/af_apsyclip.c b/libavfilter/af_apsyclip.c index 5afc3930c1..35ef2cef17 100644 --- a/libavfilter/af_apsyclip.c +++ b/libavfilter/af_apsyclip.c @@ -637,17 +637,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_apsyclip = { - .name = "apsyclip", - .description = NULL_IF_CONFIG_SMALL("Audio Psychoacoustic Clipper."), +const FFFilter ff_af_apsyclip = { + .p.name = "apsyclip", + .p.description = NULL_IF_CONFIG_SMALL("Audio Psychoacoustic Clipper."), + .p.priv_class = &apsyclip_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioPsyClipContext), - .priv_class = &apsyclip_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .activate = activate, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c index 4272e5f3a0..71f79a4475 100644 --- a/libavfilter/af_apulsator.c +++ b/libavfilter/af_apulsator.c @@ -249,11 +249,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_apulsator = { - .name = "apulsator", - .description = NULL_IF_CONFIG_SMALL("Audio pulsator."), +const FFFilter ff_af_apulsator = { + .p.name = "apulsator", + .p.description = NULL_IF_CONFIG_SMALL("Audio pulsator."), + .p.priv_class = &apulsator_class, .priv_size = sizeof(AudioPulsatorContext), - .priv_class = &apulsator_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c index d6de074041..ea9927e7cf 100644 --- a/libavfilter/af_aresample.c +++ b/libavfilter/af_aresample.c @@ -26,6 +26,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/downmix_info.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavutil/avassert.h" @@ -42,7 +43,6 @@ typedef struct AResampleContext { struct SwrContext *swr; int64_t next_pts; int more_data; - int eof; } AResampleContext; static av_cold int preinit(AVFilterContext *ctx) @@ -123,6 +123,7 @@ static int query_formats(const AVFilterContext *ctx, return ff_channel_layouts_ref(out_layouts, &cfg_out[0]->channel_layouts); } +#define SWR_CH_MAX 64 static int config_output(AVFilterLink *outlink) { @@ -132,6 +133,7 @@ static int config_output(AVFilterLink *outlink) AResampleContext *aresample = ctx->priv; AVChannelLayout out_layout = { 0 }; int64_t out_rate; + const AVFrameSideData *sd; enum AVSampleFormat out_format; char inchl_buf[128], outchl_buf[128]; @@ -142,6 +144,44 @@ static int config_output(AVFilterLink *outlink) if (ret < 0) return ret; + sd = av_frame_side_data_get(inlink->side_data, inlink->nb_side_data, + AV_FRAME_DATA_DOWNMIX_INFO); + if (sd) { + const AVDownmixInfo *di = (AVDownmixInfo *)sd->data; + enum AVMatrixEncoding matrix_encoding = AV_MATRIX_ENCODING_NONE; + double center_mix_level, surround_mix_level; + + switch (di->preferred_downmix_type) { + case AV_DOWNMIX_TYPE_LTRT: + matrix_encoding = AV_MATRIX_ENCODING_DOLBY; + center_mix_level = di->center_mix_level_ltrt; + surround_mix_level = di->surround_mix_level_ltrt; + break; + case AV_DOWNMIX_TYPE_DPLII: + matrix_encoding = AV_MATRIX_ENCODING_DPLII; + center_mix_level = di->center_mix_level_ltrt; + surround_mix_level = di->surround_mix_level_ltrt; + break; + default: + center_mix_level = di->center_mix_level; + surround_mix_level = di->surround_mix_level; + break; + } + + av_log(ctx, AV_LOG_VERBOSE, "Mix levels: center %f - " + "surround %f - lfe %f.\n", + center_mix_level, surround_mix_level, di->lfe_mix_level); + + av_opt_set_double(aresample->swr, "clev", center_mix_level, 0); + av_opt_set_double(aresample->swr, "slev", surround_mix_level, 0); + av_opt_set_double(aresample->swr, "lfe_mix_level", di->lfe_mix_level, 0); + av_opt_set_int(aresample->swr, "matrix_encoding", matrix_encoding, 0); + + if (av_channel_layout_compare(&outlink->ch_layout, &out_layout)) + av_frame_side_data_remove(&outlink->side_data, &outlink->nb_side_data, + AV_FRAME_DATA_DOWNMIX_INFO); + } + ret = swr_init(aresample->swr); if (ret < 0) return ret; @@ -168,7 +208,7 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) +static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref, AVFrame **outsamplesref_ret) { AVFilterContext *ctx = inlink->dst; AResampleContext *aresample = ctx->priv; @@ -179,27 +219,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) AVFrame *outsamplesref; int ret; + *outsamplesref_ret = NULL; delay = swr_get_delay(aresample->swr, outlink->sample_rate); if (delay > 0) n_out += FFMIN(delay, FFMAX(4096, n_out)); outsamplesref = ff_get_audio_buffer(outlink, n_out); - - if(!outsamplesref) { - av_frame_free(&insamplesref); + if (!outsamplesref) return AVERROR(ENOMEM); - } av_frame_copy_props(outsamplesref, insamplesref); outsamplesref->format = outlink->format; ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout); if (ret < 0) { av_frame_free(&outsamplesref); - av_frame_free(&insamplesref); return ret; } outsamplesref->sample_rate = outlink->sample_rate; + if (av_channel_layout_compare(&outsamplesref->ch_layout, &insamplesref->ch_layout)) + av_frame_side_data_remove_by_props(&outsamplesref->side_data, &outsamplesref->nb_side_data, + AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT); + if(insamplesref->pts != AV_NOPTS_VALUE) { int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den); int64_t outpts= swr_next_pts(aresample->swr, inpts); @@ -212,8 +253,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) (void *)insamplesref->extended_data, n_in); if (n_out <= 0) { av_frame_free(&outsamplesref); - av_frame_free(&insamplesref); - ff_inlink_request_frame(inlink); return 0; } @@ -221,9 +260,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref) outsamplesref->nb_samples = n_out; - ret = ff_filter_frame(outlink, outsamplesref); - av_frame_free(&insamplesref); - return ret; + *outsamplesref_ret = outsamplesref; + return 1; } static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret) @@ -246,7 +284,7 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0); if (n_out <= 0) { av_frame_free(&outsamplesref); - return (n_out == 0) ? AVERROR_EOF : n_out; + return n_out; } outsamplesref->sample_rate = outlink->sample_rate; @@ -254,73 +292,63 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref outsamplesref->pts = pts; - return 0; + return 1; } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; AResampleContext *aresample = ctx->priv; + AVFrame *frame; int ret = 0, status; int64_t pts; + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + // First try to get data from the internal buffers if (aresample->more_data) { AVFrame *outsamplesref; - if (flush_frame(outlink, 0, &outsamplesref) >= 0) { - return ff_filter_frame(outlink, outsamplesref); - } - } - aresample->more_data = 0; - - if (!aresample->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) - aresample->eof = 1; - - // Second request more data from the input - if (!aresample->eof) - FF_FILTER_FORWARD_WANTED(outlink, inlink); - - // Third if we hit the end flush - if (aresample->eof) { - AVFrame *outsamplesref; - - if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0) { - if (ret == AVERROR_EOF) { - ff_outlink_set_status(outlink, AVERROR_EOF, aresample->next_pts); - return 0; - } - return ret; - } - - return ff_filter_frame(outlink, outsamplesref); - } - - ff_filter_set_ready(ctx, 100); - return 0; -} - -static int activate(AVFilterContext *ctx) -{ - AResampleContext *aresample = ctx->priv; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; - - FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - - if (!aresample->eof && ff_inlink_queued_frames(inlink)) { - AVFrame *frame = NULL; - int ret; - - ret = ff_inlink_consume_frame(inlink, &frame); + ret = flush_frame(outlink, 0, &outsamplesref); if (ret < 0) return ret; if (ret > 0) - return filter_frame(inlink, frame); + return ff_filter_frame(outlink, outsamplesref); + } + aresample->more_data = 0; + + // Then consume frames from inlink + while ((ret = ff_inlink_consume_frame(inlink, &frame))) { + AVFrame *outsamplesref; + if (ret < 0) + return ret; + + ret = filter_frame(inlink, frame, &outsamplesref); + av_frame_free(&frame); + if (ret < 0) + return ret; + if (ret > 0) + return ff_filter_frame(outlink, outsamplesref); } - return request_frame(outlink); + // If we hit the end flush + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + AVFrame *outsamplesref; + + ret = flush_frame(outlink, 1, &outsamplesref); + if (ret < 0) + return ret; + if (ret > 0) + return ff_filter_frame(outlink, outsamplesref); + ff_outlink_set_status(outlink, status, aresample->next_pts); + return 0; + } + + // If not, request more data from the input + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static const AVClass *resample_child_class_iterate(void **iter) @@ -361,14 +389,14 @@ static const AVFilterPad aresample_outputs[] = { }, }; -const AVFilter ff_af_aresample = { - .name = "aresample", - .description = NULL_IF_CONFIG_SMALL("Resample audio data."), +const FFFilter ff_af_aresample = { + .p.name = "aresample", + .p.description = NULL_IF_CONFIG_SMALL("Resample audio data."), + .p.priv_class = &aresample_class, .preinit = preinit, .activate = activate, .uninit = uninit, .priv_size = sizeof(AResampleContext), - .priv_class = &aresample_class, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(aresample_outputs), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_arls.c b/libavfilter/af_arls.c index 3f182454e4..a74d632d37 100644 --- a/libavfilter/af_arls.c +++ b/libavfilter/af_arls.c @@ -281,18 +281,18 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_arls = { - .name = "arls", - .description = NULL_IF_CONFIG_SMALL("Apply Recursive Least Squares algorithm to first audio stream."), +const FFFilter ff_af_arls = { + .p.name = "arls", + .p.description = NULL_IF_CONFIG_SMALL("Apply Recursive Least Squares algorithm to first audio stream."), + .p.priv_class = &arls_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioRLSContext), - .priv_class = &arls_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_arnndn.c b/libavfilter/af_arnndn.c index 3c2ae6370d..27a35c8492 100644 --- a/libavfilter/af_arnndn.c +++ b/libavfilter/af_arnndn.c @@ -1596,18 +1596,18 @@ static const AVOption arnndn_options[] = { AVFILTER_DEFINE_CLASS(arnndn); -const AVFilter ff_af_arnndn = { - .name = "arnndn", - .description = NULL_IF_CONFIG_SMALL("Reduce noise from speech using Recurrent Neural Networks."), +const FFFilter ff_af_arnndn = { + .p.name = "arnndn", + .p.description = NULL_IF_CONFIG_SMALL("Reduce noise from speech using Recurrent Neural Networks."), + .p.priv_class = &arnndn_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioRNNContext), - .priv_class = &arnndn_class, .activate = activate, .init = init, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c index 7765690fd8..ea74940179 100644 --- a/libavfilter/af_asdr.c +++ b/libavfilter/af_asdr.c @@ -266,45 +266,45 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_asdr = { - .name = "asdr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Signal-to-Distortion Ratio."), +const FFFilter ff_af_asdr = { + .p.name = "asdr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Signal-to-Distortion Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), }; -const AVFilter ff_af_apsnr = { - .name = "apsnr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Peak Signal-to-Noise Ratio."), +const FFFilter ff_af_apsnr = { + .p.name = "apsnr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Peak Signal-to-Noise Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), }; -const AVFilter ff_af_asisdr = { - .name = "asisdr", - .description = NULL_IF_CONFIG_SMALL("Measure Audio Scale-Invariant Signal-to-Distortion Ratio."), +const FFFilter ff_af_asisdr = { + .p.name = "asisdr", + .p.description = NULL_IF_CONFIG_SMALL("Measure Audio Scale-Invariant Signal-to-Distortion Ratio."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY | + AVFILTER_FLAG_SLICE_THREADS | + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioSDRContext), .activate = activate, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY | - AVFILTER_FLAG_SLICE_THREADS | - AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index 3d2d99dae2..137fab9403 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -102,14 +102,14 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; } -const AVFilter ff_af_asetnsamples = { - .name = "asetnsamples", - .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."), +const FFFilter ff_af_asetnsamples = { + .p.name = "asetnsamples", + .p.description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."), + .p.priv_class = &asetnsamples_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(ASNSContext), - .priv_class = &asetnsamples_class, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), .activate = activate, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c index 061edebdf0..9cf4cb806b 100644 --- a/libavfilter/af_asetrate.c +++ b/libavfilter/af_asetrate.c @@ -111,14 +111,14 @@ static const AVFilterPad asetrate_outputs[] = { }, }; -const AVFilter ff_af_asetrate = { - .name = "asetrate", - .description = NULL_IF_CONFIG_SMALL("Change the sample rate without " +const FFFilter ff_af_asetrate = { + .p.name = "asetrate", + .p.description = NULL_IF_CONFIG_SMALL("Change the sample rate without " "altering the data."), + .p.priv_class = &asetrate_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ASetRateContext), FILTER_INPUTS(asetrate_inputs), FILTER_OUTPUTS(asetrate_outputs), FILTER_QUERY_FUNC2(query_formats), - .priv_class = &asetrate_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c index b83847b866..57f1ebf535 100644 --- a/libavfilter/af_ashowinfo.c +++ b/libavfilter/af_ashowinfo.c @@ -120,7 +120,7 @@ static void print_peak(AVFilterContext *ctx, const char *str, uint32_t peak) if (!peak) av_log(ctx, AV_LOG_INFO, "unknown"); else - av_log(ctx, AV_LOG_INFO, "%f", (float)peak / UINT32_MAX); + av_log(ctx, AV_LOG_INFO, "%f", peak / 100000.0f); av_log(ctx, AV_LOG_INFO, ", "); } @@ -241,12 +241,12 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_ashowinfo = { - .name = "ashowinfo", - .description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."), +const FFFilter ff_af_ashowinfo = { + .p.name = "ashowinfo", + .p.description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(AShowInfoContext), .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), }; diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c index 232ed05c01..19923f2c34 100644 --- a/libavfilter/af_asoftclip.c +++ b/libavfilter/af_asoftclip.c @@ -473,16 +473,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asoftclip = { - .name = "asoftclip", - .description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."), +const FFFilter ff_af_asoftclip = { + .p.name = "asoftclip", + .p.description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."), + .p.priv_class = &asoftclip_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASoftClipContext), - .priv_class = &asoftclip_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .uninit = uninit, .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_aspectralstats.c b/libavfilter/af_aspectralstats.c index ca79395514..ac7da748ee 100644 --- a/libavfilter/af_aspectralstats.c +++ b/libavfilter/af_aspectralstats.c @@ -608,15 +608,15 @@ static const AVFilterPad aspectralstats_outputs[] = { }, }; -const AVFilter ff_af_aspectralstats = { - .name = "aspectralstats", - .description = NULL_IF_CONFIG_SMALL("Show frequency domain statistics about audio frames."), +const FFFilter ff_af_aspectralstats = { + .p.name = "aspectralstats", + .p.description = NULL_IF_CONFIG_SMALL("Show frequency domain statistics about audio frames."), + .p.priv_class = &aspectralstats_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioSpectralStatsContext), - .priv_class = &aspectralstats_class, .uninit = uninit, .activate = activate, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(aspectralstats_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c index 8e8eeb19a7..c39ac772d3 100644 --- a/libavfilter/af_asr.c +++ b/libavfilter/af_asr.c @@ -173,14 +173,14 @@ static const AVFilterPad asr_inputs[] = { }, }; -const AVFilter ff_af_asr = { - .name = "asr", - .description = NULL_IF_CONFIG_SMALL("Automatic Speech Recognition."), +const FFFilter ff_af_asr = { + .p.name = "asr", + .p.description = NULL_IF_CONFIG_SMALL("Automatic Speech Recognition."), + .p.priv_class = &asr_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ASRContext), - .priv_class = &asr_class, .init = asr_init, .uninit = asr_uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(asr_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c index 62ebc3f83b..e5be00ec0b 100644 --- a/libavfilter/af_astats.c +++ b/libavfilter/af_astats.c @@ -836,7 +836,7 @@ static void print_stats(AVFilterContext *ctx) av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); if (s->measure_perchannel & MEASURE_RMS_TROUGH) if (p->min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); + av_log(ctx, AV_LOG_INFO, "RMS through dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); if (s->measure_perchannel & MEASURE_CREST_FACTOR) av_log(ctx, AV_LOG_INFO, "Crest factor: %f\n", p->sigma_x2 ? FFMAX(-p->nmin, p->nmax) / sqrt(p->sigma_x2 / p->nb_samples) : 1); if (s->measure_perchannel & MEASURE_FLAT_FACTOR) @@ -896,7 +896,7 @@ static void print_stats(AVFilterContext *ctx) av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2))); if (s->measure_overall & MEASURE_RMS_TROUGH) if (min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); + av_log(ctx, AV_LOG_INFO, "RMS through dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); if (s->measure_overall & MEASURE_FLAT_FACTOR) av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); if (s->measure_overall & MEASURE_PEAK_COUNT) @@ -956,11 +956,12 @@ static const AVFilterPad astats_outputs[] = { }, }; -const AVFilter ff_af_astats = { - .name = "astats", - .description = NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."), +const FFFilter ff_af_astats = { + .p.name = "astats", + .p.description = NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."), + .p.priv_class = &astats_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(AudioStatsContext), - .priv_class = &astats_class, .uninit = uninit, FILTER_INPUTS(astats_inputs), FILTER_OUTPUTS(astats_outputs), @@ -969,5 +970,4 @@ const AVFilter ff_af_astats = { AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_asubboost.c b/libavfilter/af_asubboost.c index 5698f50287..58135626b9 100644 --- a/libavfilter/af_asubboost.c +++ b/libavfilter/af_asubboost.c @@ -238,16 +238,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asubboost = { - .name = "asubboost", - .description = NULL_IF_CONFIG_SMALL("Boost subwoofer frequencies."), +const FFFilter ff_af_asubboost = { + .p.name = "asubboost", + .p.description = NULL_IF_CONFIG_SMALL("Boost subwoofer frequencies."), + .p.priv_class = &asubboost_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASubBoostContext), - .priv_class = &asubboost_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_asupercut.c b/libavfilter/af_asupercut.c index 76e9d4b969..3e032d74bd 100644 --- a/libavfilter/af_asupercut.c +++ b/libavfilter/af_asupercut.c @@ -333,18 +333,18 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_asupercut = { - .name = "asupercut", - .description = NULL_IF_CONFIG_SMALL("Cut super frequencies."), +const FFFilter ff_af_asupercut = { + .p.name = "asupercut", + .p.description = NULL_IF_CONFIG_SMALL("Cut super frequencies."), + .p.priv_class = &asupercut_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), - .priv_class = &asupercut_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption asubcut_options[] = { @@ -356,18 +356,18 @@ static const AVOption asubcut_options[] = { AVFILTER_DEFINE_CLASS(asubcut); -const AVFilter ff_af_asubcut = { - .name = "asubcut", - .description = NULL_IF_CONFIG_SMALL("Cut subwoofer frequencies."), +const FFFilter ff_af_asubcut = { + .p.name = "asubcut", + .p.description = NULL_IF_CONFIG_SMALL("Cut subwoofer frequencies."), + .p.priv_class = &asubcut_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), - .priv_class = &asubcut_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; static const AVOption asuperpass_asuperstop_options[] = { @@ -381,30 +381,30 @@ static const AVOption asuperpass_asuperstop_options[] = { AVFILTER_DEFINE_CLASS_EXT(asuperpass_asuperstop, "asuperpass/asuperstop", asuperpass_asuperstop_options); -const AVFilter ff_af_asuperpass = { - .name = "asuperpass", - .description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-pass filter."), - .priv_class = &asuperpass_asuperstop_class, +const FFFilter ff_af_asuperpass = { + .p.name = "asuperpass", + .p.description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-pass filter."), + .p.priv_class = &asuperpass_asuperstop_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; -const AVFilter ff_af_asuperstop = { - .name = "asuperstop", - .description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-stop filter."), - .priv_class = &asuperpass_asuperstop_class, +const FFFilter ff_af_asuperstop = { + .p.name = "asuperstop", + .p.description = NULL_IF_CONFIG_SMALL("Apply high order Butterworth band-stop filter."), + .p.priv_class = &asuperpass_asuperstop_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ASuperCutContext), .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c index 3b03caa4d0..768840d99c 100644 --- a/libavfilter/af_atempo.c +++ b/libavfilter/af_atempo.c @@ -112,7 +112,7 @@ typedef struct ATempoContext { // number of channels: int channels; - // row of bytes to skip from one sample to next, across multple channels; + // row of bytes to skip from one sample to next, across multiple channels; // stride = (number-of-channels * bits-per-sample-per-channel) / 8 int stride; @@ -1176,14 +1176,14 @@ static const AVFilterPad atempo_outputs[] = { }, }; -const AVFilter ff_af_atempo = { - .name = "atempo", - .description = NULL_IF_CONFIG_SMALL("Adjust audio tempo."), +const FFFilter ff_af_atempo = { + .p.name = "atempo", + .p.description = NULL_IF_CONFIG_SMALL("Adjust audio tempo."), + .p.priv_class = &atempo_class, .init = init, .uninit = uninit, .process_command = process_command, .priv_size = sizeof(ATempoContext), - .priv_class = &atempo_class, FILTER_INPUTS(atempo_inputs), FILTER_OUTPUTS(atempo_outputs), FILTER_SAMPLEFMTS_ARRAY(sample_fmts), diff --git a/libavfilter/af_atilt.c b/libavfilter/af_atilt.c index c8f4ba1e94..b2cdef8fbb 100644 --- a/libavfilter/af_atilt.c +++ b/libavfilter/af_atilt.c @@ -246,16 +246,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_atilt = { - .name = "atilt", - .description = NULL_IF_CONFIG_SMALL("Apply spectral tilt to audio."), +const FFFilter ff_af_atilt = { + .p.name = "atilt", + .p.description = NULL_IF_CONFIG_SMALL("Apply spectral tilt to audio."), + .p.priv_class = &atilt_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(ATiltContext), - .priv_class = &atilt_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_axcorrelate.c b/libavfilter/af_axcorrelate.c index b887c07bfb..eb61536c4e 100644 --- a/libavfilter/af_axcorrelate.c +++ b/libavfilter/af_axcorrelate.c @@ -454,11 +454,11 @@ static const AVOption axcorrelate_options[] = { AVFILTER_DEFINE_CLASS(axcorrelate); -const AVFilter ff_af_axcorrelate = { - .name = "axcorrelate", - .description = NULL_IF_CONFIG_SMALL("Cross-correlate two audio streams."), +const FFFilter ff_af_axcorrelate = { + .p.name = "axcorrelate", + .p.description = NULL_IF_CONFIG_SMALL("Cross-correlate two audio streams."), + .p.priv_class = &axcorrelate_class, .priv_size = sizeof(AudioXCorrelateContext), - .priv_class = &axcorrelate_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index dc7f19d7ea..88992e36b9 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -1453,10 +1453,12 @@ static av_cold int name_##_init(AVFilterContext *ctx) \ return 0; \ } \ \ -const AVFilter ff_af_##name_ = { \ - .name = #name_, \ - .description = NULL_IF_CONFIG_SMALL(description_), \ - .priv_class = &priv_class_##_class, \ +const FFFilter ff_af_##name_ = { \ + .p.name = #name_, \ + .p.description = NULL_IF_CONFIG_SMALL(description_), \ + .p.priv_class = &priv_class_##_class, \ + .p.flags = AVFILTER_FLAG_SLICE_THREADS | \ + AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ .priv_size = sizeof(BiquadsContext), \ .init = name_##_init, \ .activate = activate, \ @@ -1465,7 +1467,6 @@ const AVFilter ff_af_##name_ = { \ FILTER_OUTPUTS(outputs), \ FILTER_QUERY_FUNC2(query_formats), \ .process_command = process_command, \ - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ } #define DEFINE_BIQUAD_FILTER(name, description) \ diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c index 006c8564fc..a6580a69ea 100644 --- a/libavfilter/af_bs2b.c +++ b/libavfilter/af_bs2b.c @@ -205,11 +205,11 @@ static const AVFilterPad bs2b_outputs[] = { }, }; -const AVFilter ff_af_bs2b = { - .name = "bs2b", - .description = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."), +const FFFilter ff_af_bs2b = { + .p.name = "bs2b", + .p.description = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."), + .p.priv_class = &bs2b_class, .priv_size = sizeof(Bs2bContext), - .priv_class = &bs2b_class, .init = init, .uninit = uninit, FILTER_INPUTS(bs2b_inputs), diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 7a99ac7780..b864317312 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -290,6 +290,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) for (i = 0; i < s->nch; i++) { s->map[i].in_channel_idx = i; s->map[i].out_channel_idx = i; + s->map[i].out_channel = av_channel_layout_channel_from_index(&s->output_layout, i); } } else if (s->nch != s->output_layout.nb_channels) { char buf[256]; @@ -444,13 +445,13 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = { }, }; -const AVFilter ff_af_channelmap = { - .name = "channelmap", - .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), +const FFFilter ff_af_channelmap = { + .p.name = "channelmap", + .p.description = NULL_IF_CONFIG_SMALL("Remap audio channels."), + .p.priv_class = &channelmap_class, .init = channelmap_init, .uninit = channelmap_uninit, .priv_size = sizeof(ChannelMapContext), - .priv_class = &channelmap_class, FILTER_INPUTS(avfilter_af_channelmap_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(channelmap_query_formats), diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index 64b6c7a1e1..638e81593c 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -228,29 +228,20 @@ static int activate(AVFilterContext *ctx) return 0; } - for (int i = 0; i < ctx->nb_outputs; i++) { - if (ff_outlink_get_status(ctx->outputs[i])) - continue; - - if (ff_outlink_frame_wanted(ctx->outputs[i])) { - ff_inlink_request_frame(inlink); - return 0; - } - } + FF_FILTER_FORWARD_WANTED_ANY(ctx, inlink); return FFERROR_NOT_READY; } -const AVFilter ff_af_channelsplit = { - .name = "channelsplit", - .description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams."), +const FFFilter ff_af_channelsplit = { + .p.name = "channelsplit", + .p.description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams."), + .p.priv_class = &channelsplit_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, .priv_size = sizeof(ChannelSplitContext), - .priv_class = &channelsplit_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), - .outputs = NULL, FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, }; diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c index 7b3f5be9ab..f7eeea3a23 100644 --- a/libavfilter/af_chorus.c +++ b/libavfilter/af_chorus.c @@ -339,11 +339,11 @@ static const AVFilterPad chorus_outputs[] = { }, }; -const AVFilter ff_af_chorus = { - .name = "chorus", - .description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."), +const FFFilter ff_af_chorus = { + .p.name = "chorus", + .p.description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."), + .p.priv_class = &chorus_class, .priv_size = sizeof(ChorusContext), - .priv_class = &chorus_class, .init = init, .uninit = uninit, FILTER_INPUTS(chorus_inputs), diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c index 1aedc0f6bb..69de1360f1 100644 --- a/libavfilter/af_compand.c +++ b/libavfilter/af_compand.c @@ -542,12 +542,12 @@ static const AVFilterPad compand_outputs[] = { }; -const AVFilter ff_af_compand = { - .name = "compand", - .description = NULL_IF_CONFIG_SMALL( +const FFFilter ff_af_compand = { + .p.name = "compand", + .p.description = NULL_IF_CONFIG_SMALL( "Compress or expand audio dynamic range."), + .p.priv_class = &compand_class, .priv_size = sizeof(CompandContext), - .priv_class = &compand_class, .init = init, .uninit = uninit, FILTER_INPUTS(compand_inputs), diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c index 9d307fd1f3..67f0b8f29b 100644 --- a/libavfilter/af_compensationdelay.c +++ b/libavfilter/af_compensationdelay.c @@ -166,15 +166,15 @@ static const AVFilterPad compensationdelay_inputs[] = { }, }; -const AVFilter ff_af_compensationdelay = { - .name = "compensationdelay", - .description = NULL_IF_CONFIG_SMALL("Audio Compensation Delay Line."), +const FFFilter ff_af_compensationdelay = { + .p.name = "compensationdelay", + .p.description = NULL_IF_CONFIG_SMALL("Audio Compensation Delay Line."), + .p.priv_class = &compensationdelay_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(CompensationDelayContext), - .priv_class = &compensationdelay_class, .uninit = uninit, FILTER_INPUTS(compensationdelay_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index 1d70e40643..bc2fcf52b4 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -373,16 +373,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_crossfeed = { - .name = "crossfeed", - .description = NULL_IF_CONFIG_SMALL("Apply headphone crossfeed filter."), +const FFFilter ff_af_crossfeed = { + .p.name = "crossfeed", + .p.description = NULL_IF_CONFIG_SMALL("Apply headphone crossfeed filter."), + .p.priv_class = &crossfeed_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(CrossfeedContext), - .priv_class = &crossfeed_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c index f7f4b063bf..3cb5dc71d8 100644 --- a/libavfilter/af_crystalizer.c +++ b/libavfilter/af_crystalizer.c @@ -233,17 +233,17 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_crystalizer = { - .name = "crystalizer", - .description = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."), +const FFFilter ff_af_crystalizer = { + .p.name = "crystalizer", + .p.description = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."), + .p.priv_class = &crystalizer_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(CrystalizerContext), - .priv_class = &crystalizer_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c index bea15e51d9..9aec777e1f 100644 --- a/libavfilter/af_dcshift.c +++ b/libavfilter/af_dcshift.c @@ -122,14 +122,14 @@ static const AVFilterPad dcshift_inputs[] = { }, }; -const AVFilter ff_af_dcshift = { - .name = "dcshift", - .description = NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."), +const FFFilter ff_af_dcshift = { + .p.name = "dcshift", + .p.description = NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."), + .p.priv_class = &dcshift_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(DCShiftContext), - .priv_class = &dcshift_class, .init = init, FILTER_INPUTS(dcshift_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_S32P), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c index b5fad9789b..657604267c 100644 --- a/libavfilter/af_deesser.c +++ b/libavfilter/af_deesser.c @@ -194,14 +194,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_deesser = { - .name = "deesser", - .description = NULL_IF_CONFIG_SMALL("Apply de-essing to the audio."), +const FFFilter ff_af_deesser = { + .p.name = "deesser", + .p.description = NULL_IF_CONFIG_SMALL("Apply de-essing to the audio."), + .p.priv_class = &deesser_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(DeesserContext), - .priv_class = &deesser_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_dialoguenhance.c b/libavfilter/af_dialoguenhance.c index cae8375547..df9b2d6af2 100644 --- a/libavfilter/af_dialoguenhance.c +++ b/libavfilter/af_dialoguenhance.c @@ -217,16 +217,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_dialoguenhance = { - .name = "dialoguenhance", - .description = NULL_IF_CONFIG_SMALL("Audio Dialogue Enhancement."), +const FFFilter ff_af_dialoguenhance = { + .p.name = "dialoguenhance", + .p.description = NULL_IF_CONFIG_SMALL("Audio Dialogue Enhancement."), + .p.priv_class = &dialoguenhance_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioDialogueEnhanceContext), - .priv_class = &dialoguenhance_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .activate = activate, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_drmeter.c b/libavfilter/af_drmeter.c index e5859e9d82..7eae49c0b9 100644 --- a/libavfilter/af_drmeter.c +++ b/libavfilter/af_drmeter.c @@ -138,7 +138,7 @@ static void print_stats(AVFilterContext *ctx) int peak_bin = BINS; if (!p->nb_samples) { - av_log(ctx, AV_LOG_INFO, "No data, dynamic range not meassurable\n"); + av_log(ctx, AV_LOG_INFO, "No data, dynamic range not measurable\n"); return; } @@ -197,13 +197,13 @@ static const AVFilterPad drmeter_outputs[] = { }, }; -const AVFilter ff_af_drmeter = { - .name = "drmeter", - .description = NULL_IF_CONFIG_SMALL("Measure audio dynamic range."), +const FFFilter ff_af_drmeter = { + .p.name = "drmeter", + .p.description = NULL_IF_CONFIG_SMALL("Measure audio dynamic range."), + .p.priv_class = &drmeter_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(DRMeterContext), - .priv_class = &drmeter_class, .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(drmeter_inputs), FILTER_OUTPUTS(drmeter_outputs), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c index 90b3f8bbee..ddeedf6258 100644 --- a/libavfilter/af_dynaudnorm.c +++ b/libavfilter/af_dynaudnorm.c @@ -1020,9 +1020,12 @@ static const AVFilterPad avfilter_af_dynaudnorm_inputs[] = { }, }; -const AVFilter ff_af_dynaudnorm = { - .name = "dynaudnorm", - .description = NULL_IF_CONFIG_SMALL("Dynamic Audio Normalizer."), +const FFFilter ff_af_dynaudnorm = { + .p.name = "dynaudnorm", + .p.description = NULL_IF_CONFIG_SMALL("Dynamic Audio Normalizer."), + .p.priv_class = &dynaudnorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(DynamicAudioNormalizerContext), .init = init, .uninit = uninit, @@ -1030,8 +1033,5 @@ const AVFilter ff_af_dynaudnorm = { FILTER_INPUTS(avfilter_af_dynaudnorm_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .priv_class = &dynaudnorm_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index a457481741..49a98787ec 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -236,9 +236,9 @@ static const AVFilterPad earwax_inputs[] = { }, }; -const AVFilter ff_af_earwax = { - .name = "earwax", - .description = NULL_IF_CONFIG_SMALL("Widen the stereo image."), +const FFFilter ff_af_earwax = { + .p.name = "earwax", + .p.description = NULL_IF_CONFIG_SMALL("Widen the stereo image."), .priv_size = sizeof(EarwaxContext), .uninit = uninit, FILTER_INPUTS(earwax_inputs), diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index e511a2b968..5403267597 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -122,14 +122,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_extrastereo = { - .name = "extrastereo", - .description = NULL_IF_CONFIG_SMALL("Increase difference between stereo audio channels."), +const FFFilter ff_af_extrastereo = { + .p.name = "extrastereo", + .p.description = NULL_IF_CONFIG_SMALL("Increase difference between stereo audio channels."), + .p.priv_class = &extrastereo_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(ExtraStereoContext), - .priv_class = &extrastereo_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c index 386d8cd242..f14983b431 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -808,6 +808,8 @@ static int config_input(AVFilterLink *inlink) if ((ret = av_tx_init(&s->analysis_rdft, &s->analysis_rdft_fn, AV_TX_FLOAT_RDFT, 0, 1 << rdft_bits, &scale, 0)) < 0) return ret; s->dump_buf = av_malloc_array(s->analysis_rdft_len + 2, sizeof(*s->dump_buf)); + if (!s->dump_buf) + return AVERROR(ENOMEM); } s->analysis_buf = av_malloc_array((s->analysis_rdft_len + 2), sizeof(*s->analysis_buf)); @@ -955,14 +957,14 @@ static const AVFilterPad firequalizer_outputs[] = { }, }; -const AVFilter ff_af_firequalizer = { - .name = "firequalizer", - .description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."), +const FFFilter ff_af_firequalizer = { + .p.name = "firequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Finite Impulse Response Equalizer."), + .p.priv_class = &firequalizer_class, .uninit = uninit, .process_command = process_command, .priv_size = sizeof(FIREqualizerContext), FILTER_INPUTS(firequalizer_inputs), FILTER_OUTPUTS(firequalizer_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), - .priv_class = &firequalizer_class, }; diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c index 092ffcaa23..c5c70d76f9 100644 --- a/libavfilter/af_flanger.c +++ b/libavfilter/af_flanger.c @@ -195,11 +195,11 @@ static const AVFilterPad flanger_inputs[] = { }, }; -const AVFilter ff_af_flanger = { - .name = "flanger", - .description = NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."), +const FFFilter ff_af_flanger = { + .p.name = "flanger", + .p.description = NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."), + .p.priv_class = &flanger_class, .priv_size = sizeof(FlangerContext), - .priv_class = &flanger_class, .init = init, .uninit = uninit, FILTER_INPUTS(flanger_inputs), diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c index 6726c85298..4260bb8556 100644 --- a/libavfilter/af_haas.c +++ b/libavfilter/af_haas.c @@ -218,11 +218,11 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_haas = { - .name = "haas", - .description = NULL_IF_CONFIG_SMALL("Apply Haas Stereo Enhancer."), +const FFFilter ff_af_haas = { + .p.name = "haas", + .p.description = NULL_IF_CONFIG_SMALL("Apply Haas Stereo Enhancer."), + .p.priv_class = &haas_class, .priv_size = sizeof(HaasContext), - .priv_class = &haas_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index c9d992d017..6bded8ef74 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -1758,11 +1758,11 @@ static const AVFilterPad avfilter_af_hdcd_inputs[] = { }, }; -const AVFilter ff_af_hdcd = { - .name = "hdcd", - .description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."), +const FFFilter ff_af_hdcd = { + .p.name = "hdcd", + .p.description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."), + .p.priv_class = &hdcd_class, .priv_size = sizeof(HDCDContext), - .priv_class = &hdcd_class, .init = init, .uninit = uninit, FILTER_INPUTS(avfilter_af_hdcd_inputs), diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index fccd8d3f12..fd07633498 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -776,16 +776,15 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_headphone = { - .name = "headphone", - .description = NULL_IF_CONFIG_SMALL("Apply headphone binaural spatialization with HRTFs in additional streams."), +const FFFilter ff_af_headphone = { + .p.name = "headphone", + .p.description = NULL_IF_CONFIG_SMALL("Apply headphone binaural spatialization with HRTFs in additional streams."), + .p.priv_class = &headphone_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(HeadphoneContext), - .priv_class = &headphone_class, .init = init, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index 0ea53248b6..de13f8f2dc 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -595,17 +595,16 @@ static const AVFilterPad avfilter_af_join_outputs[] = { }, }; -const AVFilter ff_af_join = { - .name = "join", - .description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into " +const FFFilter ff_af_join = { + .p.name = "join", + .p.description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into " "multi-channel output."), + .p.priv_class = &join_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(JoinContext), - .priv_class = &join_class, .init = join_init, .uninit = join_uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(avfilter_af_join_outputs), FILTER_QUERY_FUNC2(join_query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 35ff90b1a8..0ae2b902cb 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -810,16 +810,15 @@ static const AVFilterPad ladspa_outputs[] = { }, }; -const AVFilter ff_af_ladspa = { - .name = "ladspa", - .description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."), +const FFFilter ff_af_ladspa = { + .p.name = "ladspa", + .p.description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."), + .p.priv_class = &ladspa_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(LADSPAContext), - .priv_class = &ladspa_class, .init = init, .uninit = uninit, .process_command = process_command, - .inputs = 0, FILTER_OUTPUTS(ladspa_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index d63a713818..432b9710a5 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -926,11 +926,11 @@ static const AVFilterPad avfilter_af_loudnorm_inputs[] = { }, }; -const AVFilter ff_af_loudnorm = { - .name = "loudnorm", - .description = NULL_IF_CONFIG_SMALL("EBU R128 loudness normalization"), +const FFFilter ff_af_loudnorm = { + .p.name = "loudnorm", + .p.description = NULL_IF_CONFIG_SMALL("EBU R128 loudness normalization"), + .p.priv_class = &loudnorm_class, .priv_size = sizeof(LoudNormContext), - .priv_class = &loudnorm_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c index db9b1e3639..e5097d60d4 100644 --- a/libavfilter/af_lv2.c +++ b/libavfilter/af_lv2.c @@ -166,8 +166,9 @@ static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) return NULL; } -static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) +static void connect_ports(AVFilterContext *ctx, AVFrame *in, AVFrame *out) { + LV2Context *s = ctx->priv; int ich = 0, och = 0, i; for (i = 0; i < s->nb_ports; i++) { @@ -180,7 +181,7 @@ static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) } 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); + av_log(ctx, 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)) { @@ -217,7 +218,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - connect_ports(s, in, out); + connect_ports(ctx, in, out); lilv_instance_run(s->instance, in->nb_samples); @@ -245,7 +246,7 @@ static int request_frame(AVFilterLink *outlink) if (!out) return AVERROR(ENOMEM); - connect_ports(s, out, out); + connect_ports(ctx, out, out); lilv_instance_run(s->instance, out->nb_samples); @@ -302,7 +303,7 @@ static int config_output(AVFilterLink *outlink) 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))); + av_log(ctx, AV_LOG_ERROR, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(s->plugin))); return AVERROR(EINVAL); } @@ -370,7 +371,7 @@ static int config_output(AVFilterLink *outlink) 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); + av_log(ctx, AV_LOG_WARNING, "Unknown option: <%s>\n", str); } else { index = lilv_port_get_index(s->plugin, port); s->controls[index] = val; @@ -404,7 +405,7 @@ static av_cold int init(AVFilterContext *ctx) 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); + av_log(ctx, AV_LOG_ERROR, "Invalid plugin URI <%s>\n", s->plugin_uri); return AVERROR(EINVAL); } @@ -414,7 +415,7 @@ static av_cold int init(AVFilterContext *ctx) lilv_node_free(uri); if (!plugin) { - av_log(s, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); + av_log(ctx, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); return AVERROR(EINVAL); } @@ -549,7 +550,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar 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", cmd); + av_log(ctx, AV_LOG_WARNING, "Unknown option: <%s>\n", cmd); } else { index = lilv_port_get_index(s->plugin, port); s->controls[index] = atof(args); @@ -590,16 +591,15 @@ static const AVFilterPad lv2_outputs[] = { }, }; -const AVFilter ff_af_lv2 = { - .name = "lv2", - .description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), +const FFFilter ff_af_lv2 = { + .p.name = "lv2", + .p.description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), + .p.priv_class = &lv2_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS, .priv_size = sizeof(LV2Context), - .priv_class = &lv2_class, .init = init, .uninit = uninit, .process_command = process_command, - .inputs = 0, FILTER_OUTPUTS(lv2_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c index b2f61fc5f9..855d893550 100644 --- a/libavfilter/af_mcompand.c +++ b/libavfilter/af_mcompand.c @@ -634,12 +634,12 @@ static const AVFilterPad mcompand_outputs[] = { }; -const AVFilter ff_af_mcompand = { - .name = "mcompand", - .description = NULL_IF_CONFIG_SMALL( +const FFFilter ff_af_mcompand = { + .p.name = "mcompand", + .p.description = NULL_IF_CONFIG_SMALL( "Multiband Compress or expand audio dynamic range."), + .p.priv_class = &mcompand_class, .priv_size = sizeof(MCompandContext), - .priv_class = &mcompand_class, .uninit = uninit, FILTER_INPUTS(mcompand_inputs), FILTER_OUTPUTS(mcompand_outputs), diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 0d20b0307b..3c577edfe1 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -196,7 +196,7 @@ static av_cold int init(AVFilterContext *ctx) sign = 1; while (1) { gain = 1; - if (sscanf(arg, "%lf%n *%n", &gain, &len, &len)) + if (sscanf(arg, "%lf%n *%n", &gain, &len, &len) >= 1) arg += len; if (parse_channel_name(&arg, &in_ch_id, &named)){ av_log(ctx, AV_LOG_ERROR, @@ -416,11 +416,11 @@ static const AVFilterPad pan_inputs[] = { }, }; -const AVFilter ff_af_pan = { - .name = "pan", - .description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."), +const FFFilter ff_af_pan = { + .p.name = "pan", + .p.description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."), + .p.priv_class = &pan_class, .priv_size = sizeof(PanContext), - .priv_class = &pan_class, .init = init, .uninit = uninit, FILTER_INPUTS(pan_inputs), diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c index e3e2e921c4..db67cc6f4b 100644 --- a/libavfilter/af_replaygain.c +++ b/libavfilter/af_replaygain.c @@ -643,12 +643,12 @@ static const AVOption replaygain_options[] = { AVFILTER_DEFINE_CLASS(replaygain); -const AVFilter ff_af_replaygain = { - .name = "replaygain", - .description = NULL_IF_CONFIG_SMALL("ReplayGain scanner."), +const FFFilter ff_af_replaygain = { + .p.name = "replaygain", + .p.description = NULL_IF_CONFIG_SMALL("ReplayGain scanner."), + .p.priv_class = &replaygain_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(ReplayGainContext), - .priv_class = &replaygain_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(replaygain_inputs), FILTER_OUTPUTS(replaygain_outputs), FILTER_QUERY_FUNC2(query_formats), diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index cf055f77d0..eedd96b195 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -205,11 +205,11 @@ static const AVFilterPad rubberband_inputs[] = { }, }; -const AVFilter ff_af_rubberband = { - .name = "rubberband", - .description = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."), +const FFFilter ff_af_rubberband = { + .p.name = "rubberband", + .p.description = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."), + .p.priv_class = &rubberband_class, .priv_size = sizeof(RubberBandContext), - .priv_class = &rubberband_class, .uninit = uninit, .activate = activate, FILTER_INPUTS(rubberband_inputs), diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index d2bc63f5de..492442df86 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -363,10 +363,10 @@ static const AVFilterPad sidechaincompress_outputs[] = { }, }; -const AVFilter ff_af_sidechaincompress = { - .name = "sidechaincompress", - .description = NULL_IF_CONFIG_SMALL("Sidechain compressor."), - .priv_class = &sidechaincompress_acompressor_class, +const FFFilter ff_af_sidechaincompress = { + .p.name = "sidechaincompress", + .p.description = NULL_IF_CONFIG_SMALL("Sidechain compressor."), + .p.priv_class = &sidechaincompress_acompressor_class, .priv_size = sizeof(SidechainCompressContext), .activate = activate, .uninit = uninit, @@ -424,10 +424,10 @@ static const AVFilterPad acompressor_outputs[] = { }, }; -const AVFilter ff_af_acompressor = { - .name = "acompressor", - .description = NULL_IF_CONFIG_SMALL("Audio compressor."), - .priv_class = &sidechaincompress_acompressor_class, +const FFFilter ff_af_acompressor = { + .p.name = "acompressor", + .p.description = NULL_IF_CONFIG_SMALL("Audio compressor."), + .p.priv_class = &sidechaincompress_acompressor_class, .priv_size = sizeof(SidechainCompressContext), FILTER_INPUTS(acompressor_inputs), FILTER_OUTPUTS(acompressor_outputs), diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index 9bb17400e7..532f6b08af 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -45,7 +45,7 @@ typedef struct SilenceDetectContext { 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, + void (*silencedetect)(AVFilterContext *ctx, AVFrame *insamples, int nb_samples, int64_t nb_samples_notify, AVRational time_base); } SilenceDetectContext; @@ -75,10 +75,11 @@ static void set_meta(AVFrame *insamples, int channel, const char *key, char *val 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, +static av_always_inline void update(AVFilterContext *ctx, AVFrame *insamples, int is_silence, int current_sample, int64_t nb_samples_notify, AVRational time_base) { + SilenceDetectContext *s = ctx->priv; int channel = current_sample % s->independent_channels; if (is_silence) { if (s->start[channel] == INT64_MIN) { @@ -89,8 +90,8 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, 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", + av_log(ctx, AV_LOG_INFO, "channel: %d | ", channel); + av_log(ctx, AV_LOG_INFO, "silence_start: %s\n", av_ts2timestr(s->start[channel], &time_base)); } } @@ -107,8 +108,8 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, 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_log(ctx, AV_LOG_INFO, "channel: %d | ", channel); + av_log(ctx, AV_LOG_INFO, "silence_end: %s | silence_duration: %s\n", av_ts2timestr(end_pts, &time_base), av_ts2timestr(duration_ts, &time_base)); } @@ -118,24 +119,26 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, } #define SILENCE_DETECT(name, type) \ -static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, \ +static void silencedetect_##name(AVFilterContext *ctx, AVFrame *insamples, \ int nb_samples, int64_t nb_samples_notify, \ AVRational time_base) \ { \ + SilenceDetectContext *s = ctx->priv; \ const type *p = (const type *)insamples->data[0]; \ const type noise = s->noise; \ int i; \ \ for (i = 0; i < nb_samples; i++, p++) \ - update(s, insamples, *p < noise && *p > -noise, i, \ + update(ctx, insamples, *p < noise && *p > -noise, i, \ nb_samples_notify, time_base); \ } #define SILENCE_DETECT_PLANAR(name, type) \ -static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, \ +static void silencedetect_##name(AVFilterContext *ctx, AVFrame *insamples, \ int nb_samples, int64_t nb_samples_notify, \ AVRational time_base) \ { \ + SilenceDetectContext *s = ctx->priv; \ const int channels = insamples->ch_layout.nb_channels; \ const type noise = s->noise; \ \ @@ -143,7 +146,7 @@ static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, for (int i = 0; i < nb_samples; i++) { \ for (int ch = 0; ch < insamples->ch_layout.nb_channels; ch++) { \ const type *p = (const type *)insamples->extended_data[ch]; \ - update(s, insamples, p[i] < noise && p[i] > -noise, \ + update(ctx, insamples, p[i] < noise && p[i] > -noise, \ channels * i + ch, \ nb_samples_notify, time_base); \ } \ @@ -209,7 +212,8 @@ static int config_input(AVFilterLink *inlink) static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { - SilenceDetectContext *s = inlink->dst->priv; + AVFilterContext *ctx = inlink->dst; + SilenceDetectContext *s = ctx->priv; const int nb_channels = inlink->ch_layout.nb_channels; const int srate = inlink->sample_rate; const int nb_samples = insamples->nb_samples * nb_channels; @@ -226,7 +230,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) s->frame_end = insamples->pts + av_rescale_q(insamples->nb_samples, (AVRational){ 1, s->last_sample_rate }, inlink->time_base); - s->silencedetect(s, insamples, nb_samples, nb_samples_notify, + s->silencedetect(ctx, insamples, nb_samples, nb_samples_notify, inlink->time_base); return ff_filter_frame(inlink->dst->outputs[0], insamples); @@ -239,7 +243,7 @@ static av_cold void uninit(AVFilterContext *ctx) for (c = 0; c < s->independent_channels; c++) if (s->start[c] > INT64_MIN) - update(s, NULL, 0, c, 0, s->time_base); + update(ctx, NULL, 0, c, 0, s->time_base); av_freep(&s->nb_null_samples); av_freep(&s->start); } @@ -253,9 +257,11 @@ static const AVFilterPad silencedetect_inputs[] = { }, }; -const AVFilter ff_af_silencedetect = { - .name = "silencedetect", - .description = NULL_IF_CONFIG_SMALL("Detect silence."), +const FFFilter ff_af_silencedetect = { + .p.name = "silencedetect", + .p.description = NULL_IF_CONFIG_SMALL("Detect silence."), + .p.priv_class = &silencedetect_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(SilenceDetectContext), .uninit = uninit, FILTER_INPUTS(silencedetect_inputs), @@ -264,6 +270,4 @@ const AVFilter ff_af_silencedetect = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), - .priv_class = &silencedetect_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index 3cc518a7eb..fe12fd598f 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -478,11 +478,12 @@ static const AVFilterPad silenceremove_outputs[] = { }, }; -const AVFilter ff_af_silenceremove = { - .name = "silenceremove", - .description = NULL_IF_CONFIG_SMALL("Remove silence."), +const FFFilter ff_af_silenceremove = { + .p.name = "silenceremove", + .p.description = NULL_IF_CONFIG_SMALL("Remove silence."), + .p.priv_class = &silenceremove_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(SilenceRemoveContext), - .priv_class = &silenceremove_class, .init = init, .activate = activate, .uninit = uninit, @@ -491,5 +492,4 @@ const AVFilter ff_af_silenceremove = { FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), .process_command = ff_filter_process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c index 178b9c0b53..c1b9563566 100644 --- a/libavfilter/af_sofalizer.c +++ b/libavfilter/af_sofalizer.c @@ -734,7 +734,7 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int AVComplexFloat *fft_in_r = NULL; float *data_ir_l = NULL; float *data_ir_r = NULL; - int offset = 0; /* used for faster pointer arithmetics in for-loop */ + int offset = 0; /* used for faster pointer arithmetic in for-loop */ int i, j, azim_orig = azim, elev_orig = elev; int ret = 0; int n_current; @@ -954,7 +954,7 @@ fail: av_freep(&data_hrtf_l); /* free temporary HRTF memory */ av_freep(&data_hrtf_r); - av_freep(&data_ir_l); /* free temprary IR memory */ + av_freep(&data_ir_l); /* free temporary IR memory */ av_freep(&data_ir_r); av_freep(&fft_out_l); /* free temporary FFT memory */ @@ -1088,16 +1088,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_sofalizer = { - .name = "sofalizer", - .description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."), +const FFFilter ff_af_sofalizer = { + .p.name = "sofalizer", + .p.description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."), + .p.priv_class = &sofalizer_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(SOFAlizerContext), - .priv_class = &sofalizer_class, .init = init, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c index 840c432c1a..9e2ba6381c 100644 --- a/libavfilter/af_speechnorm.c +++ b/libavfilter/af_speechnorm.c @@ -590,16 +590,16 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_speechnorm = { - .name = "speechnorm", - .description = NULL_IF_CONFIG_SMALL("Speech Normalizer."), +const FFFilter ff_af_speechnorm = { + .p.name = "speechnorm", + .p.description = NULL_IF_CONFIG_SMALL("Speech Normalizer."), + .p.priv_class = &speechnorm_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(SpeechNormalizerContext), - .priv_class = &speechnorm_class, .activate = activate, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = process_command, }; diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c index bbbc88cd4f..4f2e2616b6 100644 --- a/libavfilter/af_stereotools.c +++ b/libavfilter/af_stereotools.c @@ -379,15 +379,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_stereotools = { - .name = "stereotools", - .description = NULL_IF_CONFIG_SMALL("Apply various stereo tools."), +const FFFilter ff_af_stereotools = { + .p.name = "stereotools", + .p.description = NULL_IF_CONFIG_SMALL("Apply various stereo tools."), + .p.priv_class = &stereotools_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(StereoToolsContext), - .priv_class = &stereotools_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c index 66aa24a03c..312a24ffe2 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -161,15 +161,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_stereowiden = { - .name = "stereowiden", - .description = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."), +const FFFilter ff_af_stereowiden = { + .p.name = "stereowiden", + .p.description = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."), + .p.priv_class = &stereowiden_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(StereoWidenContext), - .priv_class = &stereowiden_class, .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_superequalizer.c b/libavfilter/af_superequalizer.c index bdf6e12afe..402d9d0af3 100644 --- a/libavfilter/af_superequalizer.c +++ b/libavfilter/af_superequalizer.c @@ -350,11 +350,11 @@ static const AVOption superequalizer_options[] = { AVFILTER_DEFINE_CLASS(superequalizer); -const AVFilter ff_af_superequalizer = { - .name = "superequalizer", - .description = NULL_IF_CONFIG_SMALL("Apply 18 band equalization filter."), +const FFFilter ff_af_superequalizer = { + .p.name = "superequalizer", + .p.description = NULL_IF_CONFIG_SMALL("Apply 18 band equalization filter."), + .p.priv_class = &superequalizer_class, .priv_size = sizeof(SuperEqualizerContext), - .priv_class = &superequalizer_class, .init = init, .activate = activate, .uninit = uninit, diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index 95efe4685a..46380192a2 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -1510,17 +1510,17 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_af_surround = { - .name = "surround", - .description = NULL_IF_CONFIG_SMALL("Apply audio surround upmix filter."), +const FFFilter ff_af_surround = { + .p.name = "surround", + .p.description = NULL_IF_CONFIG_SMALL("Apply audio surround upmix filter."), + .p.priv_class = &surround_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .priv_size = sizeof(AudioSurroundContext), - .priv_class = &surround_class, .init = init, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, }; diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c index 0c781a2de3..d6bf06e217 100644 --- a/libavfilter/af_tremolo.c +++ b/libavfilter/af_tremolo.c @@ -122,14 +122,14 @@ static const AVFilterPad avfilter_af_tremolo_inputs[] = { }, }; -const AVFilter ff_af_tremolo = { - .name = "tremolo", - .description = NULL_IF_CONFIG_SMALL("Apply tremolo effect."), +const FFFilter ff_af_tremolo = { + .p.name = "tremolo", + .p.description = NULL_IF_CONFIG_SMALL("Apply tremolo effect."), + .p.priv_class = &tremolo_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(TremoloContext), - .priv_class = &tremolo_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_tremolo_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c index a3bf90ae8e..f4fd697a78 100644 --- a/libavfilter/af_vibrato.c +++ b/libavfilter/af_vibrato.c @@ -166,14 +166,14 @@ static const AVFilterPad avfilter_af_vibrato_inputs[] = { }, }; -const AVFilter ff_af_vibrato = { - .name = "vibrato", - .description = NULL_IF_CONFIG_SMALL("Apply vibrato effect."), +const FFFilter ff_af_vibrato = { + .p.name = "vibrato", + .p.description = NULL_IF_CONFIG_SMALL("Apply vibrato effect."), + .p.priv_class = &vibrato_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(VibratoContext), - .priv_class = &vibrato_class, .uninit = uninit, FILTER_INPUTS(avfilter_af_vibrato_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_virtualbass.c b/libavfilter/af_virtualbass.c index d2f28ab1a1..41df742aa6 100644 --- a/libavfilter/af_virtualbass.c +++ b/libavfilter/af_virtualbass.c @@ -171,14 +171,14 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_af_virtualbass = { - .name = "virtualbass", - .description = NULL_IF_CONFIG_SMALL("Audio Virtual Bass."), +const FFFilter ff_af_virtualbass = { + .p.name = "virtualbass", + .p.description = NULL_IF_CONFIG_SMALL("Audio Virtual Bass."), + .p.priv_class = &virtualbass_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .priv_size = sizeof(AudioVirtualBassContext), - .priv_class = &virtualbass_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, .process_command = ff_filter_process_command, }; diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index ed924cf45f..471bffeceb 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -48,9 +48,6 @@ static const char *const var_names[] = { "nb_channels", ///< number of channels "nb_consumed_samples", ///< number of samples consumed by the filter "nb_samples", ///< number of samples in the current frame -#if FF_API_FRAME_PKT - "pos", ///< position in the file of the frame -#endif "pts", ///< frame presentation timestamp "sample_rate", ///< sample rate "startpts", ///< PTS at start of stream @@ -289,9 +286,6 @@ static int config_output(AVFilterLink *outlink) vol->var_values[VAR_N] = vol->var_values[VAR_NB_CONSUMED_SAMPLES] = vol->var_values[VAR_NB_SAMPLES] = -#if FF_API_FRAME_PKT - vol->var_values[VAR_POS] = -#endif vol->var_values[VAR_PTS] = vol->var_values[VAR_STARTPTS] = vol->var_values[VAR_STARTT] = @@ -383,15 +377,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) vol->var_values[VAR_T ] = TS2T(buf->pts, inlink->time_base); vol->var_values[VAR_N ] = inl->frame_count_out; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - { - int64_t pos; - pos = buf->pkt_pos; - vol->var_values[VAR_POS] = pos == -1 ? NAN : pos; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (vol->eval_mode == EVAL_MODE_FRAME) set_volume(ctx); @@ -471,16 +456,16 @@ static const AVFilterPad avfilter_af_volume_outputs[] = { }, }; -const AVFilter ff_af_volume = { - .name = "volume", - .description = NULL_IF_CONFIG_SMALL("Change input volume."), +const FFFilter ff_af_volume = { + .p.name = "volume", + .p.description = NULL_IF_CONFIG_SMALL("Change input volume."), + .p.priv_class = &volume_class, + .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .priv_size = sizeof(VolumeContext), - .priv_class = &volume_class, .init = init, .uninit = uninit, FILTER_INPUTS(avfilter_af_volume_inputs), FILTER_OUTPUTS(avfilter_af_volume_outputs), FILTER_QUERY_FUNC2(query_formats), - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .process_command = process_command, }; diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h index c3756ee969..e9527eea8a 100644 --- a/libavfilter/af_volume.h +++ b/libavfilter/af_volume.h @@ -47,9 +47,6 @@ enum VolumeVarName { VAR_NB_CHANNELS, VAR_NB_CONSUMED_SAMPLES, VAR_NB_SAMPLES, -#if FF_API_FRAME_PKT - VAR_POS, -#endif VAR_PTS, VAR_SAMPLE_RATE, VAR_STARTPTS, diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c index 25f7bf5695..6437687c8d 100644 --- a/libavfilter/af_volumedetect.c +++ b/libavfilter/af_volumedetect.c @@ -122,12 +122,12 @@ static const AVFilterPad volumedetect_inputs[] = { }, }; -const AVFilter ff_af_volumedetect = { - .name = "volumedetect", - .description = NULL_IF_CONFIG_SMALL("Detect audio volume."), +const FFFilter ff_af_volumedetect = { + .p.name = "volumedetect", + .p.description = NULL_IF_CONFIG_SMALL("Detect audio volume."), + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(VolDetectContext), .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(volumedetect_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P), diff --git a/libavfilter/af_whisper.c b/libavfilter/af_whisper.c new file mode 100644 index 0000000000..385180b4ed --- /dev/null +++ b/libavfilter/af_whisper.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2025 Vittorio Palmisano + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libavutil/channel_layout.h" +#include "libavutil/samplefmt.h" +#include "libavfilter/avfilter.h" +#include "libavfilter/audio.h" +#include "libavutil/mem.h" +#include "libavutil/avstring.h" +#include "libavutil/internal.h" +#include "libavformat/avio.h" +#include "libavutil/thread.h" + +#include "formats.h" + +typedef struct WhisperContext { + const AVClass *class; + char *model_path; + char *language; + bool use_gpu; + int gpu_device; + char *vad_model_path; + float vad_threshold; + int64_t vad_min_speech_duration; + int64_t vad_min_silence_duration; + + int64_t queue; + char *destination; + char *format; + + struct whisper_context *ctx_wsp; + struct whisper_vad_context *ctx_vad; + struct whisper_vad_params vad_params; + + float *audio_buffer; + int audio_buffer_queue_size; + int audio_buffer_fill_size; + int audio_buffer_vad_size; + int64_t audio_buffer_start_ms; + + int eof; + int64_t next_pts; + + AVIOContext *avio_context; + int index; +} WhisperContext; + +static void cb_log(enum ggml_log_level level, const char *text, void *user_data) +{ + AVFilterContext *ctx = user_data; + int av_log_level = AV_LOG_DEBUG; + switch (level) { + case GGML_LOG_LEVEL_ERROR: + av_log_level = AV_LOG_ERROR; + break; + case GGML_LOG_LEVEL_WARN: + av_log_level = AV_LOG_WARNING; + break; + } + av_log(ctx, av_log_level, "%s", text); +} + +static int init(AVFilterContext *ctx) +{ + WhisperContext *wctx = ctx->priv; + + static AVOnce init_static_once = AV_ONCE_INIT; + ff_thread_once(&init_static_once, ggml_backend_load_all); + + whisper_log_set(cb_log, ctx); + + // Init whisper context + if (!wctx->model_path) { + av_log(ctx, AV_LOG_ERROR, "No whisper model path specified. Use the 'model' option.\n"); + return AVERROR(EINVAL); + } + + struct whisper_context_params params = whisper_context_default_params(); + params.use_gpu = wctx->use_gpu; + params.gpu_device = wctx->gpu_device; + + wctx->ctx_wsp = whisper_init_from_file_with_params(wctx->model_path, params); + if (wctx->ctx_wsp == NULL) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialize whisper context from model: %s\n", wctx->model_path); + return AVERROR(EIO); + } + + // Init buffer + wctx->audio_buffer_queue_size = av_rescale(wctx->queue, WHISPER_SAMPLE_RATE, AV_TIME_BASE); + wctx->audio_buffer = av_malloc_array(wctx->audio_buffer_queue_size, sizeof(*wctx->audio_buffer)); + if (!wctx->audio_buffer) + return AVERROR(ENOMEM); + + // Init VAD model context + if (wctx->vad_model_path) { + struct whisper_vad_context_params ctx_params = whisper_vad_default_context_params(); + ctx_params.n_threads = ff_filter_get_nb_threads(ctx); + // ctx_params.use_gpu = wctx->use_gpu; TODO (see: whisper_vad_init_context) + ctx_params.gpu_device = wctx->gpu_device; + wctx->ctx_vad = whisper_vad_init_from_file_with_params(wctx->vad_model_path, ctx_params); + + wctx->vad_params = whisper_vad_default_params(); + wctx->vad_params.threshold = wctx->vad_threshold; + wctx->vad_params.min_speech_duration_ms = av_rescale(wctx->vad_min_speech_duration, 1000, AV_TIME_BASE); + wctx->vad_params.min_silence_duration_ms = av_rescale(wctx->vad_min_silence_duration, 1000, AV_TIME_BASE); + wctx->vad_params.max_speech_duration_s = av_rescale(wctx->queue, 1, AV_TIME_BASE); + wctx->vad_params.speech_pad_ms = 0; + wctx->vad_params.samples_overlap = 0; + } + + wctx->next_pts = AV_NOPTS_VALUE; + + if (wctx->destination && strcmp("", wctx->destination)) { + const char *dst = wctx->destination; + if (!strcmp("-", dst)) + dst = "pipe:1"; + int ret = avio_open(&wctx->avio_context, dst, AVIO_FLAG_WRITE); + + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Could not open %s: %s\n", wctx->destination, av_err2str(ret)); + return ret; + } + + wctx->avio_context->direct = AVIO_FLAG_DIRECT; + } + + av_log(ctx, AV_LOG_INFO, + "Whisper filter initialized: model: %s lang: %s queue: %ld ms\n", + wctx->model_path, wctx->language, wctx->queue / 1000); + + return 0; +} + +static void uninit(AVFilterContext *ctx) +{ + WhisperContext *wctx = ctx->priv; + + if (wctx->audio_buffer_fill_size > 0) { + av_log(ctx, AV_LOG_WARNING, + "Remaining audio buffer %d samples (%d seconds) after stopping\n", + wctx->audio_buffer_fill_size, wctx->audio_buffer_fill_size / WHISPER_SAMPLE_RATE); + } + + if (wctx->ctx_vad) { + whisper_vad_free(wctx->ctx_vad); + wctx->ctx_vad = NULL; + } + + if (wctx->ctx_wsp) { + whisper_free(wctx->ctx_wsp); + wctx->ctx_wsp = NULL; + } + + av_freep(&wctx->audio_buffer); + + if (wctx->avio_context) + avio_closep(&wctx->avio_context); +} + +static void run_transcription(AVFilterContext *ctx, AVFrame *frame, int samples) +{ + WhisperContext *wctx = ctx->priv; + samples = FFMAX(0, FFMIN(samples, wctx->audio_buffer_fill_size)); + + if (!wctx->ctx_wsp || samples == 0) + return; + + const int64_t timestamp_ms = wctx->audio_buffer_start_ms; + const float duration = (float) samples / WHISPER_SAMPLE_RATE; + + av_log(ctx, AV_LOG_INFO, + "run transcription at %ld ms, %d/%d samples (%.2f seconds)...\n", + timestamp_ms, samples, wctx->audio_buffer_fill_size, duration); + + struct whisper_full_params params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + params.language = wctx->language; + params.n_threads = ff_filter_get_nb_threads(ctx); + params.print_special = 0; + params.print_progress = 0; + params.print_realtime = 0; + params.print_timestamps = 0; + + if (whisper_full(wctx->ctx_wsp, params, wctx->audio_buffer, samples) != 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to process audio with whisper.cpp\n"); + return; + } + + const int n_segments = whisper_full_n_segments(wctx->ctx_wsp); + char *segments_text = NULL; + + for (int i = 0; i < n_segments; ++i) { + const char *text = whisper_full_get_segment_text(wctx->ctx_wsp, i); + if (av_isspace(text[0])) + text++; + char *text_cleaned = av_strireplace(text, "[BLANK_AUDIO]", ""); + + if (av_strnlen(text_cleaned, 1) == 0) { + av_freep(&text_cleaned); + continue; + } + + const bool turn = whisper_full_get_segment_speaker_turn_next(wctx->ctx_wsp, i); + const int64_t t0_ms = whisper_full_get_segment_t0(wctx->ctx_wsp, i) * 10; + const int64_t t1_ms = whisper_full_get_segment_t1(wctx->ctx_wsp, i) * 10; + + av_log(ctx, AV_LOG_DEBUG, " [%ld-%ld%s]: \"%s\"\n", + timestamp_ms + t0_ms, timestamp_ms + t1_ms, turn ? " (turn)" : "", text_cleaned); + + if (segments_text) { + char *new_text = av_asprintf("%s%s", segments_text, text_cleaned); + av_freep(&segments_text); + segments_text = new_text; + } else + segments_text = av_strdup(text_cleaned); + + if (wctx->avio_context) { + const int64_t start_t = timestamp_ms + t0_ms; + const int64_t end_t = timestamp_ms + t1_ms; + char *buf = NULL; + + if (!av_strcasecmp(wctx->format, "srt")) { + buf = + av_asprintf + ("%d\n%02ld:%02ld:%02ld.%03ld --> %02ld:%02ld:%02ld.%03ld\n%s\n\n", + wctx->index, start_t / 3600000, + (start_t / 60000) % 60, (start_t / 1000) % 60, + start_t % 1000, end_t / 3600000, (end_t / 60000) % 60, + (end_t / 1000) % 60, end_t % 1000, text_cleaned); + } else if (!av_strcasecmp(wctx->format, "json")) { + buf = av_asprintf("{\"start\":%ld,\"end\":%ld,\"text\":\"%s\"}\n", start_t, end_t, text_cleaned); + } else + buf = av_strdup(text_cleaned); + + if (buf) { + avio_write(wctx->avio_context, buf, strlen(buf)); + av_freep(&buf); + } + } + + av_freep(&text_cleaned); + } + + wctx->index++; + + AVDictionary **metadata = &frame->metadata; + if (metadata && segments_text) { + av_dict_set(metadata, "lavfi.whisper.text", segments_text, 0); + char *duration_text = av_asprintf("%f", duration); + av_dict_set(metadata, "lavfi.whisper.duration", duration_text, AV_DICT_DONT_STRDUP_VAL); + } + av_freep(&segments_text); + + if (wctx->audio_buffer_fill_size > samples) { + memcpy(wctx->audio_buffer, wctx->audio_buffer + samples, + (wctx->audio_buffer_fill_size - samples) * sizeof(*wctx->audio_buffer)); + wctx->audio_buffer_start_ms += duration * 1000; + } + wctx->audio_buffer_fill_size -= samples; + wctx->audio_buffer_vad_size = wctx->audio_buffer_fill_size; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + WhisperContext *wctx = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + const int samples = frame->nb_samples; + const float *input_data = (const float *) frame->data[0]; + + if (wctx->audio_buffer_fill_size + samples > wctx->audio_buffer_queue_size) { + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + } + + if (!wctx->audio_buffer_fill_size) + wctx->audio_buffer_start_ms = av_rescale_q(frame->pts, + (AVRational) {1000, 1}, + (AVRational) {inlink->time_base.den, inlink->time_base.num}); + memcpy(wctx->audio_buffer + wctx->audio_buffer_fill_size, input_data, samples * sizeof(*wctx->audio_buffer)); + wctx->audio_buffer_fill_size += samples; + + if (wctx->ctx_vad + && (wctx->audio_buffer_fill_size - wctx->audio_buffer_vad_size) >= + av_rescale(wctx->vad_min_speech_duration + wctx->vad_min_silence_duration, WHISPER_SAMPLE_RATE, AV_TIME_BASE)) { + struct whisper_vad_segments *segments = whisper_vad_segments_from_samples(wctx->ctx_vad, + wctx->vad_params, + wctx->audio_buffer, + wctx->audio_buffer_fill_size); + wctx->audio_buffer_vad_size = wctx->audio_buffer_fill_size; + + if (!segments) { + av_log(ctx, AV_LOG_ERROR, "failed to detect VAD\n"); + } else { + int n_segments = whisper_vad_segments_n_segments(segments); + + if (n_segments > 0) { + const float start_ms = whisper_vad_segments_get_segment_t0(segments, 0) * 10.0; + const float end_ms = whisper_vad_segments_get_segment_t1(segments, n_segments - 1) * 10.0; + int end_pos = (int) (end_ms * WHISPER_SAMPLE_RATE / 1000); + + if (end_pos <= wctx->audio_buffer_fill_size - + av_rescale(wctx->vad_min_silence_duration, WHISPER_SAMPLE_RATE, AV_TIME_BASE)) { + av_log(ctx, AV_LOG_INFO, + "VAD detected %d segments, start: %.0f ms, end: %.0f ms (buffer: %d ms)\n", + n_segments, start_ms, end_ms, 1000 * wctx->audio_buffer_fill_size / WHISPER_SAMPLE_RATE); + run_transcription(ctx, frame, end_pos); + } + } + + whisper_vad_free_segments(segments); + } + } else if (wctx->audio_buffer_fill_size >= wctx->audio_buffer_queue_size) + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + + wctx->next_pts = frame->pts + av_rescale_q(samples, (AVRational) { + 1, inlink->sample_rate} + , inlink->time_base); + return ff_filter_frame(outlink, frame); +} + +static int push_last_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + WhisperContext *wctx = ctx->priv; + AVFrame *frame; + int n_out = 1; + + if (ctx->is_disabled || wctx->audio_buffer_fill_size == 0) + return 0; + frame = ff_get_audio_buffer(outlink, n_out); + if (!frame) + return AVERROR(ENOMEM); + + av_samples_set_silence(frame->extended_data, 0, n_out, frame->ch_layout.nb_channels, frame->format); + + frame->pts = wctx->next_pts; + if (wctx->next_pts != AV_NOPTS_VALUE) + wctx->next_pts += av_rescale_q(n_out, (AVRational) { + 1, outlink->sample_rate} + , outlink->time_base); + + run_transcription(ctx, frame, wctx->audio_buffer_fill_size); + + return ff_filter_frame(outlink, frame); +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + WhisperContext *wctx = ctx->priv; + int64_t pts; + int status; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!wctx->eof && ff_inlink_queued_frames(inlink)) { + AVFrame *frame = NULL; + int ret; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, frame); + } + + if (!wctx->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) + wctx->eof = status == AVERROR_EOF; + + if (wctx->eof) { + push_last_frame(outlink); + + ff_outlink_set_status(outlink, AVERROR_EOF, wctx->next_pts); + return 0; + } + + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; + AVChannelLayout chlayouts[] = { FF_COUNT2LAYOUT(1), { 0 } }; + int sample_rates[] = { WHISPER_SAMPLE_RATE, -1 }; + int ret; + + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + if (ret < 0) + return ret; + + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); + if (ret < 0) + return ret; + + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); +} + +#define OFFSET(x) offsetof(WhisperContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +#define HOURS 3600000000 + +static const AVOption whisper_options[] = { + { "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, + { "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS }, + { "queue", "Audio queue size", OFFSET(queue), AV_OPT_TYPE_DURATION, {.i64 = 3000000}, 20000, HOURS, .flags = FLAGS }, + { "use_gpu", "Use GPU for processing", OFFSET(use_gpu), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = FLAGS }, + { "gpu_device", "GPU device to use", OFFSET(gpu_device), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, .flags = FLAGS }, + { "destination", "Output destination", OFFSET(destination), AV_OPT_TYPE_STRING, {.str = ""}, .flags = FLAGS }, + { "format", "Output format (text|srt|json)", OFFSET(format), AV_OPT_TYPE_STRING, {.str = "text"},.flags = FLAGS }, + { "vad_model", "Path to the VAD model file", OFFSET(vad_model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, + { "vad_threshold", "VAD threshold", OFFSET(vad_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 0.5}, 0.0, 1.0, .flags = FLAGS }, + { "vad_min_speech_duration", "Minimum speech duration for VAD", OFFSET(vad_min_speech_duration), AV_OPT_TYPE_DURATION, {.i64 = 100000}, 20000, HOURS, .flags = FLAGS }, + { "vad_min_silence_duration", "Minimum silence duration for VAD", OFFSET(vad_min_silence_duration), AV_OPT_TYPE_DURATION, {.i64 = 500000}, 0, HOURS, .flags = FLAGS }, + { NULL } +}; + +static const AVClass whisper_class = { + .class_name = "whisper", + .item_name = av_default_item_name, + .option = whisper_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFFilter ff_af_whisper = { + .p.name = "whisper", + .p.description = NULL_IF_CONFIG_SMALL("Transcribe audio using whisper.cpp."), + .p.priv_class = &whisper_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, + .init = init, + .uninit = uninit, + .activate = activate, + .priv_size = sizeof(WhisperContext), + FILTER_INPUTS(ff_audio_default_filterpad), + FILTER_OUTPUTS(ff_audio_default_filterpad), + FILTER_QUERY_FUNC2(query_formats), +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9819f0f95b..cca4ce0288 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -20,602 +20,611 @@ */ #include "avfilter.h" +#include "filters.h" -extern const AVFilter ff_af_aap; -extern const AVFilter ff_af_abench; -extern const AVFilter ff_af_acompressor; -extern const AVFilter ff_af_acontrast; -extern const AVFilter ff_af_acopy; -extern const AVFilter ff_af_acue; -extern const AVFilter ff_af_acrossfade; -extern const AVFilter ff_af_acrossover; -extern const AVFilter ff_af_acrusher; -extern const AVFilter ff_af_adeclick; -extern const AVFilter ff_af_adeclip; -extern const AVFilter ff_af_adecorrelate; -extern const AVFilter ff_af_adelay; -extern const AVFilter ff_af_adenorm; -extern const AVFilter ff_af_aderivative; -extern const AVFilter ff_af_adrc; -extern const AVFilter ff_af_adynamicequalizer; -extern const AVFilter ff_af_adynamicsmooth; -extern const AVFilter ff_af_aecho; -extern const AVFilter ff_af_aemphasis; -extern const AVFilter ff_af_aeval; -extern const AVFilter ff_af_aexciter; -extern const AVFilter ff_af_afade; -extern const AVFilter ff_af_afftdn; -extern const AVFilter ff_af_afftfilt; -extern const AVFilter ff_af_afir; -extern const AVFilter ff_af_aformat; -extern const AVFilter ff_af_afreqshift; -extern const AVFilter ff_af_afwtdn; -extern const AVFilter ff_af_agate; -extern const AVFilter ff_af_aiir; -extern const AVFilter ff_af_aintegral; -extern const AVFilter ff_af_ainterleave; -extern const AVFilter ff_af_alatency; -extern const AVFilter ff_af_alimiter; -extern const AVFilter ff_af_allpass; -extern const AVFilter ff_af_aloop; -extern const AVFilter ff_af_amerge; -extern const AVFilter ff_af_ametadata; -extern const AVFilter ff_af_amix; -extern const AVFilter ff_af_amultiply; -extern const AVFilter ff_af_anequalizer; -extern const AVFilter ff_af_anlmdn; -extern const AVFilter ff_af_anlmf; -extern const AVFilter ff_af_anlms; -extern const AVFilter ff_af_anull; -extern const AVFilter ff_af_apad; -extern const AVFilter ff_af_aperms; -extern const AVFilter ff_af_aphaser; -extern const AVFilter ff_af_aphaseshift; -extern const AVFilter ff_af_apsnr; -extern const AVFilter ff_af_apsyclip; -extern const AVFilter ff_af_apulsator; -extern const AVFilter ff_af_arealtime; -extern const AVFilter ff_af_aresample; -extern const AVFilter ff_af_areverse; -extern const AVFilter ff_af_arls; -extern const AVFilter ff_af_arnndn; -extern const AVFilter ff_af_asdr; -extern const AVFilter ff_af_asegment; -extern const AVFilter ff_af_aselect; -extern const AVFilter ff_af_asendcmd; -extern const AVFilter ff_af_asetnsamples; -extern const AVFilter ff_af_asetpts; -extern const AVFilter ff_af_asetrate; -extern const AVFilter ff_af_asettb; -extern const AVFilter ff_af_ashowinfo; -extern const AVFilter ff_af_asidedata; -extern const AVFilter ff_af_asisdr; -extern const AVFilter ff_af_asoftclip; -extern const AVFilter ff_af_aspectralstats; -extern const AVFilter ff_af_asplit; -extern const AVFilter ff_af_asr; -extern const AVFilter ff_af_astats; -extern const AVFilter ff_af_astreamselect; -extern const AVFilter ff_af_asubboost; -extern const AVFilter ff_af_asubcut; -extern const AVFilter ff_af_asupercut; -extern const AVFilter ff_af_asuperpass; -extern const AVFilter ff_af_asuperstop; -extern const AVFilter ff_af_atempo; -extern const AVFilter ff_af_atilt; -extern const AVFilter ff_af_atrim; -extern const AVFilter ff_af_axcorrelate; -extern const AVFilter ff_af_azmq; -extern const AVFilter ff_af_bandpass; -extern const AVFilter ff_af_bandreject; -extern const AVFilter ff_af_bass; -extern const AVFilter ff_af_biquad; -extern const AVFilter ff_af_bs2b; -extern const AVFilter ff_af_channelmap; -extern const AVFilter ff_af_channelsplit; -extern const AVFilter ff_af_chorus; -extern const AVFilter ff_af_compand; -extern const AVFilter ff_af_compensationdelay; -extern const AVFilter ff_af_crossfeed; -extern const AVFilter ff_af_crystalizer; -extern const AVFilter ff_af_dcshift; -extern const AVFilter ff_af_deesser; -extern const AVFilter ff_af_dialoguenhance; -extern const AVFilter ff_af_drmeter; -extern const AVFilter ff_af_dynaudnorm; -extern const AVFilter ff_af_earwax; -extern const AVFilter ff_af_ebur128; -extern const AVFilter ff_af_equalizer; -extern const AVFilter ff_af_extrastereo; -extern const AVFilter ff_af_firequalizer; -extern const AVFilter ff_af_flanger; -extern const AVFilter ff_af_haas; -extern const AVFilter ff_af_hdcd; -extern const AVFilter ff_af_headphone; -extern const AVFilter ff_af_highpass; -extern const AVFilter ff_af_highshelf; -extern const AVFilter ff_af_join; -extern const AVFilter ff_af_ladspa; -extern const AVFilter ff_af_loudnorm; -extern const AVFilter ff_af_lowpass; -extern const AVFilter ff_af_lowshelf; -extern const AVFilter ff_af_lv2; -extern const AVFilter ff_af_mcompand; -extern const AVFilter ff_af_pan; -extern const AVFilter ff_af_replaygain; -extern const AVFilter ff_af_rubberband; -extern const AVFilter ff_af_sidechaincompress; -extern const AVFilter ff_af_sidechaingate; -extern const AVFilter ff_af_silencedetect; -extern const AVFilter ff_af_silenceremove; -extern const AVFilter ff_af_sofalizer; -extern const AVFilter ff_af_speechnorm; -extern const AVFilter ff_af_stereotools; -extern const AVFilter ff_af_stereowiden; -extern const AVFilter ff_af_superequalizer; -extern const AVFilter ff_af_surround; -extern const AVFilter ff_af_tiltshelf; -extern const AVFilter ff_af_treble; -extern const AVFilter ff_af_tremolo; -extern const AVFilter ff_af_vibrato; -extern const AVFilter ff_af_virtualbass; -extern const AVFilter ff_af_volume; -extern const AVFilter ff_af_volumedetect; +extern const FFFilter ff_af_aap; +extern const FFFilter ff_af_abench; +extern const FFFilter ff_af_acompressor; +extern const FFFilter ff_af_acontrast; +extern const FFFilter ff_af_acopy; +extern const FFFilter ff_af_acue; +extern const FFFilter ff_af_acrossfade; +extern const FFFilter ff_af_acrossover; +extern const FFFilter ff_af_acrusher; +extern const FFFilter ff_af_adeclick; +extern const FFFilter ff_af_adeclip; +extern const FFFilter ff_af_adecorrelate; +extern const FFFilter ff_af_adelay; +extern const FFFilter ff_af_adenorm; +extern const FFFilter ff_af_aderivative; +extern const FFFilter ff_af_adrc; +extern const FFFilter ff_af_adynamicequalizer; +extern const FFFilter ff_af_adynamicsmooth; +extern const FFFilter ff_af_aecho; +extern const FFFilter ff_af_aemphasis; +extern const FFFilter ff_af_aeval; +extern const FFFilter ff_af_aexciter; +extern const FFFilter ff_af_afade; +extern const FFFilter ff_af_afftdn; +extern const FFFilter ff_af_afftfilt; +extern const FFFilter ff_af_afir; +extern const FFFilter ff_af_aformat; +extern const FFFilter ff_af_afreqshift; +extern const FFFilter ff_af_afwtdn; +extern const FFFilter ff_af_agate; +extern const FFFilter ff_af_aiir; +extern const FFFilter ff_af_aintegral; +extern const FFFilter ff_af_ainterleave; +extern const FFFilter ff_af_alatency; +extern const FFFilter ff_af_alimiter; +extern const FFFilter ff_af_allpass; +extern const FFFilter ff_af_aloop; +extern const FFFilter ff_af_amerge; +extern const FFFilter ff_af_ametadata; +extern const FFFilter ff_af_amix; +extern const FFFilter ff_af_amultiply; +extern const FFFilter ff_af_anequalizer; +extern const FFFilter ff_af_anlmdn; +extern const FFFilter ff_af_anlmf; +extern const FFFilter ff_af_anlms; +extern const FFFilter ff_af_anull; +extern const FFFilter ff_af_apad; +extern const FFFilter ff_af_aperms; +extern const FFFilter ff_af_aphaser; +extern const FFFilter ff_af_aphaseshift; +extern const FFFilter ff_af_apsnr; +extern const FFFilter ff_af_apsyclip; +extern const FFFilter ff_af_apulsator; +extern const FFFilter ff_af_arealtime; +extern const FFFilter ff_af_aresample; +extern const FFFilter ff_af_areverse; +extern const FFFilter ff_af_arls; +extern const FFFilter ff_af_arnndn; +extern const FFFilter ff_af_asdr; +extern const FFFilter ff_af_asegment; +extern const FFFilter ff_af_aselect; +extern const FFFilter ff_af_asendcmd; +extern const FFFilter ff_af_asetnsamples; +extern const FFFilter ff_af_asetpts; +extern const FFFilter ff_af_asetrate; +extern const FFFilter ff_af_asettb; +extern const FFFilter ff_af_ashowinfo; +extern const FFFilter ff_af_asidedata; +extern const FFFilter ff_af_asisdr; +extern const FFFilter ff_af_asoftclip; +extern const FFFilter ff_af_aspectralstats; +extern const FFFilter ff_af_asplit; +extern const FFFilter ff_af_asr; +extern const FFFilter ff_af_astats; +extern const FFFilter ff_af_astreamselect; +extern const FFFilter ff_af_asubboost; +extern const FFFilter ff_af_asubcut; +extern const FFFilter ff_af_asupercut; +extern const FFFilter ff_af_asuperpass; +extern const FFFilter ff_af_asuperstop; +extern const FFFilter ff_af_atempo; +extern const FFFilter ff_af_atilt; +extern const FFFilter ff_af_atrim; +extern const FFFilter ff_af_axcorrelate; +extern const FFFilter ff_af_azmq; +extern const FFFilter ff_af_bandpass; +extern const FFFilter ff_af_bandreject; +extern const FFFilter ff_af_bass; +extern const FFFilter ff_af_biquad; +extern const FFFilter ff_af_bs2b; +extern const FFFilter ff_af_channelmap; +extern const FFFilter ff_af_channelsplit; +extern const FFFilter ff_af_chorus; +extern const FFFilter ff_af_compand; +extern const FFFilter ff_af_compensationdelay; +extern const FFFilter ff_af_crossfeed; +extern const FFFilter ff_af_crystalizer; +extern const FFFilter ff_af_dcshift; +extern const FFFilter ff_af_deesser; +extern const FFFilter ff_af_dialoguenhance; +extern const FFFilter ff_af_drmeter; +extern const FFFilter ff_af_dynaudnorm; +extern const FFFilter ff_af_earwax; +extern const FFFilter ff_af_ebur128; +extern const FFFilter ff_af_equalizer; +extern const FFFilter ff_af_extrastereo; +extern const FFFilter ff_af_firequalizer; +extern const FFFilter ff_af_flanger; +extern const FFFilter ff_af_haas; +extern const FFFilter ff_af_hdcd; +extern const FFFilter ff_af_headphone; +extern const FFFilter ff_af_highpass; +extern const FFFilter ff_af_highshelf; +extern const FFFilter ff_af_join; +extern const FFFilter ff_af_ladspa; +extern const FFFilter ff_af_loudnorm; +extern const FFFilter ff_af_lowpass; +extern const FFFilter ff_af_lowshelf; +extern const FFFilter ff_af_lv2; +extern const FFFilter ff_af_mcompand; +extern const FFFilter ff_af_pan; +extern const FFFilter ff_af_replaygain; +extern const FFFilter ff_af_rubberband; +extern const FFFilter ff_af_sidechaincompress; +extern const FFFilter ff_af_sidechaingate; +extern const FFFilter ff_af_silencedetect; +extern const FFFilter ff_af_silenceremove; +extern const FFFilter ff_af_sofalizer; +extern const FFFilter ff_af_speechnorm; +extern const FFFilter ff_af_stereotools; +extern const FFFilter ff_af_stereowiden; +extern const FFFilter ff_af_superequalizer; +extern const FFFilter ff_af_surround; +extern const FFFilter ff_af_tiltshelf; +extern const FFFilter ff_af_treble; +extern const FFFilter ff_af_tremolo; +extern const FFFilter ff_af_vibrato; +extern const FFFilter ff_af_virtualbass; +extern const FFFilter ff_af_volume; +extern const FFFilter ff_af_volumedetect; +extern const FFFilter ff_af_whisper; -extern const AVFilter ff_asrc_aevalsrc; -extern const AVFilter ff_asrc_afdelaysrc; -extern const AVFilter ff_asrc_afireqsrc; -extern const AVFilter ff_asrc_afirsrc; -extern const AVFilter ff_asrc_anoisesrc; -extern const AVFilter ff_asrc_anullsrc; -extern const AVFilter ff_asrc_flite; -extern const AVFilter ff_asrc_hilbert; -extern const AVFilter ff_asrc_sinc; -extern const AVFilter ff_asrc_sine; +extern const FFFilter ff_asrc_aevalsrc; +extern const FFFilter ff_asrc_afdelaysrc; +extern const FFFilter ff_asrc_afireqsrc; +extern const FFFilter ff_asrc_afirsrc; +extern const FFFilter ff_asrc_anoisesrc; +extern const FFFilter ff_asrc_anullsrc; +extern const FFFilter ff_asrc_flite; +extern const FFFilter ff_asrc_hilbert; +extern const FFFilter ff_asrc_sinc; +extern const FFFilter ff_asrc_sine; -extern const AVFilter ff_asink_anullsink; +extern const FFFilter ff_asink_anullsink; -extern const AVFilter ff_vf_addroi; -extern const AVFilter ff_vf_alphaextract; -extern const AVFilter ff_vf_alphamerge; -extern const AVFilter ff_vf_amplify; -extern const AVFilter ff_vf_ass; -extern const AVFilter ff_vf_atadenoise; -extern const AVFilter ff_vf_avgblur; -extern const AVFilter ff_vf_avgblur_opencl; -extern const AVFilter ff_vf_avgblur_vulkan; -extern const AVFilter ff_vf_backgroundkey; -extern const AVFilter ff_vf_bbox; -extern const AVFilter ff_vf_bench; -extern const AVFilter ff_vf_bilateral; -extern const AVFilter ff_vf_bilateral_cuda; -extern const AVFilter ff_vf_bitplanenoise; -extern const AVFilter ff_vf_blackdetect; -extern const AVFilter ff_vf_blackframe; -extern const AVFilter ff_vf_blend; -extern const AVFilter ff_vf_blend_vulkan; -extern const AVFilter ff_vf_blockdetect; -extern const AVFilter ff_vf_blurdetect; -extern const AVFilter ff_vf_bm3d; -extern const AVFilter ff_vf_boxblur; -extern const AVFilter ff_vf_boxblur_opencl; -extern const AVFilter ff_vf_bwdif; -extern const AVFilter ff_vf_bwdif_cuda; -extern const AVFilter ff_vf_bwdif_vulkan; -extern const AVFilter ff_vf_cas; -extern const AVFilter ff_vf_ccrepack; -extern const AVFilter ff_vf_chromaber_vulkan; -extern const AVFilter ff_vf_chromahold; -extern const AVFilter ff_vf_chromakey; -extern const AVFilter ff_vf_chromakey_cuda; -extern const AVFilter ff_vf_chromanr; -extern const AVFilter ff_vf_chromashift; -extern const AVFilter ff_vf_ciescope; -extern const AVFilter ff_vf_codecview; -extern const AVFilter ff_vf_colorbalance; -extern const AVFilter ff_vf_colorchannelmixer; -extern const AVFilter ff_vf_colorcontrast; -extern const AVFilter ff_vf_colorcorrect; -extern const AVFilter ff_vf_colorize; -extern const AVFilter ff_vf_colorkey; -extern const AVFilter ff_vf_colorkey_opencl; -extern const AVFilter ff_vf_colorhold; -extern const AVFilter ff_vf_colorlevels; -extern const AVFilter ff_vf_colormap; -extern const AVFilter ff_vf_colormatrix; -extern const AVFilter ff_vf_colorspace; -extern const AVFilter ff_vf_colorspace_cuda; -extern const AVFilter ff_vf_colortemperature; -extern const AVFilter ff_vf_convolution; -extern const AVFilter ff_vf_convolution_opencl; -extern const AVFilter ff_vf_convolve; -extern const AVFilter ff_vf_copy; -extern const AVFilter ff_vf_coreimage; -extern const AVFilter ff_vf_corr; -extern const AVFilter ff_vf_cover_rect; -extern const AVFilter ff_vf_crop; -extern const AVFilter ff_vf_cropdetect; -extern const AVFilter ff_vf_cue; -extern const AVFilter ff_vf_curves; -extern const AVFilter ff_vf_datascope; -extern const AVFilter ff_vf_dblur; -extern const AVFilter ff_vf_dctdnoiz; -extern const AVFilter ff_vf_deband; -extern const AVFilter ff_vf_deblock; -extern const AVFilter ff_vf_decimate; -extern const AVFilter ff_vf_deconvolve; -extern const AVFilter ff_vf_dedot; -extern const AVFilter ff_vf_deflate; -extern const AVFilter ff_vf_deflicker; -extern const AVFilter ff_vf_deinterlace_qsv; -extern const AVFilter ff_vf_deinterlace_vaapi; -extern const AVFilter ff_vf_dejudder; -extern const AVFilter ff_vf_delogo; -extern const AVFilter ff_vf_denoise_vaapi; -extern const AVFilter ff_vf_derain; -extern const AVFilter ff_vf_deshake; -extern const AVFilter ff_vf_deshake_opencl; -extern const AVFilter ff_vf_despill; -extern const AVFilter ff_vf_detelecine; -extern const AVFilter ff_vf_dilation; -extern const AVFilter ff_vf_dilation_opencl; -extern const AVFilter ff_vf_displace; -extern const AVFilter ff_vf_dnn_classify; -extern const AVFilter ff_vf_dnn_detect; -extern const AVFilter ff_vf_dnn_processing; -extern const AVFilter ff_vf_doubleweave; -extern const AVFilter ff_vf_drawbox; -extern const AVFilter ff_vf_drawgraph; -extern const AVFilter ff_vf_drawgrid; -extern const AVFilter ff_vf_drawtext; -extern const AVFilter ff_vf_edgedetect; -extern const AVFilter ff_vf_elbg; -extern const AVFilter ff_vf_entropy; -extern const AVFilter ff_vf_epx; -extern const AVFilter ff_vf_eq; -extern const AVFilter ff_vf_erosion; -extern const AVFilter ff_vf_erosion_opencl; -extern const AVFilter ff_vf_estdif; -extern const AVFilter ff_vf_exposure; -extern const AVFilter ff_vf_extractplanes; -extern const AVFilter ff_vf_fade; -extern const AVFilter ff_vf_feedback; -extern const AVFilter ff_vf_fftdnoiz; -extern const AVFilter ff_vf_fftfilt; -extern const AVFilter ff_vf_field; -extern const AVFilter ff_vf_fieldhint; -extern const AVFilter ff_vf_fieldmatch; -extern const AVFilter ff_vf_fieldorder; -extern const AVFilter ff_vf_fillborders; -extern const AVFilter ff_vf_find_rect; -extern const AVFilter ff_vf_flip_vulkan; -extern const AVFilter ff_vf_floodfill; -extern const AVFilter ff_vf_format; -extern const AVFilter ff_vf_fps; -extern const AVFilter ff_vf_framepack; -extern const AVFilter ff_vf_framerate; -extern const AVFilter ff_vf_framestep; -extern const AVFilter ff_vf_freezedetect; -extern const AVFilter ff_vf_freezeframes; -extern const AVFilter ff_vf_frei0r; -extern const AVFilter ff_vf_fspp; -extern const AVFilter ff_vf_fsync; -extern const AVFilter ff_vf_gblur; -extern const AVFilter ff_vf_gblur_vulkan; -extern const AVFilter ff_vf_geq; -extern const AVFilter ff_vf_gradfun; -extern const AVFilter ff_vf_graphmonitor; -extern const AVFilter ff_vf_grayworld; -extern const AVFilter ff_vf_greyedge; -extern const AVFilter ff_vf_guided; -extern const AVFilter ff_vf_haldclut; -extern const AVFilter ff_vf_hflip; -extern const AVFilter ff_vf_hflip_vulkan; -extern const AVFilter ff_vf_histeq; -extern const AVFilter ff_vf_histogram; -extern const AVFilter ff_vf_hqdn3d; -extern const AVFilter ff_vf_hqx; -extern const AVFilter ff_vf_hstack; -extern const AVFilter ff_vf_hsvhold; -extern const AVFilter ff_vf_hsvkey; -extern const AVFilter ff_vf_hue; -extern const AVFilter ff_vf_huesaturation; -extern const AVFilter ff_vf_hwdownload; -extern const AVFilter ff_vf_hwmap; -extern const AVFilter ff_vf_hwupload; -extern const AVFilter ff_vf_hwupload_cuda; -extern const AVFilter ff_vf_hysteresis; -extern const AVFilter ff_vf_iccdetect; -extern const AVFilter ff_vf_iccgen; -extern const AVFilter ff_vf_identity; -extern const AVFilter ff_vf_idet; -extern const AVFilter ff_vf_il; -extern const AVFilter ff_vf_inflate; -extern const AVFilter ff_vf_interlace; -extern const AVFilter ff_vf_interleave; -extern const AVFilter ff_vf_kerndeint; -extern const AVFilter ff_vf_kirsch; -extern const AVFilter ff_vf_lagfun; -extern const AVFilter ff_vf_latency; -extern const AVFilter ff_vf_lcevc; -extern const AVFilter ff_vf_lenscorrection; -extern const AVFilter ff_vf_lensfun; -extern const AVFilter ff_vf_libplacebo; -extern const AVFilter ff_vf_libvmaf; -extern const AVFilter ff_vf_libvmaf_cuda; -extern const AVFilter ff_vf_limitdiff; -extern const AVFilter ff_vf_limiter; -extern const AVFilter ff_vf_loop; -extern const AVFilter ff_vf_lumakey; -extern const AVFilter ff_vf_lut; -extern const AVFilter ff_vf_lut1d; -extern const AVFilter ff_vf_lut2; -extern const AVFilter ff_vf_lut3d; -extern const AVFilter ff_vf_lutrgb; -extern const AVFilter ff_vf_lutyuv; -extern const AVFilter ff_vf_maskedclamp; -extern const AVFilter ff_vf_maskedmax; -extern const AVFilter ff_vf_maskedmerge; -extern const AVFilter ff_vf_maskedmin; -extern const AVFilter ff_vf_maskedthreshold; -extern const AVFilter ff_vf_maskfun; -extern const AVFilter ff_vf_mcdeint; -extern const AVFilter ff_vf_median; -extern const AVFilter ff_vf_mergeplanes; -extern const AVFilter ff_vf_mestimate; -extern const AVFilter ff_vf_metadata; -extern const AVFilter ff_vf_midequalizer; -extern const AVFilter ff_vf_minterpolate; -extern const AVFilter ff_vf_mix; -extern const AVFilter ff_vf_monochrome; -extern const AVFilter ff_vf_morpho; -extern const AVFilter ff_vf_mpdecimate; -extern const AVFilter ff_vf_msad; -extern const AVFilter ff_vf_multiply; -extern const AVFilter ff_vf_negate; -extern const AVFilter ff_vf_nlmeans; -extern const AVFilter ff_vf_nlmeans_opencl; -extern const AVFilter ff_vf_nlmeans_vulkan; -extern const AVFilter ff_vf_nnedi; -extern const AVFilter ff_vf_noformat; -extern const AVFilter ff_vf_noise; -extern const AVFilter ff_vf_normalize; -extern const AVFilter ff_vf_null; -extern const AVFilter ff_vf_ocr; -extern const AVFilter ff_vf_ocv; -extern const AVFilter ff_vf_oscilloscope; -extern const AVFilter ff_vf_overlay; -extern const AVFilter ff_vf_overlay_opencl; -extern const AVFilter ff_vf_overlay_qsv; -extern const AVFilter ff_vf_overlay_vaapi; -extern const AVFilter ff_vf_overlay_vulkan; -extern const AVFilter ff_vf_overlay_cuda; -extern const AVFilter ff_vf_owdenoise; -extern const AVFilter ff_vf_pad; -extern const AVFilter ff_vf_pad_opencl; -extern const AVFilter ff_vf_palettegen; -extern const AVFilter ff_vf_paletteuse; -extern const AVFilter ff_vf_perms; -extern const AVFilter ff_vf_perspective; -extern const AVFilter ff_vf_phase; -extern const AVFilter ff_vf_photosensitivity; -extern const AVFilter ff_vf_pixdesctest; -extern const AVFilter ff_vf_pixelize; -extern const AVFilter ff_vf_pixscope; -extern const AVFilter ff_vf_pp; -extern const AVFilter ff_vf_pp7; -extern const AVFilter ff_vf_premultiply; -extern const AVFilter ff_vf_prewitt; -extern const AVFilter ff_vf_prewitt_opencl; -extern const AVFilter ff_vf_procamp_vaapi; -extern const AVFilter ff_vf_program_opencl; -extern const AVFilter ff_vf_pseudocolor; -extern const AVFilter ff_vf_psnr; -extern const AVFilter ff_vf_pullup; -extern const AVFilter ff_vf_qp; -extern const AVFilter ff_vf_qrencode; -extern const AVFilter ff_vf_quirc; -extern const AVFilter ff_vf_random; -extern const AVFilter ff_vf_readeia608; -extern const AVFilter ff_vf_readvitc; -extern const AVFilter ff_vf_realtime; -extern const AVFilter ff_vf_remap; -extern const AVFilter ff_vf_remap_opencl; -extern const AVFilter ff_vf_removegrain; -extern const AVFilter ff_vf_removelogo; -extern const AVFilter ff_vf_repeatfields; -extern const AVFilter ff_vf_reverse; -extern const AVFilter ff_vf_rgbashift; -extern const AVFilter ff_vf_roberts; -extern const AVFilter ff_vf_roberts_opencl; -extern const AVFilter ff_vf_rotate; -extern const AVFilter ff_vf_sab; -extern const AVFilter ff_vf_scale; -extern const AVFilter ff_vf_scale_cuda; -extern const AVFilter ff_vf_scale_npp; -extern const AVFilter ff_vf_scale_qsv; -extern const AVFilter ff_vf_scale_vaapi; -extern const AVFilter ff_vf_scale_vt; -extern const AVFilter ff_vf_scale_vulkan; -extern const AVFilter ff_vf_scale2ref; -extern const AVFilter ff_vf_scale2ref_npp; -extern const AVFilter ff_vf_scdet; -extern const AVFilter ff_vf_scharr; -extern const AVFilter ff_vf_scroll; -extern const AVFilter ff_vf_segment; -extern const AVFilter ff_vf_select; -extern const AVFilter ff_vf_selectivecolor; -extern const AVFilter ff_vf_sendcmd; -extern const AVFilter ff_vf_separatefields; -extern const AVFilter ff_vf_setdar; -extern const AVFilter ff_vf_setfield; -extern const AVFilter ff_vf_setparams; -extern const AVFilter ff_vf_setpts; -extern const AVFilter ff_vf_setrange; -extern const AVFilter ff_vf_setsar; -extern const AVFilter ff_vf_settb; -extern const AVFilter ff_vf_sharpen_npp; -extern const AVFilter ff_vf_sharpness_vaapi; -extern const AVFilter ff_vf_shear; -extern const AVFilter ff_vf_showinfo; -extern const AVFilter ff_vf_showpalette; -extern const AVFilter ff_vf_shuffleframes; -extern const AVFilter ff_vf_shufflepixels; -extern const AVFilter ff_vf_shuffleplanes; -extern const AVFilter ff_vf_sidedata; -extern const AVFilter ff_vf_signalstats; -extern const AVFilter ff_vf_signature; -extern const AVFilter ff_vf_siti; -extern const AVFilter ff_vf_smartblur; -extern const AVFilter ff_vf_sobel; -extern const AVFilter ff_vf_sobel_opencl; -extern const AVFilter ff_vf_split; -extern const AVFilter ff_vf_spp; -extern const AVFilter ff_vf_sr; -extern const AVFilter ff_vf_ssim; -extern const AVFilter ff_vf_ssim360; -extern const AVFilter ff_vf_stereo3d; -extern const AVFilter ff_vf_streamselect; -extern const AVFilter ff_vf_subtitles; -extern const AVFilter ff_vf_super2xsai; -extern const AVFilter ff_vf_swaprect; -extern const AVFilter ff_vf_swapuv; -extern const AVFilter ff_vf_tblend; -extern const AVFilter ff_vf_telecine; -extern const AVFilter ff_vf_thistogram; -extern const AVFilter ff_vf_threshold; -extern const AVFilter ff_vf_thumbnail; -extern const AVFilter ff_vf_thumbnail_cuda; -extern const AVFilter ff_vf_tile; -extern const AVFilter ff_vf_tiltandshift; -extern const AVFilter ff_vf_tinterlace; -extern const AVFilter ff_vf_tlut2; -extern const AVFilter ff_vf_tmedian; -extern const AVFilter ff_vf_tmidequalizer; -extern const AVFilter ff_vf_tmix; -extern const AVFilter ff_vf_tonemap; -extern const AVFilter ff_vf_tonemap_opencl; -extern const AVFilter ff_vf_tonemap_vaapi; -extern const AVFilter ff_vf_tpad; -extern const AVFilter ff_vf_transpose; -extern const AVFilter ff_vf_transpose_npp; -extern const AVFilter ff_vf_transpose_opencl; -extern const AVFilter ff_vf_transpose_vaapi; -extern const AVFilter ff_vf_transpose_vt; -extern const AVFilter ff_vf_transpose_vulkan; -extern const AVFilter ff_vf_trim; -extern const AVFilter ff_vf_unpremultiply; -extern const AVFilter ff_vf_unsharp; -extern const AVFilter ff_vf_unsharp_opencl; -extern const AVFilter ff_vf_untile; -extern const AVFilter ff_vf_uspp; -extern const AVFilter ff_vf_v360; -extern const AVFilter ff_vf_vaguedenoiser; -extern const AVFilter ff_vf_varblur; -extern const AVFilter ff_vf_vectorscope; -extern const AVFilter ff_vf_vflip; -extern const AVFilter ff_vf_vflip_vulkan; -extern const AVFilter ff_vf_vfrdet; -extern const AVFilter ff_vf_vibrance; -extern const AVFilter ff_vf_vidstabdetect; -extern const AVFilter ff_vf_vidstabtransform; -extern const AVFilter ff_vf_vif; -extern const AVFilter ff_vf_vignette; -extern const AVFilter ff_vf_vmafmotion; -extern const AVFilter ff_vf_vpp_qsv; -extern const AVFilter ff_vf_vstack; -extern const AVFilter ff_vf_w3fdif; -extern const AVFilter ff_vf_waveform; -extern const AVFilter ff_vf_weave; -extern const AVFilter ff_vf_xbr; -extern const AVFilter ff_vf_xcorrelate; -extern const AVFilter ff_vf_xfade; -extern const AVFilter ff_vf_xfade_opencl; -extern const AVFilter ff_vf_xfade_vulkan; -extern const AVFilter ff_vf_xmedian; -extern const AVFilter ff_vf_xpsnr; -extern const AVFilter ff_vf_xstack; -extern const AVFilter ff_vf_yadif; -extern const AVFilter ff_vf_yadif_cuda; -extern const AVFilter ff_vf_yadif_videotoolbox; -extern const AVFilter ff_vf_yaepblur; -extern const AVFilter ff_vf_zmq; -extern const AVFilter ff_vf_zoompan; -extern const AVFilter ff_vf_zscale; -extern const AVFilter ff_vf_hstack_vaapi; -extern const AVFilter ff_vf_vstack_vaapi; -extern const AVFilter ff_vf_xstack_vaapi; -extern const AVFilter ff_vf_hstack_qsv; -extern const AVFilter ff_vf_vstack_qsv; -extern const AVFilter ff_vf_xstack_qsv; -extern const AVFilter ff_vf_pad_vaapi; -extern const AVFilter ff_vf_drawbox_vaapi; +extern const FFFilter ff_vf_addroi; +extern const FFFilter ff_vf_alphaextract; +extern const FFFilter ff_vf_alphamerge; +extern const FFFilter ff_vf_amplify; +extern const FFFilter ff_vf_ass; +extern const FFFilter ff_vf_atadenoise; +extern const FFFilter ff_vf_avgblur; +extern const FFFilter ff_vf_avgblur_opencl; +extern const FFFilter ff_vf_avgblur_vulkan; +extern const FFFilter ff_vf_backgroundkey; +extern const FFFilter ff_vf_bbox; +extern const FFFilter ff_vf_bench; +extern const FFFilter ff_vf_bilateral; +extern const FFFilter ff_vf_bilateral_cuda; +extern const FFFilter ff_vf_bitplanenoise; +extern const FFFilter ff_vf_blackdetect; +extern const FFFilter ff_vf_blackdetect_vulkan; +extern const FFFilter ff_vf_blackframe; +extern const FFFilter ff_vf_blend; +extern const FFFilter ff_vf_blend_vulkan; +extern const FFFilter ff_vf_blockdetect; +extern const FFFilter ff_vf_blurdetect; +extern const FFFilter ff_vf_bm3d; +extern const FFFilter ff_vf_boxblur; +extern const FFFilter ff_vf_boxblur_opencl; +extern const FFFilter ff_vf_bwdif; +extern const FFFilter ff_vf_bwdif_cuda; +extern const FFFilter ff_vf_bwdif_vulkan; +extern const FFFilter ff_vf_cas; +extern const FFFilter ff_vf_ccrepack; +extern const FFFilter ff_vf_chromaber_vulkan; +extern const FFFilter ff_vf_chromahold; +extern const FFFilter ff_vf_chromakey; +extern const FFFilter ff_vf_chromakey_cuda; +extern const FFFilter ff_vf_chromanr; +extern const FFFilter ff_vf_chromashift; +extern const FFFilter ff_vf_ciescope; +extern const FFFilter ff_vf_codecview; +extern const FFFilter ff_vf_colorbalance; +extern const FFFilter ff_vf_colorchannelmixer; +extern const FFFilter ff_vf_colorcontrast; +extern const FFFilter ff_vf_colorcorrect; +extern const FFFilter ff_vf_colordetect; +extern const FFFilter ff_vf_colorize; +extern const FFFilter ff_vf_colorkey; +extern const FFFilter ff_vf_colorkey_opencl; +extern const FFFilter ff_vf_colorhold; +extern const FFFilter ff_vf_colorlevels; +extern const FFFilter ff_vf_colormap; +extern const FFFilter ff_vf_colormatrix; +extern const FFFilter ff_vf_colorspace; +extern const FFFilter ff_vf_colorspace_cuda; +extern const FFFilter ff_vf_colortemperature; +extern const FFFilter ff_vf_convolution; +extern const FFFilter ff_vf_convolution_opencl; +extern const FFFilter ff_vf_convolve; +extern const FFFilter ff_vf_copy; +extern const FFFilter ff_vf_coreimage; +extern const FFFilter ff_vf_corr; +extern const FFFilter ff_vf_cover_rect; +extern const FFFilter ff_vf_crop; +extern const FFFilter ff_vf_cropdetect; +extern const FFFilter ff_vf_cue; +extern const FFFilter ff_vf_curves; +extern const FFFilter ff_vf_datascope; +extern const FFFilter ff_vf_dblur; +extern const FFFilter ff_vf_dctdnoiz; +extern const FFFilter ff_vf_deband; +extern const FFFilter ff_vf_deblock; +extern const FFFilter ff_vf_decimate; +extern const FFFilter ff_vf_deconvolve; +extern const FFFilter ff_vf_dedot; +extern const FFFilter ff_vf_deflate; +extern const FFFilter ff_vf_deflicker; +extern const FFFilter ff_vf_deinterlace_qsv; +extern const FFFilter ff_vf_deinterlace_vaapi; +extern const FFFilter ff_vf_dejudder; +extern const FFFilter ff_vf_delogo; +extern const FFFilter ff_vf_denoise_vaapi; +extern const FFFilter ff_vf_derain; +extern const FFFilter ff_vf_deshake; +extern const FFFilter ff_vf_deshake_opencl; +extern const FFFilter ff_vf_despill; +extern const FFFilter ff_vf_detelecine; +extern const FFFilter ff_vf_dilation; +extern const FFFilter ff_vf_dilation_opencl; +extern const FFFilter ff_vf_displace; +extern const FFFilter ff_vf_dnn_classify; +extern const FFFilter ff_vf_dnn_detect; +extern const FFFilter ff_vf_dnn_processing; +extern const FFFilter ff_vf_doubleweave; +extern const FFFilter ff_vf_drawbox; +extern const FFFilter ff_vf_drawgraph; +extern const FFFilter ff_vf_drawgrid; +extern const FFFilter ff_vf_drawtext; +extern const FFFilter ff_vf_edgedetect; +extern const FFFilter ff_vf_elbg; +extern const FFFilter ff_vf_entropy; +extern const FFFilter ff_vf_epx; +extern const FFFilter ff_vf_eq; +extern const FFFilter ff_vf_erosion; +extern const FFFilter ff_vf_erosion_opencl; +extern const FFFilter ff_vf_estdif; +extern const FFFilter ff_vf_exposure; +extern const FFFilter ff_vf_extractplanes; +extern const FFFilter ff_vf_fade; +extern const FFFilter ff_vf_feedback; +extern const FFFilter ff_vf_fftdnoiz; +extern const FFFilter ff_vf_fftfilt; +extern const FFFilter ff_vf_field; +extern const FFFilter ff_vf_fieldhint; +extern const FFFilter ff_vf_fieldmatch; +extern const FFFilter ff_vf_fieldorder; +extern const FFFilter ff_vf_fillborders; +extern const FFFilter ff_vf_find_rect; +extern const FFFilter ff_vf_flip_vulkan; +extern const FFFilter ff_vf_floodfill; +extern const FFFilter ff_vf_format; +extern const FFFilter ff_vf_fps; +extern const FFFilter ff_vf_framepack; +extern const FFFilter ff_vf_framerate; +extern const FFFilter ff_vf_framestep; +extern const FFFilter ff_vf_freezedetect; +extern const FFFilter ff_vf_freezeframes; +extern const FFFilter ff_vf_frei0r; +extern const FFFilter ff_vf_fspp; +extern const FFFilter ff_vf_fsync; +extern const FFFilter ff_vf_gblur; +extern const FFFilter ff_vf_gblur_vulkan; +extern const FFFilter ff_vf_geq; +extern const FFFilter ff_vf_gradfun; +extern const FFFilter ff_vf_graphmonitor; +extern const FFFilter ff_vf_grayworld; +extern const FFFilter ff_vf_greyedge; +extern const FFFilter ff_vf_guided; +extern const FFFilter ff_vf_haldclut; +extern const FFFilter ff_vf_hflip; +extern const FFFilter ff_vf_hflip_vulkan; +extern const FFFilter ff_vf_histeq; +extern const FFFilter ff_vf_histogram; +extern const FFFilter ff_vf_hqdn3d; +extern const FFFilter ff_vf_hqx; +extern const FFFilter ff_vf_hstack; +extern const FFFilter ff_vf_hsvhold; +extern const FFFilter ff_vf_hsvkey; +extern const FFFilter ff_vf_hue; +extern const FFFilter ff_vf_huesaturation; +extern const FFFilter ff_vf_hwdownload; +extern const FFFilter ff_vf_hwmap; +extern const FFFilter ff_vf_hwupload; +extern const FFFilter ff_vf_hwupload_cuda; +extern const FFFilter ff_vf_hysteresis; +extern const FFFilter ff_vf_iccdetect; +extern const FFFilter ff_vf_iccgen; +extern const FFFilter ff_vf_identity; +extern const FFFilter ff_vf_idet; +extern const FFFilter ff_vf_il; +extern const FFFilter ff_vf_inflate; +extern const FFFilter ff_vf_interlace; +extern const FFFilter ff_vf_interlace_vulkan; +extern const FFFilter ff_vf_interleave; +extern const FFFilter ff_vf_kerndeint; +extern const FFFilter ff_vf_kirsch; +extern const FFFilter ff_vf_lagfun; +extern const FFFilter ff_vf_latency; +extern const FFFilter ff_vf_lcevc; +extern const FFFilter ff_vf_lenscorrection; +extern const FFFilter ff_vf_lensfun; +extern const FFFilter ff_vf_libplacebo; +extern const FFFilter ff_vf_libvmaf; +extern const FFFilter ff_vf_libvmaf_cuda; +extern const FFFilter ff_vf_limitdiff; +extern const FFFilter ff_vf_limiter; +extern const FFFilter ff_vf_loop; +extern const FFFilter ff_vf_lumakey; +extern const FFFilter ff_vf_lut; +extern const FFFilter ff_vf_lut1d; +extern const FFFilter ff_vf_lut2; +extern const FFFilter ff_vf_lut3d; +extern const FFFilter ff_vf_lutrgb; +extern const FFFilter ff_vf_lutyuv; +extern const FFFilter ff_vf_maskedclamp; +extern const FFFilter ff_vf_maskedmax; +extern const FFFilter ff_vf_maskedmerge; +extern const FFFilter ff_vf_maskedmin; +extern const FFFilter ff_vf_maskedthreshold; +extern const FFFilter ff_vf_maskfun; +extern const FFFilter ff_vf_mcdeint; +extern const FFFilter ff_vf_median; +extern const FFFilter ff_vf_mergeplanes; +extern const FFFilter ff_vf_mestimate; +extern const FFFilter ff_vf_metadata; +extern const FFFilter ff_vf_midequalizer; +extern const FFFilter ff_vf_minterpolate; +extern const FFFilter ff_vf_mix; +extern const FFFilter ff_vf_monochrome; +extern const FFFilter ff_vf_morpho; +extern const FFFilter ff_vf_mpdecimate; +extern const FFFilter ff_vf_msad; +extern const FFFilter ff_vf_multiply; +extern const FFFilter ff_vf_negate; +extern const FFFilter ff_vf_nlmeans; +extern const FFFilter ff_vf_nlmeans_opencl; +extern const FFFilter ff_vf_nlmeans_vulkan; +extern const FFFilter ff_vf_nnedi; +extern const FFFilter ff_vf_noformat; +extern const FFFilter ff_vf_noise; +extern const FFFilter ff_vf_normalize; +extern const FFFilter ff_vf_null; +extern const FFFilter ff_vf_ocr; +extern const FFFilter ff_vf_ocv; +extern const FFFilter ff_vf_oscilloscope; +extern const FFFilter ff_vf_overlay; +extern const FFFilter ff_vf_overlay_opencl; +extern const FFFilter ff_vf_overlay_qsv; +extern const FFFilter ff_vf_overlay_vaapi; +extern const FFFilter ff_vf_overlay_vulkan; +extern const FFFilter ff_vf_overlay_cuda; +extern const FFFilter ff_vf_owdenoise; +extern const FFFilter ff_vf_pad; +extern const FFFilter ff_vf_pad_cuda; +extern const FFFilter ff_vf_pad_opencl; +extern const FFFilter ff_vf_palettegen; +extern const FFFilter ff_vf_paletteuse; +extern const FFFilter ff_vf_perms; +extern const FFFilter ff_vf_perspective; +extern const FFFilter ff_vf_phase; +extern const FFFilter ff_vf_photosensitivity; +extern const FFFilter ff_vf_pixdesctest; +extern const FFFilter ff_vf_pixelize; +extern const FFFilter ff_vf_pixscope; +extern const FFFilter ff_vf_pp7; +extern const FFFilter ff_vf_premultiply; +extern const FFFilter ff_vf_prewitt; +extern const FFFilter ff_vf_prewitt_opencl; +extern const FFFilter ff_vf_procamp_vaapi; +extern const FFFilter ff_vf_program_opencl; +extern const FFFilter ff_vf_pseudocolor; +extern const FFFilter ff_vf_psnr; +extern const FFFilter ff_vf_pullup; +extern const FFFilter ff_vf_qp; +extern const FFFilter ff_vf_qrencode; +extern const FFFilter ff_vf_quirc; +extern const FFFilter ff_vf_random; +extern const FFFilter ff_vf_readeia608; +extern const FFFilter ff_vf_readvitc; +extern const FFFilter ff_vf_realtime; +extern const FFFilter ff_vf_remap; +extern const FFFilter ff_vf_remap_opencl; +extern const FFFilter ff_vf_removegrain; +extern const FFFilter ff_vf_removelogo; +extern const FFFilter ff_vf_repeatfields; +extern const FFFilter ff_vf_reverse; +extern const FFFilter ff_vf_rgbashift; +extern const FFFilter ff_vf_roberts; +extern const FFFilter ff_vf_roberts_opencl; +extern const FFFilter ff_vf_rotate; +extern const FFFilter ff_vf_sab; +extern const FFFilter ff_vf_scale; +extern const FFFilter ff_vf_vpp_amf; +extern const FFFilter ff_vf_sr_amf; +extern const FFFilter ff_vf_scale_cuda; +extern const FFFilter ff_vf_scale_d3d11; +extern const FFFilter ff_vf_scale_npp; +extern const FFFilter ff_vf_scale_qsv; +extern const FFFilter ff_vf_scale_vaapi; +extern const FFFilter ff_vf_scale_vt; +extern const FFFilter ff_vf_scale_vulkan; +extern const FFFilter ff_vf_scale2ref; +extern const FFFilter ff_vf_scale2ref_npp; +extern const FFFilter ff_vf_scdet; +extern const FFFilter ff_vf_scdet_vulkan; +extern const FFFilter ff_vf_scharr; +extern const FFFilter ff_vf_scroll; +extern const FFFilter ff_vf_segment; +extern const FFFilter ff_vf_select; +extern const FFFilter ff_vf_selectivecolor; +extern const FFFilter ff_vf_sendcmd; +extern const FFFilter ff_vf_separatefields; +extern const FFFilter ff_vf_setdar; +extern const FFFilter ff_vf_setfield; +extern const FFFilter ff_vf_setparams; +extern const FFFilter ff_vf_setpts; +extern const FFFilter ff_vf_setrange; +extern const FFFilter ff_vf_setsar; +extern const FFFilter ff_vf_settb; +extern const FFFilter ff_vf_sharpen_npp; +extern const FFFilter ff_vf_sharpness_vaapi; +extern const FFFilter ff_vf_shear; +extern const FFFilter ff_vf_showinfo; +extern const FFFilter ff_vf_showpalette; +extern const FFFilter ff_vf_shuffleframes; +extern const FFFilter ff_vf_shufflepixels; +extern const FFFilter ff_vf_shuffleplanes; +extern const FFFilter ff_vf_sidedata; +extern const FFFilter ff_vf_signalstats; +extern const FFFilter ff_vf_signature; +extern const FFFilter ff_vf_siti; +extern const FFFilter ff_vf_smartblur; +extern const FFFilter ff_vf_sobel; +extern const FFFilter ff_vf_sobel_opencl; +extern const FFFilter ff_vf_split; +extern const FFFilter ff_vf_spp; +extern const FFFilter ff_vf_sr; +extern const FFFilter ff_vf_ssim; +extern const FFFilter ff_vf_ssim360; +extern const FFFilter ff_vf_stereo3d; +extern const FFFilter ff_vf_streamselect; +extern const FFFilter ff_vf_subtitles; +extern const FFFilter ff_vf_super2xsai; +extern const FFFilter ff_vf_swaprect; +extern const FFFilter ff_vf_swapuv; +extern const FFFilter ff_vf_tblend; +extern const FFFilter ff_vf_telecine; +extern const FFFilter ff_vf_thistogram; +extern const FFFilter ff_vf_threshold; +extern const FFFilter ff_vf_thumbnail; +extern const FFFilter ff_vf_thumbnail_cuda; +extern const FFFilter ff_vf_tile; +extern const FFFilter ff_vf_tiltandshift; +extern const FFFilter ff_vf_tinterlace; +extern const FFFilter ff_vf_tlut2; +extern const FFFilter ff_vf_tmedian; +extern const FFFilter ff_vf_tmidequalizer; +extern const FFFilter ff_vf_tmix; +extern const FFFilter ff_vf_tonemap; +extern const FFFilter ff_vf_tonemap_opencl; +extern const FFFilter ff_vf_tonemap_vaapi; +extern const FFFilter ff_vf_tpad; +extern const FFFilter ff_vf_transpose; +extern const FFFilter ff_vf_transpose_npp; +extern const FFFilter ff_vf_transpose_opencl; +extern const FFFilter ff_vf_transpose_vaapi; +extern const FFFilter ff_vf_transpose_vt; +extern const FFFilter ff_vf_transpose_vulkan; +extern const FFFilter ff_vf_trim; +extern const FFFilter ff_vf_unpremultiply; +extern const FFFilter ff_vf_unsharp; +extern const FFFilter ff_vf_unsharp_opencl; +extern const FFFilter ff_vf_untile; +extern const FFFilter ff_vf_uspp; +extern const FFFilter ff_vf_v360; +extern const FFFilter ff_vf_vaguedenoiser; +extern const FFFilter ff_vf_varblur; +extern const FFFilter ff_vf_vectorscope; +extern const FFFilter ff_vf_vflip; +extern const FFFilter ff_vf_vflip_vulkan; +extern const FFFilter ff_vf_vfrdet; +extern const FFFilter ff_vf_vibrance; +extern const FFFilter ff_vf_vidstabdetect; +extern const FFFilter ff_vf_vidstabtransform; +extern const FFFilter ff_vf_vif; +extern const FFFilter ff_vf_vignette; +extern const FFFilter ff_vf_vmafmotion; +extern const FFFilter ff_vf_vpp_qsv; +extern const FFFilter ff_vf_vstack; +extern const FFFilter ff_vf_w3fdif; +extern const FFFilter ff_vf_waveform; +extern const FFFilter ff_vf_weave; +extern const FFFilter ff_vf_xbr; +extern const FFFilter ff_vf_xcorrelate; +extern const FFFilter ff_vf_xfade; +extern const FFFilter ff_vf_xfade_opencl; +extern const FFFilter ff_vf_xfade_vulkan; +extern const FFFilter ff_vf_xmedian; +extern const FFFilter ff_vf_xpsnr; +extern const FFFilter ff_vf_xstack; +extern const FFFilter ff_vf_yadif; +extern const FFFilter ff_vf_yadif_cuda; +extern const FFFilter ff_vf_yadif_videotoolbox; +extern const FFFilter ff_vf_yaepblur; +extern const FFFilter ff_vf_zmq; +extern const FFFilter ff_vf_zoompan; +extern const FFFilter ff_vf_zscale; +extern const FFFilter ff_vf_hstack_vaapi; +extern const FFFilter ff_vf_vstack_vaapi; +extern const FFFilter ff_vf_xstack_vaapi; +extern const FFFilter ff_vf_hstack_qsv; +extern const FFFilter ff_vf_vstack_qsv; +extern const FFFilter ff_vf_xstack_qsv; +extern const FFFilter ff_vf_pad_vaapi; +extern const FFFilter ff_vf_drawbox_vaapi; -extern const AVFilter ff_vsrc_allrgb; -extern const AVFilter ff_vsrc_allyuv; -extern const AVFilter ff_vsrc_cellauto; -extern const AVFilter ff_vsrc_color; -extern const AVFilter ff_vsrc_color_vulkan; -extern const AVFilter ff_vsrc_colorchart; -extern const AVFilter ff_vsrc_colorspectrum; -extern const AVFilter ff_vsrc_coreimagesrc; -extern const AVFilter ff_vsrc_ddagrab; -extern const AVFilter ff_vsrc_frei0r_src; -extern const AVFilter ff_vsrc_gradients; -extern const AVFilter ff_vsrc_haldclutsrc; -extern const AVFilter ff_vsrc_life; -extern const AVFilter ff_vsrc_mandelbrot; -extern const AVFilter ff_vsrc_mptestsrc; -extern const AVFilter ff_vsrc_nullsrc; -extern const AVFilter ff_vsrc_openclsrc; -extern const AVFilter ff_vsrc_qrencodesrc; -extern const AVFilter ff_vsrc_pal75bars; -extern const AVFilter ff_vsrc_pal100bars; -extern const AVFilter ff_vsrc_perlin; -extern const AVFilter ff_vsrc_rgbtestsrc; -extern const AVFilter ff_vsrc_sierpinski; -extern const AVFilter ff_vsrc_smptebars; -extern const AVFilter ff_vsrc_smptehdbars; -extern const AVFilter ff_vsrc_testsrc; -extern const AVFilter ff_vsrc_testsrc2; -extern const AVFilter ff_vsrc_yuvtestsrc; -extern const AVFilter ff_vsrc_zoneplate; +extern const FFFilter ff_vsrc_allrgb; +extern const FFFilter ff_vsrc_allyuv; +extern const FFFilter ff_vsrc_cellauto; +extern const FFFilter ff_vsrc_color; +extern const FFFilter ff_vsrc_color_vulkan; +extern const FFFilter ff_vsrc_colorchart; +extern const FFFilter ff_vsrc_colorspectrum; +extern const FFFilter ff_vsrc_coreimagesrc; +extern const FFFilter ff_vsrc_ddagrab; +extern const FFFilter ff_vsrc_frei0r_src; +extern const FFFilter ff_vsrc_gradients; +extern const FFFilter ff_vsrc_haldclutsrc; +extern const FFFilter ff_vsrc_life; +extern const FFFilter ff_vsrc_mandelbrot; +extern const FFFilter ff_vsrc_mptestsrc; +extern const FFFilter ff_vsrc_nullsrc; +extern const FFFilter ff_vsrc_openclsrc; +extern const FFFilter ff_vsrc_qrencodesrc; +extern const FFFilter ff_vsrc_pal75bars; +extern const FFFilter ff_vsrc_pal100bars; +extern const FFFilter ff_vsrc_perlin; +extern const FFFilter ff_vsrc_rgbtestsrc; +extern const FFFilter ff_vsrc_sierpinski; +extern const FFFilter ff_vsrc_smptebars; +extern const FFFilter ff_vsrc_smptehdbars; +extern const FFFilter ff_vsrc_testsrc; +extern const FFFilter ff_vsrc_testsrc2; +extern const FFFilter ff_vsrc_yuvtestsrc; +extern const FFFilter ff_vsrc_zoneplate; -extern const AVFilter ff_vsink_nullsink; +extern const FFFilter ff_vsink_nullsink; /* multimedia filters */ -extern const AVFilter ff_avf_a3dscope; -extern const AVFilter ff_avf_abitscope; -extern const AVFilter ff_avf_adrawgraph; -extern const AVFilter ff_avf_agraphmonitor; -extern const AVFilter ff_avf_ahistogram; -extern const AVFilter ff_avf_aphasemeter; -extern const AVFilter ff_avf_avectorscope; -extern const AVFilter ff_avf_concat; -extern const AVFilter ff_avf_showcqt; -extern const AVFilter ff_avf_showcwt; -extern const AVFilter ff_avf_showfreqs; -extern const AVFilter ff_avf_showspatial; -extern const AVFilter ff_avf_showspectrum; -extern const AVFilter ff_avf_showspectrumpic; -extern const AVFilter ff_avf_showvolume; -extern const AVFilter ff_avf_showwaves; -extern const AVFilter ff_avf_showwavespic; -extern const AVFilter ff_vaf_spectrumsynth; +extern const FFFilter ff_avf_a3dscope; +extern const FFFilter ff_avf_abitscope; +extern const FFFilter ff_avf_adrawgraph; +extern const FFFilter ff_avf_agraphmonitor; +extern const FFFilter ff_avf_ahistogram; +extern const FFFilter ff_avf_aphasemeter; +extern const FFFilter ff_avf_avectorscope; +extern const FFFilter ff_avf_concat; +extern const FFFilter ff_avf_showcqt; +extern const FFFilter ff_avf_showcwt; +extern const FFFilter ff_avf_showfreqs; +extern const FFFilter ff_avf_showspatial; +extern const FFFilter ff_avf_showspectrum; +extern const FFFilter ff_avf_showspectrumpic; +extern const FFFilter ff_avf_showvolume; +extern const FFFilter ff_avf_showwaves; +extern const FFFilter ff_avf_showwavespic; +extern const FFFilter ff_vaf_spectrumsynth; /* multimedia sources */ -extern const AVFilter ff_avsrc_avsynctest; -extern const AVFilter ff_avsrc_amovie; -extern const AVFilter ff_avsrc_movie; +extern const FFFilter ff_avsrc_avsynctest; +extern const FFFilter ff_avsrc_amovie; +extern const FFFilter 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 const AVFilter ff_asrc_abuffer; -extern const AVFilter ff_vsrc_buffer; -extern const AVFilter ff_asink_abuffer; -extern const AVFilter ff_vsink_buffer; +extern const FFFilter ff_asrc_abuffer; +extern const FFFilter ff_vsrc_buffer; +extern const FFFilter ff_asink_abuffer; +extern const FFFilter ff_vsink_buffer; #include "libavfilter/filter_list.c" @@ -623,12 +632,14 @@ extern const AVFilter ff_vsink_buffer; const AVFilter *av_filter_iterate(void **opaque) { uintptr_t i = (uintptr_t)*opaque; - const AVFilter *f = filter_list[i]; + const FFFilter *f = filter_list[i]; - if (f) + if (f) { *opaque = (void*)(i + 1); + return &f->p; + } - return f; + return NULL; } const AVFilter *avfilter_get_by_name(const char *name) diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c index 5ba1c7288d..e65705177c 100644 --- a/libavfilter/asink_anullsink.c +++ b/libavfilter/asink_anullsink.c @@ -36,10 +36,10 @@ static const AVFilterPad avfilter_asink_anullsink_inputs[] = { }, }; -const AVFilter ff_asink_anullsink = { - .name = "anullsink", - .description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input audio."), +const FFFilter ff_asink_anullsink = { + .p.name = "anullsink", + .p.description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input audio."), + .p.outputs = NULL, .priv_size = 0, FILTER_INPUTS(avfilter_asink_anullsink_inputs), - .outputs = NULL, }; diff --git a/libavfilter/asrc_afdelaysrc.c b/libavfilter/asrc_afdelaysrc.c index c235f0c27a..3efa94a942 100644 --- a/libavfilter/asrc_afdelaysrc.c +++ b/libavfilter/asrc_afdelaysrc.c @@ -80,22 +80,24 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, frame); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AFDelaySrcContext *s = ctx->priv; + const AFDelaySrcContext *s = ctx->priv; AVChannelLayout chlayouts[] = { s->chlayout, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static int config_output(AVFilterLink *outlink) @@ -138,13 +140,12 @@ static const AVOption afdelaysrc_options[] = { AVFILTER_DEFINE_CLASS(afdelaysrc); -const AVFilter ff_asrc_afdelaysrc = { - .name = "afdelaysrc", - .description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."), +const FFFilter ff_asrc_afdelaysrc = { + .p.name = "afdelaysrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."), + .p.priv_class = &afdelaysrc_class, .priv_size = sizeof(AFDelaySrcContext), - .priv_class = &afdelaysrc_class, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(afdelaysrc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_afirsrc.c b/libavfilter/asrc_afirsrc.c index bc450ec822..5efcbdcca0 100644 --- a/libavfilter/asrc_afirsrc.c +++ b/libavfilter/asrc_afirsrc.c @@ -92,7 +92,7 @@ static av_cold int init(AVFilterContext *ctx) AudioFIRSourceContext *s = ctx->priv; if (!(s->nb_taps & 1)) { - av_log(s, AV_LOG_WARNING, "Number of taps %d must be odd length.\n", s->nb_taps); + av_log(ctx, AV_LOG_WARNING, "Number of taps %d must be odd length.\n", s->nb_taps); s->nb_taps |= 1; } @@ -113,24 +113,26 @@ static av_cold void uninit(AVFilterContext *ctx) av_tx_uninit(&s->itx_ctx); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioFIRSourceContext *s = ctx->priv; + const AudioFIRSourceContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static int parse_string(char *str, float **items, int *nb_items, int *items_size) @@ -295,17 +297,16 @@ static const AVFilterPad afirsrc_outputs[] = { }, }; -const AVFilter ff_asrc_afirsrc = { - .name = "afirsrc", - .description = NULL_IF_CONFIG_SMALL("Generate a FIR coefficients audio stream."), +const FFFilter ff_asrc_afirsrc = { + .p.name = "afirsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a FIR coefficients audio stream."), + .p.priv_class = &afirsrc_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(AudioFIRSourceContext), - .inputs = NULL, FILTER_OUTPUTS(afirsrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &afirsrc_class, + FILTER_QUERY_FUNC2(query_formats), }; #define DEFAULT_BANDS "25 40 63 100 160 250 400 630 1000 1600 2500 4000 6300 10000 16000 24000" @@ -577,14 +578,13 @@ static const AVFilterPad afireqsrc_outputs[] = { }, }; -const AVFilter ff_asrc_afireqsrc = { - .name = "afireqsrc", - .description = NULL_IF_CONFIG_SMALL("Generate a FIR equalizer coefficients audio stream."), +const FFFilter ff_asrc_afireqsrc = { + .p.name = "afireqsrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a FIR equalizer coefficients audio stream."), + .p.priv_class = &afireqsrc_class, .uninit = uninit, .activate = activate, .priv_size = sizeof(AudioFIRSourceContext), - .inputs = NULL, FILTER_OUTPUTS(afireqsrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &afireqsrc_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_anoisesrc.c b/libavfilter/asrc_anoisesrc.c index a67b2abe9c..ba425d7925 100644 --- a/libavfilter/asrc_anoisesrc.c +++ b/libavfilter/asrc_anoisesrc.c @@ -83,24 +83,26 @@ static const AVOption anoisesrc_options[] = { AVFILTER_DEFINE_CLASS(anoisesrc); -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ANoiseSrcContext *s = ctx->priv; + const ANoiseSrcContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static double white_filter(double white, double *buf) @@ -237,13 +239,12 @@ static const AVFilterPad anoisesrc_outputs[] = { }, }; -const AVFilter ff_asrc_anoisesrc = { - .name = "anoisesrc", - .description = NULL_IF_CONFIG_SMALL("Generate a noise audio signal."), +const FFFilter ff_asrc_anoisesrc = { + .p.name = "anoisesrc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a noise audio signal."), + .p.priv_class = &anoisesrc_class, .priv_size = sizeof(ANoiseSrcContext), - .inputs = NULL, .activate = activate, FILTER_OUTPUTS(anoisesrc_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &anoisesrc_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c index 3249cc33ad..7d74319dff 100644 --- a/libavfilter/asrc_anullsrc.c +++ b/libavfilter/asrc_anullsrc.c @@ -61,18 +61,20 @@ static const AVOption anullsrc_options[]= { AVFILTER_DEFINE_CLASS(anullsrc); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ANullContext *null = ctx->priv; + const ANullContext *null = ctx->priv; const AVChannelLayout chlayouts[] = { null->ch_layout, { 0 } }; int sample_rates[] = { null->sample_rate, -1 }; int ret; - if ((ret = ff_set_common_formats (ctx, ff_all_formats (AVMEDIA_TYPE_AUDIO))) < 0 || - (ret = ff_set_common_samplerates_from_list(ctx, sample_rates)) < 0) + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); + if (ret < 0) return ret; - return ff_set_common_channel_layouts_from_list(ctx, chlayouts); + return ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); } static av_cold int config_props(AVFilterLink *outlink) @@ -118,13 +120,12 @@ static const AVFilterPad avfilter_asrc_anullsrc_outputs[] = { }, }; -const AVFilter ff_asrc_anullsrc = { - .name = "anullsrc", - .description = NULL_IF_CONFIG_SMALL("Null audio source, return empty audio frames."), +const FFFilter ff_asrc_anullsrc = { + .p.name = "anullsrc", + .p.description = NULL_IF_CONFIG_SMALL("Null audio source, return empty audio frames."), + .p.priv_class = &anullsrc_class, .priv_size = sizeof(ANullContext), - .inputs = NULL, FILTER_OUTPUTS(avfilter_asrc_anullsrc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &anullsrc_class, }; diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c index 5962bf55bb..33576beade 100644 --- a/libavfilter/asrc_flite.c +++ b/libavfilter/asrc_flite.c @@ -255,24 +255,35 @@ static av_cold void uninit(AVFilterContext *ctx) av_audio_fifo_free(flite->fifo); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - FliteContext *flite = ctx->priv; + const FliteContext *flite = ctx->priv; + + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE, + }; + int sample_rates[] = { flite->sample_rate, -1 }; + AVChannelLayout layouts[2] = { + { .nb_channels = 0 }, + }; + int ret; - AVFilterChannelLayouts *chlayouts = NULL; - AVFilterFormats *sample_formats = NULL; - AVFilterFormats *sample_rates = NULL; - AVChannelLayout chlayout = { 0 }; + av_channel_layout_default(&layouts[0], flite->nb_channels); - av_channel_layout_default(&chlayout, flite->nb_channels); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; - if ((ret = ff_add_channel_layout (&chlayouts , &chlayout )) < 0 || - (ret = ff_set_common_channel_layouts (ctx , chlayouts )) < 0 || - (ret = ff_add_format (&sample_formats, AV_SAMPLE_FMT_S16 )) < 0 || - (ret = ff_set_common_formats (ctx , sample_formats )) < 0 || - (ret = ff_add_format (&sample_rates , flite->sample_rate )) < 0 || - (ret = ff_set_common_samplerates (ctx , sample_rates )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) + return ret; + + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); + if (ret < 0) return ret; return 0; @@ -339,15 +350,14 @@ static const AVFilterPad flite_outputs[] = { }, }; -const AVFilter ff_asrc_flite = { - .name = "flite", - .description = NULL_IF_CONFIG_SMALL("Synthesize voice from text using libflite."), +const FFFilter ff_asrc_flite = { + .p.name = "flite", + .p.description = NULL_IF_CONFIG_SMALL("Synthesize voice from text using libflite."), + .p.priv_class = &flite_class, .init = init, .uninit = uninit, .priv_size = sizeof(FliteContext), .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(flite_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &flite_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c index e38af7123b..1470056e9b 100644 --- a/libavfilter/asrc_hilbert.c +++ b/libavfilter/asrc_hilbert.c @@ -61,7 +61,7 @@ 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); + av_log(ctx, AV_LOG_ERROR, "Number of taps %d must be odd length.\n", s->nb_taps); return AVERROR(EINVAL); } @@ -75,7 +75,9 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->taps); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { HilbertContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; @@ -84,15 +86,15 @@ static av_cold int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static av_cold int config_props(AVFilterLink *outlink) @@ -159,15 +161,14 @@ static const AVFilterPad hilbert_outputs[] = { }, }; -const AVFilter ff_asrc_hilbert = { - .name = "hilbert", - .description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), +const FFFilter ff_asrc_hilbert = { + .p.name = "hilbert", + .p.description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), + .p.priv_class = &hilbert_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(HilbertContext), - .inputs = NULL, FILTER_OUTPUTS(hilbert_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &hilbert_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c index 94046f76b9..ef6841c876 100644 --- a/libavfilter/asrc_sinc.c +++ b/libavfilter/asrc_sinc.c @@ -74,22 +74,24 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, frame); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - SincContext *s = ctx->priv; + const SincContext *s = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { s->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static float *make_lpf(int num_taps, float Fc, float beta, float rho, @@ -199,8 +201,9 @@ static float safe_log(float x) return -26; } -static int fir_to_phase(SincContext *s, float **h, int *len, int *post_len, float phase) +static int fir_to_phase(AVFilterContext *ctx, float **h, int *len, int *post_len, float phase) { + SincContext *s = ctx->priv; float *pi_wraps, *work, phase1 = (phase > 50.f ? 100.f - phase : phase) / 50.f; int i, work_len, begin, end, imp_peak = 0, peak = 0, ret; float imp_sum = 0, peak_imp_sum = 0, scale = 1.f; @@ -311,7 +314,7 @@ static int fir_to_phase(SincContext *s, float **h, int *len, int *post_len, floa } *post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1); - av_log(s, AV_LOG_DEBUG, "%d nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)\n", + av_log(ctx, AV_LOG_DEBUG, "%d nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)\n", work_len, pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak, work[imp_peak], *len, *post_len, 100.f - 100.f * *post_len / (*len - 1)); @@ -327,7 +330,7 @@ static int config_output(AVFilterLink *outlink) SincContext *s = ctx->priv; float Fn = s->sample_rate * .5f; float *h[2]; - int i, n, post_peak, longer; + int i, n, post_peak, longer, ret; outlink->sample_rate = s->sample_rate; s->pts = 0; @@ -358,9 +361,9 @@ static int config_output(AVFilterLink *outlink) } if (s->phase != 50.f) { - int ret = fir_to_phase(s, &h[longer], &n, &post_peak, s->phase); + ret = fir_to_phase(ctx, &h[longer], &n, &post_peak, s->phase); if (ret < 0) - return ret; + goto cleanup; } else { post_peak = n >> 1; } @@ -368,17 +371,21 @@ static int config_output(AVFilterLink *outlink) s->n = 1 << (av_log2(n) + 1); s->rdft_len = 1 << av_log2(n); s->coeffs = av_calloc(s->n, sizeof(*s->coeffs)); - if (!s->coeffs) - return AVERROR(ENOMEM); + if (!s->coeffs) { + ret = AVERROR(ENOMEM); + goto cleanup; + } for (i = 0; i < n; i++) s->coeffs[i] = h[longer][i]; - av_free(h[longer]); av_tx_uninit(&s->tx); av_tx_uninit(&s->itx); + ret = 0; - return 0; +cleanup: + av_free(h[longer]); + return ret; } static av_cold void uninit(AVFilterContext *ctx) @@ -419,14 +426,13 @@ static const AVOption sinc_options[] = { AVFILTER_DEFINE_CLASS(sinc); -const AVFilter ff_asrc_sinc = { - .name = "sinc", - .description = NULL_IF_CONFIG_SMALL("Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients."), +const FFFilter ff_asrc_sinc = { + .p.name = "sinc", + .p.description = NULL_IF_CONFIG_SMALL("Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients."), + .p.priv_class = &sinc_class, .priv_size = sizeof(SincContext), - .priv_class = &sinc_class, .uninit = uninit, .activate = activate, - .inputs = NULL, FILTER_OUTPUTS(sinc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c index 2e444ba196..1175a79746 100644 --- a/libavfilter/asrc_sine.c +++ b/libavfilter/asrc_sine.c @@ -30,6 +30,14 @@ #include "filters.h" #include "formats.h" +typedef struct SamplingContext { + uint32_t phi; ///< current phase of the sine (2pi = 1<<32) + uint32_t dphi; ///< phase increment between two samples + int phi_rem; ///< current fractional phase in 1/dphi_den subfractions + int dphi_rem; + int dphi_den; +} SamplingContext; + typedef struct SineContext { const AVClass *class; double frequency; @@ -40,13 +48,11 @@ typedef struct SineContext { int64_t duration; int16_t *sin; int64_t pts; - uint32_t phi; ///< current phase of the sine (2pi = 1<<32) - uint32_t dphi; ///< phase increment between two samples + SamplingContext signal; + SamplingContext beep; unsigned beep_period; unsigned beep_index; unsigned beep_length; - uint32_t phi_beep; ///< current phase of the beep - uint32_t dphi_beep; ///< phase increment of the beep } SineContext; #define CONTEXT SineContext @@ -143,6 +149,35 @@ enum { VAR_VARS_NB }; +static void sampling_init(SamplingContext *c, double frequency, int sample_rate) +{ + AVRational r; + int r_den, max_r_den; + + max_r_den = INT_MAX / sample_rate; + frequency = fmod(frequency, sample_rate); + r = av_d2q(fmod(frequency, 1.0), max_r_den); + r_den = FFMIN(r.den, max_r_den); + c->dphi = ldexp(frequency, 32) / sample_rate; + c->dphi_den = r_den * sample_rate; + c->dphi_rem = round((ldexp(frequency, 32) / sample_rate - c->dphi) * c->dphi_den); + if (c->dphi_rem >= c->dphi_den) { + c->dphi++; + c->dphi_rem = 0; + } + c->phi_rem = (-c->dphi_den - 1) / 2; +} + +static av_always_inline void sampling_advance(SamplingContext *c) +{ + c->phi += c->dphi; + c->phi_rem += c->dphi_rem; + if (c->phi_rem >= 0) { + c->phi_rem -= c->dphi_den; + c->phi++; + } +} + static av_cold int init(AVFilterContext *ctx) { int ret; @@ -150,14 +185,13 @@ static av_cold int init(AVFilterContext *ctx) if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD))) return AVERROR(ENOMEM); - sine->dphi = ldexp(sine->frequency, 32) / sine->sample_rate + 0.5; + sampling_init(&sine->signal, sine->frequency, sine->sample_rate); make_sin_table(sine->sin); if (sine->beep_factor) { sine->beep_period = sine->sample_rate; sine->beep_length = sine->beep_period / 25; - sine->dphi_beep = ldexp(sine->beep_factor * sine->frequency, 32) / - sine->sample_rate + 0.5; + sampling_init(&sine->beep, sine->beep_factor * sine->frequency, sine->sample_rate); } ret = av_expr_parse(&sine->samples_per_frame_expr, @@ -178,22 +212,24 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&sine->sin); } -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - SineContext *sine = ctx->priv; + const SineContext *sine = ctx->priv; static const AVChannelLayout chlayouts[] = { AV_CHANNEL_LAYOUT_MONO, { 0 } }; int sample_rates[] = { sine->sample_rate, -1 }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_formats_from_list(ctx, sample_fmts); + int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts); if (ret < 0) return ret; - return ff_set_common_samplerates_from_list(ctx, sample_rates); + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); } static av_cold int config_props(AVFilterLink *outlink) @@ -221,7 +257,7 @@ static int activate(AVFilterContext *ctx) if (!ff_outlink_frame_wanted(outlink)) return FFERROR_NOT_READY; if (nb_samples <= 0) { - av_log(sine, AV_LOG_WARNING, "nb samples expression evaluated to %d, " + av_log(ctx, AV_LOG_WARNING, "nb samples expression evaluated to %d, " "defaulting to 1024\n", nb_samples); nb_samples = 1024; } @@ -239,11 +275,11 @@ static int activate(AVFilterContext *ctx) samples = (int16_t *)frame->data[0]; for (i = 0; i < nb_samples; i++) { - samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)]; - sine->phi += sine->dphi; + samples[i] = sine->sin[sine->signal.phi >> (32 - LOG_PERIOD)]; + sampling_advance(&sine->signal); if (sine->beep_index < sine->beep_length) { - samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] * 2; - sine->phi_beep += sine->dphi_beep; + samples[i] += sine->sin[sine->beep.phi >> (32 - LOG_PERIOD)] * 2; + sampling_advance(&sine->beep); } if (++sine->beep_index == sine->beep_period) sine->beep_index = 0; @@ -262,15 +298,14 @@ static const AVFilterPad sine_outputs[] = { }, }; -const AVFilter ff_asrc_sine = { - .name = "sine", - .description = NULL_IF_CONFIG_SMALL("Generate sine wave audio signal."), +const FFFilter ff_asrc_sine = { + .p.name = "sine", + .p.description = NULL_IF_CONFIG_SMALL("Generate sine wave audio signal."), + .p.priv_class = &sine_class, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(SineContext), - .inputs = NULL, FILTER_OUTPUTS(sine_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &sine_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_a3dscope.c b/libavfilter/avf_a3dscope.c index dd08990512..fb08720412 100644 --- a/libavfilter/avf_a3dscope.c +++ b/libavfilter/avf_a3dscope.c @@ -73,30 +73,21 @@ static const AVOption a3dscope_options[] = { AVFILTER_DEFINE_CLASS(a3dscope); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -344,15 +335,15 @@ static const AVFilterPad audio3dscope_outputs[] = { }, }; -const AVFilter ff_avf_a3dscope = { - .name = "a3dscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to 3d scope video output."), +const FFFilter ff_avf_a3dscope = { + .p.name = "a3dscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to 3d scope video output."), + .p.priv_class = &a3dscope_class, .uninit = uninit, .priv_size = sizeof(Audio3dScopeContext), .activate = activate, FILTER_INPUTS(audio3dscope_inputs), FILTER_OUTPUTS(audio3dscope_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &a3dscope_class, + FILTER_QUERY_FUNC2(query_formats), .process_command = ff_filter_process_command, }; diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c index 30ed7d95e3..a4b2109473 100644 --- a/libavfilter/avf_abitscope.c +++ b/libavfilter/avf_abitscope.c @@ -65,12 +65,11 @@ static const AVOption abitscope_options[] = { AVFILTER_DEFINE_CLASS(abitscope); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S64P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, @@ -79,21 +78,11 @@ static int query_formats(AVFilterContext *ctx) int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if (!layouts) - return AVERROR(ENOMEM); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -316,14 +305,14 @@ static const AVFilterPad outputs[] = { }, }; -const AVFilter ff_avf_abitscope = { - .name = "abitscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."), +const FFFilter ff_avf_abitscope = { + .p.name = "abitscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."), + .p.priv_class = &abitscope_class, .priv_size = sizeof(AudioBitScopeContext), FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .uninit = uninit, .activate = activate, - .priv_class = &abitscope_class, }; diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c index b77307f137..ce0d82f9ec 100644 --- a/libavfilter/avf_ahistogram.c +++ b/libavfilter/avf_ahistogram.c @@ -92,28 +92,21 @@ static const AVOption ahistogram_options[] = { AVFILTER_DEFINE_CLASS(ahistogram); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret = AVERROR(EINVAL); formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (layouts = ff_all_channel_counts()) == NULL || - (ret = ff_channel_layouts_ref (layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -501,14 +494,14 @@ static const AVFilterPad ahistogram_outputs[] = { }, }; -const AVFilter ff_avf_ahistogram = { - .name = "ahistogram", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to histogram video output."), +const FFFilter ff_avf_ahistogram = { + .p.name = "ahistogram", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to histogram video output."), + .p.priv_class = &ahistogram_class, .uninit = uninit, .priv_size = sizeof(AudioHistogramContext), .activate = activate, FILTER_INPUTS(ahistogram_inputs), FILTER_OUTPUTS(ahistogram_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &ahistogram_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c index fe0968c974..eb55d56664 100644 --- a/libavfilter/avf_aphasemeter.c +++ b/libavfilter/avf_aphasemeter.c @@ -90,35 +90,32 @@ static const AVOption aphasemeter_options[] = { AVFILTER_DEFINE_CLASS(aphasemeter); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioPhaseMeterContext *s = ctx->priv; + const AudioPhaseMeterContext *s = ctx->priv; AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_formats_ref (formats, &outlink->incfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO )) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0 || - (ret = ff_channel_layouts_ref (layout , &outlink->incfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0 || + (ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0 || - (ret = ff_formats_ref(formats, &outlink->incfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; if (s->do_video) { - AVFilterLink *outlink = ctx->outputs[1]; - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[1]->formats)) < 0) return ret; } @@ -174,8 +171,9 @@ static inline void add_metadata(AVFrame *insamples, const char *key, char *value av_dict_set(&insamples->metadata, buf, value, 0); } -static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *insamples, int mono_measurement) +static inline void update_mono_detection(AVFilterContext *ctx, AVFrame *insamples, int mono_measurement) { + AudioPhaseMeterContext *s = ctx->priv; int64_t mono_duration; if (!s->is_mono && mono_measurement) { s->is_mono = 1; @@ -187,7 +185,7 @@ static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *ins mono_duration = get_duration(s->mono_idx); if (mono_duration >= s->duration) { add_metadata(insamples, "mono_start", av_ts2timestr(s->mono_idx[0], &s->time_base)); - av_log(s, AV_LOG_INFO, "mono_start: %s\n", av_ts2timestr(s->mono_idx[0], &s->time_base)); + av_log(ctx, AV_LOG_INFO, "mono_start: %s\n", av_ts2timestr(s->mono_idx[0], &s->time_base)); s->start_mono_presence = 0; } } @@ -199,14 +197,15 @@ static inline void update_mono_detection(AudioPhaseMeterContext *s, AVFrame *ins add_metadata(insamples, "mono_end", av_ts2timestr(s->mono_idx[1], &s->time_base)); add_metadata(insamples, "mono_duration", av_ts2timestr(mono_duration, &s->time_base)); } - av_log(s, AV_LOG_INFO, "mono_end: %s | mono_duration: %s\n", av_ts2timestr(s->mono_idx[1], &s->time_base), av_ts2timestr(mono_duration, &s->time_base)); + av_log(ctx, AV_LOG_INFO, "mono_end: %s | mono_duration: %s\n", av_ts2timestr(s->mono_idx[1], &s->time_base), av_ts2timestr(mono_duration, &s->time_base)); } s->is_mono = 0; } } -static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame *insamples, int out_phase_measurement) +static inline void update_out_phase_detection(AVFilterContext *ctx, AVFrame *insamples, int out_phase_measurement) { + AudioPhaseMeterContext *s = ctx->priv; int64_t out_phase_duration; if (!s->is_out_phase && out_phase_measurement) { s->is_out_phase = 1; @@ -218,7 +217,7 @@ static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame out_phase_duration = get_duration(s->out_phase_idx); if (out_phase_duration >= s->duration) { add_metadata(insamples, "out_phase_start", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); - av_log(s, AV_LOG_INFO, "out_phase_start: %s\n", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); + av_log(ctx, AV_LOG_INFO, "out_phase_start: %s\n", av_ts2timestr(s->out_phase_idx[0], &s->time_base)); s->start_out_phase_presence = 0; } } @@ -230,7 +229,7 @@ static inline void update_out_phase_detection(AudioPhaseMeterContext *s, AVFrame add_metadata(insamples, "out_phase_end", av_ts2timestr(s->out_phase_idx[1], &s->time_base)); add_metadata(insamples, "out_phase_duration", av_ts2timestr(out_phase_duration, &s->time_base)); } - av_log(s, AV_LOG_INFO, "out_phase_end: %s | out_phase_duration: %s\n", av_ts2timestr(s->out_phase_idx[1], &s->time_base), av_ts2timestr(out_phase_duration, &s->time_base)); + av_log(ctx, AV_LOG_INFO, "out_phase_end: %s | out_phase_duration: %s\n", av_ts2timestr(s->out_phase_idx[1], &s->time_base), av_ts2timestr(out_phase_duration, &s->time_base)); } s->is_out_phase = 0; } @@ -325,8 +324,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) mono_measurement = (tolerance - fphase) < FLT_EPSILON; out_phase_measurement = (angle - fphase) > FLT_EPSILON; - update_mono_detection(s, in, mono_measurement); - update_out_phase_detection(s, in, out_phase_measurement); + update_mono_detection(ctx, in, mono_measurement); + update_out_phase_detection(ctx, in, out_phase_measurement); } if (s->do_video) @@ -389,8 +388,8 @@ static av_cold void uninit(AVFilterContext *ctx) AudioPhaseMeterContext *s = ctx->priv; if (s->do_phasing_detection) { - update_mono_detection(s, NULL, 0); - update_out_phase_detection(s, NULL, 0); + update_mono_detection(ctx, NULL, 0); + update_out_phase_detection(ctx, NULL, 0); } av_frame_free(&s->out); } @@ -431,16 +430,15 @@ static const AVFilterPad inputs[] = { }, }; -const AVFilter ff_avf_aphasemeter = { - .name = "aphasemeter", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."), +const FFFilter ff_avf_aphasemeter = { + .p.name = "aphasemeter", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."), + .p.priv_class = &aphasemeter_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, .init = init, .uninit = uninit, .priv_size = sizeof(AudioPhaseMeterContext), FILTER_INPUTS(inputs), .activate = activate, - .outputs = NULL, - FILTER_QUERY_FUNC(query_formats), - .priv_class = &aphasemeter_class, - .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index 96bef32e2c..902d461d86 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -230,28 +230,29 @@ static int fade(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref (formats, &cfg_in[0]->formats )) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -485,16 +486,16 @@ static const AVFilterPad audiovectorscope_outputs[] = { }, }; -const AVFilter ff_avf_avectorscope = { - .name = "avectorscope", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to vectorscope video output."), +const FFFilter ff_avf_avectorscope = { + .p.name = "avectorscope", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to vectorscope video output."), + .p.priv_class = &avectorscope_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(AudioVectorScopeContext), .activate = activate, FILTER_INPUTS(audiovectorscope_inputs), FILTER_OUTPUTS(audiovectorscope_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &avectorscope_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, + FILTER_QUERY_FUNC2(query_formats), .process_command = ff_filter_process_command, }; diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c index 2a3d4c8b52..531aa071a0 100644 --- a/libavfilter/avf_concat.c +++ b/libavfilter/avf_concat.c @@ -72,9 +72,11 @@ static const AVOption concat_options[] = { AVFILTER_DEFINE_CLASS(concat); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ConcatContext *cat = ctx->priv; + const ConcatContext *cat = ctx->priv; unsigned type, nb_str, idx0 = 0, idx, str, seg; AVFilterFormats *formats, *rates = NULL; AVFilterChannelLayouts *layouts = NULL; @@ -87,25 +89,25 @@ static int query_formats(AVFilterContext *ctx) /* Set the output formats */ formats = ff_all_formats(type); - if ((ret = ff_formats_ref(formats, &ctx->outputs[idx]->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[idx]->formats)) < 0) return ret; if (type == AVMEDIA_TYPE_AUDIO) { rates = ff_all_samplerates(); - if ((ret = ff_formats_ref(rates, &ctx->outputs[idx]->incfg.samplerates)) < 0) + if ((ret = ff_formats_ref(rates, &cfg_out[idx]->samplerates)) < 0) return ret; layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[idx]->incfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_out[idx]->channel_layouts)) < 0) return ret; } /* Set the same formats for each corresponding input */ for (seg = 0; seg < cat->nb_segments; seg++) { - if ((ret = ff_formats_ref(formats, &ctx->inputs[idx]->outcfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[idx]->formats)) < 0) return ret; if (type == AVMEDIA_TYPE_AUDIO) { - if ((ret = ff_formats_ref(rates, &ctx->inputs[idx]->outcfg.samplerates)) < 0 || - (ret = ff_channel_layouts_ref(layouts, &ctx->inputs[idx]->outcfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref(rates, &cfg_in[idx]->samplerates)) < 0 || + (ret = ff_channel_layouts_ref(layouts, &cfg_in[idx]->channel_layouts)) < 0) return ret; } idx += ctx->nb_outputs; @@ -449,17 +451,17 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar return ret; } -const AVFilter ff_avf_concat = { - .name = "concat", - .description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."), +const FFFilter ff_avf_concat = { + .p.name = "concat", + .p.description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."), + .p.inputs = NULL, + .p.outputs = NULL, + .p.priv_class = &concat_class, + .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS, .init = init, .uninit = uninit, .activate = activate, .priv_size = sizeof(ConcatContext), - .inputs = NULL, - .outputs = NULL, - .priv_class = &concat_class, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS, - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, }; diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c index 00f679bc9e..abfae1f8fb 100644 --- a/libavfilter/avf_showcqt.c +++ b/libavfilter/avf_showcqt.c @@ -619,7 +619,7 @@ static int render_fontconfig(ShowCQTContext *s, AVFrame *tmp, char* font) FcDefaultSubstitute(pat); if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) { - av_log(s->ctx, AV_LOG_ERROR, "could not substitue fontconfig options.\n"); + av_log(s->ctx, AV_LOG_ERROR, "could not substitute fontconfig options.\n"); FcPatternDestroy(pat); FcConfigDestroy(fontconfig); return AVERROR(ENOMEM); @@ -655,6 +655,7 @@ fail: static int render_default_font(AVFrame *tmp) { const char *str = "EF G A BC D "; + const uint8_t *vga16_font = avpriv_vga16_font_get(); int x, u, v, mask; uint8_t *data = tmp->data[0]; int linesize = tmp->linesize[0]; @@ -666,7 +667,7 @@ static int render_default_font(AVFrame *tmp) for (v = 0; v < height; v++) { uint8_t *p = startptr + v * linesize + height/2 * 4 * u; for (mask = 0x80; mask; mask >>= 1, p += 4) { - if (mask & avpriv_vga16_font[str[u] * 16 + v]) + if (mask & vga16_font[str[u] * 16 + v]) p[3] = 255; else p[3] = 0; @@ -1314,12 +1315,11 @@ static av_cold void uninit(AVFilterContext *ctx) common_uninit(ctx->priv); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, @@ -1331,20 +1331,16 @@ static int query_formats(AVFilterContext *ctx) /* set input audio formats */ formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - layouts = ff_make_channel_layout_list(channel_layouts); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, channel_layouts); + if (ret < 0) return ret; /* set output video format */ formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -1520,7 +1516,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) i = insamples->nb_samples - remaining; j = s->fft_len/2 + s->remaining_fill_max - s->remaining_fill; if (remaining >= s->remaining_fill) { - for (m = 0; m < s->remaining_fill; m++) { + for (m = FFMAX(0, -j); m < s->remaining_fill; m++) { s->fft_data[j+m].re = audio_data[2*(i+m)]; s->fft_data[j+m].im = audio_data[2*(i+m)+1]; } @@ -1549,7 +1545,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) s->fft_data[m] = s->fft_data[m+step]; s->remaining_fill = step; } else { - for (m = 0; m < remaining; m++) { + for (m = FFMAX(0, -j); m < remaining; m++) { s->fft_data[j+m].re = audio_data[2*(i+m)]; s->fft_data[j+m].im = audio_data[2*(i+m)+1]; } @@ -1603,15 +1599,15 @@ static const AVFilterPad showcqt_outputs[] = { }, }; -const AVFilter ff_avf_showcqt = { - .name = "showcqt", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant/Clamped Q Transform) spectrum video output."), +const FFFilter ff_avf_showcqt = { + .p.name = "showcqt", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant/Clamped Q Transform) spectrum video output."), + .p.priv_class = &showcqt_class, .init = init, .activate = activate, .uninit = uninit, .priv_size = sizeof(ShowCQTContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showcqt_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showcqt_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showcwt.c b/libavfilter/avf_showcwt.c index 760a07f2ff..8edf2fb43b 100644 --- a/libavfilter/avf_showcwt.c +++ b/libavfilter/avf_showcwt.c @@ -222,30 +222,21 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->fdsp); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -1327,15 +1318,15 @@ static const AVFilterPad showcwt_outputs[] = { }, }; -const AVFilter ff_avf_showcwt = { - .name = "showcwt", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a CWT (Continuous Wavelet Transform) spectrum video output."), +const FFFilter ff_avf_showcwt = { + .p.name = "showcwt", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a CWT (Continuous Wavelet Transform) spectrum video output."), + .p.priv_class = &showcwt_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowCWTContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showcwt_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &showcwt_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index da31b3215e..244b013ada 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -116,32 +116,23 @@ static const AVOption showfreqs_options[] = { AVFILTER_DEFINE_CLASS(showfreqs); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -558,14 +549,14 @@ static const AVFilterPad showfreqs_outputs[] = { }, }; -const AVFilter ff_avf_showfreqs = { - .name = "showfreqs", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a frequencies video output."), +const FFFilter ff_avf_showfreqs = { + .p.name = "showfreqs", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a frequencies video output."), + .p.priv_class = &showfreqs_class, .uninit = uninit, .priv_size = sizeof(ShowFreqsContext), .activate = activate, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showfreqs_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showfreqs_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c index f7380f885a..491501e337 100644 --- a/libavfilter/avf_showspatial.c +++ b/libavfilter/avf_showspatial.c @@ -80,28 +80,26 @@ static av_cold void uninit(AVFilterContext *ctx) av_audio_fifo_free(s->fifo); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GBRP, AV_PIX_FMT_NONE }; + static const AVChannelLayout layouts[] = { AV_CHANNEL_LAYOUT_STEREO, { .nb_channels = 0 } }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref (formats, &inlink->outcfg.formats )) < 0 || - (ret = ff_add_channel_layout (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -323,15 +321,15 @@ static const AVFilterPad showspatial_outputs[] = { }, }; -const AVFilter ff_avf_showspatial = { - .name = "showspatial", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spatial video output."), +const FFFilter ff_avf_showspatial = { + .p.name = "showspatial", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spatial video output."), + .p.priv_class = &showspatial_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpatialContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showspatial_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = spatial_activate, - .priv_class = &showspatial_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 565f23c28b..ee71d55894 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -358,32 +358,23 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->frames); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -501,7 +492,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) const uint8_t *font; int font_height; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (int i = 0; txt[i]; i++) { int char_y, mask; @@ -1689,17 +1680,17 @@ static const AVFilterPad showspectrum_outputs[] = { }, }; -const AVFilter ff_avf_showspectrum = { - .name = "showspectrum", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."), +const FFFilter ff_avf_showspectrum = { + .p.name = "showspectrum", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."), + .p.priv_class = &showspectrum_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpectrumContext), FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(showspectrum_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .activate = activate, - .priv_class = &showspectrum_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, }; #endif // CONFIG_SHOWSPECTRUM_FILTER @@ -1876,16 +1867,16 @@ static const AVFilterPad showspectrumpic_outputs[] = { }, }; -const AVFilter ff_avf_showspectrumpic = { - .name = "showspectrumpic", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."), +const FFFilter ff_avf_showspectrumpic = { + .p.name = "showspectrumpic", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."), + .p.priv_class = &showspectrumpic_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, .uninit = uninit, .priv_size = sizeof(ShowSpectrumContext), FILTER_INPUTS(showspectrumpic_inputs), FILTER_OUTPUTS(showspectrumpic_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showspectrumpic_class, - .flags = AVFILTER_FLAG_SLICE_THREADS, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWSPECTRUMPIC_FILTER diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index d26fc8841d..8472e86a15 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -110,30 +110,21 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; int ret; formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -234,7 +225,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) int font_height; int i; - font = avpriv_cga_font, font_height = 8; + font = avpriv_cga_font_get(), font_height = 8; for (i = 0; txt[i]; i++) { int char_y, mask; @@ -511,15 +502,15 @@ static const AVFilterPad showvolume_outputs[] = { }, }; -const AVFilter ff_avf_showvolume = { - .name = "showvolume", - .description = NULL_IF_CONFIG_SMALL("Convert input audio volume to video output."), +const FFFilter ff_avf_showvolume = { + .p.name = "showvolume", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio volume to video output."), + .p.priv_class = &showvolume_class, .init = init, .activate = activate, .uninit = uninit, .priv_size = sizeof(ShowVolumeContext), FILTER_INPUTS(showvolume_inputs), FILTER_OUTPUTS(showvolume_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showvolume_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index 868e6a22d9..d1f1277beb 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -155,32 +155,23 @@ static av_cold void uninit(AVFilterContext *ctx) } } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; int ret; /* set input audio formats */ formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) - return ret; - - layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) - return ret; - - formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0) return ret; /* set output video format */ formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -805,17 +796,17 @@ static const AVFilterPad showwaves_outputs[] = { }, }; -const AVFilter ff_avf_showwaves = { - .name = "showwaves", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."), +const FFFilter ff_avf_showwaves = { + .p.name = "showwaves", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."), + .p.priv_class = &showwaves_class, .init = init, .uninit = uninit, .priv_size = sizeof(ShowWavesContext), FILTER_INPUTS(ff_audio_default_filterpad), .activate = activate, FILTER_OUTPUTS(showwaves_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showwaves_class, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWWAVES_FILTER @@ -917,16 +908,16 @@ static const AVFilterPad showwavespic_outputs[] = { }, }; -const AVFilter ff_avf_showwavespic = { - .name = "showwavespic", - .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."), +const FFFilter ff_avf_showwavespic = { + .p.name = "showwavespic", + .p.description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."), + .p.priv_class = &showwavespic_class, .init = init, .uninit = uninit, .priv_size = sizeof(ShowWavesContext), FILTER_INPUTS(showwavespic_inputs), FILTER_OUTPUTS(showwavespic_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &showwavespic_class, + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_SHOWWAVESPIC_FILTER diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 8a2a9e0593..5bcf0b4ef7 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -80,10 +80,11 @@ static void tlog_ref(void *ctx, AVFrame *ref, int end) static void command_queue_pop(AVFilterContext *filter) { - AVFilterCommand *c= filter->command_queue; + FFFilterContext *ctxi = fffilterctx(filter); + AVFilterCommand *c = ctxi->command_queue; av_freep(&c->arg); av_freep(&c->command); - filter->command_queue= c->next; + ctxi->command_queue = c->next; av_free(c); } @@ -159,7 +160,8 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, src->outputs[srcpad] || dst->inputs[dstpad]) return AVERROR(EINVAL); - if (!fffilterctx(src)->initialized || !fffilterctx(dst)->initialized) { + if (!(fffilterctx(src)->state_flags & AV_CLASS_STATE_INITIALIZED) || + !(fffilterctx(dst)->state_flags & AV_CLASS_STATE_INITIALIZED)) { av_log(src, AV_LOG_ERROR, "Filters must be initialized before linking.\n"); return AVERROR(EINVAL); } @@ -204,23 +206,13 @@ static void link_free(AVFilterLink **link) ff_framequeue_free(&li->fifo); ff_frame_pool_uninit(&li->frame_pool); av_channel_layout_uninit(&(*link)->ch_layout); + av_frame_side_data_free(&(*link)->side_data, &(*link)->nb_side_data); av_buffer_unref(&li->l.hw_frames_ctx); av_freep(link); } -#if FF_API_LINK_PUBLIC -void avfilter_link_free(AVFilterLink **link) -{ - link_free(link); -} -int avfilter_config_links(AVFilterContext *filter) -{ - return ff_filter_config_links(filter); -} -#endif - static void update_link_current_pts(FilterLinkInternal *li, int64_t pts) { AVFilterLink *const link = &li->l.pub; @@ -236,7 +228,8 @@ static void update_link_current_pts(FilterLinkInternal *li, int64_t pts) void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) { - filter->ready = FFMAX(filter->ready, priority); + FFFilterContext *ctxi = fffilterctx(filter); + ctxi->ready = FFMAX(ctxi->ready, priority); } /** @@ -373,7 +366,22 @@ int ff_filter_config_links(AVFilterContext *filter) "callbacks on all outputs\n"); return AVERROR(EINVAL); } - } else if ((ret = config_link(link)) < 0) { + } + + /* Copy side data before link->srcpad->config_props() is called, so the filter + * may remove it for the next filter in the chain */ + if (inlink && inlink->nb_side_data && !link->nb_side_data) { + for (int j = 0; j < inlink->nb_side_data; j++) { + ret = av_frame_side_data_clone(&link->side_data, &link->nb_side_data, + inlink->side_data[j], 0); + if (ret < 0) { + av_frame_side_data_free(&link->side_data, &link->nb_side_data); + return ret; + } + } + } + + if (config_link && (ret = config_link(link)) < 0) { av_log(link->src, AV_LOG_ERROR, "Failed to configure output pad on %s\n", link->src->name); @@ -415,7 +423,7 @@ int ff_filter_config_links(AVFilterContext *filter) } if (link->src->nb_inputs && - !(link->src->filter->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) { + !(fffilter(link->src->filter)->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) { FilterLink *l0 = ff_filter_link(link->src->inputs[0]); av_assert0(!li->l.hw_frames_ctx && @@ -475,13 +483,13 @@ int ff_request_frame(AVFilterLink *link) FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); - av_assert1(!link->dst->filter->activate); + av_assert1(!fffilter(link->dst->filter)->activate); if (li->status_out) return li->status_out; if (li->status_in) { if (ff_framequeue_queued_frames(&li->fifo)) { av_assert1(!li->frame_wanted_out); - av_assert1(link->dst->ready >= 300); + av_assert1(fffilterctx(link->dst)->ready >= 300); return 0; } else { /* Acknowledge status change. Filters using ff_request_frame() will @@ -518,7 +526,7 @@ static int64_t guess_status_pts(AVFilterContext *ctx, int status, AVRational lin return AV_NOPTS_VALUE; } -static int ff_request_frame_to_filter(AVFilterLink *link) +static int request_frame_to_filter(AVFilterLink *link) { FilterLinkInternal * const li = ff_link_internal(link); int ret = -1; @@ -542,9 +550,6 @@ static int ff_request_frame_to_filter(AVFilterLink *link) static const char *const var_names[] = { "t", "n", -#if FF_API_FRAME_PKT - "pos", -#endif "w", "h", NULL @@ -553,19 +558,17 @@ static const char *const var_names[] = { enum { VAR_T, VAR_N, -#if FF_API_FRAME_PKT - VAR_POS, -#endif VAR_W, VAR_H, VAR_VARS_NB }; -static int set_enable_expr(AVFilterContext *ctx, const char *expr) +static int set_enable_expr(FFFilterContext *ctxi, const char *expr) { + AVFilterContext *ctx = &ctxi->p; int ret; char *expr_dup; - AVExpr *old = ctx->enable; + AVExpr *old = ctxi->enable; if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) { av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported " @@ -577,15 +580,15 @@ static int set_enable_expr(AVFilterContext *ctx, const char *expr) if (!expr_dup) return AVERROR(ENOMEM); - if (!ctx->var_values) { - ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values)); - if (!ctx->var_values) { + if (!ctxi->var_values) { + ctxi->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctxi->var_values)); + if (!ctxi->var_values) { av_free(expr_dup); return AVERROR(ENOMEM); } } - ret = av_expr_parse((AVExpr**)&ctx->enable, expr_dup, var_names, + ret = av_expr_parse(&ctxi->enable, expr_dup, var_names, NULL, NULL, NULL, NULL, 0, ctx->priv); if (ret < 0) { av_log(ctx->priv, AV_LOG_ERROR, @@ -615,16 +618,16 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha av_log(filter, AV_LOG_INFO, "%s", res); return 0; }else if(!strcmp(cmd, "enable")) { - return set_enable_expr(filter, arg); - }else if(filter->filter->process_command) { - return filter->filter->process_command(filter, cmd, arg, res, res_len, flags); + return set_enable_expr(fffilterctx(filter), arg); + }else if (fffilter(filter->filter)->process_command) { + return fffilter(filter->filter)->process_command(filter, cmd, arg, res, res_len, flags); } return AVERROR(ENOSYS); } unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output) { - return is_output ? filter->nb_outputs : filter->nb_inputs; + return is_output ? fffilter(filter)->nb_outputs : fffilter(filter)->nb_inputs; } static const char *default_filter_name(void *filter_ctx) @@ -676,6 +679,7 @@ static const AVClass avfilter_class = { .child_next = filter_child_next, .child_class_iterate = filter_child_class_iterate, .option = avfilter_options, + .state_flags_offset = offsetof(FFFilterContext, state_flags), }; static int default_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, @@ -695,6 +699,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) { FFFilterContext *ctx; AVFilterContext *ret; + const FFFilter *const fi = fffilter(filter); int preinited = 0; if (!filter) @@ -708,13 +713,13 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) ret->av_class = &avfilter_class; ret->filter = filter; ret->name = inst_name ? av_strdup(inst_name) : NULL; - if (filter->priv_size) { - ret->priv = av_mallocz(filter->priv_size); + if (fi->priv_size) { + ret->priv = av_mallocz(fi->priv_size); if (!ret->priv) goto err; } - if (filter->preinit) { - if (filter->preinit(ret) < 0) + if (fi->preinit) { + if (fi->preinit(ret) < 0) goto err; preinited = 1; } @@ -727,7 +732,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) ctx->execute = default_execute; - ret->nb_inputs = filter->nb_inputs; + ret->nb_inputs = fi->nb_inputs; if (ret->nb_inputs ) { ret->input_pads = av_memdup(filter->inputs, ret->nb_inputs * sizeof(*filter->inputs)); if (!ret->input_pads) @@ -737,7 +742,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) goto err; } - ret->nb_outputs = filter->nb_outputs; + ret->nb_outputs = fi->nb_outputs; if (ret->nb_outputs) { ret->output_pads = av_memdup(filter->outputs, ret->nb_outputs * sizeof(*filter->outputs)); if (!ret->output_pads) @@ -751,7 +756,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) err: if (preinited) - filter->uninit(ret); + fi->uninit(ret); av_freep(&ret->inputs); av_freep(&ret->input_pads); ret->nb_inputs = 0; @@ -788,16 +793,18 @@ static void free_link(AVFilterLink *link) void avfilter_free(AVFilterContext *filter) { + FFFilterContext *ctxi; int i; if (!filter) return; + ctxi = fffilterctx(filter); if (filter->graph) ff_filter_graph_remove_filter(filter->graph, filter); - if (filter->filter->uninit) - filter->filter->uninit(filter); + if (fffilter(filter->filter)->uninit) + fffilter(filter->filter)->uninit(filter); for (i = 0; i < filter->nb_inputs; i++) { free_link(filter->inputs[i]); @@ -821,13 +828,12 @@ void avfilter_free(AVFilterContext *filter) av_freep(&filter->inputs); av_freep(&filter->outputs); av_freep(&filter->priv); - while(filter->command_queue){ + while (ctxi->command_queue) command_queue_pop(filter); - } av_opt_free(filter); - av_expr_free(filter->enable); - filter->enable = NULL; - av_freep(&filter->var_values); + av_expr_free(ctxi->enable); + ctxi->enable = NULL; + av_freep(&ctxi->var_values); av_free(filter); } @@ -909,7 +915,7 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) FFFilterContext *ctxi = fffilterctx(ctx); int ret = 0; - if (ctxi->initialized) { + if (ctxi->state_flags & AV_CLASS_STATE_INITIALIZED) { av_log(ctx, AV_LOG_ERROR, "Filter already initialized\n"); return AVERROR(EINVAL); } @@ -929,18 +935,18 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) ctx->thread_type = 0; } - if (ctx->filter->init) - ret = ctx->filter->init(ctx); + if (fffilter(ctx->filter)->init) + ret = fffilter(ctx->filter)->init(ctx); if (ret < 0) return ret; if (ctx->enable_str) { - ret = set_enable_expr(ctx, ctx->enable_str); + ret = set_enable_expr(ctxi, ctx->enable_str); if (ret < 0) return ret; } - ctxi->initialized = 1; + ctxi->state_flags |= AV_CLASS_STATE_INITIALIZED; return 0; } @@ -983,12 +989,45 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx) return pads[pad_idx].type; } +AVBufferRef *avfilter_link_get_hw_frames_ctx(AVFilterLink *link) +{ + FilterLink *plink = ff_filter_link(link); + if (plink->hw_frames_ctx) + return av_buffer_ref(plink->hw_frames_ctx); + + return NULL; +} + static int default_filter_frame(AVFilterLink *link, AVFrame *frame) { return ff_filter_frame(link->dst->outputs[0], frame); } -static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) +/** + * Evaluate the timeline expression of the link for the time and properties + * of the frame. + * @return >0 if enabled, 0 if disabled + * @note It does not update link->dst->is_disabled. + */ +static int evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame) +{ + FilterLink *l = ff_filter_link(link); + AVFilterContext *dstctx = link->dst; + FFFilterContext *dsti = fffilterctx(dstctx); + int64_t pts = frame->pts; + + if (!dstctx->enable_str) + return 1; + + dsti->var_values[VAR_N] = l->frame_count_out; + dsti->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); + dsti->var_values[VAR_W] = link->w; + dsti->var_values[VAR_H] = link->h; + + return fabs(av_expr_eval(dsti->enable, dsti->var_values, NULL)) >= 0.5; +} + +static int filter_frame_framed(AVFilterLink *link, AVFrame *frame) { FilterLink *l = ff_filter_link(link); int (*filter_frame)(AVFilterLink *, AVFrame *); @@ -1006,7 +1045,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) } ff_inlink_process_commands(link, frame); - dstctx->is_disabled = !ff_inlink_evaluate_timeline_at_frame(link, frame); + dstctx->is_disabled = !evaluate_timeline_at_frame(link, frame); if (dstctx->is_disabled && (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC)) @@ -1032,7 +1071,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) strcmp(link->dst->filter->name, "format") && strcmp(link->dst->filter->name, "idet") && strcmp(link->dst->filter->name, "null") && - strcmp(link->dst->filter->name, "scale")) { + strcmp(link->dst->filter->name, "scale") && + strcmp(link->dst->filter->name, "libplacebo")) { av_assert1(frame->format == link->format); av_assert1(frame->width == link->w); av_assert1(frame->height == link->h); @@ -1142,7 +1182,7 @@ static int take_samples(FilterLinkInternal *li, unsigned min, unsigned max, return 0; } -static int ff_filter_frame_to_filter(AVFilterLink *link) +static int filter_frame_to_filter(AVFilterLink *link) { FilterLinkInternal * const li = ff_link_internal(link); AVFrame *frame = NULL; @@ -1162,9 +1202,9 @@ static int ff_filter_frame_to_filter(AVFilterLink *link) produce one or more: unblock its outputs. */ filter_unblock(dst); /* AVFilterPad.filter_frame() expect frame_count_out to have the value - before the frame; ff_filter_frame_framed() will re-increment it. */ + before the frame; filter_frame_framed() will re-increment it. */ li->l.frame_count_out--; - ret = ff_filter_frame_framed(link, frame); + ret = filter_frame_framed(link, frame); if (ret < 0 && ret != li->status_out) { link_set_out_status(link, ret, AV_NOPTS_VALUE); } else { @@ -1191,7 +1231,7 @@ static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li if (!li_out->status_in) { progress++; - ret = ff_request_frame_to_filter(filter->outputs[out]); + ret = request_frame_to_filter(filter->outputs[out]); if (ret < 0) return ret; } @@ -1210,25 +1250,23 @@ static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li return 0; } -static int ff_filter_activate_default(AVFilterContext *filter) +static int filter_activate_default(AVFilterContext *filter) { unsigned i; + int nb_eofs = 0; - for (i = 0; i < filter->nb_outputs; i++) { - FilterLinkInternal *li = ff_link_internal(filter->outputs[i]); - int ret = li->status_in; - - if (ret) { - for (int j = 0; j < filter->nb_inputs; j++) - ff_inlink_set_status(filter->inputs[j], ret); - return 0; - } + for (i = 0; i < filter->nb_outputs; i++) + nb_eofs += ff_outlink_get_status(filter->outputs[i]) == AVERROR_EOF; + if (filter->nb_outputs && nb_eofs == filter->nb_outputs) { + for (int j = 0; j < filter->nb_inputs; j++) + ff_inlink_set_status(filter->inputs[j], AVERROR_EOF); + return 0; } for (i = 0; i < filter->nb_inputs; i++) { FilterLinkInternal *li = ff_link_internal(filter->inputs[i]); if (samples_ready(li, li->l.min_samples)) { - return ff_filter_frame_to_filter(filter->inputs[i]); + return filter_frame_to_filter(filter->inputs[i]); } } for (i = 0; i < filter->nb_inputs; i++) { @@ -1242,9 +1280,18 @@ static int ff_filter_activate_default(AVFilterContext *filter) FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]); if (li->frame_wanted_out && !li->frame_blocked_in) { - return ff_request_frame_to_filter(filter->outputs[i]); + return request_frame_to_filter(filter->outputs[i]); } } + for (i = 0; i < filter->nb_outputs; i++) { + FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]); + if (li->frame_wanted_out) + return request_frame_to_filter(filter->outputs[i]); + } + if (!filter->nb_outputs) { + ff_inlink_request_frame(filter->inputs[0]); + return 0; + } return FFERROR_NOT_READY; } @@ -1378,18 +1425,30 @@ static int ff_filter_activate_default(AVFilterContext *filter) Rationale: checking frame_blocked_in is necessary to avoid requesting repeatedly on a blocked input if another is not blocked (example: [buffersrc1][testsrc1][buffersrc2][testsrc2]concat=v=2). + + - If an output has frame_wanted_out > 0 call request_frame(). + + Rationale: even if all inputs are blocked an activate callback should + request a frame on some if its inputs if a frame is requested on any of + its output. + + - Request a frame on the input for sinks. + + Rationale: sinks using the old api have no way to request a frame on their + input, so we need to do it for them. */ int ff_filter_activate(AVFilterContext *filter) { + FFFilterContext *ctxi = fffilterctx(filter); + const FFFilter *const fi = fffilter(filter->filter); int ret; /* Generic timeline support is not yet implemented but should be easy */ - av_assert1(!(filter->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC && - filter->filter->activate)); - filter->ready = 0; - ret = filter->filter->activate ? filter->filter->activate(filter) : - ff_filter_activate_default(filter); + av_assert1(!(fi->p.flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC && + fi->activate)); + ctxi->ready = 0; + ret = fi->activate ? fi->activate(filter) : filter_activate_default(filter); if (ret == FFERROR_NOT_READY) ret = 0; return ret; @@ -1443,7 +1502,7 @@ static void consume_update(FilterLinkInternal *li, const AVFrame *frame) update_link_current_pts(li, frame->pts); ff_inlink_process_commands(link, frame); if (link == link->dst->inputs[0]) - link->dst->is_disabled = !ff_inlink_evaluate_timeline_at_frame(link, frame); + link->dst->is_disabled = !evaluate_timeline_at_frame(link, frame); li->l.frame_count_out++; li->l.sample_count_out += frame->nb_samples; } @@ -1537,7 +1596,8 @@ int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe) int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame) { - AVFilterCommand *cmd = link->dst->command_queue; + FFFilterContext *ctxi = fffilterctx(link->dst); + AVFilterCommand *cmd = ctxi->command_queue; while(cmd && cmd->time <= frame->pts * av_q2d(link->time_base)){ av_log(link->dst, AV_LOG_DEBUG, @@ -1545,36 +1605,11 @@ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame) cmd->time, cmd->command, cmd->arg); avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags); command_queue_pop(link->dst); - cmd= link->dst->command_queue; + cmd = ctxi->command_queue; } return 0; } -int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame) -{ - FilterLink *l = ff_filter_link(link); - AVFilterContext *dstctx = link->dst; - int64_t pts = frame->pts; -#if FF_API_FRAME_PKT -FF_DISABLE_DEPRECATION_WARNINGS - int64_t pos = frame->pkt_pos; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - if (!dstctx->enable_str) - return 1; - - dstctx->var_values[VAR_N] = l->frame_count_out; - dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); - dstctx->var_values[VAR_W] = link->w; - dstctx->var_values[VAR_H] = link->h; -#if FF_API_FRAME_PKT - dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos; -#endif - - return fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) >= 0.5; -} - void ff_inlink_request_frame(AVFilterLink *link) { av_unused FilterLinkInternal *li = ff_link_internal(link); diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 1401577c50..a92144b0a6 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -43,7 +43,6 @@ #include "libavutil/dict.h" #include "libavutil/frame.h" #include "libavutil/log.h" -#include "libavutil/samplefmt.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" @@ -70,7 +69,6 @@ const char *avfilter_configuration(void); */ const char *avfilter_license(void); -typedef struct AVFilterContext AVFilterContext; typedef struct AVFilterLink AVFilterLink; typedef struct AVFilterPad AVFilterPad; typedef struct AVFilterFormats AVFilterFormats; @@ -98,6 +96,18 @@ const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx); */ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); +/** + * Get the hardware frames context of a filter link. + * + * @param link an AVFilterLink + * + * @return a ref-counted copy of the link's hw_frames_ctx field if there is + * a hardware frames context associated with the link or NULL otherwise. + * The returned AVBufferRef needs to be released with av_buffer_unref() + * when it is no longer used. + */ +AVBufferRef* avfilter_link_get_hw_frames_ctx(AVFilterLink *link); + /** * Lists of formats / etc. supported by an end of a link. * @@ -243,204 +253,6 @@ typedef struct AVFilter { * A combination of AVFILTER_FLAG_* */ int flags; - - /***************************************************************** - * All fields below this line are not part of the public API. They - * may not be used outside of libavfilter and can be changed and - * removed at will. - * New public fields should be added right above. - ***************************************************************** - */ - - /** - * The number of entries in the list of inputs. - */ - uint8_t nb_inputs; - - /** - * The number of entries in the list of outputs. - */ - uint8_t nb_outputs; - - /** - * This field determines the state of the formats union. - * It is an enum FilterFormatsState value. - */ - uint8_t formats_state; - - /** - * Filter pre-initialization function - * - * This callback will be called immediately after the filter context is - * allocated, to allow allocating and initing sub-objects. - * - * If this callback is not NULL, the uninit callback will be called on - * allocation failure. - * - * @return 0 on success, - * AVERROR code on failure (but the code will be - * dropped and treated as ENOMEM by the calling code) - */ - int (*preinit)(AVFilterContext *ctx); - - /** - * Filter initialization function. - * - * This callback will be called only once during the filter lifetime, after - * all the options have been set, but before links between filters are - * established and format negotiation is done. - * - * Basic filter initialization should be done here. Filters with dynamic - * inputs and/or outputs should create those inputs/outputs here based on - * provided options. No more changes to this filter's inputs/outputs can be - * done after this callback. - * - * This callback must not assume that the filter links exist or frame - * parameters are known. - * - * @ref AVFilter.uninit "uninit" is guaranteed to be called even if - * initialization fails, so this callback does not have to clean up on - * failure. - * - * @return 0 on success, a negative AVERROR on failure - */ - int (*init)(AVFilterContext *ctx); - - /** - * Filter uninitialization function. - * - * Called only once right before the filter is freed. Should deallocate any - * memory held by the filter, release any buffer references, etc. It does - * not need to deallocate the AVFilterContext.priv memory itself. - * - * This callback may be called even if @ref AVFilter.init "init" was not - * called or failed, so it must be prepared to handle such a situation. - */ - void (*uninit)(AVFilterContext *ctx); - - /** - * The state of the following union is determined by formats_state. - * See the documentation of enum FilterFormatsState in internal.h. - */ - union { - /** - * Query formats supported by the filter on its inputs and outputs. - * - * This callback is called after the filter is initialized (so the inputs - * and outputs are fixed), shortly before the format negotiation. This - * callback may be called more than once. - * - * This callback must set ::AVFilterLink's - * @ref AVFilterFormatsConfig.formats "outcfg.formats" - * on every input link and - * @ref AVFilterFormatsConfig.formats "incfg.formats" - * on every output link to a list of pixel/sample formats that the filter - * supports on that link. - * For video links, this filter may also set - * @ref AVFilterFormatsConfig.color_spaces "incfg.color_spaces" - * / - * @ref AVFilterFormatsConfig.color_spaces "outcfg.color_spaces" - * and @ref AVFilterFormatsConfig.color_ranges "incfg.color_ranges" - * / - * @ref AVFilterFormatsConfig.color_ranges "outcfg.color_ranges" - * analogously. - * For audio links, this filter must also set - * @ref AVFilterFormatsConfig.samplerates "incfg.samplerates" - * / - * @ref AVFilterFormatsConfig.samplerates "outcfg.samplerates" - * and @ref AVFilterFormatsConfig.channel_layouts "incfg.channel_layouts" - * / - * @ref AVFilterFormatsConfig.channel_layouts "outcfg.channel_layouts" - * analogously. - * - * This callback must never be NULL if the union is in this state. - * - * @return zero on success, a negative value corresponding to an - * AVERROR code otherwise - */ - int (*query_func)(AVFilterContext *); - - /** - * Same as query_func(), except this function writes the results into - * provided arrays. - * - * @param cfg_in array of input format configurations with as many - * members as the filters has inputs (NULL when there are - * no inputs); - * @param cfg_out array of output format configurations with as many - * members as the filters has outputs (NULL when there - * are no outputs); - */ - int (*query_func2)(const AVFilterContext *, - struct AVFilterFormatsConfig **cfg_in, - struct AVFilterFormatsConfig **cfg_out); - /** - * A pointer to an array of admissible pixel formats delimited - * by AV_PIX_FMT_NONE. The generic code will use this list - * to indicate that this filter supports each of these pixel formats, - * provided that all inputs and outputs use the same pixel format. - * - * In addition to that the generic code will mark all inputs - * and all outputs as supporting all color spaces and ranges, as - * long as all inputs and outputs use the same color space/range. - * - * This list must never be NULL if the union is in this state. - * The type of all inputs and outputs of filters using this must - * be AVMEDIA_TYPE_VIDEO. - */ - const enum AVPixelFormat *pixels_list; - /** - * Analogous to pixels, but delimited by AV_SAMPLE_FMT_NONE - * and restricted to filters that only have AVMEDIA_TYPE_AUDIO - * inputs and outputs. - * - * In addition to that the generic code will mark all inputs - * and all outputs as supporting all sample rates and every - * channel count and channel layout, as long as all inputs - * and outputs use the same sample rate and channel count/layout. - */ - const enum AVSampleFormat *samples_list; - /** - * Equivalent to { pix_fmt, AV_PIX_FMT_NONE } as pixels_list. - */ - enum AVPixelFormat pix_fmt; - /** - * Equivalent to { sample_fmt, AV_SAMPLE_FMT_NONE } as samples_list. - */ - enum AVSampleFormat sample_fmt; - } formats; - - int priv_size; ///< size of private data to allocate for the filter - - int flags_internal; ///< Additional flags for avfilter internal use only. - - /** - * Make the filter instance process a command. - * - * @param cmd the command to process, for handling simplicity all commands must be alphanumeric only - * @param arg the argument for the command - * @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported. - * @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be - * time consuming then a filter should treat it like an unsupported command - * - * @returns >=0 on success otherwise an error code. - * AVERROR(ENOSYS) on unsupported commands - */ - int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags); - - /** - * Filter activation function. - * - * Called when any processing is needed from the filter, instead of any - * filter_frame and request_frame on pads. - * - * The function must examine inlinks and outlinks and perform a single - * step of processing. If there is nothing to do, the function must do - * nothing and not return an error. If more steps are or may be - * possible, it must use ff_filter_set_ready() to schedule another - * activation. - */ - int (*activate)(AVFilterContext *ctx); } AVFilter; /** @@ -454,7 +266,7 @@ unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output); #define AVFILTER_THREAD_SLICE (1 << 0) /** An instance of a filter */ -struct AVFilterContext { +typedef struct AVFilterContext { const AVClass *av_class; ///< needed for av_log() and filters common options const AVFilter *filter; ///< the AVFilter of which this is an instance @@ -498,12 +310,32 @@ struct AVFilterContext { */ int nb_threads; +#if FF_API_CONTEXT_PUBLIC + /** + * @deprecated unused + */ + attribute_deprecated struct AVFilterCommand *command_queue; +#endif char *enable_str; ///< enable expression string - void *enable; ///< parsed expression (AVExpr*) - double *var_values; ///< variable values for the enable expression - int is_disabled; ///< the enabled state from the last expression evaluation +#if FF_API_CONTEXT_PUBLIC + /** + * @deprecated unused + */ + attribute_deprecated + void *enable; + /** + * @deprecated unused + */ + double *var_values; +#endif + /** + * MUST NOT be accessed from outside avfilter. + * + * the enabled state from the last expression evaluation + */ + int is_disabled; /** * For filters which will create hardware frames, sets the device the @@ -518,12 +350,13 @@ struct AVFilterContext { */ AVBufferRef *hw_device_ctx; +#if FF_API_CONTEXT_PUBLIC /** - * Ready status of the filter. - * A non-0 value means that the filter needs activating; - * a higher value suggests a more urgent activation. + * @deprecated this field should never have been accessed by callers */ + attribute_deprecated unsigned ready; +#endif /** * Sets the number of extra hardware frames which the filter will @@ -540,7 +373,7 @@ struct AVFilterContext { * configured. */ int extra_hw_frames; -}; +} AVFilterContext; /** * A link between two filters. This contains pointers to the source and @@ -592,6 +425,9 @@ struct AVFilterLink { */ AVRational time_base; + AVFrameSideData **side_data; + int nb_side_data; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavfilter and can be changed and @@ -623,20 +459,6 @@ struct AVFilterLink { int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad); -#if FF_API_LINK_PUBLIC -/** - * @deprecated this function should never be called by users - */ -attribute_deprecated -void avfilter_link_free(AVFilterLink **link); - -/** - * @deprecated this function should never be called by users - */ -attribute_deprecated -int avfilter_config_links(AVFilterContext *filter); -#endif - #define AVFILTER_CMD_FLAG_ONE 1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically #define AVFILTER_CMD_FLAG_FAST 2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw) @@ -807,6 +629,14 @@ typedef struct AVFilterGraph { avfilter_execute_func *execute; char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions + + /** + * Sets the maximum number of buffered frames in the filtergraph combined. + * + * Zero means no limit. This field must be set before calling + * avfilter_graph_config(). + */ + unsigned max_buffered_frames; } AVFilterGraph; /** @@ -845,9 +675,9 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); /** - * Create and add a filter instance into an existing graph. - * The filter instance is created from the filter filt and inited - * with the parameter args. opaque is currently ignored. + * A convenience wrapper that allocates and initializes a filter in a single + * step. The filter instance is created from the filter filt and inited with the + * parameter args. opaque is currently ignored. * * In case of success put in *filt_ctx the pointer to the created * filter instance, otherwise set *filt_ctx to NULL. @@ -856,6 +686,12 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *nam * @param graph_ctx the filter graph * @return a negative AVERROR error code in case of failure, a non * negative value otherwise + * + * @warning Since the filter is initialized after this function successfully + * returns, you MUST NOT set any further options on it. If you need to + * do that, call ::avfilter_graph_alloc_filter(), followed by setting + * the options, followed by ::avfilter_init_dict() instead of this + * function. */ int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, @@ -1062,7 +898,7 @@ typedef struct AVFilterParams { char *instance_name; /** - * Options to be apllied to the filter. + * Options to be applied to the filter. * * Filled by avfilter_graph_segment_parse(). Afterwards may be freely * modified by the caller. @@ -1245,7 +1081,7 @@ int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags); * Unlabeled outputs are * - linked to the first unlinked unlabeled input in the next non-disabled * filter in the chain, if one exists - * - exported in the ouputs linked list otherwise, with NULL label + * - exported in the outputs linked list otherwise, with NULL label * * Similarly, unlinked input pads are exported in the inputs linked list. * diff --git a/libavfilter/avfilter_internal.h b/libavfilter/avfilter_internal.h index ec3933b1d1..cad4b2124b 100644 --- a/libavfilter/avfilter_internal.h +++ b/libavfilter/avfilter_internal.h @@ -100,9 +100,22 @@ typedef struct FFFilterContext { avfilter_execute_func *execute; - // 1 when avfilter_init_*() was successfully called on this filter - // 0 otherwise - int initialized; + // AV_CLASS_STATE_FLAG_* + unsigned state_flags; + + /** + * Ready status of the filter. + * A non-0 value means that the filter needs activating; + * a higher value suggests a more urgent activation. + */ + unsigned ready; + + /// parsed expression + struct AVExpr *enable; + /// variable values for the enable expression + double *var_values; + + struct AVFilterCommand *command_queue; } FFFilterContext; static inline FFFilterContext *fffilterctx(AVFilterContext *ctx) @@ -209,12 +222,4 @@ int ff_filter_graph_run_once(AVFilterGraph *graph); */ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame); -/** - * Evaluate the timeline expression of the link for the time and properties - * of the frame. - * @return >0 if enabled, 0 if disabled - * @note It does not update link->dst->is_disabled. - */ -int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame); - #endif /* AVFILTER_AVFILTER_INTERNAL_H */ diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 38077ff701..bf80391869 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -56,6 +56,8 @@ static const AVOption filtergraph_options[] = { 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, F|A }, + {"max_buffered_frames" , "maximum number of buffered frames allowed", OFFSET(max_buffered_frames), + AV_OPT_TYPE_UINT, {.i64 = 0}, 0, UINT_MAX, F|V|A }, { NULL }, }; @@ -343,16 +345,17 @@ static int filter_check_formats(AVFilterContext *ctx) static int filter_query_formats(AVFilterContext *ctx) { + const FFFilter *const filter = fffilter(ctx->filter); int ret; - if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) { - if ((ret = ctx->filter->formats.query_func(ctx)) < 0) { + if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) { + if ((ret = filter->formats.query_func(ctx)) < 0) { if (ret != AVERROR(EAGAIN)) av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n", ctx->name, av_err2str(ret)); return ret; } - } else if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { + } else if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { AVFilterFormatsConfig *cfg_in_stack[64], *cfg_out_stack[64]; AVFilterFormatsConfig **cfg_in_dyn = NULL, **cfg_out_dyn = NULL; AVFilterFormatsConfig **cfg_in, **cfg_out; @@ -385,7 +388,7 @@ static int filter_query_formats(AVFilterContext *ctx) cfg_out[i] = &l->incfg; } - ret = ctx->filter->formats.query_func2(ctx, cfg_in, cfg_out); + ret = filter->formats.query_func2(ctx, cfg_in, cfg_out); av_freep(&cfg_in_dyn); av_freep(&cfg_out_dyn); if (ret < 0) { @@ -396,8 +399,8 @@ static int filter_query_formats(AVFilterContext *ctx) } } - if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC || - ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { + if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC || + filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { ret = filter_check_formats(ctx); if (ret < 0) return ret; @@ -437,6 +440,62 @@ static int formats_declared(AVFilterContext *f) return 1; } +static void print_formats(void *log_ctx, int level, enum AVMediaType type, + const AVFilterFormats *formats) +{ + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + switch (type) { + case AVMEDIA_TYPE_VIDEO: + for (unsigned i = 0; i < formats->nb_formats; i++) + av_bprintf(&bp, "%s%s", bp.len ? " " : "", av_get_pix_fmt_name(formats->formats[i])); + break; + case AVMEDIA_TYPE_AUDIO: + for (unsigned i = 0; i < formats->nb_formats; i++) + av_bprintf(&bp, "%s%s", bp.len ? " " : "", av_get_sample_fmt_name(formats->formats[i])); + break; + default: + av_bprintf(&bp, "(unknown)"); + break; + } + + if (av_bprint_is_complete(&bp)) { + av_log(log_ctx, level, "%s\n", bp.str); + } else { + av_log(log_ctx, level, "(out of memory)\n"); + } + av_bprint_finalize(&bp, NULL); +} + +static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l) +{ + if (av_log_get_level() < level) + return; + + av_log(log_ctx, level, "Link '%s.%s' -> '%s.%s':\n" + " src: ", l->src->name, l->srcpad->name, l->dst->name, l->dstpad->name); + print_formats(log_ctx, level, l->type, l->incfg.formats); + av_log(log_ctx, level, " dst: "); + print_formats(log_ctx, level, l->type, l->outcfg.formats); +} + +static void print_filter_formats(void *log_ctx, int level, const AVFilterContext *f) +{ + if (av_log_get_level() < level) + return; + + av_log(log_ctx, level, "Filter '%s' formats:\n", f->name); + for (int i = 0; i < f->nb_inputs; i++) { + av_log(log_ctx, level, " in[%d] '%s': ", i, f->input_pads[i].name); + print_formats(log_ctx, level, f->inputs[i]->type, f->inputs[i]->outcfg.formats); + } + for (int i = 0; i < f->nb_outputs; i++) { + av_log(log_ctx, level, " out[%d] '%s': ", i, f->output_pads[i].name); + print_formats(log_ctx, level, f->outputs[i]->type, f->outputs[i]->incfg.formats); + } +} + /** * Perform one round of query_formats() and merging formats lists on the * filter graph. @@ -464,7 +523,10 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) if (ret < 0 && ret != AVERROR(EAGAIN)) return ret; /* note: EAGAIN could indicate a partial success, not counted yet */ - count_queried += ret >= 0; + if (ret >= 0) { + print_filter_formats(log_ctx, AV_LOG_DEBUG, f); + count_queried++; + } } /* go through and merge as many format lists as possible */ @@ -521,6 +583,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) "The filters '%s' and '%s' do not have a common format " "and automatic conversion is disabled.\n", link->src->name, link->dst->name); + print_link_formats(log_ctx, AV_LOG_ERROR, link); return AVERROR(EINVAL); } @@ -529,6 +592,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_log(log_ctx, AV_LOG_ERROR, "'%s' filter not present, cannot convert formats.\n", neg->conversion_filter); + print_link_formats(log_ctx, AV_LOG_ERROR, link); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto_%s_%d", @@ -580,6 +644,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); + print_link_formats(log_ctx, AV_LOG_ERROR, link); return AVERROR(ENOSYS); } } @@ -1067,8 +1132,8 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) } /* no penalty for LFE channel mismatch */ - if (av_channel_layout_channel_from_index(&in_chlayout, AV_CHAN_LOW_FREQUENCY) >= 0 && - av_channel_layout_channel_from_index(&out_chlayout, AV_CHAN_LOW_FREQUENCY) >= 0) + if (av_channel_layout_index_from_channel(&in_chlayout, AV_CHAN_LOW_FREQUENCY) >= 0 && + av_channel_layout_index_from_channel(&out_chlayout, AV_CHAN_LOW_FREQUENCY) >= 0) score += 10; av_channel_layout_from_mask(&in_chlayout, av_channel_layout_subset(&in_chlayout, ~AV_CH_LOW_FREQUENCY)); av_channel_layout_from_mask(&out_chlayout, av_channel_layout_subset(&out_chlayout, ~AV_CH_LOW_FREQUENCY)); @@ -1295,6 +1360,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) { int ret; + if (graphctx->max_buffered_frames) + fffiltergraph(graphctx)->frame_queues.max_queued = graphctx->max_buffered_frames; if ((ret = graph_check_validity(graphctx, log_ctx))) return ret; if ((ret = graph_config_formats(graphctx, log_ctx))) @@ -1348,8 +1415,9 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const for (i = 0; i < graph->nb_filters; i++) { AVFilterContext *filter = graph->filters[i]; + FFFilterContext *ctxi = fffilterctx(filter); if(filter && (!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name))){ - AVFilterCommand **queue = &filter->command_queue, *next; + AVFilterCommand **queue = &ctxi->command_queue, *next; while (*queue && (*queue)->time <= ts) queue = &(*queue)->next; next = *queue; @@ -1432,7 +1500,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) while (graphi->sink_links_count) { oldesti = graphi->sink_links[0]; oldest = &oldesti->l.pub; - if (oldest->dst->filter->activate) { + if (fffilter(oldest->dst->filter)->activate) { r = av_buffersink_get_frame_flags(oldest->dst, NULL, AV_BUFFERSINK_FLAG_PEEK); if (r != AVERROR_EOF) @@ -1453,11 +1521,13 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) } if (!graphi->sink_links_count) return AVERROR_EOF; - av_assert1(!oldest->dst->filter->activate); + av_assert1(!fffilter(oldest->dst->filter)->activate); av_assert1(oldesti->age_index >= 0); frame_count = oldesti->l.frame_count_out; while (frame_count == oldesti->l.frame_count_out) { r = ff_filter_graph_run_once(graph); + if (r == FFERROR_BUFFERSRC_EMPTY) + r = 0; if (r == AVERROR(EAGAIN) && !oldesti->frame_wanted_out && !oldesti->frame_blocked_in && !oldesti->status_in) @@ -1470,15 +1540,19 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) int ff_filter_graph_run_once(AVFilterGraph *graph) { - AVFilterContext *filter; + FFFilterContext *ctxi; unsigned i; av_assert0(graph->nb_filters); - filter = graph->filters[0]; - for (i = 1; i < graph->nb_filters; i++) - if (graph->filters[i]->ready > filter->ready) - filter = graph->filters[i]; - if (!filter->ready) + ctxi = fffilterctx(graph->filters[0]); + for (i = 1; i < graph->nb_filters; i++) { + FFFilterContext *ctxi_other = fffilterctx(graph->filters[i]); + + if (ctxi_other->ready > ctxi->ready) + ctxi = ctxi_other; + } + + if (!ctxi->ready) return AVERROR(EAGAIN); - return ff_filter_activate(filter); + return ff_filter_activate(&ctxi->p); } diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index 5811720c61..50a7da2756 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" @@ -42,28 +43,49 @@ typedef struct BufferSinkContext { const AVClass *class; unsigned warning_limit; + unsigned frame_size; /* only used for video */ +#if FF_API_BUFFERSINK_OPTS enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats int pixel_fmts_size; enum AVColorSpace *color_spaces; ///< list of accepted color spaces int color_spaces_size; enum AVColorRange *color_ranges; ///< list of accepted color ranges int color_ranges_size; +#endif + + enum AVPixelFormat *pixel_formats; + unsigned nb_pixel_formats; + + int *colorspaces; + unsigned nb_colorspaces; + + int *colorranges; + unsigned nb_colorranges; /* only used for audio */ +#if FF_API_BUFFERSINK_OPTS enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats int sample_fmts_size; char *channel_layouts_str; ///< list of accepted channel layouts int all_channel_counts; int *sample_rates; ///< list of accepted sample rates int sample_rates_size; +#endif + + enum AVSampleFormat *sample_formats; + unsigned nb_sample_formats; + + int *samplerates; + unsigned nb_samplerates; + + AVChannelLayout *channel_layouts; + unsigned nb_channel_layouts; AVFrame *peeked_frame; } BufferSinkContext; -#define NB_ITEMS(list) (list ## _size / sizeof(*list)) - int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame) { return av_buffersink_get_frame_flags(ctx, frame, 0); @@ -91,6 +113,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i int status, ret; AVFrame *cur_frame; int64_t pts; + int buffersrc_empty = 0; if (buf->peeked_frame) return return_or_keep_frame(buf, frame, buf->peeked_frame, flags); @@ -109,8 +132,15 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i return AVERROR(EAGAIN); } else if (li->frame_wanted_out) { ret = ff_filter_graph_run_once(ctx->graph); - if (ret < 0) + if (ret == FFERROR_BUFFERSRC_EMPTY) { + buffersrc_empty = 1; + } else if (ret == AVERROR(EAGAIN)) { + if (buffersrc_empty) + return ret; + ff_inlink_request_frame(inlink); + } else if (ret < 0) { return ret; + } } else { ff_inlink_request_frame(inlink); } @@ -132,11 +162,119 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx, static av_cold int common_init(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; + int ret = 0; + +#if FF_API_BUFFERSINK_OPTS + +#define CHECK_LIST_SIZE(field) \ + if (buf->field ## _size % sizeof(*buf->field)) { \ + av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ + "should be multiple of %d\n", \ + buf->field ## _size, (int)sizeof(*buf->field)); \ + return AVERROR(EINVAL); \ + } + + if (ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO) { + if ((buf->pixel_fmts_size || buf->color_spaces_size || buf->color_ranges_size) && + (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + CHECK_LIST_SIZE(pixel_fmts) + CHECK_LIST_SIZE(color_spaces) + CHECK_LIST_SIZE(color_ranges) + } else { + if ((buf->sample_fmts_size || buf->channel_layouts_str || buf->sample_rates_size) && + (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + CHECK_LIST_SIZE(sample_fmts) + CHECK_LIST_SIZE(sample_rates) + + if (buf->channel_layouts_str) { + const char *cur = buf->channel_layouts_str; + + if (buf->all_channel_counts) + av_log(ctx, AV_LOG_WARNING, + "Conflicting all_channel_counts and list in options\n"); + + while (cur) { + void *tmp; + char *next = strchr(cur, '|'); + if (next) + *next++ = 0; + + // +2 for the new element and terminator + tmp = av_realloc_array(buf->channel_layouts, buf->nb_channel_layouts + 2, + sizeof(*buf->channel_layouts)); + if (!tmp) + return AVERROR(ENOMEM); + + buf->channel_layouts = tmp; + memset(&buf->channel_layouts[buf->nb_channel_layouts], 0, + sizeof(*buf->channel_layouts) * 2); + buf->nb_channel_layouts++; + + ret = av_channel_layout_from_string(&buf->channel_layouts[buf->nb_channel_layouts - 1], cur); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur); + return ret; + } + if (ret < 0) + return ret; + + cur = next; + } + + if (buf->nb_channel_layouts) + buf->channel_layouts[buf->nb_channel_layouts] = (AVChannelLayout){ 0 }; + } + } + +#undef CHECK_LIST_SIZE + +#endif buf->warning_limit = 100; return 0; } +#define TERMINATE_ARRAY(arr, val) \ + if (s->arr) { \ + void *tmp = av_realloc_array(s->arr, s->nb_ ## arr + 1, sizeof(*s->arr)); \ + if (!tmp) \ + return AVERROR(ENOMEM); \ + s->arr = tmp; \ + s->arr[s->nb_ ## arr] = val; \ + } + +static int init_video(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(pixel_formats, AV_PIX_FMT_NONE); + TERMINATE_ARRAY(colorranges, -1); + TERMINATE_ARRAY(colorspaces, -1); + + return common_init(ctx); +} + +static int init_audio(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(sample_formats, AV_SAMPLE_FMT_NONE); + TERMINATE_ARRAY(samplerates, -1); + TERMINATE_ARRAY(channel_layouts, (AVChannelLayout){ .nb_channels = 0 }); + + return common_init(ctx); +} + +#undef TERMINATE_ARRAY + static void uninit(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; @@ -162,16 +300,30 @@ static int activate(AVFilterContext *ctx) return 0; } +static int config_input_audio(AVFilterLink *inlink) +{ + BufferSinkContext *buf = inlink->dst->priv; + FilterLink *l = ff_filter_link(inlink); + + l->min_samples = l->max_samples = buf->frame_size; + + return 0; +} + void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size) { - FilterLink *inlink = ff_filter_link(ctx->inputs[0]); + BufferSinkContext *buf = ctx->priv; + buf->frame_size = frame_size; - inlink->min_samples = inlink->max_samples = frame_size; + if (ctx->inputs && ctx->inputs[0]) { + FilterLink *l = ff_filter_link(ctx->inputs[0]); + l->min_samples = l->max_samples = buf->frame_size; + } } #define MAKE_AVFILTERLINK_ACCESSOR(type, field) \ type av_buffersink_get_##field(const AVFilterContext *ctx) { \ - av_assert0(ctx->filter->activate == activate); \ + av_assert0(fffilter(ctx->filter)->activate == activate); \ return ctx->inputs[0]->field; \ } @@ -190,20 +342,20 @@ MAKE_AVFILTERLINK_ACCESSOR(int , sample_rate ) AVRational av_buffersink_get_frame_rate(const AVFilterContext *ctx) { FilterLink *l = ff_filter_link(ctx->inputs[0]); - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return l->frame_rate; } AVBufferRef* av_buffersink_get_hw_frames_ctx(const AVFilterContext *ctx) { FilterLink *l = ff_filter_link(ctx->inputs[0]); - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return l->hw_frames_ctx; } int av_buffersink_get_channels(const AVFilterContext *ctx) { - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); return ctx->inputs[0]->ch_layout.nb_channels; } @@ -212,7 +364,7 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out AVChannelLayout ch_layout = { 0 }; int ret; - av_assert0(ctx->filter->activate == activate); + av_assert0(fffilter(ctx->filter)->activate == activate); ret = av_channel_layout_copy(&ch_layout, &ctx->inputs[0]->ch_layout); if (ret < 0) return ret; @@ -220,28 +372,52 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out return 0; } -#define CHECK_LIST_SIZE(field) \ - if (buf->field ## _size % sizeof(*buf->field)) { \ - av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ - "should be multiple of %d\n", \ - buf->field ## _size, (int)sizeof(*buf->field)); \ - return AVERROR(EINVAL); \ - } -static int vsink_query_formats(AVFilterContext *ctx) +const AVFrameSideData *const *av_buffersink_get_side_data(const AVFilterContext *ctx, + int *nb_side_data) { - BufferSinkContext *buf = ctx->priv; - unsigned i; + av_assert0(fffilter(ctx->filter)->activate == activate); + *nb_side_data = ctx->inputs[0]->nb_side_data; + return (const AVFrameSideData *const *)ctx->inputs[0]->side_data; +} + +#if FF_API_BUFFERSINK_OPTS +#define NB_ITEMS(list) (list ## _size / sizeof(*list)) +#endif + +static int vsink_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + const BufferSinkContext *buf = ctx->priv; int ret; - CHECK_LIST_SIZE(pixel_fmts) - CHECK_LIST_SIZE(color_spaces) - CHECK_LIST_SIZE(color_ranges) +#if FF_API_BUFFERSINK_OPTS + if (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges) { +#endif + if (buf->nb_pixel_formats) { + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, buf->pixel_formats); + if (ret < 0) + return ret; + } + if (buf->nb_colorspaces) { + ret = ff_set_common_color_spaces_from_list2(ctx, cfg_in, cfg_out, buf->colorspaces); + if (ret < 0) + return ret; + } + if (buf->nb_colorranges) { + ret = ff_set_common_color_ranges_from_list2(ctx, cfg_in, cfg_out, buf->colorranges); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { + unsigned i; if (buf->pixel_fmts_size) { AVFilterFormats *formats = NULL; for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++) if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) return ret; - if ((ret = ff_set_common_formats(ctx, formats)) < 0) + if ((ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } @@ -250,7 +426,7 @@ static int vsink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->color_spaces); i++) if ((ret = ff_add_format(&formats, buf->color_spaces[i])) < 0) return ret; - if ((ret = ff_set_common_color_spaces(ctx, formats)) < 0) + if ((ret = ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } @@ -259,64 +435,56 @@ static int vsink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->color_ranges); i++) if ((ret = ff_add_format(&formats, buf->color_ranges[i])) < 0) return ret; - if ((ret = ff_set_common_color_ranges(ctx, formats)) < 0) + if ((ret = ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } + } +#endif return 0; } -static int asink_query_formats(AVFilterContext *ctx) +static int asink_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - BufferSinkContext *buf = ctx->priv; - AVFilterFormats *formats = NULL; - AVChannelLayout layout = { 0 }; - AVFilterChannelLayouts *layouts = NULL; - unsigned i; + const BufferSinkContext *buf = ctx->priv; int ret; - CHECK_LIST_SIZE(sample_fmts) - CHECK_LIST_SIZE(sample_rates) +#if FF_API_BUFFERSINK_OPTS + if (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts) { +#endif + if (buf->nb_sample_formats) { + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, buf->sample_formats); + if (ret < 0) + return ret; + } + if (buf->nb_samplerates) { + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, buf->samplerates); + if (ret < 0) + return ret; + } + if (buf->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, buf->channel_layouts); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { + AVFilterFormats *formats = NULL; + unsigned i; if (buf->sample_fmts_size) { for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++) if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) return ret; - if ((ret = ff_set_common_formats(ctx, formats)) < 0) + if ((ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } - if (buf->channel_layouts_str || buf->all_channel_counts) { - if (buf->channel_layouts_str) { - const char *cur = buf->channel_layouts_str; - - while (cur) { - char *next = strchr(cur, '|'); - if (next) - *next++ = 0; - - ret = av_channel_layout_from_string(&layout, cur); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur); - return ret; - } - ret = ff_add_channel_layout(&layouts, &layout); - av_channel_layout_uninit(&layout); - if (ret < 0) - return ret; - - cur = next; - } - } - - if (buf->all_channel_counts) { - if (layouts) - av_log(ctx, AV_LOG_WARNING, - "Conflicting all_channel_counts and list in options\n"); - else if (!(layouts = ff_all_channel_counts())) - return AVERROR(ENOMEM); - } - if ((ret = ff_set_common_channel_layouts(ctx, layouts)) < 0) + if (buf->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, buf->channel_layouts); + if (ret < 0) return ret; } @@ -325,9 +493,11 @@ static int asink_query_formats(AVFilterContext *ctx) for (i = 0; i < NB_ITEMS(buf->sample_rates); i++) if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) return ret; - if ((ret = ff_set_common_samplerates(ctx, formats)) < 0) + if ((ret = ff_set_common_samplerates2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; } + } +#endif return 0; } @@ -335,19 +505,38 @@ static int asink_query_formats(AVFilterContext *ctx) #define OFFSET(x) offsetof(BufferSinkContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM static const AVOption buffersink_options[] = { - { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "pixel_formats", "array of supported pixel formats", OFFSET(pixel_formats), + AV_OPT_TYPE_PIXEL_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorspaces", "array of supported color spaces", OFFSET(colorspaces), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorranges", "array of supported color ranges", OFFSET(colorranges), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { NULL }, }; #undef FLAGS #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM static const AVOption abuffersink_options[] = { - { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, { "ch_layouts", "set a '|'-separated list of supported channel layouts", - OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "sample_formats", "array of supported sample formats", OFFSET(sample_formats), + AV_OPT_TYPE_SAMPLE_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "samplerates", "array of supported sample formats", OFFSET(samplerates), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "channel_layouts", "array of supported channel layouts", OFFSET(channel_layouts), + AV_OPT_TYPE_CHLAYOUT | AV_OPT_TYPE_FLAG_ARRAY, .flags = FLAGS }, { NULL }, }; #undef FLAGS @@ -355,28 +544,36 @@ static const AVOption abuffersink_options[] = { AVFILTER_DEFINE_CLASS(buffersink); AVFILTER_DEFINE_CLASS(abuffersink); -const AVFilter ff_vsink_buffer = { - .name = "buffersink", - .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), +const FFFilter ff_vsink_buffer = { + .p.name = "buffersink", + .p.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), + .p.priv_class = &buffersink_class, + .p.outputs = NULL, .priv_size = sizeof(BufferSinkContext), - .priv_class = &buffersink_class, - .init = common_init, + .init = init_video, .uninit = uninit, .activate = activate, FILTER_INPUTS(ff_video_default_filterpad), - .outputs = NULL, - FILTER_QUERY_FUNC(vsink_query_formats), + FILTER_QUERY_FUNC2(vsink_query_formats), }; -const AVFilter ff_asink_abuffer = { - .name = "abuffersink", - .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), - .priv_class = &abuffersink_class, +static const AVFilterPad inputs_audio[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input_audio, + }, +}; + +const FFFilter ff_asink_abuffer = { + .p.name = "abuffersink", + .p.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), + .p.priv_class = &abuffersink_class, + .p.outputs = NULL, .priv_size = sizeof(BufferSinkContext), - .init = common_init, + .init = init_audio, .uninit = uninit, .activate = activate, - FILTER_INPUTS(ff_audio_default_filterpad), - .outputs = NULL, - FILTER_QUERY_FUNC(asink_query_formats), + FILTER_INPUTS(inputs_audio), + FILTER_QUERY_FUNC2(asink_query_formats), }; diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h index 361d603679..a8435eea8f 100644 --- a/libavfilter/buffersink.h +++ b/libavfilter/buffersink.h @@ -48,26 +48,20 @@ * - av_buffersink_get_channels(), * - av_buffersink_get_ch_layout(), * - av_buffersink_get_sample_rate(). + * - av_buffersink_get_side_data(). * * The layout returned by av_buffersink_get_ch_layout() must de uninitialized * by the caller. * * The format can be constrained by setting options, using av_opt_set() and * related functions with the AV_OPT_SEARCH_CHILDREN flag. - * - pix_fmts (int list), - * - color_spaces (int list), - * - color_ranges (int list), - * - sample_fmts (int list), - * - sample_rates (int list), - * - ch_layouts (string), - * - channel_counts (int list), - * - all_channel_counts (bool). - * Most of these options are of type binary, and should be set using - * av_opt_set_int_list() or av_opt_set_bin(). If they are not set, all - * corresponding formats are accepted. - * - * As a special case, if ch_layouts is not set, all valid channel layouts are - * accepted except for UNSPEC layouts, unless all_channel_counts is set. + * - pixel_formats (array of pixel formats), + * - colorspaces (array of int), + * - colorranges (array of int), + * - sample_formats (array of sample formats), + * - samplerates (array of int), + * - channel_layouts (array of channel layouts) + * If an option is not set, all corresponding formats are accepted. */ /** @@ -129,6 +123,9 @@ int av_buffersink_get_sample_rate (const AVFilterContext *c AVBufferRef * av_buffersink_get_hw_frames_ctx (const AVFilterContext *ctx); +const AVFrameSideData *const *av_buffersink_get_side_data(const AVFilterContext *ctx, + int *nb_side_data); + /** @} */ /** diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index b5682006f0..7e86d6ffd3 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -60,8 +60,9 @@ typedef struct BufferSourceContext { int sample_rate; enum AVSampleFormat sample_fmt; int channels; - char *channel_layout_str; AVChannelLayout ch_layout; + AVFrameSideData **side_data; + int nb_side_data; int eof; int64_t last_pts; @@ -161,6 +162,17 @@ int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *par return AVERROR_BUG; } + if (param->nb_side_data > 0) + av_frame_side_data_free(&s->side_data, &s->nb_side_data); + for (int i = 0; i < param->nb_side_data; i++) { + int ret = av_frame_side_data_clone(&s->side_data, &s->nb_side_data, + param->side_data[i], 0); + if (ret < 0) { + av_frame_side_data_free(&s->side_data, &s->nb_side_data); + return ret; + } + } + return 0; } @@ -183,7 +195,7 @@ static int push_frame(AVFilterGraph *graph) ret = ff_filter_graph_run_once(graph); if (ret == AVERROR(EAGAIN)) break; - if (ret < 0) + if (ret < 0 && ret != FFERROR_BUFFERSRC_EMPTY) return ret; } return 0; @@ -240,22 +252,6 @@ int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra return AVERROR(ENOMEM); } -#if FF_API_INTERLACED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - if (copy->interlaced_frame) - copy->flags |= AV_FRAME_FLAG_INTERLACED; - if (copy->top_field_first) - copy->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - -#if FF_API_FRAME_KEY -FF_DISABLE_DEPRECATION_WARNINGS - if (copy->key_frame) - copy->flags |= AV_FRAME_FLAG_KEY; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (copy->colorspace == AVCOL_SPC_UNSPECIFIED) copy->colorspace = ctx->outputs[0]->colorspace; if (copy->color_range == AVCOL_RANGE_UNSPECIFIED) @@ -291,6 +287,13 @@ static av_cold int init_video(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "Unspecified pixel format\n"); return AVERROR(EINVAL); } + if (av_pix_fmt_desc_get(c->pix_fmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) { + if (!c->hw_frames_ctx) { + av_log(ctx, AV_LOG_ERROR, "Setting BufferSourceContext.pix_fmt " + "to a HW format requires hw_frames_ctx to be non-NULL!\n"); + return AVERROR(EINVAL); + } + } if (c->w <= 0 || c->h <= 0) { av_log(ctx, AV_LOG_ERROR, "Invalid size %dx%d\n", c->w, c->h); return AVERROR(EINVAL); @@ -363,7 +366,7 @@ static const AVOption abuffer_options[] = { { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, A }, { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, { "sample_fmt", NULL, OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, { .i64 = AV_SAMPLE_FMT_NONE }, .min = AV_SAMPLE_FMT_NONE, .max = INT_MAX, .flags = A }, - { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, + { "channel_layout", NULL, OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, .flags = A }, { "channels", NULL, OFFSET(channels), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, { NULL }, }; @@ -381,18 +384,9 @@ static av_cold int init_audio(AVFilterContext *ctx) return AVERROR(EINVAL); } - if (s->channel_layout_str || s->ch_layout.nb_channels) { + if (av_channel_layout_check(&s->ch_layout)) { int n; - if (!s->ch_layout.nb_channels) { - ret = av_channel_layout_from_string(&s->ch_layout, s->channel_layout_str); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n", - s->channel_layout_str); - return AVERROR(EINVAL); - } - } - n = s->ch_layout.nb_channels; av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf)); if (s->channels) { @@ -414,6 +408,11 @@ static av_cold int init_audio(AVFilterContext *ctx) av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf)); } + if (s->sample_rate <= 0) { + av_log(ctx, AV_LOG_ERROR, "Sample rate not set\n"); + return AVERROR(EINVAL); + } + if (!s->time_base.num) s->time_base = (AVRational){1, s->sample_rate}; @@ -430,11 +429,14 @@ static av_cold void uninit(AVFilterContext *ctx) BufferSourceContext *s = ctx->priv; av_buffer_unref(&s->hw_frames_ctx); av_channel_layout_uninit(&s->ch_layout); + av_frame_side_data_free(&s->side_data, &s->nb_side_data); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - BufferSourceContext *c = ctx->priv; + const BufferSourceContext *c = ctx->priv; AVFilterChannelLayouts *channel_layouts = NULL; AVFilterFormats *formats = NULL; AVFilterFormats *samplerates = NULL; @@ -445,21 +447,15 @@ static int query_formats(AVFilterContext *ctx) switch (ctx->outputs[0]->type) { case AVMEDIA_TYPE_VIDEO: { enum AVPixelFormat swfmt = c->pix_fmt; - if (av_pix_fmt_desc_get(swfmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) { - if (!c->hw_frames_ctx) { - av_log(ctx, AV_LOG_ERROR, "Setting BufferSourceContext.pix_fmt " - "to a HW format requires hw_frames_ctx to be non-NULL!\n"); - return AVERROR(EINVAL); - } + if (av_pix_fmt_desc_get(swfmt)->flags & AV_PIX_FMT_FLAG_HWACCEL) swfmt = ((AVHWFramesContext *) c->hw_frames_ctx->data)->sw_format; - } if ((ret = ff_add_format (&formats, c->pix_fmt)) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0) + (ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, formats)) < 0) return ret; /* force specific colorspace/range downstream only for ordinary YUV */ if (ff_fmt_is_regular_yuv(swfmt)) { if ((ret = ff_add_format(&color_spaces, c->color_space)) < 0 || - (ret = ff_set_common_color_spaces(ctx, color_spaces)) < 0) + (ret = ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, color_spaces)) < 0) return ret; if (ff_fmt_is_forced_full_range(swfmt)) { if ((ret = ff_add_format(&color_ranges, AVCOL_RANGE_JPEG)) < 0) @@ -473,21 +469,21 @@ static int query_formats(AVFilterContext *ctx) return ret; } } - if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0) + if ((ret = ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, color_ranges)) < 0) return ret; } break; } case AVMEDIA_TYPE_AUDIO: if ((ret = ff_add_format (&formats , c->sample_fmt )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || + (ret = ff_set_common_formats2 (ctx, cfg_in, cfg_out, formats)) < 0 || (ret = ff_add_format (&samplerates, c->sample_rate)) < 0 || - (ret = ff_set_common_samplerates (ctx , samplerates )) < 0) + (ret = ff_set_common_samplerates2(ctx, cfg_in, cfg_out, samplerates)) < 0) return ret; if ((ret = ff_add_channel_layout(&channel_layouts, &c->ch_layout)) < 0) return ret; - if ((ret = ff_set_common_channel_layouts(ctx, channel_layouts)) < 0) + if ((ret = ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, channel_layouts)) < 0) return ret; break; default: @@ -525,6 +521,17 @@ static int config_props(AVFilterLink *link) return AVERROR(EINVAL); } + for (int i = 0; i < c->nb_side_data; i++) { + int ret; + + ret = av_frame_side_data_clone(&link->side_data, &link->nb_side_data, + c->side_data[i], 0); + if (ret < 0) { + av_frame_side_data_free(&link->side_data, &link->nb_side_data); + return ret; + } + } + link->time_base = c->time_base; l->frame_rate = c->frame_rate; return 0; @@ -545,7 +552,7 @@ static int activate(AVFilterContext *ctx) return 0; } c->nb_failed_requests++; - return FFERROR_NOT_READY; + return FFERROR_BUFFERSRC_EMPTY; } static const AVFilterPad avfilter_vsrc_buffer_outputs[] = { @@ -556,18 +563,17 @@ static const AVFilterPad avfilter_vsrc_buffer_outputs[] = { }, }; -const AVFilter ff_vsrc_buffer = { - .name = "buffer", - .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), +const FFFilter ff_vsrc_buffer = { + .p.name = "buffer", + .p.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), + .p.priv_class = &buffer_class, .priv_size = sizeof(BufferSourceContext), .activate = activate, .init = init_video, .uninit = uninit, - .inputs = NULL, FILTER_OUTPUTS(avfilter_vsrc_buffer_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &buffer_class, + FILTER_QUERY_FUNC2(query_formats), }; static const AVFilterPad avfilter_asrc_abuffer_outputs[] = { @@ -578,16 +584,15 @@ static const AVFilterPad avfilter_asrc_abuffer_outputs[] = { }, }; -const AVFilter ff_asrc_abuffer = { - .name = "abuffer", - .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), +const FFFilter ff_asrc_abuffer = { + .p.name = "abuffer", + .p.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), + .p.priv_class = &abuffer_class, .priv_size = sizeof(BufferSourceContext), .activate = activate, .init = init_audio, .uninit = uninit, - .inputs = NULL, FILTER_OUTPUTS(avfilter_asrc_abuffer_outputs), - FILTER_QUERY_FUNC(query_formats), - .priv_class = &abuffer_class, + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 6f3344f445..2db9b8fb59 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -120,6 +120,9 @@ typedef struct AVBufferSrcParameters { */ enum AVColorSpace color_space; enum AVColorRange color_range; + + AVFrameSideData **side_data; + int nb_side_data; } AVBufferSrcParameters; /** diff --git a/libavfilter/dnn/dnn_backend_openvino.c b/libavfilter/dnn/dnn_backend_openvino.c index 2f6706dcd4..ec46e29b8a 100644 --- a/libavfilter/dnn/dnn_backend_openvino.c +++ b/libavfilter/dnn/dnn_backend_openvino.c @@ -1331,7 +1331,7 @@ static int get_output_ov(DNNModel *model, const char *input_name, int input_widt #endif ret = init_model_ov(ov_model, input_name, output_name ? &output_name : NULL, 1); if (ret != 0) { - av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO exectuable network or inference request\n"); + av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO executable network or inference request\n"); return ret; } } @@ -1487,7 +1487,7 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p ret = init_model_ov(ov_model, exec_params->input_name, exec_params->output_names, exec_params->nb_output); if (ret != 0) { - av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO exectuable network or inference request\n"); + av_log(ctx, AV_LOG_ERROR, "Failed init OpenVINO executable network or inference request\n"); return ret; } } diff --git a/libavfilter/dnn/dnn_backend_tf.c b/libavfilter/dnn/dnn_backend_tf.c index 6ca7fb6910..2c33691f96 100644 --- a/libavfilter/dnn/dnn_backend_tf.c +++ b/libavfilter/dnn/dnn_backend_tf.c @@ -833,14 +833,12 @@ static int dnn_execute_model_tf(const DNNModel *model, DNNExecBaseParams *exec_p ret = extract_lltask_from_task(task, tf_model->lltask_queue); if (ret != 0) { - av_freep(&task); av_log(ctx, AV_LOG_ERROR, "unable to extract last level task from task.\n"); return ret; } request = ff_safe_queue_pop_front(tf_model->request_queue); if (!request) { - av_freep(&task); av_log(ctx, AV_LOG_ERROR, "unable to get infer request.\n"); return AVERROR(EINVAL); } diff --git a/libavfilter/dnn/dnn_interface.c b/libavfilter/dnn/dnn_interface.c index bb477348dc..c4e410756b 100644 --- a/libavfilter/dnn/dnn_interface.c +++ b/libavfilter/dnn/dnn_interface.c @@ -137,4 +137,3 @@ const AVClass *ff_dnn_child_class_iterate_with_mask(void **iter, uint32_t backen return NULL; } - diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c index 95525d38b4..6f7dca021b 100644 --- a/libavfilter/drawutils.c +++ b/libavfilter/drawutils.c @@ -32,24 +32,23 @@ enum { RED = 0, GREEN, BLUE, ALPHA }; -int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) +static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) - return AVERROR(EINVAL); - if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL | + AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_PAL)) return AVERROR(EINVAL); av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)); if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) { - rgba_map[RED] = desc->comp[0].plane; - rgba_map[GREEN] = desc->comp[1].plane; - rgba_map[BLUE] = desc->comp[2].plane; - rgba_map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3; + if (desc->nb_components != av_pix_fmt_count_planes(av_pix_fmt_desc_get_id(desc))) + return AVERROR(EINVAL); + map[RED] = desc->comp[0].plane; + map[GREEN] = desc->comp[1].plane; + map[BLUE] = desc->comp[2].plane; + map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3; } else { int had0 = 0; unsigned depthb = 0; - unsigned i; - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { /* all components must have same depth in bytes */ unsigned db = (desc->comp[i].depth + 7) / 8; unsigned pos = desc->comp[i].offset / db; @@ -60,31 +59,47 @@ int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) return AVERROR(ENOSYS); had0 |= pos == 0; - rgba_map[i] = pos; + map[i] = pos; depthb = db; } if (desc->nb_components == 3) - rgba_map[ALPHA] = had0 ? 3 : 0; + map[ALPHA] = had0 ? 3 : 0; } - av_assert0(rgba_map[RED] != rgba_map[GREEN]); - av_assert0(rgba_map[GREEN] != rgba_map[BLUE]); - av_assert0(rgba_map[BLUE] != rgba_map[RED]); - av_assert0(rgba_map[RED] != rgba_map[ALPHA]); - av_assert0(rgba_map[GREEN] != rgba_map[ALPHA]); - av_assert0(rgba_map[BLUE] != rgba_map[ALPHA]); + av_assert0(map[RED] != map[GREEN]); + av_assert0(map[GREEN] != map[BLUE]); + av_assert0(map[BLUE] != map[RED]); + av_assert0(map[RED] != map[ALPHA]); + av_assert0(map[GREEN] != map[ALPHA]); + av_assert0(map[BLUE] != map[ALPHA]); return 0; } +int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) + return AVERROR(EINVAL); + return fill_map(desc, rgba_map); +} + +int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (desc->flags & AV_PIX_FMT_FLAG_RGB) + return AVERROR(EINVAL); + return fill_map(desc, ayuv_map); +} + int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, enum AVColorRange range, unsigned flags) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); const AVLumaCoefficients *luma = NULL; const AVComponentDescriptor *c; - unsigned i, nb_planes = 0; + unsigned nb_planes = 0; int pixelstep[MAX_PLANES] = { 0 }; int depthb = 0; @@ -105,7 +120,7 @@ int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSp ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG) return AVERROR(EINVAL); - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { int db; c = &desc->comp[i]; /* for now, only 8-16 bits formats */ @@ -156,7 +171,6 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4]) { - unsigned i; double yuvad[4]; double rgbad[4]; const AVPixFmtDescriptor *desc = draw->desc; @@ -190,7 +204,7 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4 if (desc->nb_components <= 2) yuvad[1] = yuvad[3]; - for (i = 0; i < desc->nb_components; i++) { + for (unsigned i = 0; i < desc->nb_components; i++) { unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5; if (desc->comp[i].depth > 8) color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val; @@ -213,15 +227,15 @@ void ff_copy_rectangle2(FFDrawContext *draw, int dst_x, int dst_y, int src_x, int src_y, int w, int h) { - int plane, y, wp, hp; + int wp, hp; uint8_t *p, *q; - for (plane = 0; plane < draw->nb_planes; plane++) { + for (int plane = 0; plane < draw->nb_planes; plane++) { p = pointer_at(draw, src, src_linesize, plane, src_x, src_y); q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane]; hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); - for (y = 0; y < hp; y++) { + for (int y = 0; y < hp; y++) { memcpy(q, p, wp); p += src_linesize[plane]; q += dst_linesize[plane]; @@ -233,11 +247,11 @@ void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_x, int dst_y, int w, int h) { - int plane, x, y, wp, hp; + int wp, hp; uint8_t *p0, *p; FFDrawColor color_tmp = *color; - for (plane = 0; plane < draw->nb_planes; plane++) { + for (int plane = 0; plane < draw->nb_planes; plane++) { p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]); hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); @@ -246,19 +260,19 @@ void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, p = p0; if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) { - for (x = 0; 2*x < draw->pixelstep[plane]; x++) + for (int x = 0; 2*x < draw->pixelstep[plane]; x++) color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]); } /* copy first line from color */ - for (x = 0; x < wp; x++) { + for (int x = 0; x < wp; x++) { memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]); p += draw->pixelstep[plane]; } wp *= draw->pixelstep[plane]; /* copy next lines from first line */ p = p0 + dst_linesize[plane]; - for (y = 1; y < hp; y++) { + for (int y = 1; y < hp; y++) { memcpy(p, p0, wp); p += dst_linesize[plane]; } @@ -309,14 +323,13 @@ static void blend_line(uint8_t *dst, unsigned src, unsigned alpha, { unsigned asrc = alpha * src; unsigned tau = 0x1010101 - alpha; - int x; if (left) { unsigned suba = (left * alpha) >> hsub; *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24; dst += dx; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { *dst = (*dst * tau + asrc) >> 24; dst += dx; } @@ -331,7 +344,6 @@ static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, { unsigned asrc = alpha * src; unsigned tau = 0x10001 - alpha; - int x; if (left) { unsigned suba = (left * alpha) >> hsub; @@ -339,7 +351,7 @@ static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16); dst += dx; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { uint16_t value = AV_RL16(dst); AV_WL16(dst, (value * tau + asrc) >> 16); dst += dx; @@ -356,8 +368,8 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, int dst_w, int dst_h, int x0, int y0, int w, int h) { - unsigned alpha, nb_planes, nb_comp, plane, comp; - int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; + unsigned alpha, nb_planes, nb_comp; + int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom; uint8_t *p0, *p; nb_comp = draw->desc->nb_components - @@ -377,7 +389,7 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, } nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); nb_planes += !nb_planes; - for (plane = 0; plane < nb_planes; plane++) { + for (unsigned plane = 0; plane < nb_planes; plane++) { p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); w_sub = w; h_sub = h; @@ -385,7 +397,7 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, y_sub = y0; subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); - for (comp = 0; comp < nb_comp; comp++) { + for (unsigned comp = 0; comp < nb_comp; comp++) { const int depth = draw->desc->comp[comp].depth; const int offset = draw->desc->comp[comp].offset; const int index = offset / ((depth + 7) / 8); @@ -406,14 +418,14 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, p += dst_linesize[plane]; } if (depth <= 8) { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line(p, color->comp[plane].u8[index], alpha, draw->pixelstep[plane], w_sub, draw->hsub[plane], left, right); p += dst_linesize[plane]; } } else { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line16(p, color->comp[plane].u16[index], alpha, draw->pixelstep[plane], w_sub, draw->hsub[plane], left, right); @@ -439,16 +451,16 @@ static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0) { - unsigned xm, x, y, t = 0; + unsigned t = 0; unsigned xmshf = 3 - l2depth; unsigned xmmod = 7 >> l2depth; unsigned mbits = (1 << (1 << l2depth)) - 1; unsigned mmult = 255 / mbits; uint16_t value = AV_RL16(dst); - for (y = 0; y < h; y++) { - xm = xm0; - for (x = 0; x < w; x++) { + for (unsigned y = 0; y < h; y++) { + unsigned xm = xm0; + for (unsigned x = 0; x < w; x++) { t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) * mmult; xm++; @@ -463,15 +475,15 @@ static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0) { - unsigned xm, x, y, t = 0; + unsigned t = 0; unsigned xmshf = 3 - l2depth; unsigned xmmod = 7 >> l2depth; unsigned mbits = (1 << (1 << l2depth)) - 1; unsigned mmult = 255 / mbits; - for (y = 0; y < h; y++) { - xm = xm0; - for (x = 0; x < w; x++) { + for (unsigned y = 0; y < h; y++) { + unsigned xm = xm0; + for (unsigned x = 0; x < w; x++) { t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) * mmult; xm++; @@ -488,7 +500,6 @@ static void blend_line_hv16(uint8_t *dst, int dst_delta, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband) { - int x; if (left) { blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, @@ -496,7 +507,7 @@ static void blend_line_hv16(uint8_t *dst, int dst_delta, dst += dst_delta; xm += left; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, 1 << hsub, hband, hsub + vsub, xm); dst += dst_delta; @@ -513,7 +524,6 @@ static void blend_line_hv(uint8_t *dst, int dst_delta, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband) { - int x; if (left) { blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, @@ -521,7 +531,7 @@ static void blend_line_hv(uint8_t *dst, int dst_delta, dst += dst_delta; xm += left; } - for (x = 0; x < w; x++) { + for (int x = 0; x < w; x++) { blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, 1 << hsub, hband, hsub + vsub, xm); dst += dst_delta; @@ -537,9 +547,9 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0) { - unsigned alpha, nb_planes, nb_comp, plane, comp; - int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; - uint8_t *p0, *p; + unsigned alpha, nb_planes, nb_comp; + int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom; + uint8_t *p; const uint8_t *m; nb_comp = draw->desc->nb_components - @@ -559,15 +569,15 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, } nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); nb_planes += !nb_planes; - for (plane = 0; plane < nb_planes; plane++) { - p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); + for (unsigned plane = 0; plane < nb_planes; plane++) { + uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); w_sub = mask_w; h_sub = mask_h; x_sub = x0; y_sub = y0; subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); - for (comp = 0; comp < nb_comp; comp++) { + for (unsigned comp = 0; comp < nb_comp; comp++) { const int depth = draw->desc->comp[comp].depth; const int offset = draw->desc->comp[comp].offset; const int index = offset / ((depth + 7) / 8); @@ -594,7 +604,7 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, m += top * mask_linesize; } if (depth <= 8) { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line_hv(p, draw->pixelstep[plane], color->comp[plane].u8[index], alpha, m, mask_linesize, l2depth, w_sub, @@ -604,7 +614,7 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, m += mask_linesize << draw->vsub[plane]; } } else { - for (y = 0; y < h_sub; y++) { + for (int y = 0; y < h_sub; y++) { blend_line_hv16(p, draw->pixelstep[plane], color->comp[plane].u16[index], alpha, m, mask_linesize, l2depth, w_sub, @@ -647,12 +657,11 @@ int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir, AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags) { - enum AVPixelFormat i; FFDrawContext draw; AVFilterFormats *fmts = NULL; int ret; - for (i = 0; av_pix_fmt_desc_get(i); i++) + for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++) if (ff_draw_init(&draw, i, flags) >= 0 && (ret = ff_add_format(&fmts, i)) < 0) return NULL; diff --git a/libavfilter/drawutils.h b/libavfilter/drawutils.h index 90df55107a..f4903d1a86 100644 --- a/libavfilter/drawutils.h +++ b/libavfilter/drawutils.h @@ -29,6 +29,7 @@ #include "libavutil/pixfmt.h" int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt); +int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt); #define MAX_PLANES 4 diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c index 3f1fa23ae4..2546adc281 100644 --- a/libavfilter/f_bench.c +++ b/libavfilter/f_bench.c @@ -80,7 +80,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->n++; s->min = FFMIN(s->min, diff); s->max = FFMAX(s->max, diff); - av_log(s, AV_LOG_INFO, "t:%f avg:%f max:%f min:%f\n", + av_log(ctx, AV_LOG_INFO, "t:%f avg:%f max:%f min:%f\n", T2F(diff), T2F(s->sum / s->n), T2F(s->max), T2F(s->min)); } av_dict_set(&in->metadata, START_TIME_KEY, NULL, 0); @@ -101,15 +101,15 @@ static const AVFilterPad bench_inputs[] = { }, }; -const AVFilter ff_vf_bench = { - .name = "bench", - .description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), +const FFFilter ff_vf_bench = { + .p.name = "bench", + .p.description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), + .p.priv_class = &bench_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(BenchContext), .init = init, FILTER_INPUTS(bench_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), - .priv_class = &bench_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; #endif /* CONFIG_BENCH_FILTER */ @@ -125,14 +125,14 @@ static const AVFilterPad abench_inputs[] = { }, }; -const AVFilter ff_af_abench = { - .name = "abench", - .description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), +const FFFilter ff_af_abench = { + .p.name = "abench", + .p.description = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."), + .p.priv_class = &abench_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(BenchContext), .init = init, FILTER_INPUTS(abench_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - .priv_class = &abench_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, }; #endif /* CONFIG_ABENCH_FILTER */ diff --git a/libavfilter/f_cue.c b/libavfilter/f_cue.c index 38500bb515..63027c7c2e 100644 --- a/libavfilter/f_cue.c +++ b/libavfilter/f_cue.c @@ -100,10 +100,10 @@ static const AVOption options[] = { AVFILTER_DEFINE_CLASS_EXT(cue_acue, "(a)cue", options); #if CONFIG_CUE_FILTER -const AVFilter ff_vf_cue = { - .name = "cue", - .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), - .priv_class = &cue_acue_class, +const FFFilter ff_vf_cue = { + .p.name = "cue", + .p.description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .p.priv_class = &cue_acue_class, .priv_size = sizeof(CueContext), FILTER_INPUTS(ff_video_default_filterpad), FILTER_OUTPUTS(ff_video_default_filterpad), @@ -112,12 +112,12 @@ const AVFilter ff_vf_cue = { #endif /* CONFIG_CUE_FILTER */ #if CONFIG_ACUE_FILTER -const AVFilter ff_af_acue = { - .name = "acue", - .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), - .priv_class = &cue_acue_class, +const FFFilter ff_af_acue = { + .p.name = "acue", + .p.description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .p.priv_class = &cue_acue_class, + .p.flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(CueContext), - .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(ff_audio_default_filterpad), .activate = activate, diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index 7c6a83be7d..f781e8c2fe 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -127,9 +127,10 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE @@ -137,7 +138,7 @@ static int query_formats(AVFilterContext *ctx) int ret; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(fmts_list, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(fmts_list, &cfg_out[0]->formats)) < 0) return ret; return 0; @@ -473,16 +474,16 @@ static const AVFilterPad drawgraph_inputs[] = { }, }; -const AVFilter ff_vf_drawgraph = { - .name = "drawgraph", - .description = NULL_IF_CONFIG_SMALL("Draw a graph using input video metadata."), +const FFFilter ff_vf_drawgraph = { + .p.name = "drawgraph", + .p.description = NULL_IF_CONFIG_SMALL("Draw a graph using input video metadata."), + .p.priv_class = &drawgraph_class, .priv_size = sizeof(DrawGraphContext), - .priv_class = &drawgraph_class, .init = init, .uninit = uninit, FILTER_INPUTS(drawgraph_inputs), FILTER_OUTPUTS(drawgraph_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_DRAWGRAPH_FILTER @@ -497,15 +498,15 @@ static const AVFilterPad adrawgraph_inputs[] = { }, }; -const AVFilter ff_avf_adrawgraph = { - .name = "adrawgraph", - .description = NULL_IF_CONFIG_SMALL("Draw a graph using input audio metadata."), - .priv_class = &drawgraph_class, +const FFFilter ff_avf_adrawgraph = { + .p.name = "adrawgraph", + .p.description = NULL_IF_CONFIG_SMALL("Draw a graph using input audio metadata."), + .p.priv_class = &drawgraph_class, .priv_size = sizeof(DrawGraphContext), .init = init, .uninit = uninit, FILTER_INPUTS(adrawgraph_inputs), FILTER_OUTPUTS(drawgraph_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; #endif // CONFIG_ADRAWGRAPH_FILTER diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c index f71c230b45..a352f3831f 100644 --- a/libavfilter/f_ebur128.c +++ b/libavfilter/f_ebur128.c @@ -43,6 +43,8 @@ #include "formats.h" #include "video.h" +#include "f_ebur128.h" + #define ABS_THRES -70 ///< silence gate: we discard anything below this absolute (LUFS) threshold #define ABS_UP_THRES 10 ///< upper loud limit to consider (ABS_THRES being the minimum) #define HIST_GRAIN 100 ///< defines histogram precision @@ -62,7 +64,7 @@ struct hist_entry { }; struct integrator { - double **cache; ///< window of filtered samples (N ms) + double *cache; ///< window of filtered samples (N ms) int cache_pos; ///< focus on the last added bin in the cache array int cache_size; double *sum; ///< sum of the last N ms filtered samples (cache content) @@ -77,6 +79,7 @@ struct rect { int x, y, w, h; }; typedef struct EBUR128Context { const AVClass *class; ///< AVClass context for log and options purpose + EBUR128DSPContext dsp; /* peak metering */ int peak_mode; ///< enabled peak modes @@ -113,16 +116,6 @@ typedef struct EBUR128Context { int idx_insample; ///< current sample position of processed samples in single input frame AVFrame *insamples; ///< input samples reference, updated regularly - /* Filter caches. - * The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */ - double *x; ///< 3 input samples cache for each channel - double *y; ///< 3 pre-filter samples cache for each channel - double *z; ///< 3 RLB-filter samples cache for each channel - double pre_b[3]; ///< pre-filter numerator coefficients - double pre_a[3]; ///< pre-filter denominator coefficients - double rlb_b[3]; ///< rlb-filter numerator coefficients - double rlb_a[3]; ///< rlb-filter denominator coefficients - struct integrator i400; ///< 400ms integrator, used for Momentary loudness (M), and Integrated loudness (I) struct integrator i3000; ///< 3s integrator, used for Short term loudness (S), and Loudness Range (LRA) @@ -253,8 +246,8 @@ static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, int font_height; va_list vl; - if (ftid == FONT16) font = avpriv_vga16_font, font_height = 16; - else if (ftid == FONT8) font = avpriv_cga_font, font_height = 8; + if (ftid == FONT16) font = avpriv_vga16_font_get(), font_height = 16; + else if (ftid == FONT8) font = avpriv_cga_font_get(), font_height = 8; else return; va_start(vl, fmt); @@ -406,21 +399,21 @@ static int config_audio_input(AVFilterLink *inlink) double a0 = 1.0 + K / Q + K * K; - ebur128->pre_b[0] = (Vh + Vb * K / Q + K * K) / a0; - ebur128->pre_b[1] = 2.0 * (K * K - Vh) / a0; - ebur128->pre_b[2] = (Vh - Vb * K / Q + K * K) / a0; - ebur128->pre_a[1] = 2.0 * (K * K - 1.0) / a0; - ebur128->pre_a[2] = (1.0 - K / Q + K * K) / a0; + ebur128->dsp.pre.b0 = (Vh + Vb * K / Q + K * K) / a0; + ebur128->dsp.pre.b1 = 2.0 * (K * K - Vh) / a0; + ebur128->dsp.pre.b2 = (Vh - Vb * K / Q + K * K) / a0; + ebur128->dsp.pre.a1 = 2.0 * (K * K - 1.0) / a0; + ebur128->dsp.pre.a2 = (1.0 - K / Q + K * K) / a0; f0 = 38.13547087602444; Q = 0.5003270373238773; K = tan(M_PI * f0 / (double)inlink->sample_rate); - ebur128->rlb_b[0] = 1.0; - ebur128->rlb_b[1] = -2.0; - ebur128->rlb_b[2] = 1.0; - ebur128->rlb_a[1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); - ebur128->rlb_a[2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); + ebur128->dsp.rlb.b0 = 1.0; + ebur128->dsp.rlb.b1 = -2.0; + ebur128->dsp.rlb.b2 = 1.0; + ebur128->dsp.rlb.a1 = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); + ebur128->dsp.rlb.a2 = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); /* Force 100ms framing in case of metadata injection: the frames must have * a granularity of the window overlap to be accurately exploited. @@ -446,20 +439,21 @@ static int config_audio_output(AVFilterLink *outlink) AV_CH_SURROUND_DIRECT_LEFT |AV_CH_SURROUND_DIRECT_RIGHT) ebur128->nb_channels = nb_channels; - ebur128->x = av_calloc(nb_channels, 3 * sizeof(*ebur128->x)); - ebur128->y = av_calloc(nb_channels, 3 * sizeof(*ebur128->y)); - ebur128->z = av_calloc(nb_channels, 3 * sizeof(*ebur128->z)); + ebur128->dsp.y = av_calloc(nb_channels, 3 * sizeof(*ebur128->dsp.y)); + ebur128->dsp.z = av_calloc(nb_channels, 3 * sizeof(*ebur128->dsp.z)); ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting)); - if (!ebur128->ch_weighting || !ebur128->x || !ebur128->y || !ebur128->z) + if (!ebur128->ch_weighting || !ebur128->dsp.y || !ebur128->dsp.z) return AVERROR(ENOMEM); #define I400_BINS(x) ((x) * 4 / 10) #define I3000_BINS(x) ((x) * 3) + ebur128->i400.cache_size = I400_BINS(outlink->sample_rate); + ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate); ebur128->i400.sum = av_calloc(nb_channels, sizeof(*ebur128->i400.sum)); ebur128->i3000.sum = av_calloc(nb_channels, sizeof(*ebur128->i3000.sum)); - ebur128->i400.cache = av_calloc(nb_channels, sizeof(*ebur128->i400.cache)); - ebur128->i3000.cache = av_calloc(nb_channels, sizeof(*ebur128->i3000.cache)); + ebur128->i400.cache = av_calloc(nb_channels * ebur128->i400.cache_size, sizeof(*ebur128->i400.cache)); + ebur128->i3000.cache = av_calloc(nb_channels * ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache)); if (!ebur128->i400.sum || !ebur128->i3000.sum || !ebur128->i400.cache || !ebur128->i3000.cache) return AVERROR(ENOMEM); @@ -474,17 +468,6 @@ static int config_audio_output(AVFilterLink *outlink) } else { ebur128->ch_weighting[i] = 1.0; } - - if (!ebur128->ch_weighting[i]) - continue; - - /* bins buffer for the two integration window (400ms and 3s) */ - ebur128->i400.cache_size = I400_BINS(outlink->sample_rate); - ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate); - ebur128->i400.cache[i] = av_calloc(ebur128->i400.cache_size, sizeof(*ebur128->i400.cache[0])); - ebur128->i3000.cache[i] = av_calloc(ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache[0])); - if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i]) - return AVERROR(ENOMEM); } #if CONFIG_SWRESAMPLE @@ -519,6 +502,9 @@ static int config_audio_output(AVFilterLink *outlink) return AVERROR(ENOMEM); } +#if ARCH_X86 + ff_ebur128_init_x86(&ebur128->dsp, nb_channels); +#endif return 0; } @@ -596,6 +582,8 @@ static av_cold int init(AVFilterContext *ctx) /* summary */ av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter); + ebur128->dsp.filter_channels = ff_ebur128_filter_channels_c; + ebur128->dsp.find_peak = ff_ebur128_find_peak_c; return 0; } @@ -626,11 +614,65 @@ static int gate_update(struct integrator *integ, double power, return gate_hist_pos; } +void ff_ebur128_filter_channels_c(const EBUR128DSPContext *dsp, + const double *restrict samples, + double *restrict cache_400, + double *restrict cache_3000, + double *restrict sum_400, + double *restrict sum_3000, + const int nb_channels) +{ + const EBUR128Biquad pre = dsp->pre; + const EBUR128Biquad rlb = dsp->rlb; + + for (int ch = 0; ch < nb_channels; ch++) { + /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */ +#define FILTER(DST, SRC, FILT) do { \ + const double tmp = DST[0] = FILT.b0 * SRC + DST[1]; \ + DST[1] = FILT.b1 * SRC + DST[2] - FILT.a1 * tmp; \ + DST[2] = FILT.b2 * SRC - FILT.a2 * tmp; \ +} while (0) + + const double x = samples[ch]; + double *restrict y = &dsp->y[3 * ch]; + double *restrict z = &dsp->z[3 * ch]; + + // TODO: merge both filters in one? + FILTER(y, x, pre); // apply pre-filter + FILTER(z, *y, rlb); // apply RLB-filter + + /* add the new value, and limit the sum to the cache size (400ms or 3s) + * by removing the oldest one */ + const double bin = *z * *z; + sum_400 [ch] += bin - cache_400[ch]; + sum_3000[ch] += bin - cache_3000[ch]; + cache_400[ch] = cache_3000[ch] = bin; + } +} + +double ff_ebur128_find_peak_c(double *restrict ch_peaks, const int nb_channels, + const double *samples, const int nb_samples) +{ + double maxpeak = 0.0; + for (int ch = 0; ch < nb_channels; ch++) { + double ch_peak = ch_peaks[ch]; + for (int i = 0; i < nb_samples; i++) { + const double sample = fabs(samples[i * nb_channels]); + ch_peak = FFMAX(ch_peak, sample); + } + maxpeak = FFMAX(maxpeak, ch_peak); + ch_peaks[ch] = ch_peak; + } + + return maxpeak; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { - int i, ch, idx_insample, ret; + int ret; AVFilterContext *ctx = inlink->dst; EBUR128Context *ebur128 = ctx->priv; + const EBUR128DSPContext *dsp = &ebur128->dsp; const int nb_channels = ebur128->nb_channels; const int nb_samples = insamples->nb_samples; const double *samples = (double *)insamples->data[0]; @@ -643,87 +685,48 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) (const uint8_t **)insamples->data, nb_samples); if (ret < 0) return ret; - for (ch = 0; ch < nb_channels; ch++) - ebur128->true_peaks_per_frame[ch] = 0.0; - for (idx_insample = 0; idx_insample < ret; idx_insample++) { - for (ch = 0; ch < nb_channels; ch++) { - ebur128->true_peaks[ch] = FFMAX(ebur128->true_peaks[ch], fabs(*swr_samples)); - ebur128->true_peaks_per_frame[ch] = FFMAX(ebur128->true_peaks_per_frame[ch], - fabs(*swr_samples)); - swr_samples++; - } + + memset(ebur128->true_peaks_per_frame, 0, + nb_channels * sizeof(*ebur128->true_peaks_per_frame)); + + double peak = dsp->find_peak(ebur128->true_peaks_per_frame, nb_channels, + swr_samples, ret); + + for (int ch = 0; ch < nb_channels; ch++) { + peak = FFMAX(peak, ebur128->true_peaks[ch]); + ebur128->true_peaks[ch] = FFMAX(ebur128->true_peaks[ch], + ebur128->true_peaks_per_frame[ch]); } + + ebur128->true_peak = DBFS(peak); } #endif - for (idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) { - const int bin_id_400 = ebur128->i400.cache_pos; - const int bin_id_3000 = ebur128->i3000.cache_pos; + if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS) { + double peak = dsp->find_peak(ebur128->sample_peaks, nb_channels, + samples, nb_samples); + ebur128->sample_peak = DBFS(peak); + } -#define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \ - ebur128->i##time.cache_pos++; \ - if (ebur128->i##time.cache_pos == \ - ebur128->i##time.cache_size) { \ - ebur128->i##time.filled = 1; \ - ebur128->i##time.cache_pos = 0; \ - } \ -} while (0) + for (int idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) { + const int bin_id_400 = ebur128->i400.cache_pos++; + const int bin_id_3000 = ebur128->i3000.cache_pos++; - MOVE_TO_NEXT_CACHED_ENTRY(400); - MOVE_TO_NEXT_CACHED_ENTRY(3000); - - for (ch = 0; ch < nb_channels; ch++) { - double bin; - - if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS) - ebur128->sample_peaks[ch] = FFMAX(ebur128->sample_peaks[ch], fabs(samples[idx_insample * nb_channels + ch])); - - ebur128->x[ch * 3] = samples[idx_insample * nb_channels + ch]; // set X[i] - - if (!ebur128->ch_weighting[ch]) - continue; - - /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */ -#define FILTER(Y, X, NUM, DEN) do { \ - double *dst = ebur128->Y + ch*3; \ - double *src = ebur128->X + ch*3; \ - dst[2] = dst[1]; \ - dst[1] = dst[0]; \ - dst[0] = src[0]*NUM[0] + src[1]*NUM[1] + src[2]*NUM[2] \ - - dst[1]*DEN[1] - dst[2]*DEN[2]; \ -} while (0) - - // TODO: merge both filters in one? - FILTER(y, x, ebur128->pre_b, ebur128->pre_a); // apply pre-filter - ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1]; - ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ]; - FILTER(z, y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter - - bin = ebur128->z[ch * 3] * ebur128->z[ch * 3]; - - /* add the new value, and limit the sum to the cache size (400ms or 3s) - * by removing the oldest one */ - ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400]; - ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000]; - - /* override old cache entry with the new value */ - ebur128->i400.cache [ch][bin_id_400 ] = bin; - ebur128->i3000.cache[ch][bin_id_3000] = bin; + if (ebur128->i400.cache_pos == ebur128->i400.cache_size) { + ebur128->i400.filled = 1; + ebur128->i400.cache_pos = 0; } -#define FIND_PEAK(global, sp, ptype) do { \ - int ch; \ - double maxpeak; \ - maxpeak = 0.0; \ - if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \ - for (ch = 0; ch < ebur128->nb_channels; ch++) \ - maxpeak = FFMAX(maxpeak, sp[ch]); \ - global = DBFS(maxpeak); \ - } \ -} while (0) + if (ebur128->i3000.cache_pos == ebur128->i3000.cache_size) { + ebur128->i3000.filled = 1; + ebur128->i3000.cache_pos = 0; + } - FIND_PEAK(ebur128->sample_peak, ebur128->sample_peaks, SAMPLES); - FIND_PEAK(ebur128->true_peak, ebur128->true_peaks, TRUE); + dsp->filter_channels(dsp, &samples[idx_insample * nb_channels], + &ebur128->i400.cache[bin_id_400 * nb_channels], + &ebur128->i3000.cache[bin_id_3000 * nb_channels], + ebur128->i400.sum, ebur128->i3000.sum, + nb_channels); /* For integrated loudness, gating blocks are 400ms long with 75% * overlap (see BS.1770-2 p5), so a re-computation is needed each 100ms @@ -741,7 +744,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) #define COMPUTE_LOUDNESS(m, time) do { \ if (ebur128->i##time.filled) { \ /* weighting sum of the last