Compare commits
304 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce3c09c101 | |||
| 584952257a | |||
| 1f463e44dc | |||
| 578c2dbf1d | |||
| 1166148417 | |||
| b7d139be74 | |||
| c69542aa9b | |||
| 45179413ee | |||
| eac505e3e8 | |||
| 90b5fc8479 | |||
| 93aeb8edd3 | |||
| c9fc3f79d0 | |||
| f99a022cbf | |||
| d215ba76a0 | |||
| 6d00e599fd | |||
| 53a987a274 | |||
| f866705d4d | |||
| 792cde9879 | |||
| dba917bab5 | |||
| 9193beee0d | |||
| eb98bef9d2 | |||
| 38b88335f9 | |||
| 241723a2ac | |||
| b8ae2fb714 | |||
| 86590257a5 | |||
| f7bbcb91b7 | |||
| 8c2e27e7bc | |||
| 4d786a8648 | |||
| d82bcad879 | |||
| ad3e1ef726 | |||
| 68c4d7ec8c | |||
| 3c0b18a3a6 | |||
| cb112ece1c | |||
| 269201a990 | |||
| 5c56b48dbe | |||
| b94b712611 | |||
| e33bbfbee6 | |||
| f9d7f434c0 | |||
| 29616f5919 | |||
| 223764a43e | |||
| 213b6561ba | |||
| b9dc787d28 | |||
| b6fcd2919d | |||
| 55db63567d | |||
| af681f61b7 | |||
| 68a3f37058 | |||
| 8db78165b3 | |||
| 5541caa9d6 | |||
| 48cdd6b6aa | |||
| 3c51be6c26 | |||
| 0e43e30cda | |||
| faa81d0b18 | |||
| 733cce258b | |||
| 9825a8af1d | |||
| 874de02d87 | |||
| 79b1d1e1aa | |||
| ae9dd27979 | |||
| 2cf7bb6089 | |||
| 1034b144ff | |||
| 7aecd49777 | |||
| 352f6dfbe1 | |||
| 2dfc8f3919 | |||
| 84087839af | |||
| 4b32214900 | |||
| 52af067ac2 | |||
| 8280545165 | |||
| 31a192f5dd | |||
| a4152636b8 | |||
| a0e7ee5468 | |||
| ee25d8ec07 | |||
| e3ce59ba68 | |||
| bcee8b9f0b | |||
| e3d0fca1bb | |||
| 101bb4c249 | |||
| 797cbc7413 | |||
| 3a9a2f13de | |||
| 849ed5f176 | |||
| e15ede87a3 | |||
| 417061746d | |||
| 31be6491d2 | |||
| cb55da3768 | |||
| d4175fe20d | |||
| d5ac401940 | |||
| 08597a382e | |||
| b77508937f | |||
| 9006342109 | |||
| 28c0fda2cd | |||
| 6a25c9adfc | |||
| 46a66b2ccc | |||
| 5da47b2752 | |||
| e61c9faabd | |||
| a6740266e0 | |||
| b7f3a666ca | |||
| 363435f591 | |||
| ea01723885 | |||
| 36beb07e57 | |||
| e569af76bc | |||
| 5ff3913787 | |||
| cbc62ea2c8 | |||
| 9906b38d1d | |||
| 41e1b6d817 | |||
| 89d9ad0345 | |||
| a153f5f2fa | |||
| a8a7a2afa1 | |||
| 2b81143984 | |||
| 36abe87a0b | |||
| b3a15b4ee1 | |||
| 2834b438ec | |||
| 532063e7ff | |||
| b0570f35cf | |||
| 5a409e87b7 | |||
| 734b17cb98 | |||
| 2fd0577bc9 | |||
| 23b50185c6 | |||
| f80ccca187 | |||
| 0bbf29dee3 | |||
| af81aaae76 | |||
| 61218852d1 | |||
| 0cda9f02e7 | |||
| bdcec7edb8 | |||
| 643048daef | |||
| 27766a8f74 | |||
| 8b45f41791 | |||
| 96f9a6e28c | |||
| 2812a5b8d7 | |||
| eb588c4f78 | |||
| 2196cd43dc | |||
| 9318eb0a98 | |||
| 1c871a90bf | |||
| 64fd93e361 | |||
| 83853cf1e8 | |||
| 86dd0a3adf | |||
| d7ceb10bfe | |||
| 9516e6900a | |||
| e302bafe79 | |||
| a991b3e110 | |||
| 167c14a418 | |||
| e9b3388dcb | |||
| 07d615e903 | |||
| 69ca310fb7 | |||
| 61ffafe95b | |||
| 621d35023a | |||
| 16474a560e | |||
| 507d8e8284 | |||
| ccae7f536b | |||
| 88c482d7b7 | |||
| d14ea0d715 | |||
| 182bc42768 | |||
| 96d5d4c75d | |||
| 377fb77be3 | |||
| cba36a17af | |||
| 5e1a71ce13 | |||
| cb2f4b4f5f | |||
| d7e1d91762 | |||
| f966d1eea6 | |||
| 874cd67a3c | |||
| 022642e3ad | |||
| bda47c505f | |||
| 27561c4e39 | |||
| ce82410ef8 | |||
| bcdca173aa | |||
| 56e8d17d9b | |||
| 56f758b8b4 | |||
| 83e8541aa6 | |||
| e0e38acd2f | |||
| e4c7fbf6c0 | |||
| 9eb9f4799f | |||
| 58d4114d36 | |||
| b21e00eda5 | |||
| 3728de467d | |||
| da9dd86bdc | |||
| 8c31bbbb37 | |||
| 470685bd1d | |||
| 6f746f57d8 | |||
| fb216b5fac | |||
| 1068a26663 | |||
| 239f2c733d | |||
| 6266867e7b | |||
| 2c28491579 | |||
| 140d581786 | |||
| e2c6836694 | |||
| d2597ecda6 | |||
| 0a69adf4ee | |||
| 1d24758bd1 | |||
| 0a752b7913 | |||
| 847b2afc9c | |||
| bad324bd68 | |||
| eaf5015aa8 | |||
| e483eb921d | |||
| 76dddbc961 | |||
| af2a176fd2 | |||
| 698000f5bd | |||
| f6dd450a26 | |||
| 31855e032c | |||
| 77f2c227c2 | |||
| 102c590a5f | |||
| ad62419fb8 | |||
| 874f26fe96 | |||
| dc3742fd7f | |||
| cdd6df0104 | |||
| 2d646e5584 | |||
| 62a87e5516 | |||
| 19fc59fde6 | |||
| 0ba002f92d | |||
| 8462c37595 | |||
| 6c2e9930b2 | |||
| 5bb3c22021 | |||
| d26ce3ec60 | |||
| d1b0069077 | |||
| 7d612d27ae | |||
| 031fae5c41 | |||
| f9a9fae557 | |||
| 3e57f240cc | |||
| b5489087f3 | |||
| 66d96bd65e | |||
| cdfa960ddf | |||
| ee35cdda74 | |||
| e9fc881384 | |||
| df197112c2 | |||
| 76fd415fce | |||
| dd2a960971 | |||
| 9e5a493d71 | |||
| 797504295b | |||
| a3abd79fde | |||
| 01d380bdb2 | |||
| 9cbd7e2589 | |||
| 9601014f1e | |||
| 5fe5d2a13b | |||
| 44fe8891c8 | |||
| 5a1dc812b1 | |||
| fa1ac7bd8a | |||
| ea84befff6 | |||
| d5d2f063ff | |||
| 08a31e67af | |||
| 8c7ec4b4b5 | |||
| 0b0a2d236d | |||
| 71818d86ae | |||
| e927c11cfc | |||
| f5e4bf6dbd | |||
| c47b33c61c | |||
| f7103aa69e | |||
| b81bc90e0c | |||
| c3fa0d869b | |||
| ff129c8f04 | |||
| 097668f94c | |||
| 355269a9f0 | |||
| 059489977b | |||
| 93b8ad91bf | |||
| ff47e29b10 | |||
| 3127b0db72 | |||
| 75d37c499d | |||
| 7f5c90f77e | |||
| 0fa756d03d | |||
| 735c84b57f | |||
| a3475e2554 | |||
| bd7f101bda | |||
| 3ec48e4bc6 | |||
| 2bb6264105 | |||
| 9abdfda6f2 | |||
| 395dc6fa27 | |||
| a2e15f15b0 | |||
| 9047fa1b08 | |||
| e1a84cd003 | |||
| 5c923e26ab | |||
| c471fce2bf | |||
| 5f3122760f | |||
| 43a4771cd0 | |||
| 8a8881d226 | |||
| 7dad4d2cb5 | |||
| a5a1653a9e | |||
| 0a8bf5fcaa | |||
| 29e0d0ef13 | |||
| 93c915a572 | |||
| fcbbd8b394 | |||
| 7df9a56f0d | |||
| 6f890cb104 | |||
| 42692d0f57 | |||
| 259ee609ac | |||
| b6a617c8bf | |||
| a5696b44a6 | |||
| 5bc4a9898c | |||
| b6faea362a | |||
| ca6e0ee7aa | |||
| f851191ce6 | |||
| 60f3904718 | |||
| 56217dccd6 | |||
| 4f72addce1 | |||
| 1f217b4b7d | |||
| 0ce7bd66a7 | |||
| 2803bcd5d5 | |||
| 2cf15d3fc0 | |||
| c9cf8cf9c3 | |||
| 21719ece26 | |||
| b842218402 | |||
| c88ae59e31 | |||
| 711b69c615 | |||
| 511387e49a | |||
| c9a5f7c6ca | |||
| 680ac1aa32 | |||
| b013bbf092 | |||
| d8d4a96414 | |||
| b1da475805 | |||
| b6db764c86 | |||
| 0ab823b47a |
@@ -57,7 +57,6 @@ libavcodec/.*png.* @Traneptora
|
||||
libavcodec/.*prores.* @lynne
|
||||
libavcodec/rangecoder.* @michaelni
|
||||
libavcodec/ratecontrol.* @michaelni
|
||||
libavcodec/rkmpp* @quink
|
||||
libavcodec/rv60.* @pross
|
||||
libavcodec/sgirle.* @pross
|
||||
libavcodec/.*siren.* @lynne
|
||||
@@ -110,7 +109,6 @@ libavfilter/vf_find_rect.* @michaelni
|
||||
libavfilter/vf_icc.* @haasn
|
||||
libavfilter/vf_libplacebo.* @haasn
|
||||
libavfilter/vf_libvmaf.* @kylophone
|
||||
libavfilter/vf_mpdecimate.* @dana-feng
|
||||
libavfilter/vf_premultiply.* @haasn
|
||||
libavfilter/vf_scale.* @haasn
|
||||
libavfilter/vf_scale_vt.* @quink
|
||||
@@ -141,8 +139,6 @@ libavformat/electronicarts.* @pross
|
||||
libavformat/.*exif.* @Traneptora
|
||||
libavformat/filmstrip.* @pross
|
||||
libavformat/frm.* @pross
|
||||
libavformat/hls.* @kasper93
|
||||
libavformat/hxvs.* @quink
|
||||
libavformat/iamf.* @jamrial
|
||||
libavformat/icecast.c @ePirat
|
||||
libavformat/ico.* @pross
|
||||
@@ -157,7 +153,6 @@ libavformat/mlv.* @pross
|
||||
libavformat/mm.* @pross
|
||||
libavformat/msp.* @pross
|
||||
libavformat/mv.* @pross
|
||||
libavformat/ogg.* @toots
|
||||
libavformat/pp_bnk.* @zane
|
||||
libavformat/rm.* @pross
|
||||
libavformat/sauce.* @pross
|
||||
@@ -198,7 +193,6 @@ libavutil/aarch64/.* @lynne @mstorsjo
|
||||
libavutil/arm/.* @mstorsjo
|
||||
libavutil/ppc/.* @sean_mcg
|
||||
libavutil/riscv/.* @Courmisch
|
||||
libavutil/wasm/.* @quink
|
||||
libavutil/x86/.* @lynne
|
||||
|
||||
# swresample
|
||||
@@ -232,26 +226,8 @@ doc/.* @GyanD
|
||||
# tests
|
||||
# =====
|
||||
tests/checkasm/riscv/.* @Courmisch
|
||||
libavutil/tests/ambient_viewing_environment.* @MarcosAsh
|
||||
libavutil/tests/buffer.* @MarcosAsh
|
||||
libavutil/tests/csp.* @MarcosAsh
|
||||
libavutil/tests/dovi_meta.* @MarcosAsh
|
||||
libavutil/tests/hdr_dynamic_vivid_metadata.* @MarcosAsh
|
||||
libavutil/tests/mastering_display_metadata.* @MarcosAsh
|
||||
libavutil/tests/tdrdi.* @MarcosAsh
|
||||
libavutil/tests/timestamp.* @MarcosAsh
|
||||
libavutil/tests/video_hint.* @MarcosAsh
|
||||
tests/ref/.*drawvg.* @ayosec
|
||||
tests/ref/fate/ambient_viewing_environment @MarcosAsh
|
||||
tests/ref/fate/buffer @MarcosAsh
|
||||
tests/ref/fate/csp @MarcosAsh
|
||||
tests/ref/fate/dovi_meta @MarcosAsh
|
||||
tests/ref/fate/hdr_dynamic_vivid_metadata @MarcosAsh
|
||||
tests/ref/fate/mastering_display_metadata @MarcosAsh
|
||||
tests/ref/fate/sub-mcc.* @programmerjake
|
||||
tests/ref/fate/tdrdi @MarcosAsh
|
||||
tests/ref/fate/timestamp @MarcosAsh
|
||||
tests/ref/fate/video_hint @MarcosAsh
|
||||
|
||||
# Forgejo
|
||||
# =======
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Summary of changes
|
||||
|
||||
Briefly describe what this PR does and why.
|
||||
|
||||
<!--
|
||||
If this PR requires new FATE test samples, attach them to the PR and
|
||||
list their target paths below (relative to the fate-suite root).
|
||||
|
||||
Attached filenames must match the sample's filename:
|
||||
|
||||
```fate-samples
|
||||
# e.g. vorbis/new-sample.ogg
|
||||
```
|
||||
-->
|
||||
@@ -1,40 +0,0 @@
|
||||
name: Rebase PR onto target
|
||||
|
||||
inputs:
|
||||
path:
|
||||
description: Directory to run in
|
||||
required: false
|
||||
default: .
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Rebase onto target branch
|
||||
if: ${{ forge.event_name == 'pull_request' }}
|
||||
working-directory: ${{ inputs.path }}
|
||||
run: |
|
||||
set -x
|
||||
# Fetch all PR commits + merge-base
|
||||
commits=$(curl -s -o /dev/null -w '%header{X-Total-Count}' '${{ forge.api_url }}/repos/${{ forge.repository }}/pulls/${{ forge.event.pull_request.number }}/commits?limit=1&verification=false&files=false')
|
||||
git fetch -vv --deepen=$commits origin pull/${{ forge.event.pull_request.number }}/head
|
||||
|
||||
if [ "$(wc -l < .git/shallow)" -ne 1 ]; then
|
||||
echo "Complex PR history detected, falling back to merge"
|
||||
git fetch -vv --unshallow origin pull/${{ forge.event.pull_request.number }}/head
|
||||
git fetch -vv origin ${{ forge.base_ref }}
|
||||
git merge --no-edit origin/${{ forge.base_ref }} \
|
||||
|| { echo "Does not merge cleanly with ${{ forge.base_ref }}"; exit 1; }
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Unfortunately, Forgejo does not update the merge-base when PR branch
|
||||
# is updated, the `forge.event.pull_request.merge_base` is stale value,
|
||||
# from the time when PR was created. We cannot rely on it, so try to
|
||||
# infer parent commit of the PR from the shallow clone that we have.
|
||||
base=$(cat .git/shallow)
|
||||
|
||||
# Fetch target branch
|
||||
git fetch -vv --depth=1 origin ${{ forge.base_ref }}
|
||||
# Rebase PR commits onto the current state of target branch
|
||||
git rebase --onto origin/${{ forge.base_ref }} $base \
|
||||
|| { echo "Does not rebase cleanly onto ${{ forge.base_ref }}"; exit 1; }
|
||||
@@ -1,174 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2026 Romain Beauxis <romain.beauxis@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Inject PR attachment samples into the fate-suite directory.
|
||||
|
||||
Usage: inject-pr-samples.py <pr-number>
|
||||
|
||||
Reads SAMPLES from the environment (defaults to fate-suite). For each path
|
||||
listed in a ```fate-samples``` block in the PR description, downloads the
|
||||
matching PR attachment into $SAMPLES/<path>.
|
||||
|
||||
The PR description should contain a block like:
|
||||
|
||||
```fate-samples
|
||||
vorbis/tos.ogg
|
||||
mov/some-new-sample.mov
|
||||
```
|
||||
|
||||
Each filename must match a file attached to the PR.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import urllib.request
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
FORGEJO_API = "https://code.ffmpeg.org/api/v1/repos/ffmpeg/ffmpeg/issues"
|
||||
ATTACHMENT_BASE = "https://code.ffmpeg.org/attachments/"
|
||||
|
||||
|
||||
def fetch_json(url):
|
||||
with urllib.request.urlopen(url) as r:
|
||||
return json.load(r)
|
||||
|
||||
|
||||
def parse_fate_samples(body):
|
||||
paths = []
|
||||
in_block = False
|
||||
for line in body.splitlines():
|
||||
if line == "```fate-samples":
|
||||
in_block = True
|
||||
elif line == "```" and in_block:
|
||||
break
|
||||
elif in_block:
|
||||
parts = line.split()
|
||||
if len(parts) == 1:
|
||||
paths.append(parts[0])
|
||||
return paths
|
||||
|
||||
|
||||
MAX_PATH_DEPTH = 3
|
||||
|
||||
|
||||
def validate_path(path):
|
||||
p = PurePosixPath(path)
|
||||
if p.is_absolute():
|
||||
raise ValueError(f"path must be relative: {path!r}")
|
||||
if ".." in p.parts:
|
||||
raise ValueError(f"path must not contain '..': {path!r}")
|
||||
if not p.parts:
|
||||
raise ValueError(f"empty path")
|
||||
if len(p.parts) > MAX_PATH_DEPTH:
|
||||
raise ValueError(f"path too deep (max {MAX_PATH_DEPTH} components): {path!r}")
|
||||
|
||||
|
||||
def validate_url(url):
|
||||
if not url.startswith(ATTACHMENT_BASE):
|
||||
raise ValueError(f"unexpected attachment URL: {url!r}")
|
||||
|
||||
|
||||
def digest(path):
|
||||
h = hashlib.sha256()
|
||||
with open(path, "rb") as f:
|
||||
while chunk := f.read(1 << 16):
|
||||
h.update(chunk)
|
||||
return h.digest()
|
||||
|
||||
|
||||
def download(url, dst):
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.NamedTemporaryFile(dir=dst.parent, delete=False) as tmp:
|
||||
tmp_path = Path(tmp.name)
|
||||
try:
|
||||
with urllib.request.urlopen(url) as r:
|
||||
while chunk := r.read(1 << 16):
|
||||
tmp.write(chunk)
|
||||
if dst.exists() and digest(dst) != digest(tmp_path):
|
||||
raise ValueError(f"already exists with different content: {dst}")
|
||||
tmp_path.rename(dst)
|
||||
except:
|
||||
tmp_path.unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2 or not re.fullmatch(r"[0-9]+", sys.argv[1]):
|
||||
print(f"Usage: {sys.argv[0]} <pr-number>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
pr_number = sys.argv[1]
|
||||
samples_dir = Path(os.environ.get("SAMPLES", "fate-suite"))
|
||||
|
||||
pr = fetch_json(f"{FORGEJO_API}/{pr_number}")
|
||||
assets = {a["name"]: a["browser_download_url"] for a in pr.get("assets", [])}
|
||||
paths = parse_fate_samples(pr.get("body", ""))
|
||||
|
||||
if not paths:
|
||||
sys.exit(0)
|
||||
|
||||
new_samples = False
|
||||
|
||||
for path in paths:
|
||||
try:
|
||||
validate_path(path)
|
||||
except ValueError as e:
|
||||
print(f"fate-samples: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
name = PurePosixPath(path).name
|
||||
url = assets.get(name)
|
||||
if url is None:
|
||||
print(f"fate-samples: no attachment named {name!r}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
validate_url(url)
|
||||
except ValueError as e:
|
||||
print(f"fate-samples: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
dst = samples_dir / path
|
||||
is_new = not dst.exists()
|
||||
try:
|
||||
download(url, dst)
|
||||
except ValueError as e:
|
||||
print(f"fate-samples: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if is_new:
|
||||
new_samples = True
|
||||
print(f"Injected: {path}")
|
||||
|
||||
output_file = os.environ.get("FORGEJO_OUTPUT")
|
||||
if output_file:
|
||||
with open(output_file, "a") as f:
|
||||
print(f"new_samples={'true' if new_samples else 'false'}", file=f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,14 +1,5 @@
|
||||
exclude: ^tests/ref/
|
||||
|
||||
# This repository keeps its pre-commit config in this nondefault path.
|
||||
# Install hooks from here with:
|
||||
# pre-commit install -c .forgejo/pre-commit/config.yaml
|
||||
# The command above installs both the pre-commit and commit-msg hooks because
|
||||
# default_install_hook_types includes them below.
|
||||
default_install_hook_types:
|
||||
- pre-commit
|
||||
- commit-msg
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
@@ -29,15 +20,9 @@ repos:
|
||||
- id: trailing-whitespace
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-commit-message
|
||||
name: validate commit message format
|
||||
language: script
|
||||
entry: ./tools/check_commit_msg.sh
|
||||
stages: [commit-msg]
|
||||
always_run: true
|
||||
- id: arm-asm-indent
|
||||
name: fix arm/aarch64 assembly indentation
|
||||
files: ^.*/(arm|aarch64)/.*\.S$
|
||||
- id: aarch64-asm-indent
|
||||
name: fix aarch64 assembly indentation
|
||||
files: ^.*/aarch64/.*\.S$
|
||||
language: script
|
||||
entry: ./tools/check_arm_indent.sh --apply
|
||||
pass_filenames: false
|
||||
@@ -48,4 +33,4 @@ repos:
|
||||
args:
|
||||
- --ignore-words=.forgejo/pre-commit/ignored-words.txt
|
||||
- --ignore-multiline-regex=codespell:off.*?(codespell:on|\Z)
|
||||
exclude: ^tools/(patcheck|clean-diff)|tests/checkasm/ext/.*$
|
||||
exclude: ^tools/(patcheck|clean-diff)$
|
||||
|
||||
@@ -69,7 +69,6 @@ pEvents
|
||||
PixelX
|
||||
Psot
|
||||
quater
|
||||
re-use
|
||||
readd
|
||||
recuse
|
||||
redY
|
||||
|
||||
@@ -22,7 +22,6 @@ jobs:
|
||||
with:
|
||||
configuration-path: .forgejo/labeler/labeler.yml
|
||||
repo-token: ${{ secrets.AUTOLABELER_TOKEN }}
|
||||
sync-labels: true
|
||||
- name: Label by title-match
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
|
||||
@@ -16,8 +16,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Rebase onto target branch
|
||||
uses: ./.forgejo/actions/rebase-pr
|
||||
- name: Install pre-commit CI
|
||||
id: install
|
||||
run: |
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/8.1
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
@@ -29,8 +29,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Rebase onto target branch
|
||||
uses: ./.forgejo/actions/rebase-pr
|
||||
- name: Configure
|
||||
run: |
|
||||
./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 \
|
||||
@@ -60,42 +58,26 @@ jobs:
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite-${{ steps.fate.outputs.hash }}
|
||||
- name: Inject PR Samples
|
||||
id: inject
|
||||
if: ${{ forge.event_name == 'pull_request' }}
|
||||
run: SAMPLES=$PWD/fate-suite .forgejo/inject-pr-samples.py ${{ forge.event.pull_request.number }}
|
||||
- name: Run Fate
|
||||
run: |
|
||||
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
|
||||
find . -name "*.err" -exec printf '::group::%s\n' {} \; -exec cat {} \; -exec printf '::endgroup::\n' \;
|
||||
exit ${FATERES:-0}
|
||||
- name: Fail if new samples were injected
|
||||
if: ${{ steps.inject.outputs.new_samples == 'true' }}
|
||||
run: |
|
||||
echo "New FATE samples were injected from PR attachments. Please add them to the official fate-suite before merging."
|
||||
exit 1
|
||||
run_fate_full:
|
||||
name: Fate (Full, ${{ matrix.target_exec }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: ['ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest']
|
||||
image: ['ghcr.io/btbn/ffmpeg-builds/win64-gpl-8.1:latest']
|
||||
target_exec: ['wine']
|
||||
runs-on: linux-amd64
|
||||
container: ${{ matrix.image }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ffmpeg
|
||||
- name: Rebase onto target branch
|
||||
uses: ./ffmpeg/.forgejo/actions/rebase-pr
|
||||
with:
|
||||
path: ffmpeg
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
../ffmpeg/configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \
|
||||
./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" \
|
||||
@@ -105,7 +87,7 @@ jobs:
|
||||
cat ffbuild/config.log
|
||||
exit ${CFGRES:-0}
|
||||
- name: Build
|
||||
run: make -C build -j$(nproc)
|
||||
run: make -j$(nproc)
|
||||
- name: Restore Cached Fate-Suite
|
||||
id: cache
|
||||
uses: actions/cache/restore@v5
|
||||
@@ -117,7 +99,7 @@ jobs:
|
||||
- name: Sync Fate-Suite
|
||||
id: fate
|
||||
run: |
|
||||
make -C build fate-rsync SAMPLES=$PWD/fate-suite
|
||||
make fate-rsync SAMPLES=$PWD/fate-suite
|
||||
echo "hash=$(find fate-suite -type f -printf "%P %s %T@\n" | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
|
||||
- name: Cache Fate-Suite
|
||||
uses: actions/cache/save@v5
|
||||
@@ -125,21 +107,12 @@ jobs:
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite-${{ steps.fate.outputs.hash }}
|
||||
- name: Inject PR Samples
|
||||
id: inject
|
||||
if: ${{ forge.event_name == 'pull_request' }}
|
||||
run: SAMPLES=$PWD/fate-suite ffmpeg/.forgejo/inject-pr-samples.py ${{ forge.event.pull_request.number }}
|
||||
- name: Run Fate
|
||||
run: |
|
||||
if [[ "${{ matrix.target_exec }}" == "wine" ]]; then
|
||||
export WINEDEBUG=-all
|
||||
export FREI0R_PATH="$(winepath -w "$FREI0R_PATH")"
|
||||
fi
|
||||
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make -C build fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
|
||||
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
|
||||
find . -name "*.err" -exec printf '::group::%s\n' {} \; -exec cat {} \; -exec printf '::endgroup::\n' \;
|
||||
exit ${FATERES:-0}
|
||||
- name: Fail if new samples were injected
|
||||
if: ${{ steps.inject.outputs.new_samples == 'true' }}
|
||||
run: |
|
||||
echo "New FATE samples were injected from PR attachments. Please add them to the official fate-suite before merging."
|
||||
exit 1
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
*.spv
|
||||
*.spv.c
|
||||
*.spv.gz
|
||||
*.gen.asm
|
||||
*.gen.c
|
||||
*.gen.S
|
||||
*.ptx
|
||||
*.ptx.c
|
||||
*.ptx.gz
|
||||
@@ -40,9 +37,6 @@
|
||||
/ffmpeg
|
||||
/ffplay
|
||||
/ffprobe
|
||||
/checkasm_config_generated.asm
|
||||
/checkasm_config_generated.h
|
||||
/checkasm_header_config_generated.h
|
||||
/config.asm
|
||||
/config.h
|
||||
/config_components.asm
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Note to Github users
|
||||
|
||||
Patches should be submitted to [Forgejo](https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls) or the [ffmpeg-devel mailing list](https://ffmpeg.org/mailman/listinfo/ffmpeg-devel) using `git format-patch` or `git send-email`. Github pull requests should be avoided because they are not part of our review process and **will be ignored**.
|
||||
|
||||
See [https://ffmpeg.org/developer.html#Contributing](https://ffmpeg.org/developer.html#Contributing) for more information.
|
||||
|
||||
@@ -1,32 +1,245 @@
|
||||
Entries are sorted chronologically from oldest to youngest within each release,
|
||||
releases are sorted from youngest to oldest.
|
||||
|
||||
version <next>:
|
||||
- extensively improved AAC encoder
|
||||
- APV Vulkan encoder
|
||||
|
||||
version 8.1.2:
|
||||
swscale/x86/rgb_2_rgb: fix uyvytoyuv422 overwrite on odd width
|
||||
swscale/aarch64: fix uyvy/yuyv to yuv420p/yuv422p on odd width
|
||||
avcodec/snowenc: fix SIGFPE in get_dc() when a block lies outside the plane
|
||||
avcodec/snowenc: fix out-of-bounds OBMC read in get_dc() for narrow planes
|
||||
(fforge/pr/23505) avformat/tls_gnutls:fix crash when connecting to peer
|
||||
libavcodec/jpeg2000htdec: remove trailing whitespace
|
||||
libavdevice/alsa.c: fix NULL pointer dereference
|
||||
avcodec/libjxlenc: check orientation tag metadata before reading
|
||||
avformat/icecast: reject CR/LF in metadata header values
|
||||
avfilter/avf_showspectrum: Fix allocation check
|
||||
avformat/sctp: add size check in sctp_read() matching sctp_write()
|
||||
avcodec/jpeg2000: Fix undefined behavior on ROI shift-up
|
||||
aacdec_usac_mps212: reject reserved freq_res value
|
||||
avcodec/aac/aacdec_usac_mps212: Off-by-one bounds check in ff_aac_ec_data_deci()
|
||||
Update for 8.1.2
|
||||
avcodec/snowenc: fix out-of-bounds memcpy in get_block_rd() for narrow planes
|
||||
avutil/eval: apply unary sign to print, squish, gauss and lerp
|
||||
avcodec/cbs_av1_syntax_template: reset seen_frame_header on sequence headers
|
||||
avfilter/convolution: compute user matrix products in unsigned
|
||||
avformat/mpegts: use av_fast_realloc() for prg
|
||||
avfilter/avf_showcwt: fix DIRECTION_DU EOF fill clearing the wrong rows
|
||||
avfilter/avf_showcwt: fix DIRECTION_RL EOF fill clearing the wrong columns
|
||||
avfilter/avf_showcwt: avoid undefined float to int conversion of nb_consumed_samples
|
||||
avfilter/avf_showcwt: fix out of array read in compute_kernel
|
||||
avfilter/v360: compute remap table offsets in 64bit
|
||||
avfilter/v360: reject out-of-range dimensions
|
||||
swresample/x86/resample: write only int16 in the int16 resampler
|
||||
avformat/rtpenc_amr: Check input size
|
||||
swscale/ppc: fix ASAN stack-buffer-overflow in yuv2planeX
|
||||
swscale/ppc: fix LOAD_FILTER overread in VSX path
|
||||
avcodec/sanm: reject codec37 frames taller than the allocated buffer
|
||||
avcodec/sanm: reject codec47 frames taller than the allocated buffer
|
||||
avfilter: use ff_slice_pos() for per-slice boundary computation
|
||||
avfilter: add ff_slice_pos() helper for slice boundaries
|
||||
(origin/release/8.1, fforge/release/8.1) avformat/iamf_writer: reject muxing PCM streams
|
||||
avfilter/estdif: avoid signed overflow in slice boundary calculation
|
||||
swscale: support sliced input with cascaded scaling contexts
|
||||
avformat/rtspdec: bound Content-Length in the ANNOUNCE handler to SDP_MAX_SIZE
|
||||
avcodec/cbs_h266_syntax_template: reject subpic info with res_change_in_clvs
|
||||
avcodec/misc4: Check nb channels
|
||||
avcodec/rv10, rv34: check init_get_bits8() before RealVideo bit access
|
||||
avformat/http: reject request-line tokens not terminated by whitespace
|
||||
avformat/mov: reject out of range ispe dimensions, avoid overflow summing HEIF tile dimensions
|
||||
avcodec/agm: validate actual src_y against prev plane in decode_inter_plane
|
||||
avformat/dhav: Fix second integer overflow in get_duration()
|
||||
fftools/ffmpeg_dec: deep-copy subtitle_header to fix use-after-free
|
||||
avcodec/hevc/ps: Check window parameters
|
||||
avcodec/hevc/ps: Factor window reading out
|
||||
avcodec/truespeech: reject iterations count whose * 240 product overflows 32-bit
|
||||
libavcodec/options_table: gamma22 and gamma28 aliases
|
||||
avcodec/on2avc: reject subframe count whose * SUBFRAME_SIZE product overflows 32-bit
|
||||
avfilter/zmq: initialize send_buf before shared cleanup on parse failure
|
||||
avcodec/adpcm: fix signed integer overflow in get_nb_samples()
|
||||
avformat/matroskadec: avoid signed overflow in DASH cue time differences
|
||||
avcodec/fastaudio: reject subframes count whose * 256 product overflows 32-bit
|
||||
avcodec/vc2enc_dwt: avoid signed overflow in the 9/7 DWT lifting
|
||||
avcodec/vc2enc_dwt: avoid signed overflow in the 5/3 and Haar DWT
|
||||
avformat/dashdec: Fail with any inner stream count being 0
|
||||
avcodec/mjpegdec: require progress in AVRn interlaced field loop
|
||||
avcodec/mwsc: do not dereference a missing reference frame
|
||||
avcodec/misc4: reject invalid sample rate
|
||||
swscale/output: avoid signed overflow in yuv2rgba64_1 alpha
|
||||
swscale/output: avoid signed overflow in yuv2rgba64_full_1 alpha
|
||||
tools/target_dem_fuzzer: do not exit on io_buffer allocation failure
|
||||
avformat/gxfenc: Check timecode and propagate error
|
||||
swscale/rgb2rgb_template: use unsigned for <<24
|
||||
avformat/iamf_parse: bound substream count by remaining OBU size
|
||||
avformat/matroskadec: bound TRACKENTRY parsing by max_streams
|
||||
avcodec/diracdec: fix heap buffer overflow in edge_emu_buffer
|
||||
avformat/rtmppkt: Check recursion depth
|
||||
avcodec/tdsc: propagate max_pixels to the JPEG tile decoder
|
||||
avcodec/imm5: propagate max_pixels to the H264/HEVC sub-decoders
|
||||
avcodec/cri: propagate max_pixels to the JPEG tile decoder
|
||||
avcodec/jpeglsdec: only apply color transform to decoded rows
|
||||
avcodec/adpcm: require block_align to be a multiple of channels in ADPCM_PSXC init
|
||||
avfilter/avf_showcwt: fix out-of-bounds read in du scroll
|
||||
avfilter/f_ebur128: avoid signed-int wrap when sizing per-channel cache
|
||||
avformat/mov: cap HEIF ICC profile copies via c*max_streams to bound CPU and memory
|
||||
avcodec/aac/aacdec_usac: reject explicit usacSamplingFrequency of 0
|
||||
avcodec/aac/aacdec_usac: avoid signed overflow in decode_tsd
|
||||
avcodec/aac/aacdec: reject decoded frame without a valid sample rate
|
||||
avformat/iff: check av_get_packet() result in ANIM branch
|
||||
avcodec/cbs_h266_syntax_template: Fix pps_exp_slice_height_in_ctus_minus1 range
|
||||
avfilter/vf_scale: split rational multiply
|
||||
avcodec/bsf/dts2pts: fix binary tree invariant violation on selective dec_poc
|
||||
avfilter/vf_drawtext: Avoid double free in glyph_enu_border_free()
|
||||
avfilter/vf_drawtext: plug error-path leaks in measure_text/draw_text
|
||||
avfilter/vf_drawtext: shape_text_hb() free allocated things on error
|
||||
avfilter/vf_drawtext: avoid double-free of aliased FT_Glyph in glyph_enu_free
|
||||
avfilter/vf_drawtext: don't double-free glyph that has been cached in tree
|
||||
avfilter/vf_drawtext: always check pixel_mode == FT_PIXEL_MODE_MONO
|
||||
avcodec/cook: bound subpacket channel sum against channel count
|
||||
avcodec/apv_decode: avoid using apv_cbc
|
||||
avformat/mxfdec: Remove unneeded check
|
||||
avformat/ftp: Check string used for RNTO
|
||||
avformat/ftp: Check for Telnet IAC characters and other non printable ASCII chars
|
||||
avformat/ftp: reject CR/LF in the URL path to prevent FTP command injection
|
||||
avcodec/jpeg2000dec: Clear header derived variables
|
||||
avcodec/bsf/smpte436m_to_eia608: properly frees stuff on errors in ff_smpte436m_to_eia608_filter()
|
||||
tests/checkasm/crc: retain offset values between calls
|
||||
avformat/avc: Adjust get_ue_golomb() to handle 32 bit
|
||||
avformat/whip: require remote DTLS fingerprint in SDP answer
|
||||
avcodec/x86/vorbisdsp: change cmpleps to cmpltps in inverse coupling
|
||||
avcodec/liboapvenc: derive and validate APV profile from pixel format
|
||||
avformat/dashdec: bound manifest reloads and fragment-open retries
|
||||
avfilter/af_join: fix wrong loop bound in buffer dedup (use-after-free)
|
||||
avcodec/nvenc: fix compatibility with Video Codec SDK 13.1
|
||||
avformat/mov: validate APV access unit length before passing to decoder
|
||||
avcodec/h264_slice: guard color_frame() against chroma-width underflow
|
||||
avcodec/magicyuv: reject slice_height misaligned with chroma vshift
|
||||
avcodec/magicyuv: Expand the s->interlaced slice-height sanity check
|
||||
avcodec/magicyuv: Fix 1 line MEDIAN slices
|
||||
avformat/mxfdec: zero-init Sony MPEG-4 extradata and add padding
|
||||
avformat/soxdec: Check sample_rate for nan
|
||||
tests/tiny_ssim: fixed mistake in ssim_c1 calculation
|
||||
avformat/hls: Check TIME-OFFSET value
|
||||
avformat/hls: Check url_offset and size
|
||||
avcodec/prores_raw: reject invalid tile alignment values
|
||||
avformat/ty: check rec_size
|
||||
avformat/ogg: Fix overflow and stale oggvorbis_private values
|
||||
avformat/rtpenc_xiph: bail out when the max payload size underflows
|
||||
avformat/rtpenc_aac: reject packets smaller than the ADTS header
|
||||
avcodec/jpeg2000dec: compute mask in decode_clnpass() like in decode_sigpass()
|
||||
avformat/flvdec: Check size at the top of the main loop
|
||||
avformat/vividas: fix misaligned access
|
||||
avformat/mccdec: dont pass NULL to bytestream2_put_buffer()
|
||||
avcodec/g2meet: The stack is EPIC_PIX_STACK_SIZE
|
||||
avcodec/h2645_sei: Initialize side data before deallocation
|
||||
avfilter/boxblur: Fix off by one errors
|
||||
avformat/assenc: Add the missing parentheses
|
||||
avcodec/diracdec: Enlarge `mctmp` to cover the worst-case `blheight·ybsep + yblen` rows, and break the MC loop when no output rows remain
|
||||
tools/zmqsend: free the AVBprint buffer after using it
|
||||
[Wave] Fix issues with unaligned metadata chunks.
|
||||
avformat/mpegts: Dont assume fc->priv_data is a MpegTSContext
|
||||
fftools/graph: Add missing include "libavutil/mem.h" for fftools/graph/graphprint.c
|
||||
avcodec/cbs_h266_syntax_template: tighten sh_num_tiles_in_slice_minus1 upper bound
|
||||
avcodec/hevc: limit missing-ref fill to coded planes
|
||||
avformat/mov: Fix negative index given to can_seek_to_key_sample()
|
||||
avcodec/hdrdec: fix pixel count decrement in RLE decompress loop
|
||||
(fforge/pr/23464) forgejo/workflows: update test workflow for 8.1 release
|
||||
(fforge/pr/23445) aarch64: vp9lpf: Fix GCS violations
|
||||
(fforge/pr/23303) avformat/mov: don't abort on unsupported or invalid chnl boxes
|
||||
avformat/mov_chan: keep the layout untouched on chan/chnl box failure
|
||||
(fforge/pr/23240) avformat/oggparsevorbis.c: Prevent integer overflow when summing header lengths; add bounds check.
|
||||
(fforge/pr/23187) avformat/oggparsecelt: bound extra_headers to avoid an effectively infinite loop
|
||||
(fforge/pr/23111) avformat/demux: use correct close function for custom io
|
||||
avformat/hlsenc: use correct close function for custom io
|
||||
avformat/hlsenc: respect io_open set in AVFormatContext
|
||||
avformat/dashenc: respect io_open set in AVFormatContext
|
||||
avformat/dashdec: respect io_open set in AVFormatContext
|
||||
vulkan: fix using encode caps before querying
|
||||
avformat/rtpdec_av1: fix buffer overflow due to variable confusion
|
||||
|
||||
|
||||
version 9.0:
|
||||
- Extend AMF Color Converter (vf_vpp_amf) HDR capabilities
|
||||
- LCEVC track muxing support in MP4 muxer
|
||||
- Playdate video encoder and muxer
|
||||
- Add v360_vulkan filter
|
||||
- HE-AAC 960 decoding (DAB+)
|
||||
- transpose_cuda filter
|
||||
- Add AMF Frame Rate Converter (vf_frc_amf) filter
|
||||
- SMPTE 2094-50 metadata support and passthrough
|
||||
- ProRes RAW VideoToolbox hwaccel
|
||||
- APV Vulkan hwaccel
|
||||
- Animated WebP decoder
|
||||
- Animated WebP demuxer
|
||||
- Remove CELT decoding support (doesn't affect Opus CELT)
|
||||
- Remove ogg/celt parsing
|
||||
- Bitstream filter to split Dolby Vision multi-layer HEVC
|
||||
- Add AMF hardware memory mapping support.
|
||||
- ONNX Runtime DNN backend with GPU execution provider support
|
||||
- Remove deprecated NVENC options and support for pre-11.1 SDK versions
|
||||
- iTerm2 inline image protocol muxer
|
||||
|
||||
version 8.1.1:
|
||||
avcodec/aac/aacdec_usac_mps212: fix attach_lsb() OOB after huff_decode
|
||||
avcodec/dfpwmdec: Check nb_samples
|
||||
avcodec/alsdec: do not set nbits invalidly
|
||||
swscale/swscale_unscaled: adjust last line copy
|
||||
swscale/swscale: Check srcSliceY and srcSliceH
|
||||
avformat/avidec: check LIST size in avi_load_index()
|
||||
avformat/avidec: validate INFO list size before parsing
|
||||
avformat/matroskadec: Check audio.sub_packet_h * audio.frame_size
|
||||
libavformat/xwma: fix overflow in seek position
|
||||
avformat/pcm: Use 64bit for byte_rate
|
||||
avcodec/adpcm: signed integer overflow in ADPCM_N64
|
||||
avcodec/hevc/ps: validate rep_format dimensions in multi-layer SPS
|
||||
avfilter/vf_kerndeint: Check for minimum height
|
||||
avcodec/ralf: Add the missing return statement after the error log
|
||||
avfilter/vf_codecview: Clamp block to the visible frame region
|
||||
avcodec/zmbv: reject XOR data that overruns the decompression buffer
|
||||
avcodec/rasc: fix heap use-after-free in decode_move()
|
||||
avformat/rtpdec_mpeg4: reject zero-length AU header sections
|
||||
avcodec/hevc/refs: Check multiplication in alloc_frame()
|
||||
fftools/ffmpeg_opt: validate stream index in negative map handling
|
||||
avformat/rtmpproto: prevent integer overflow accumulating FLV buffer size
|
||||
avformat/rtmpproto: validate compressed SWF header length
|
||||
avformat/rtsp: Fix out-of-bounds read in SDP parser when control_url is empty
|
||||
avformat/rtpdec_latm: avoid integer overflow in LATM length parsing
|
||||
avcodec/h264: recompute per-slice direct mode state for every slice
|
||||
avcodec/h264_refs: Clear stale pointers from ref_list
|
||||
avcodec/pdvdec: Check input space before buffer allocation
|
||||
avformat/concat: guard total_size overflow
|
||||
avformat/iamf_parse.c: Fix potential integer overflow in opus_decoder_config()
|
||||
avcodec/wmaenc: Fix missing padding in extradata
|
||||
avformat: Fix various extradata padding issues
|
||||
avcodec/tdsc: remove double stride adjustment
|
||||
avformat/cafdec: fix negative index use in read_seek
|
||||
avcodec/notchlc: Check 255 loops
|
||||
avformat/rtpdec_jpeg: check qtable_len
|
||||
avformat/vividas: use-of-uninitialized-value in keybuffer
|
||||
avcodec/tdsc: Check jpeg size
|
||||
avcodec/tdsc: Better input size check
|
||||
avcodec/tdsc: Check tile_size
|
||||
avcodec/decode: Better documentation for ff_set_dimensions()
|
||||
avformat/mov: Limit maximum box size for mov_read_lhvc()
|
||||
avformat/mov: reject dimg references with zero entries
|
||||
avformat/mov: check extradata in mov_read_dops()
|
||||
avformat/mov: Check read size for opus extradata
|
||||
avformat/rtspdec: reject non-positive ANNOUNCE Content-Length
|
||||
avformat/wavdec: Fix use-of-uninitialized-value in find_guid()
|
||||
lavfi: vf_drawtext: check memory allocation
|
||||
avcodec/svq1dec: Check input space for minimum
|
||||
avcodec/vp9: Rollback dimensions when format is rejected
|
||||
avformat/rtpdec_qdm2: Check block_size
|
||||
avfilter/vf_ssim360: fix integer overflow in tape_length allocation
|
||||
avcodec/escape130: Initialize old_y_avg
|
||||
avutil/samplefmt: Dont claim that av_get_sample_fmt_string checks sample_fmt
|
||||
swscale: fix signed integer overflow in color conversion arithmetic
|
||||
avformat: check avio_read() return values in dss/dtshd/mlv
|
||||
avformat/whip: check RTP history packet size before RTX retransmission
|
||||
avcodec/aac/aacdec_usac: Implement missing bits of otts_bands_phase and residual_bands computation
|
||||
avcodec/alsdec: preserve full float value in zero-truncated samples
|
||||
avcodec/alsdec: propagate read_diff_float_data() errors in read_frame_data()
|
||||
avcodec/alsdec: fix mantissa unpacking in compressed Part A path
|
||||
avfilter/vf_drawtext: fix newline rendered as .notdef glyph
|
||||
avcodec/pngdec: fix dead overflow check in decode_text_to_exif()
|
||||
avcodec/vp9: fix cbs fragment leak on error
|
||||
libavfilter/vf_v360: fix operator precedence in stereo loop condition
|
||||
avcodec/alsdec: fix abs(INT_MIN) UB in read_diff_float_data()
|
||||
avformat/rsd: reject short ADPCM_THP extradata reads
|
||||
avformat/mov: Handle integer overflow in MOV parser
|
||||
avcodec/dvdsub_parser: Fix buf_size check
|
||||
avfilter/af_pan: fix sscanf() return value checks in parse_channel_name
|
||||
avutil/bswap: fix implicit conversion warning in av_bswap64
|
||||
avcodec/h2645_sei: don't use provider_code uninitialized
|
||||
(fforge/pr/22943) avformat/hls_sample_encryption: add missing padding for audio setup buffer
|
||||
(fforge/pr/22826) lavc/videotoolbox_vp9: fix vpcC flags offset
|
||||
lavc/videotoolboxenc: return SEI parse errors
|
||||
vulkan: fix encode feedback query handling
|
||||
avcodec/cbs_lcevc: fix writing process blocks with size 6
|
||||
avformat/mov: don't try to create an LCEVC group if there's a single track
|
||||
(fforge/pr/22563) aarch64: Add Armv9.3-A GCS (Guarded Control Stack) support
|
||||
aarch64: hevcdsp: Make returns match the call site
|
||||
(fforge/pr/22545) avcodec/lcevcdec: don't try to derive final dimensions from SAR
|
||||
avcodec/lcevc_parser: move the resolution type table to a header
|
||||
avcodec/cbs_lcevc: don't look for process blocks if the unit was not decomposed
|
||||
|
||||
version 8.1:
|
||||
- ffprobe -codec option
|
||||
|
||||
+10
-6
@@ -1,4 +1,4 @@
|
||||
# Installing FFmpeg
|
||||
## Installing FFmpeg
|
||||
|
||||
0. If you like to include source plugins, merge them before configure
|
||||
for example run tools/merge-all-source-plugins
|
||||
@@ -14,11 +14,15 @@ path when launching `configure`, e.g. `/ffmpegdir/ffmpeg/configure`.
|
||||
|
||||
3. Type `make install` to install all binaries and libraries you built.
|
||||
|
||||
## NOTICE
|
||||
NOTICE
|
||||
------
|
||||
|
||||
- Non system dependencies (e.g. libx264, libvpx) are disabled by default.
|
||||
- Non system dependencies (e.g. libx264, libvpx) are disabled by default.
|
||||
|
||||
## NOTICE for Package Maintainers
|
||||
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.
|
||||
- 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.
|
||||
|
||||
+8
-17
@@ -65,14 +65,14 @@ Communication
|
||||
=============
|
||||
website (T: https://git.ffmpeg.org/ffmpeg-web) Deby Barbara Lepage
|
||||
fate.ffmpeg.org (L: fate-admin@ffmpeg.org) (W: https://fate.ffmpeg.org) (P: https://ffmpeg.org/fate.html) (S: https://git.ffmpeg.org/fateserver) Timo Rothenpieler
|
||||
Trac bug tracker [X] (W: https://trac.ffmpeg.org) Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos
|
||||
Forgejo issue tracker (W: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues)
|
||||
Trac bug tracker (W: https://trac.ffmpeg.org) Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos
|
||||
Patchwork [2] (W: https://patchwork.ffmpeg.org) Andriy Gelman
|
||||
mailing lists (W: https://ffmpeg.org/contact.html#MailingLists) Baptiste Coudurier
|
||||
Twitter Reynaldo H. Verdejo Pinochet
|
||||
Launchpad Timothy Gu
|
||||
ffmpeg-security [2] (L: ffmpeg-security@ffmpeg.org) (W: https://ffmpeg.org/security.html) Michael Niedermayer, Reimar Doeffinger
|
||||
|
||||
|
||||
libavutil
|
||||
=========
|
||||
|
||||
@@ -93,7 +93,6 @@ Other:
|
||||
hash Reimar Doeffinger
|
||||
hwcontext_cuda* Timo Rothenpieler
|
||||
hwcontext_d3d12va* Wu Jianhua
|
||||
hwcontext_oh* Zhao Zhili
|
||||
hwcontext_vulkan* [2] Lynne
|
||||
intfloat* Michael Niedermayer
|
||||
integer.c, integer.h Michael Niedermayer
|
||||
@@ -159,7 +158,7 @@ Codecs:
|
||||
asv* Michael Niedermayer
|
||||
atrac3plus* Maxim Poliakovski
|
||||
audiotoolbox* rcombs
|
||||
avs2* Huiwen Ren, Zhao Zhili
|
||||
avs2* Huiwen Ren
|
||||
bgmc.c, bgmc.h Thilo Borgmann
|
||||
binkaudio.c Peter Ross
|
||||
cavs* Stefan Gehrer
|
||||
@@ -233,7 +232,7 @@ Codecs:
|
||||
msvideo1.c Mike Melanson
|
||||
nuv.c Reimar Doeffinger
|
||||
nvdec*, nvenc* Timo Rothenpieler
|
||||
oh* Zhao Zhili
|
||||
omx.c Martin Storsjo, Aman Gupta
|
||||
opus* Rostislav Pehlivanov
|
||||
pcx.c Ivo van Poorten
|
||||
pgssubdec.c Reimar Doeffinger
|
||||
@@ -244,7 +243,6 @@ Codecs:
|
||||
qtrle.c Mike Melanson
|
||||
ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni
|
||||
resample2.c Michael Niedermayer
|
||||
rkmppenc* Zhao Zhili
|
||||
rl2.c Sascha Sommer
|
||||
rpza.c Roberto Togni
|
||||
rtjpeg.c, rtjpeg.h Reimar Doeffinger
|
||||
@@ -252,6 +250,7 @@ Codecs:
|
||||
sanm.c Manuel Lauss
|
||||
smc.c Mike Melanson
|
||||
snow* Michael Niedermayer, Loren Merritt
|
||||
sonic.c Alex Beregszaszi
|
||||
speedhq.c Steinar H. Gunderson
|
||||
srt* Aurelien Jacobs
|
||||
sunrast.c Ivo van Poorten
|
||||
@@ -318,10 +317,6 @@ libavfilter
|
||||
===========
|
||||
|
||||
Generic parts:
|
||||
|
||||
Framework and orphaned filters Nicolas George
|
||||
(except hardware acceleration)
|
||||
|
||||
graphdump.c Nicolas George
|
||||
|
||||
motion_estimation.c Davinder Singh
|
||||
@@ -353,9 +348,7 @@ Filters:
|
||||
vf_minterpolate.c Davinder Singh
|
||||
vf_readvitc.c Tobias Rapp (CC t.rapp at noa-archive dot com)
|
||||
vf_scale.c [2] Michael Niedermayer
|
||||
vf_scale_vt.c Zhao Zhili
|
||||
vf_tonemap_opencl.c Ruiling Song
|
||||
vf_transpose_vt.c Zhao Zhili
|
||||
vf_yadif.c [2] Michael Niedermayer
|
||||
vf_xfade_vulkan.c [2] Marvin Scholz (CC <epirat07@gmail.com>)
|
||||
|
||||
@@ -413,9 +406,7 @@ Muxers/Demuxers:
|
||||
flvenc.c Michael Niedermayer, Steven Liu
|
||||
gxf.c Reimar Doeffinger
|
||||
gxfenc.c Baptiste Coudurier
|
||||
hls.c Kacper Michajłow
|
||||
hlsenc.c Christian Suloway, Steven Liu
|
||||
hxvs.c Zhao Zhili
|
||||
iamf* [2] James Almer
|
||||
idcin.c Mike Melanson
|
||||
idroqdec.c Mike Melanson
|
||||
@@ -451,9 +442,9 @@ Muxers/Demuxers:
|
||||
nsvdec.c Francois Revol
|
||||
nut* Michael Niedermayer
|
||||
nuv.c Reimar Doeffinger
|
||||
oggdec.c, oggdec.h David Conrad, Romain Beauxis
|
||||
oggenc.c Baptiste Coudurier, Romain Beauxis
|
||||
oggparse*.c David Conrad, Romain Beauxis
|
||||
oggdec.c, oggdec.h David Conrad
|
||||
oggenc.c Baptiste Coudurier
|
||||
oggparse*.c David Conrad
|
||||
oma.c Maxim Poliakovski
|
||||
pp_bnk.c Zane van Iperen
|
||||
psxstr.c Mike Melanson
|
||||
|
||||
@@ -106,7 +106,7 @@ ffbuild/.config: $(CONFIGURABLE_COMPONENTS)
|
||||
@-printf '\nWARNING: $(?) newer than config_components.h, rerun configure\n\n'
|
||||
@-tput sgr0 2>/dev/null
|
||||
|
||||
SUBDIR_VARS := CLEANFILES FFLIBS DEVPROGS HOSTPROGS TESTPROGS TOOLS \
|
||||
SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \
|
||||
HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \
|
||||
ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \
|
||||
ALTIVEC-OBJS VSX-OBJS X86ASM-OBJS \
|
||||
@@ -143,10 +143,8 @@ ifeq ($(STRIPTYPE),direct)
|
||||
else
|
||||
$(RM) $@
|
||||
$(CP) $< $@
|
||||
ifneq ($(STRIPTYPE),nostrip)
|
||||
$(STRIP) $@
|
||||
endif
|
||||
endif
|
||||
|
||||
%$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS))
|
||||
@@ -189,8 +187,7 @@ clean::
|
||||
$(RM) -rf coverage.info coverage.info.in lcov
|
||||
|
||||
distclean:: clean
|
||||
$(RM) .version config.asm config.h config_components.* mapfile \
|
||||
checkasm_config_generated.* checkasm_header_config_generated.h \
|
||||
$(RM) .version config.asm config.h config_components.* mapfile \
|
||||
ffbuild/.config ffbuild/config.* libavutil/avconfig.h \
|
||||
version.h libavutil/ffversion.h libavcodec/codec_names.h \
|
||||
libavcodec/bsf_list.c libavformat/protocol_list.c \
|
||||
@@ -205,8 +202,8 @@ endif
|
||||
config:
|
||||
$(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION)
|
||||
|
||||
build: all alltools devprogs examples testprogs
|
||||
check: all alltools devprogs examples testprogs fate
|
||||
build: all alltools examples testprogs
|
||||
check: all alltools examples testprogs fate
|
||||
|
||||
include $(SRC_PATH)/tests/Makefile
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# FFmpeg README
|
||||
FFmpeg README
|
||||
=============
|
||||
|
||||
FFmpeg is a collection of libraries and tools to process multimedia content
|
||||
such as audio, video, subtitles and related metadata.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
┌──────────────────────────────────────┐
|
||||
│ RELEASE NOTES for FFmpeg 8.1 "Hoare" │
|
||||
└──────────────────────────────────────┘
|
||||
|
||||
The FFmpeg Project proudly presents FFmpeg 8.1 "Hoare", about 7
|
||||
months after the release of FFmpeg 8.0.
|
||||
|
||||
A complete Changelog is available at the root of the project, and the
|
||||
complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git
|
||||
|
||||
We hope you will like this release as much as we enjoyed working on it, and
|
||||
as usual, if you have any questions about it, or any FFmpeg related topic,
|
||||
feel free to join us on the #ffmpeg IRC channel (on irc.libera.chat) or ask
|
||||
on the mailing-lists.
|
||||
@@ -182,7 +182,6 @@ static inline __device__ float fabsf(float a) { return __builtin_fabsf(a); }
|
||||
static inline __device__ float fabs(float a) { return __builtin_fabsf(a); }
|
||||
static inline __device__ double fabs(double a) { return __builtin_fabs(a); }
|
||||
static inline __device__ float sqrtf(float a) { return __builtin_sqrtf(a); }
|
||||
static inline __device__ float rintf(float a) { return __builtin_rintf(a); }
|
||||
|
||||
static inline __device__ float __saturatef(float a) { return __nvvm_saturate_f(a); }
|
||||
static inline __device__ float __sinf(float a) { return __nvvm_sin_approx_f(a); }
|
||||
|
||||
@@ -33,11 +33,6 @@ if [ ! -f "$vscript" ]; then
|
||||
fi
|
||||
|
||||
for object in "$@"; do
|
||||
case "$object" in
|
||||
@*)
|
||||
object="${object#@}"
|
||||
;;
|
||||
esac
|
||||
if [ ! -f "$object" ]; then
|
||||
echo "Object does not exist: ${object}" >&2
|
||||
exit 1
|
||||
|
||||
+2
-68
@@ -1,77 +1,11 @@
|
||||
The last version increases of all libraries were on 2026-06-23.
|
||||
The last version increases of all libraries were on 2025-03-28
|
||||
|
||||
API changes, most recent first:
|
||||
|
||||
2026-06-23 - 61693f6c35f - lavu 60.34.100 - hwcontext_vulkan.h
|
||||
Switch AVVkFrame.access to VkAccessFlagBits2.
|
||||
|
||||
2026-06-23 - 191be14fb6d - lavc 62.37.100 - packet.h
|
||||
av_packet_pack_dictionary() now accepts const AVDictionary*.
|
||||
|
||||
2026-06-10 - 12dc67b6fe0 - lavu 60.33.100 - frame.h
|
||||
Add AV_FRAME_DATA_RAW_COLOR_PARAMS.
|
||||
|
||||
2026-06-03 - 972c0cf91f4 - lsws 9.8.100 - swscale.h
|
||||
Add enum SwsBackend and SwsContext.backends
|
||||
|
||||
2026-06-02 - 9fe5758da5c - lavu 60.32.100 - hwcontext_vulkan.h
|
||||
Add AVVulkanDeviceContext.queue_flags.
|
||||
|
||||
2026-05-31 - 1e3883df9f0 - lavf 62.19.100 - avformat.h
|
||||
Add AVStreamGroupLayeredVideo
|
||||
Add AVStreamGroup.params.layered_video
|
||||
Add AV_STREAM_GROUP_PARAMS_DOLBY_VISION
|
||||
Deprecate AVStreamGroupLCEVC
|
||||
Deprecate AVStreamGroup.params.lcevc
|
||||
|
||||
2026-05-30 - 5f6dff5e7db - lavc 62.35.100 - packet.h
|
||||
Add AV_PKT_DATA_HEVC_CONF side data type.
|
||||
|
||||
2026-05-14 - xxxxxxxxxxx - lavf 62.18.100 - avformat.h
|
||||
Add AV_FDEBUG_ID3V2 debug flag, deprecate FF_FDEBUG_TS in favor of
|
||||
AV_FDEBUG_TS.
|
||||
|
||||
2026-05-17 - a5822fca94f - lavf 62.17.100 - avformat.h
|
||||
Add AV_STREAM_GROUP_PARAMS_TREF.
|
||||
Add AVStreamGroupTREF.
|
||||
|
||||
2026-05-16 - c0bdc3b62a5 - lavf 62.16.100 - avformat.h
|
||||
Add AVFMT_FIXED_FRAMESIZE.
|
||||
|
||||
2026-05-16 - b1120b1ed80 - lavc 62.33.100 - avcodec.h
|
||||
Add AV_CODEC_FLAG2_FIXED_FRAME_SIZE.
|
||||
|
||||
2026-05-12 - 99908c6e05e - lavu 60.31.100 - frame.h
|
||||
Add IAMF frame side data types to enum AVFrameSideDataType:
|
||||
- AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM
|
||||
- AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM
|
||||
- AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM
|
||||
|
||||
2026-05-05 - 5c557dd5d55 - lavf 62.15.100 - avformat.h
|
||||
Add av_program_copy().
|
||||
|
||||
2026-05-05 - 7623379a770 - lavf 62.14.100 - avformat.h
|
||||
Add av_program_add_stream_index2().
|
||||
|
||||
2026-04-14 - 7faa6ee2aa - lavc 62.30.100 - packet.h
|
||||
Add AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.
|
||||
|
||||
2026-04-09 - 6ba6db4f19 - lavu 60.30.100 - hdr_dynamic_metadata.h frame.h
|
||||
Add AVDynamicHDRSmpte2094App5 struct and functions.
|
||||
Add AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.
|
||||
|
||||
2026-03-14 - c102e89448a - lavu 60.29.100 - hwcontext_vulkan.h
|
||||
2026-03-14 - xxxxxxxxxx - lavu 60.26.100 - hwcontext_vulkan.h
|
||||
Deprecate AVVulkanDeviceContext.lock_queue and
|
||||
AVVulkanDeviceContext.unlock_queue without replacement.
|
||||
|
||||
2026-03-12 - 3503b19711c - lsws 9.7.100 - swscale.h
|
||||
Add enum SwsScaler, and SwsContext.scaler/scaler_sub.
|
||||
|
||||
2026-03-11 - 910000fe59d - lavu 60.28.100 - hwcontext_amf.h
|
||||
Add av_amf_display_mastering_meta_to_hdrmeta(), av_amf_light_metadata_to_hdrmeta().
|
||||
Add av_amf_extract_hdr_metadata(), av_amf_attach_hdr_metadata().
|
||||
Add av_amf_get_color_profile().
|
||||
|
||||
2026-03-07 - c23d56b173a - lavc 62.26.100 - codec_desc.h
|
||||
Add AV_CODEC_PROP_ENHANCEMENT.
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
This document is work in progress
|
||||
|
||||
*What is CVSS*
|
||||
The Common Vulnerability Scoring System (CVSS) is an open, industry-standard framework used to measure and communicate the severity of software vulnerabilities, ranging from 0.0 to 10.0.
|
||||
|
||||
*Why we need this Document*
|
||||
It is important that FFmpeg CVEs have consistent and correct CVSS, not only for the obvious reason that one can recognize the severity of an issue at first glance.
|
||||
But also as these numbers form the basis of rewards paid in bug bounty systems. Inconsistent CVSS could lead to unfair payouts.
|
||||
|
||||
*What is this Document*
|
||||
Prior 2026, FFmpeg had no guideline about CVSS.
|
||||
This document describes how to select the CVSS for a FFmpeg related CVE. It currently only covers the Base Score.
|
||||
|
||||
*What is the CVSS Base Score*
|
||||
AV Attack Vector (Network, Adjacent, Local, Physical)
|
||||
AC Attack Complexity (Low, High)
|
||||
PR Privileges Required (None, Low, High)
|
||||
UI User Interaction (None, Required)
|
||||
S Scope (Unchanged, Changed)
|
||||
C Confidentiality (None, Low, High)
|
||||
I Integrity (None, Low, High)
|
||||
A Availability (None, Low, High)
|
||||
|
||||
|
||||
*Things people have set incorrectly*
|
||||
|
||||
Below are general guidelines and in specific cases other things may apply.
|
||||
|
||||
Attack Vector.
|
||||
Quote from https://www.first.org/cvss/v3.1/user-guide
|
||||
"Specifically, analysts should only score for Network or Adjacent when a vulnerability is bound to the network stack.
|
||||
Vulnerabilities which require user interaction to download or receive malicious content (which could also be delivered locally, e.g., via USB drives) should be scored as Local."
|
||||
|
||||
Availability.
|
||||
FFmpeg Crashes -> AVAILABILITY IMPACT: Low
|
||||
FFmpeg is frequently used as a short-lived, single-run process instead of a continuously running service that handles ongoing streams of user input. In that usage model, a crash usually causes only limited disruption.
|
||||
|
||||
User Interaction
|
||||
Please consider if an attacker can actually set the parameters required for an attack.
|
||||
In general arbitrary filter parameters cannot be set by an attacker and require the user/account owner/admin to set them
|
||||
+1
-1
@@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = 8.1.2
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
+3
-3
@@ -54,7 +54,7 @@ TEXIDEP = perl $(SRC_PATH)/doc/texidep.pl $(SRC_PATH) $< $@ >$(@:%=%.d)
|
||||
doc/%.txt: TAG = TXT
|
||||
doc/%.txt: doc/%.texi
|
||||
$(Q)$(TEXIDEP)
|
||||
$(M)$(MAKEINFO) --force --no-headers -o $@ $< 2>/dev/null
|
||||
$(M)makeinfo --force --no-headers -o $@ $< 2>/dev/null
|
||||
|
||||
GENTEXI = format codec
|
||||
GENTEXI := $(GENTEXI:%=doc/avoptions_%.texi)
|
||||
@@ -69,11 +69,11 @@ doc/%-all.html: TAG = HTML
|
||||
ifdef HAVE_MAKEINFO_HTML
|
||||
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
|
||||
$(Q)$(TEXIDEP)
|
||||
$(M)$(MAKEINFO) --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||
$(M)makeinfo --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||
|
||||
doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
|
||||
$(Q)$(TEXIDEP)
|
||||
$(M)$(MAKEINFO) --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||
$(M)makeinfo --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
|
||||
else
|
||||
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
|
||||
$(Q)$(TEXIDEP)
|
||||
|
||||
@@ -124,33 +124,6 @@ that this level currently behaves the same as @samp{limited} in libavcodec.
|
||||
@end table
|
||||
@end table
|
||||
|
||||
@section dovi_split
|
||||
|
||||
Split a Dolby Vision Profile 7 multi-layer HEVC bitstream. Profile 7 carries the
|
||||
enhancement-layer HEVC bitstream interleaved inside the base-layer access units,
|
||||
wrapped in user-unspecified NAL units of type 63 (UNSPEC63), and the RPU metadata
|
||||
as a sibling user-unspecified NAL of type 62 (UNSPEC62).
|
||||
|
||||
@table @option
|
||||
@item mode
|
||||
Which Dolby Vision components to keep in the output bitstream.
|
||||
@table @samp
|
||||
@item bl
|
||||
Base layer only: drop every UNSPEC63 (EL) and every UNSPEC62 (RPU).
|
||||
The output is a plain HEVC stream with no Dolby Vision markers. This is the
|
||||
default.
|
||||
@item bl_rpu
|
||||
Base layer with the RPU NAL kept.
|
||||
@item el
|
||||
Enhancement layer only: for every UNSPEC63 NAL, strip the two-byte outer NAL
|
||||
header and emit the inner payload. The result is a standalone HEVC bitstream.
|
||||
UNSPEC62 (RPU) is dropped.
|
||||
@item el_rpu
|
||||
Enhancement layer with the RPU NAL kept verbatim. Same as @samp{el}, but the
|
||||
UNSPEC62 RPU NALs are also emitted alongside the unwrapped EL NALs.
|
||||
@end table
|
||||
@end table
|
||||
|
||||
@section dump_extra
|
||||
|
||||
Add extradata to the beginning of the filtered packets except when
|
||||
|
||||
@@ -7,6 +7,11 @@ V
|
||||
Disable the default terse mode, the full command issued by make and its
|
||||
output will be shown on the screen.
|
||||
|
||||
DBG
|
||||
Preprocess x86 external assembler files to a .dbg.asm file in the object
|
||||
directory, which then gets compiled. Helps in developing those assembler
|
||||
files.
|
||||
|
||||
DESTDIR
|
||||
Destination directory for the install targets, useful to prepare packages
|
||||
or install FFmpeg in cross-environments.
|
||||
|
||||
@@ -646,8 +646,6 @@ Do not skip samples and export skip information as frame side data.
|
||||
Do not reset ASS ReadOrder field on flush.
|
||||
@item icc_profiles
|
||||
Generate/parse embedded ICC profiles from/to colorimetry tags.
|
||||
@item fixed_frame_size
|
||||
Force audio encoders to use a fixed frame size.
|
||||
@end table
|
||||
|
||||
@item export_side_data @var{flags} (@emph{decoding/encoding,audio,video,subtitles})
|
||||
|
||||
@@ -307,6 +307,14 @@ This decoder generates wave patterns according to predefined sequences. Its
|
||||
use is purely internal and the format of the data it accepts is not publicly
|
||||
documented.
|
||||
|
||||
@section libcelt
|
||||
|
||||
libcelt decoder wrapper.
|
||||
|
||||
libcelt allows libavcodec to decode the Xiph CELT ultra-low delay audio codec.
|
||||
Requires the presence of the libcelt headers and library during configuration.
|
||||
You need to explicitly configure the build with @code{--enable-libcelt}.
|
||||
|
||||
@section libgsm
|
||||
|
||||
libgsm decoder wrapper.
|
||||
|
||||
@@ -1181,51 +1181,10 @@ RIFF Wave Audio demuxer.
|
||||
|
||||
This demuxer accepts the following options:
|
||||
@table @option
|
||||
@item ignore_length @var{bool}
|
||||
Ignore the size of the @code{data} chunk and keep reading until the end of the file if set.
|
||||
May be useful to read broken or partial files where the header was not properly updated,
|
||||
but will misinterpret files with non-audio chunks after the @code{data} chunk.
|
||||
Default is disabled.
|
||||
|
||||
@item max_size
|
||||
Specify the maximum packet size in bytes for the demuxed packets. By default
|
||||
this is set to 0, which means that a sensible value is chosen based on the
|
||||
input format.
|
||||
@end table
|
||||
|
||||
@section webp
|
||||
|
||||
Animated WebP demuxer.
|
||||
|
||||
It accepts the following options:
|
||||
|
||||
@table @option
|
||||
@item -min_delay @var{int}
|
||||
Set the minimum valid delay between frames in milliseconds.
|
||||
Range is 0 to 60000. Default value is 10.
|
||||
|
||||
@item -max_webp_delay @var{int}
|
||||
Set the maximum valid delay between frames in milliseconds.
|
||||
Range is 0 to 16777215. Default value is 16777215 (over four hours),
|
||||
the maximum value allowed by the specification.
|
||||
|
||||
@item -default_delay @var{int}
|
||||
Set the default delay between frames in milliseconds.
|
||||
Range is 0 to 60000. Default value is 100.
|
||||
|
||||
@item -ignore_loop @var{bool}
|
||||
WebP files can contain information to loop a certain number of times
|
||||
(or infinitely). If @option{ignore_loop} is set to true, then the loop
|
||||
setting from the input will be ignored and looping will not occur.
|
||||
If set to false, then looping will occur and will cycle the number
|
||||
of times according to the WebP. Default value is true.
|
||||
|
||||
@item usebgcolor @var{bool}
|
||||
WebP files contain a background color hint in the ANIM chunk, but the
|
||||
WebP specification says that viewer applications are not required to
|
||||
use it. If @option{usebgcolor} is set to true, then the background
|
||||
color hint will be used, otherwise transparent black will be used for
|
||||
the background. Default value is false.
|
||||
@end table
|
||||
|
||||
@c man end DEMUXERS
|
||||
|
||||
+4
-33
@@ -225,25 +225,6 @@ AVStream *stream;
|
||||
AVStream* stream;
|
||||
@end example
|
||||
|
||||
@item
|
||||
When sensible, prefer a narrow variable scope, especially in for loops:
|
||||
|
||||
@example c, good
|
||||
// Good
|
||||
for (unsigned i = 0; i < submix->nb_elements; i++) @{
|
||||
// Do something...
|
||||
@}
|
||||
@end example
|
||||
|
||||
@example c, bad
|
||||
// Bad style
|
||||
unsigned i;
|
||||
//...
|
||||
for (i = 0; i < submix->nb_elements; i++) @{
|
||||
// Do something...
|
||||
@}
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
|
||||
If you work on a file that does not follow these guidelines consistently,
|
||||
@@ -387,7 +368,7 @@ symbols. If in doubt, just avoid names starting with @code{_} altogether.
|
||||
Casts should be used only when necessary. Unneeded parentheses
|
||||
should also be avoided if they don't make the code easier to understand.
|
||||
@item
|
||||
Where applicable, SI units shall be used. For example timeouts should use seconds as the fundamental unit not microseconds.
|
||||
Where applicable, SI units shall be used. For example timeouts should use seconds as the fundamental unit not micro seconds.
|
||||
That means a bare value like @samp{1.0} must mean 1 second, @samp{50m} means 50 milliseconds. For weight, gram shall be used.
|
||||
@end itemize
|
||||
|
||||
@@ -488,25 +469,15 @@ later on.
|
||||
Also if you have doubts about splitting or not splitting, do not hesitate to
|
||||
ask/discuss it on the developer mailing list.
|
||||
|
||||
@subheading Bug fixes intended for backporting should stay focused.
|
||||
Keep bug fixes as small as possible while fully fixing the reported issue.
|
||||
Changes not needed for correctness or robustness should be submitted separately,
|
||||
especially if they increase complexity or affect backporting.
|
||||
|
||||
@subheading Cosmetic changes should be kept in separate patches.
|
||||
We refuse source indentation and other cosmetic changes if they are mixed
|
||||
with functional changes, such commits will be rejected and removed. However,
|
||||
indentation changes that can be ignored by @code{git diff --ignore-all-space}
|
||||
(e.g. changes in whitespace amount, leading/trailing spaces) may be mixed with
|
||||
functional changes, since reviewers can use @code{git diff -w} or
|
||||
@code{git log -p --ignore-all-space} to review only the functional parts of
|
||||
the change. Forgejo's pull request interface also provides a
|
||||
``Hide whitespace changes'' option for this purpose. Every
|
||||
with functional changes, such commits will be rejected and removed. Every
|
||||
developer has his own indentation style, you should not change it. Of course
|
||||
if you (re)write something, you can use your own style, even though we would
|
||||
prefer if the indentation throughout FFmpeg was consistent (Many projects
|
||||
force a given indentation style - we do not.). If you really need to make
|
||||
non-whitespace cosmetic changes, separate them strictly from real changes.
|
||||
indentation changes (try to avoid this), separate them strictly from real
|
||||
changes.
|
||||
|
||||
NOTE: If you had to put if()@{ .. @} over a large (> 5 lines) chunk of code,
|
||||
then either do NOT change the indentation of the inner part within (do not
|
||||
|
||||
@@ -1045,10 +1045,6 @@ Other values include 0 for mono and stereo, 1 for surround sound with masking
|
||||
and LFE bandwidth optimizations, and 255 for independent streams with an
|
||||
unspecified channel layout.
|
||||
|
||||
@item dtx (N.A.)
|
||||
Allow discontinuous transmission when set to 1. The default value is 0
|
||||
(disabled).
|
||||
|
||||
@item apply_phase_inv (N.A.) (requires libopus >= 1.2)
|
||||
If set to 0, disables the use of phase inversion for intensity stereo,
|
||||
improving the quality of mono downmixes, but slightly reducing normal stereo
|
||||
|
||||
@@ -42,11 +42,7 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Could not open %s\n", filename);
|
||||
return;
|
||||
}
|
||||
f = fopen(filename,"wb");
|
||||
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
|
||||
for (i = 0; i < ysize; i++)
|
||||
fwrite(buf + i * wrap, 1, xsize, f);
|
||||
|
||||
@@ -336,17 +336,15 @@ int main (int argc, char **argv)
|
||||
|
||||
if (video_stream) {
|
||||
printf("Play the output video file with the command:\n"
|
||||
"ffplay -f rawvideo -pixel_format %s -video_size %dx%d %s\n",
|
||||
"ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
|
||||
av_get_pix_fmt_name(pix_fmt), width, height,
|
||||
video_dst_filename);
|
||||
}
|
||||
|
||||
if (audio_stream) {
|
||||
enum AVSampleFormat sfmt = audio_dec_ctx->sample_fmt;
|
||||
AVChannelLayout mono = AV_CHANNEL_LAYOUT_MONO;
|
||||
AVChannelLayout *ch_layout = &audio_dec_ctx->ch_layout;
|
||||
int n_channels = audio_dec_ctx->ch_layout.nb_channels;
|
||||
const char *fmt;
|
||||
char buf[64];
|
||||
|
||||
if (av_sample_fmt_is_planar(sfmt)) {
|
||||
const char *packed = av_get_sample_fmt_name(sfmt);
|
||||
@@ -354,18 +352,15 @@ int main (int argc, char **argv)
|
||||
"(%s). This example will output the first channel only.\n",
|
||||
packed ? packed : "?");
|
||||
sfmt = av_get_packed_sample_fmt(sfmt);
|
||||
ch_layout = &mono;
|
||||
n_channels = 1;
|
||||
}
|
||||
|
||||
if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
|
||||
goto end;
|
||||
|
||||
if ((ret = av_channel_layout_describe(ch_layout, buf, sizeof(buf))) < 0)
|
||||
goto end;
|
||||
|
||||
printf("Play the output audio file with the command:\n"
|
||||
"ffplay -f %s -ch_layout %s -sample_rate %d %s\n",
|
||||
fmt, buf, audio_dec_ctx->sample_rate,
|
||||
"ffplay -f %s -ac %d -ar %d %s\n",
|
||||
fmt, n_channels, audio_dec_ctx->sample_rate,
|
||||
audio_dst_filename);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,7 @@
|
||||
/* check that a given sample format is supported by the encoder */
|
||||
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
|
||||
{
|
||||
const void *out_config;
|
||||
int ret = avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT,
|
||||
0, &out_config, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error getting supported sample formats\n");
|
||||
exit(1);
|
||||
}
|
||||
const enum AVSampleFormat *p = out_config;
|
||||
|
||||
if (!p)
|
||||
return 1;
|
||||
const enum AVSampleFormat *p = codec->sample_fmts;
|
||||
|
||||
while (*p != AV_SAMPLE_FMT_NONE) {
|
||||
if (*p == sample_fmt)
|
||||
@@ -64,19 +54,13 @@ static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt
|
||||
/* just pick the highest supported samplerate */
|
||||
static int select_sample_rate(const AVCodec *codec)
|
||||
{
|
||||
const void *out_config;
|
||||
int ret = avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_SAMPLE_RATE,
|
||||
0, &out_config, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error getting supported sample rates\n");
|
||||
exit(1);
|
||||
}
|
||||
const int *p = out_config;
|
||||
const int *p;
|
||||
int best_samplerate = 0;
|
||||
|
||||
if (!p)
|
||||
if (!codec->supported_samplerates)
|
||||
return 44100;
|
||||
|
||||
p = codec->supported_samplerates;
|
||||
while (*p) {
|
||||
if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
|
||||
best_samplerate = *p;
|
||||
@@ -88,19 +72,13 @@ static int select_sample_rate(const AVCodec *codec)
|
||||
/* select layout with the highest channel count */
|
||||
static int select_channel_layout(const AVCodec *codec, AVChannelLayout *dst)
|
||||
{
|
||||
const void *out_config;
|
||||
int ret = avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT,
|
||||
0, &out_config, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error getting supported channel layouts\n");
|
||||
exit(1);
|
||||
}
|
||||
const AVChannelLayout *p = out_config, *best_ch_layout;
|
||||
const AVChannelLayout *p, *best_ch_layout;
|
||||
int best_nb_channels = 0;
|
||||
|
||||
if (!p)
|
||||
if (!codec->ch_layouts)
|
||||
return av_channel_layout_copy(dst, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
|
||||
|
||||
p = codec->ch_layouts;
|
||||
while (p->nb_channels) {
|
||||
int nb_channels = p->nb_channels;
|
||||
|
||||
@@ -240,10 +218,10 @@ int main(int argc, char **argv)
|
||||
samples = (uint16_t*)frame->data[0];
|
||||
|
||||
for (j = 0; j < c->frame_size; j++) {
|
||||
samples[c->ch_layout.nb_channels*j] = (int)(sin(t) * 10000);
|
||||
samples[2*j] = (int)(sin(t) * 10000);
|
||||
|
||||
for (k = 1; k < c->ch_layout.nb_channels; k++)
|
||||
samples[c->ch_layout.nb_channels*j + k] = samples[c->ch_layout.nb_channels*j];
|
||||
samples[2*j + k] = samples[2*j];
|
||||
t += tincr;
|
||||
}
|
||||
encode(c, frame, pkt, f);
|
||||
|
||||
@@ -132,9 +132,8 @@ static int decode_write(AVCodecContext *avctx, AVPacket *packet)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, 1, size, output_file) != size) {
|
||||
if ((ret = fwrite(buffer, 1, size, output_file)) < 0) {
|
||||
fprintf(stderr, "Failed to dump raw data.\n");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -233,10 +232,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* open the file to dump raw data */
|
||||
output_file = fopen(argv[3], "w+b");
|
||||
if (!output_file) {
|
||||
fprintf(stderr, "Cannot open output file '%s'\n", argv[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* actual decoding and dump the raw data */
|
||||
while (ret >= 0) {
|
||||
|
||||
+9
-25
@@ -127,7 +127,7 @@ static void add_stream(OutputStream *ost, AVFormatContext *oc,
|
||||
enum AVCodecID codec_id)
|
||||
{
|
||||
AVCodecContext *c;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* find the encoder */
|
||||
*codec = avcodec_find_encoder(codec_id);
|
||||
@@ -157,37 +157,21 @@ static void add_stream(OutputStream *ost, AVFormatContext *oc,
|
||||
ost->enc = c;
|
||||
|
||||
switch ((*codec)->type) {
|
||||
case AVMEDIA_TYPE_AUDIO: {
|
||||
const void *codec_config;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
c->sample_fmt = (*codec)->sample_fmts ?
|
||||
(*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
|
||||
c->bit_rate = 64000;
|
||||
ret = avcodec_get_supported_config(c, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT,
|
||||
0, &codec_config, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to get supported sample formats\n");
|
||||
exit(1);
|
||||
}
|
||||
c->sample_fmt = codec_config ? *(const enum AVSampleFormat*)codec_config
|
||||
: AV_SAMPLE_FMT_FLTP;
|
||||
ret = avcodec_get_supported_config(c, NULL, AV_CODEC_CONFIG_SAMPLE_RATE,
|
||||
0, &codec_config, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to get supported sample rates\n");
|
||||
exit(1);
|
||||
}
|
||||
if (codec_config) {
|
||||
const int *supported_samplerates = codec_config;
|
||||
c->sample_rate = supported_samplerates[0];
|
||||
for (; *supported_samplerates; supported_samplerates++) {
|
||||
if (*supported_samplerates == 44100)
|
||||
c->sample_rate = 44100;
|
||||
if ((*codec)->supported_samplerates) {
|
||||
c->sample_rate = (*codec)->supported_samplerates[0];
|
||||
for (i = 0; (*codec)->supported_samplerates[i]; i++) {
|
||||
if ((*codec)->supported_samplerates[i] == 44100)
|
||||
c->sample_rate = 44100;
|
||||
}
|
||||
} else {
|
||||
c->sample_rate = 44100;
|
||||
}
|
||||
av_channel_layout_copy(&c->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
|
||||
ost->st->time_base = (AVRational){ 1, c->sample_rate };
|
||||
break;
|
||||
}
|
||||
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
c->codec_id = codec_id;
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#include <libavutil/error.h>
|
||||
#include <libavutil/hwcontext.h>
|
||||
#include <libavutil/hwcontext_qsv.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/mem.h>
|
||||
|
||||
static int get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
|
||||
@@ -89,16 +88,9 @@ static int decode_packet(AVCodecContext *decoder_ctx,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++) {
|
||||
int h = sw_frame->height >> (i > 0);
|
||||
int linesize = av_image_get_linesize(sw_frame->format, sw_frame->width, i);
|
||||
if (linesize < 0) {
|
||||
ret = linesize;
|
||||
goto fail;
|
||||
}
|
||||
for (j = 0; j < h; j++)
|
||||
avio_write(output_ctx, sw_frame->data[i] + j * sw_frame->linesize[i], linesize);
|
||||
}
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++)
|
||||
for (j = 0; j < (sw_frame->height >> (i > 0)); j++)
|
||||
avio_write(output_ctx, sw_frame->data[i] + j * sw_frame->linesize[i], sw_frame->width);
|
||||
|
||||
fail:
|
||||
av_frame_unref(sw_frame);
|
||||
|
||||
@@ -430,9 +430,7 @@ int main(int argc, char **argv)
|
||||
|
||||
end:
|
||||
avformat_close_input(&ifmt_ctx);
|
||||
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&ofmt_ctx->pb);
|
||||
avformat_free_context(ofmt_ctx);
|
||||
avformat_close_input(&ofmt_ctx);
|
||||
avcodec_free_context(&decoder_ctx);
|
||||
avcodec_free_context(&encoder_ctx);
|
||||
av_buffer_unref(&hw_device_ctx);
|
||||
|
||||
@@ -184,7 +184,7 @@ end:
|
||||
avformat_close_input(&ifmt_ctx);
|
||||
|
||||
/* close output */
|
||||
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
|
||||
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
|
||||
avio_closep(&ofmt_ctx->pb);
|
||||
avformat_free_context(ofmt_ctx);
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ static int open_output_file(const char *filename)
|
||||
enc_ctx->width = dec_ctx->width;
|
||||
enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
|
||||
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
ret = avcodec_get_supported_config(dec_ctx, NULL,
|
||||
AV_CODEC_CONFIG_PIX_FORMAT, 0,
|
||||
(const void**)&pix_fmts, NULL);
|
||||
|
||||
@@ -195,7 +195,7 @@ static int open_output_file(const char *filename)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
ret = avcodec_get_supported_config(dec_ctx, NULL,
|
||||
AV_CODEC_CONFIG_SAMPLE_FORMAT, 0,
|
||||
(const void**)&sample_fmts, NULL);
|
||||
|
||||
|
||||
@@ -152,7 +152,6 @@ static int open_output_file(const char *filename,
|
||||
AVIOContext *output_io_context = NULL;
|
||||
AVStream *stream = NULL;
|
||||
const AVCodec *output_codec = NULL;
|
||||
const void *sample_fmts;
|
||||
int error;
|
||||
|
||||
/* Open the output file to write to it. */
|
||||
@@ -208,12 +207,8 @@ static int open_output_file(const char *filename,
|
||||
/* Set the basic encoder parameters.
|
||||
* The input file's sample rate is used to avoid a sample rate conversion. */
|
||||
av_channel_layout_default(&avctx->ch_layout, OUTPUT_CHANNELS);
|
||||
error = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT,
|
||||
0, &sample_fmts, NULL);
|
||||
av_assert0(error >= 0);
|
||||
avctx->sample_fmt = sample_fmts ? *(const enum AVSampleFormat*)sample_fmts
|
||||
: input_codec_context->sample_fmt;
|
||||
avctx->sample_rate = input_codec_context->sample_rate;
|
||||
avctx->sample_fmt = output_codec->sample_fmts[0];
|
||||
avctx->bit_rate = OUTPUT_BIT_RATE;
|
||||
|
||||
/* Set the sample rate for the container. */
|
||||
|
||||
@@ -96,6 +96,7 @@ static int encode_write(AVCodecContext *avctx, AVFrame *frame, FILE *fout)
|
||||
|
||||
end:
|
||||
av_packet_free(&enc_pkt);
|
||||
ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ int main(int argc, char *argv[])
|
||||
height = atoi(argv[2]);
|
||||
size = width * height;
|
||||
|
||||
if (!(fin = fopen(argv[3], "rb"))) {
|
||||
if (!(fin = fopen(argv[3], "r"))) {
|
||||
fprintf(stderr, "Fail to open input file : %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@@ -197,8 +198,7 @@ int main(int argc, char *argv[])
|
||||
goto close;
|
||||
}
|
||||
|
||||
err = encode_write(avctx, hw_frame, fout);
|
||||
if (err != AVERROR(EAGAIN) && err < 0) {
|
||||
if ((err = (encode_write(avctx, hw_frame, fout))) < 0) {
|
||||
fprintf(stderr, "Failed to encode.\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
@@ -294,9 +294,7 @@ int main(int argc, char **argv)
|
||||
|
||||
end:
|
||||
avformat_close_input(&ifmt_ctx);
|
||||
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&ofmt_ctx->pb);
|
||||
avformat_free_context(ofmt_ctx);
|
||||
avformat_close_input(&ofmt_ctx);
|
||||
avcodec_free_context(&decoder_ctx);
|
||||
avcodec_free_context(&encoder_ctx);
|
||||
av_buffer_unref(&hw_device_ctx);
|
||||
|
||||
+13
-28
@@ -1569,27 +1569,6 @@ Set whether on display the image should be vertically flipped.
|
||||
|
||||
See the @code{-display_rotation} option for more details.
|
||||
|
||||
@item -mastering_display[:@var{stream_specifier}] @var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} (@emph{input,per-stream})
|
||||
Set video mastering display metadata.
|
||||
|
||||
@var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} is a string specifying
|
||||
X,Y display primaries for GBR channels and white point (WP) in units of
|
||||
0.00002, and max-min luminance (L) values in units of 0.0001 candela per
|
||||
meter square. The values are unsigned integers representing the numerator
|
||||
of a rational with an implicit denominator of 50000 for GBR and (WP), and
|
||||
implicit denominator 10000 for (L).
|
||||
|
||||
This option overrides the mastering display metadata stored in the file,
|
||||
if any.
|
||||
|
||||
@item -content_light[:@var{stream_specifier}] @var{%u,%u} (@emph{input,per-stream})
|
||||
Set video content light metadata.
|
||||
|
||||
@var{%u,%u} is a string specifying max content light level and maximum picture
|
||||
average light level.
|
||||
|
||||
This option overrides the content light metadata stored in the file, if any.
|
||||
|
||||
@item -vn (@emph{input/output})
|
||||
As an input option, blocks all video streams of a file from being filtered or
|
||||
being automatically selected or mapped for any output. See @code{-discard}
|
||||
@@ -2388,19 +2367,25 @@ If either the input or output is blocked leading to actual read speed falling be
|
||||
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 -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
|
||||
Set video sync method / framerate mode.
|
||||
@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
|
||||
but can be overridden for a stream by setting fps_mode. vsync is deprecated and will be
|
||||
removed in the future.
|
||||
|
||||
For compatibility reasons some of the values for vsync can be specified as numbers (shown
|
||||
in parentheses in the following table).
|
||||
|
||||
@table @option
|
||||
@item passthrough
|
||||
@item passthrough (0)
|
||||
Each frame is passed with its timestamp from the demuxer to the muxer.
|
||||
@item cfr
|
||||
@item cfr (1)
|
||||
Frames will be duplicated and dropped to achieve exactly the requested
|
||||
constant frame rate.
|
||||
@item vfr
|
||||
@item vfr (2)
|
||||
Frames are passed through with their timestamp or dropped so as to
|
||||
prevent 2 frames from having the same timestamp.
|
||||
@item auto
|
||||
@item auto (-1)
|
||||
Chooses between cfr and vfr depending on muxer capabilities. This is the
|
||||
default method.
|
||||
@end table
|
||||
@@ -2430,7 +2415,7 @@ Do not process input timestamps, but keep their values without trying
|
||||
to sanitize them. In particular, do not remove the initial start time
|
||||
offset value.
|
||||
|
||||
Note that, depending on the @option{fps_mode} option or on specific muxer
|
||||
Note that, depending on the @option{vsync} option or on specific muxer
|
||||
processing (e.g. in case the format option @option{avoid_negative_ts}
|
||||
is enabled) the output timestamps may mismatch with the input
|
||||
timestamps even when this option is selected.
|
||||
|
||||
@@ -357,7 +357,6 @@
|
||||
<xsd:complexType name="streamGroupComponentType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="subcomponents" type="ffprobe:streamGroupSubComponentList" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="side_data_list" type="ffprobe:packetSideDataListType" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="component_entry" type="ffprobe:streamGroupEntryType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
+317
-254
@@ -7743,11 +7743,6 @@ The file path of the downloaded whisper.cpp model (mandatory).
|
||||
The language to use for transcription ('auto' for auto-detect).
|
||||
Default value: @code{"auto"}
|
||||
|
||||
@item translate
|
||||
If enabled, translate the transcription from the source language to English. A
|
||||
multilingual model is required to enable this option.
|
||||
Default value: @code{"false"}
|
||||
|
||||
@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,
|
||||
@@ -7780,8 +7775,8 @@ Default value: @code{"text"}
|
||||
|
||||
@item max_len
|
||||
Maximum segment length in characters. When set to a value greater than 0,
|
||||
transcription segments will be split by word to not exceed this length. This is
|
||||
useful for generating subtitles with shorter lines.
|
||||
transcription segments will be split to not exceed this length. This is useful
|
||||
for generating subtitles with shorter lines.
|
||||
Default value: @code{"0"}
|
||||
|
||||
@item vad_model
|
||||
@@ -8611,24 +8606,21 @@ Same as the @ref{subtitles} filter, except that it doesn't require libavcodec
|
||||
and libavformat to work. On the other hand, it is limited to ASS (Advanced
|
||||
Substation Alpha) subtitles files.
|
||||
|
||||
This filter accepts @option{filename}/@option{f}, @option{original_size},
|
||||
@option{fontsdir}, and @option{alpha} from the @ref{subtitles} filter, plus the
|
||||
following option:
|
||||
This filter accepts the following option in addition to the common options from
|
||||
the @ref{subtitles} filter:
|
||||
|
||||
@table @option
|
||||
@item shaping
|
||||
Set the shaping engine.
|
||||
Set the shaping engine
|
||||
|
||||
Available values are:
|
||||
@table @samp
|
||||
@item auto
|
||||
The default libass shaping engine, which is the best available.
|
||||
@item simple
|
||||
Fast, font-agnostic shaper that can do only substitutions.
|
||||
Fast, font-agnostic shaper that can do only substitutions
|
||||
@item complex
|
||||
Slower shaper using OpenType for substitutions and positioning. Required
|
||||
for correct rendering of complex scripts such as Arabic, Hebrew, Devanagari
|
||||
and Thai. Requires libass to be built with HarfBuzz.
|
||||
Slower shaper using OpenType for substitutions and positioning
|
||||
@end table
|
||||
|
||||
The default is @code{auto}.
|
||||
@@ -12224,42 +12216,18 @@ and configure FFmpeg with @code{--enable-libtorch
|
||||
--extra-cflags=-I/libtorch_root/libtorch/include/torch/csrc/api/include
|
||||
--extra-ldflags=-L/libtorch_root/libtorch/lib/}
|
||||
|
||||
@item onnx
|
||||
ONNX Runtime backend. To enable this backend you need to install the
|
||||
ONNX Runtime library (see @url{https://onnxruntime.ai/}) and configure
|
||||
FFmpeg with @code{--enable-libonnxruntime}.
|
||||
|
||||
The current ONNX Runtime backend expects 4-D input and output tensors
|
||||
with NCHW layout and 32-bit floating-point element type (ONNX
|
||||
@code{FLOAT}); models with integer or other element types (e.g.
|
||||
@code{UINT8}) are not supported and will be rejected at load time.
|
||||
Models using NHWC layout or other ranks are not yet
|
||||
supported. Only single-input models are supported; the backend binds
|
||||
exactly one input tensor when running the model.
|
||||
|
||||
The @option{input} and @option{output} options are optional for the
|
||||
ONNX Runtime backend; when they are omitted the backend resolves the
|
||||
tensor names from the session.
|
||||
|
||||
The ONNX Runtime backend runs inference synchronously using a single
|
||||
inference request. The shared @option{async} and @option{nireq} options
|
||||
therefore have no effect for @code{dnn_backend=onnx}; inference always
|
||||
runs synchronously regardless of their values.
|
||||
|
||||
@end table
|
||||
|
||||
@item model
|
||||
Set path to model file specifying network architecture and its parameters.
|
||||
Note that different backends use different file formats. TensorFlow, OpenVINO,
|
||||
Libtorch, and ONNX Runtime backends can load files for only their respective formats.
|
||||
Note that different backends use different file formats. TensorFlow, OpenVINO
|
||||
and Libtorch backend can load files for only its format.
|
||||
|
||||
@item input
|
||||
Set the input name of the dnn network. Required for the TensorFlow backend;
|
||||
optional for the ONNX Runtime backend.
|
||||
Set the input name of the dnn network.
|
||||
|
||||
@item output
|
||||
Set the output name of the dnn network. Required for the TensorFlow backend;
|
||||
optional for the ONNX Runtime backend.
|
||||
Set the output name of the dnn network.
|
||||
|
||||
@item backend_configs
|
||||
Set the configs to be passed into backend. To use async execution, set async (default: set).
|
||||
@@ -12268,20 +12236,6 @@ Roll back to sync execution if the backend does not support async.
|
||||
For tensorflow backend, you can set its configs with @option{sess_config} options,
|
||||
please use tools/python/tf_sess_config.py to get the configs of TensorFlow backend for your system.
|
||||
|
||||
@item device
|
||||
Set the device to run the model. For the ONNX Runtime backend this selects the
|
||||
execution provider: @code{cpu} (default), @code{cuda} (NVIDIA GPU),
|
||||
@code{dml} (DirectML, Windows only) or @code{vitisai} (AMD Ryzen AI NPU).
|
||||
|
||||
@item device_id
|
||||
Set the device index used by GPU execution providers (e.g. @code{cuda} or
|
||||
@code{dml}) for the ONNX Runtime backend. Default is 0.
|
||||
|
||||
@item threads_per_operation
|
||||
ONNX Runtime backend only. Set the number of CPU threads used per ONNX
|
||||
Runtime operator when running with @code{device=cpu}. Default is 0 (let
|
||||
ONNX Runtime choose automatically). Has no effect for GPU/NPU providers.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
@@ -14790,73 +14744,6 @@ This flag is enabled by default.
|
||||
@end table
|
||||
@end table
|
||||
|
||||
@section frc_amf
|
||||
|
||||
Double the frame rate, using Frame Rate Converter (FRC) provided by
|
||||
AMD Advanced Media Framework library for hardware acceleration.
|
||||
|
||||
The filter accepts the following options:
|
||||
|
||||
@table @option
|
||||
@item engine_type
|
||||
Specify the engine used to run shaders.
|
||||
@table @samp
|
||||
@item dx11
|
||||
DirectX 11.
|
||||
|
||||
@item dx12
|
||||
DirectX 12 (Default value).
|
||||
@end table
|
||||
|
||||
@item enable
|
||||
Boolean value: enable/disable FRC. Dynamic value, can be altered at a runtime
|
||||
without re-initializing the filter. (Default value: enabled).
|
||||
|
||||
@item fallback_mode
|
||||
Fallback behavior in case of low interpolation confidence.
|
||||
@table @samp
|
||||
@item duplicate
|
||||
Duplicate frame.
|
||||
|
||||
@item blend
|
||||
Blend two frames together (Default value).
|
||||
@end table
|
||||
|
||||
@item indicator
|
||||
Boolean value: show FRC indicator square in the top left corner of the video
|
||||
(Default value: disabled).
|
||||
|
||||
@item profile
|
||||
Level of hierarchical motion search.
|
||||
@table @samp
|
||||
@item low
|
||||
Less levels of hierarchical motion search.
|
||||
Only recommended for extremely low resolutions.
|
||||
|
||||
@item high
|
||||
Recommended for any resolution up to 1440p. (Default value)
|
||||
|
||||
@item super
|
||||
More levels of hierarchical motion search. Recommended for resolutions 1440p
|
||||
or higher.
|
||||
@end table
|
||||
|
||||
@item mv_search_mode
|
||||
Performance mode of the motion search.
|
||||
@table @samp
|
||||
@item native
|
||||
Conduct motion search on the full resolution of source images.
|
||||
|
||||
@item performance
|
||||
Conduct motion search on the down scaled source images.
|
||||
Recommended for APU or low end GPU for better performance.
|
||||
@end table
|
||||
|
||||
@item use_future_frame
|
||||
Boolean value: enable dependency on future frame, improves quality for the cost
|
||||
of latency (Default value: enabled).
|
||||
@end table
|
||||
|
||||
@section framestep
|
||||
|
||||
Select one frame every N-th frame.
|
||||
@@ -23392,23 +23279,6 @@ at least libass release 0.17.0 (or LIBASS_VERSION 0x01600010), @emph{and} libass
|
||||
have been built with libunibreak.
|
||||
|
||||
The option is enabled by default except for native ASS.
|
||||
|
||||
@item shaping
|
||||
Set the shaping engine.
|
||||
|
||||
Available values are:
|
||||
@table @samp
|
||||
@item auto
|
||||
The default libass shaping engine, which is the best available.
|
||||
@item simple
|
||||
Fast, font-agnostic shaper that can do only substitutions.
|
||||
@item complex
|
||||
Slower shaper using OpenType for substitutions and positioning. Required
|
||||
for correct rendering of complex scripts such as Arabic, Hebrew, Devanagari
|
||||
and Thai. Requires libass to be built with HarfBuzz.
|
||||
@end table
|
||||
|
||||
The default is @code{auto}.
|
||||
@end table
|
||||
|
||||
If the first key is not specified, it is assumed that the first value
|
||||
@@ -23777,9 +23647,9 @@ The value must be between @code{0} and @var{nb_frames - 1}. Default is @code{0}.
|
||||
@item
|
||||
Produce 8x8 PNG tiles of all keyframes (@option{-skip_frame nokey}) in a movie:
|
||||
@example
|
||||
ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -fps_mode passthrough keyframes%03d.png
|
||||
ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -vsync 0 keyframes%03d.png
|
||||
@end example
|
||||
The @option{-fps_mode passthrough} is necessary to prevent @command{ffmpeg} from
|
||||
The @option{-vsync 0} is necessary to prevent @command{ffmpeg} from
|
||||
duplicating each output frame to accommodate the originally detected frame
|
||||
rate.
|
||||
|
||||
@@ -25778,22 +25648,6 @@ Work the same as the identical @ref{scale} filter options.
|
||||
@item reset_sar
|
||||
Works the same as the identical @ref{scale} filter option.
|
||||
|
||||
@item in_color_range
|
||||
Override input color range.
|
||||
|
||||
@item out_color_range
|
||||
Specify output color range.
|
||||
|
||||
The accepted values for in_trc and out_trc are:
|
||||
@table @samp
|
||||
@item studio
|
||||
Studio (or restricted, or MPEG) color range.
|
||||
|
||||
@item full
|
||||
Full (or JPEG) color range.
|
||||
|
||||
@end table
|
||||
|
||||
@anchor{color_profile}
|
||||
@item color_profile
|
||||
Specify all color properties at once.
|
||||
@@ -25811,13 +25665,10 @@ BT.2020
|
||||
|
||||
@end table
|
||||
|
||||
@item in_trc
|
||||
Override input transfer characteristics.
|
||||
|
||||
@item out_trc
|
||||
@item trc
|
||||
Specify output transfer characteristics.
|
||||
|
||||
The accepted values for in_trc and out_trc are:
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt709
|
||||
BT.709
|
||||
@@ -25869,13 +25720,10 @@ ARIB_STD_B67
|
||||
|
||||
@end table
|
||||
|
||||
@item in_primaries
|
||||
Override input color primaries.
|
||||
|
||||
@item out_primaries
|
||||
@item primaries
|
||||
Specify output color primaries.
|
||||
|
||||
The accepted values for in_primaries and out_primaries are:
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt709
|
||||
BT.709
|
||||
@@ -25927,13 +25775,6 @@ Upscale to 4K and change color profile to bt2020.
|
||||
@example
|
||||
vpp_amf=4096:2160:color_profile=bt2020
|
||||
@end example
|
||||
|
||||
@item
|
||||
Override input primaries and input transfer characteristics, change both to bt709.
|
||||
|
||||
@example
|
||||
vpp_amf=color_profile=bt2020:in_trc=smpte2084:in_primaries=bt2020:out_trc=bt709:out_primaries=bt709
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@anchor{vstack}
|
||||
@@ -27115,19 +26956,7 @@ value.
|
||||
@chapter CUDA Video Filters
|
||||
@c man begin CUDA Video Filters
|
||||
|
||||
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
|
||||
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
|
||||
@@ -27162,7 +26991,23 @@ Since CUDA filters operate exclusively on GPU memory, frame data must sometimes
|
||||
@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.
|
||||
|
||||
@section bilateral_cuda
|
||||
@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.
|
||||
@@ -27182,7 +27027,7 @@ Set window size of the bilateral function to determine the number of neighbours
|
||||
If the number entered is even, one will be added automatically.
|
||||
Allowed range is 1 to 255. Default is 1.
|
||||
@end table
|
||||
@subsection Examples
|
||||
@subsubsection Examples
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@@ -27201,7 +27046,7 @@ Apply the bilateral filter on a video.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section bwdif_cuda
|
||||
@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
|
||||
@@ -27253,13 +27098,13 @@ Only deinterlace frames marked as interlaced.
|
||||
The default value is @code{all}.
|
||||
@end table
|
||||
|
||||
@section chromakey_cuda
|
||||
@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}.
|
||||
|
||||
@subsection Examples
|
||||
@subsubsection Examples
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@@ -27295,7 +27140,7 @@ Process two software sources, explicitly uploading the frames:
|
||||
|
||||
@end itemize
|
||||
|
||||
@section colorspace_cuda
|
||||
@subsection colorspace_cuda
|
||||
|
||||
CUDA accelerated implementation of the colorspace filter.
|
||||
|
||||
@@ -27328,7 +27173,7 @@ JPEG (full) range
|
||||
@end table
|
||||
|
||||
@anchor{overlay_cuda}
|
||||
@section overlay_cuda
|
||||
@subsection overlay_cuda
|
||||
|
||||
Overlay one video on top of another.
|
||||
|
||||
@@ -27407,13 +27252,13 @@ This filter also supports the @ref{framesync} options.
|
||||
|
||||
|
||||
@anchor{pad_cuda}
|
||||
@section 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.
|
||||
|
||||
@subsection Examples
|
||||
@subsubsection Examples
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@@ -27430,7 +27275,7 @@ ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=ih
|
||||
@end itemize
|
||||
|
||||
@anchor{scale_cuda}
|
||||
@section 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.
|
||||
@@ -27499,7 +27344,7 @@ Works the same as the identical @ref{scale} filter option.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
@subsubsection Examples
|
||||
|
||||
@itemize
|
||||
@item
|
||||
@@ -27523,7 +27368,7 @@ scale_cuda=passthrough=0
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@section thumbnail_cuda
|
||||
@subsection thumbnail_cuda
|
||||
|
||||
Select the most representative frame in a given sequence of consecutive frames using CUDA.
|
||||
|
||||
@@ -27539,7 +27384,7 @@ the end. Default is @code{100}.
|
||||
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.
|
||||
|
||||
@subsection Example
|
||||
@subsubsection Example
|
||||
|
||||
@itemize
|
||||
|
||||
@@ -27551,57 +27396,7 @@ Thumbnails are extracted from every @var{n}=150-frame batch, selecting one per b
|
||||
|
||||
@end itemize
|
||||
|
||||
@section transpose_cuda
|
||||
|
||||
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.
|
||||
|
||||
@item reversal
|
||||
Rotate by 180 degrees.
|
||||
|
||||
@item hflip
|
||||
Flip horizontally.
|
||||
|
||||
@item vflip
|
||||
Flip vertically.
|
||||
@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 yadif_cuda
|
||||
@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
|
||||
@@ -27659,6 +27454,274 @@ Only deinterlace frames marked as interlaced.
|
||||
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
|
||||
@@ -32276,7 +32339,7 @@ select=n=2:e='mod(n, 2)+1' [odd][even]; [odd] pad=h=2*ih [tmp]; [tmp][even] over
|
||||
Select useful frames from an ffconcat file which is using inpoints and
|
||||
outpoints but where the source files are not intra frame only.
|
||||
@example
|
||||
ffmpeg -copyts -segment_time_metadata 1 -i input.ffconcat -fps_mode passthrough -vf select=concatdec_select -af aselect=concatdec_select output.avi
|
||||
ffmpeg -copyts -vsync 0 -segment_time_metadata 1 -i input.ffconcat -vf select=concatdec_select -af aselect=concatdec_select output.avi
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
|
||||
@@ -100,9 +100,6 @@ Print specific debug info.
|
||||
Possible values:
|
||||
@table @samp
|
||||
@item ts
|
||||
Print timestamp information.
|
||||
@item id3v2
|
||||
Print ID3v2 frame data when demuxing files containing ID3v2 tags.
|
||||
@end table
|
||||
|
||||
@item max_delay @var{integer} (@emph{input/output})
|
||||
|
||||
@@ -205,39 +205,6 @@ FFmpeg can make use of this library, originating in Modplug-XMMS, to read from M
|
||||
See @url{https://github.com/Konstanty/libmodplug}. Pass @code{--enable-libmodplug} to configure to
|
||||
enable it.
|
||||
|
||||
@section ONNX Runtime
|
||||
|
||||
FFmpeg can make use of the ONNX Runtime library as a backend for DNN based filters.
|
||||
|
||||
Go to @url{https://onnxruntime.ai/} and follow the instructions for installing
|
||||
the library. Pre-built packages are available for various platforms.
|
||||
|
||||
Configure FFmpeg with ONNX Runtime support:
|
||||
|
||||
@example
|
||||
./configure \
|
||||
--enable-libonnxruntime \
|
||||
--extra-cflags="-I/path/to/onnxruntime/include" \
|
||||
--extra-ldflags="-L/path/to/onnxruntime/lib"
|
||||
@end example
|
||||
|
||||
On ELF-based systems (Linux, BSD) you may also want to embed the
|
||||
library search path so that the installed @file{ffmpeg} binary finds the
|
||||
shared library at run time without setting @env{LD_LIBRARY_PATH}:
|
||||
|
||||
@example
|
||||
./configure \
|
||||
--enable-libonnxruntime \
|
||||
--extra-cflags="-I/path/to/onnxruntime/include" \
|
||||
--extra-ldflags="-L/path/to/onnxruntime/lib -Wl,-rpath,/path/to/onnxruntime/lib"
|
||||
@end example
|
||||
|
||||
The @code{-Wl,-rpath} flag is ELF-specific and should be omitted on
|
||||
other platforms (Windows, macOS).
|
||||
|
||||
For MinGW GCC builds, add the @code{-D_stdcall=__stdcall} flag for compatibility
|
||||
with ONNX Runtime headers.
|
||||
|
||||
@section OpenCORE, VisualOn, and Fraunhofer libraries
|
||||
|
||||
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
|
||||
@@ -1328,6 +1295,8 @@ following image formats are supported:
|
||||
@item Bink Audio @tab @tab X
|
||||
@tab Used in Bink and Smacker files in many games.
|
||||
@item Bonk audio @tab @tab X
|
||||
@item CELT @tab @tab E
|
||||
@tab decoding supported through external library libcelt
|
||||
@item codec2 @tab E @tab E
|
||||
@tab en/decoding supported through external library libcodec2
|
||||
@item CRI HCA @tab @tab X
|
||||
|
||||
+1
-2
@@ -52,8 +52,7 @@ Web, mail, and public facing git, also website git
|
||||
|
||||
fftrac VM:
|
||||
----------
|
||||
trac.ffmpeg.org Legacy issue tracking
|
||||
code.ffmpeg.org Primary issue tracking
|
||||
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.
|
||||
|
||||
|
||||
@@ -21,10 +21,7 @@ a mail for every change to every issue.
|
||||
|
||||
The subscription URL for the ffmpeg-trac list is:
|
||||
https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-trac
|
||||
The primary issue tracker is:
|
||||
https://code.ffmpeg.org/FFmpeg/FFmpeg/issues
|
||||
|
||||
Legacy issues may still exist on:
|
||||
The URL of the webinterface of the tracker is:
|
||||
https://trac.ffmpeg.org
|
||||
|
||||
Type:
|
||||
|
||||
+4
-195
@@ -1330,21 +1330,11 @@ element. Imply that the @option{single_file} option is set to
|
||||
@var{true}. In the template, @code{$ext$} is replaced with the file
|
||||
name extension specific for the segment format.
|
||||
|
||||
@item availability_start_time_ms @var{milliseconds}
|
||||
Set the MPD @code{availabilityStartTime} attribute as Unix epoch time in
|
||||
milliseconds. If set to @code{0}, the wall clock is used when the first
|
||||
packet is written. This is useful for live outputs that need a stable
|
||||
availability start time across restarts.
|
||||
|
||||
@item streaming @var{bool}
|
||||
Enable or disable chunk streaming mode of output. In chunk streaming
|
||||
mode, each frame will be a @code{moof} fragment which forms a
|
||||
chunk. This is disabled by default.
|
||||
|
||||
@item suggested_presentation_delay @var{duration}
|
||||
Set the MPD @code{suggestedPresentationDelay} attribute. If set to
|
||||
@code{0}, the last segment duration is used.
|
||||
|
||||
@item target_latency @var{target_latency}
|
||||
Set an intended target latency in seconds for serving (fractional
|
||||
value can be set). Applicable only when the @option{streaming} and
|
||||
@@ -1769,7 +1759,7 @@ See also the @ref{framehash} and @ref{md5} muxers.
|
||||
Animated GIF muxer.
|
||||
|
||||
Note that the GIF format has a very large time base: the delay between two frames can
|
||||
therefore not be smaller than one centisecond.
|
||||
therefore not be smaller than one centi second.
|
||||
|
||||
@subsection Options
|
||||
@table @option
|
||||
@@ -2654,12 +2644,6 @@ writing is completed. Default is disabled.
|
||||
@item protocol_opts @var{options_list}
|
||||
Set protocol options as a :-separated list of key=value parameters. Values
|
||||
containing the @code{:} special character must be escaped.
|
||||
|
||||
@item update_filemtime @var{bool}
|
||||
If set to 1, set each output file's modification time to the
|
||||
@code{creation_time} metadata value plus the frame's PTS offset.
|
||||
If @code{creation_time} is missing or unparsable, a warning is
|
||||
logged and the option is ignored. Default value is 0.
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
@@ -2668,7 +2652,7 @@ logged and the option is ignored. Default value is 0.
|
||||
Use @command{ffmpeg} for creating a sequence of files @file{img-001.jpeg},
|
||||
@file{img-002.jpeg}, ..., taking one image every second from the input video:
|
||||
@example
|
||||
ffmpeg -i in.avi -fps_mode cfr -r 1 -f image2 'img-%03d.jpeg'
|
||||
ffmpeg -i in.avi -vsync cfr -r 1 -f image2 'img-%03d.jpeg'
|
||||
@end example
|
||||
|
||||
Note that with @command{ffmpeg}, if the format is not specified with the
|
||||
@@ -2676,7 +2660,7 @@ Note that with @command{ffmpeg}, if the format is not specified with the
|
||||
format, the image2 muxer is automatically selected, so the previous
|
||||
command can be written as:
|
||||
@example
|
||||
ffmpeg -i in.avi -fps_mode cfr -r 1 'img-%03d.jpeg'
|
||||
ffmpeg -i in.avi -vsync cfr -r 1 'img-%03d.jpeg'
|
||||
@end example
|
||||
|
||||
Note also that the pattern must not necessarily contain "%d" or
|
||||
@@ -2728,58 +2712,6 @@ computer-generated compositions.
|
||||
|
||||
This muxer accepts a single audio stream containing PCM data.
|
||||
|
||||
@section iterm2
|
||||
iTerm2 inline image protocol muxer.
|
||||
|
||||
This muxer writes video frames as OSC 1337 inline images for display in
|
||||
terminals that support the iTerm2 image protocol. Use @option{-re} to limit
|
||||
the output rate to the source framerate; without it, frames are emitted as
|
||||
fast as they are encoded, which is usually not desired for live display.
|
||||
|
||||
Frames are sent with the multipart form of the protocol, which splits each
|
||||
image across several short control sequences. This avoids the per-sequence
|
||||
size limit that otherwise discards large frames, and requires iTerm2 3.5 or
|
||||
newer.
|
||||
|
||||
The output is a self-contained byte stream and can be redirected to a file.
|
||||
Replaying the file with @command{cat} displays the images in the terminal.
|
||||
|
||||
@subsection Options
|
||||
@table @option
|
||||
@item display_width @var{size}
|
||||
Set the displayed image width. @var{size} can be @samp{auto}, @var{N} terminal
|
||||
cells, @var{N}px pixels, or @var{N}% of the terminal width. When unset, the
|
||||
terminal derives the width from the image.
|
||||
|
||||
@item display_height @var{size}
|
||||
Set the displayed image height. @var{size} uses the same syntax as
|
||||
@option{display_width}. When unset, the terminal derives the height from the
|
||||
image.
|
||||
|
||||
@item keep_aspect @var{bool}
|
||||
Preserve the input aspect ratio when scaling. Default is enabled.
|
||||
|
||||
@item tmux @var{bool}
|
||||
Wrap image data in tmux DCS passthrough. This requires a tmux version whose
|
||||
passthrough sequence size limit is large enough for image data, with
|
||||
passthrough enabled via @command{tmux set -g allow-passthrough on}. Default is
|
||||
disabled.
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
|
||||
Display a video in an iTerm2 terminal:
|
||||
@example
|
||||
ffmpeg -re -i input.mp4 -f iterm2 -
|
||||
@end example
|
||||
|
||||
Scale the displayed image to 40 terminal cells tall. Inside tmux, enable
|
||||
passthrough first with @command{tmux set -g allow-passthrough on}, then add
|
||||
@option{tmux}:
|
||||
@example
|
||||
ffmpeg -re -i input.mp4 -f iterm2 -display_height 40 -tmux 1 -
|
||||
@end example
|
||||
|
||||
@section ivf
|
||||
On2 IVF muxer.
|
||||
|
||||
@@ -2819,14 +2751,6 @@ song lyrics with an audio file, such as MP3, Vorbis, or MIDI.
|
||||
|
||||
This muxer accepts a single @samp{subrip} or @samp{text} subtitles stream.
|
||||
|
||||
@subsection Options
|
||||
@table @option
|
||||
@item precision @var{number}
|
||||
Set the number of decimal digits used for the fractional (sub-second)
|
||||
part of the timestamps. Range is @code{1} to @code{6}. Default is
|
||||
@code{2}, i.e. centiseconds.
|
||||
@end table
|
||||
|
||||
@subsection Metadata
|
||||
The following metadata tags are converted to the format corresponding
|
||||
metadata:
|
||||
@@ -3145,7 +3069,7 @@ Default is @code{0x0001}.
|
||||
Set the @samp{original_network_id}. This is unique identifier of a
|
||||
network in DVB. Its main use is in the unique identification of a service
|
||||
through the path @samp{Original_Network_ID, Transport_Stream_ID}. Default
|
||||
is @code{0xff01}.
|
||||
is @code{0x0001}.
|
||||
|
||||
@item mpegts_service_id @var{integer}
|
||||
Set the @samp{service_id}, also known as program in DVB. Default is
|
||||
@@ -3172,8 +3096,6 @@ MPEG2 Digital HDTV service.
|
||||
Advanced Codec Digital SDTV service.
|
||||
@item advanced_codec_digital_hdtv
|
||||
Advanced Codec Digital HDTV service.
|
||||
@item hevc_digital_hdtv
|
||||
HEVC Digital Television service.
|
||||
@end table
|
||||
|
||||
@item mpegts_pmt_start_pid @var{integer}
|
||||
@@ -3350,19 +3272,6 @@ ogg files can be safely chained.
|
||||
|
||||
@end table
|
||||
|
||||
@section pdv
|
||||
|
||||
Playdate Video muxer.
|
||||
|
||||
This muxer writes the Playdate video container used by Panic's Playdate SDK.
|
||||
It requires a seekable output and a single PDV video stream.
|
||||
|
||||
@table @option
|
||||
@item max_frames @var{frames}
|
||||
Reserve space for at most @var{frames} video frames in the file header. This
|
||||
option is mandatory.
|
||||
@end table
|
||||
|
||||
@anchor{rcwtenc}
|
||||
@section rcwt
|
||||
|
||||
@@ -3608,13 +3517,6 @@ Wrap around segment index once it reaches @var{limit}.
|
||||
@item segment_start_number @var{number}
|
||||
Set the sequence number of the first segment. Defaults to @code{0}.
|
||||
|
||||
@item segment_wrap_number @var{number}
|
||||
Set the number of times the segment index is assumed to have already wrapped
|
||||
when generating the indexes reported in the segment list. Together with
|
||||
@option{segment_wrap} and @option{segment_start_number} it offsets the reported
|
||||
index, which is computed as @code{segment_start_number + segment_wrap *
|
||||
segment_wrap_number}. Defaults to @code{0}.
|
||||
|
||||
@item strftime @var{1|0}
|
||||
Use the @code{strftime} function to define the name of the new
|
||||
segments to write. If this is selected, the output segment name must
|
||||
@@ -3641,25 +3543,6 @@ argument must be a time duration specification, and defaults to 0.
|
||||
If enabled, write an empty segment if there are no packets during the period a
|
||||
segment would usually span. Otherwise, the segment will be filled with the next
|
||||
packet written. Defaults to @code{0}.
|
||||
|
||||
@item write_header_trailer @var{bool}
|
||||
Write a header to the first segment and a trailer to the last one, instead of
|
||||
writing a header and a trailer to every individual segment. Disabling it
|
||||
(@code{false}) also forces @option{individual_header_trailer} to @code{false},
|
||||
so that no segment is given a header or trailer. Default value is @code{true}.
|
||||
|
||||
@item individual_header_trailer @var{bool}
|
||||
If enabled, write a complete header and trailer to every segment, making each
|
||||
segment an independently usable file. If disabled (@code{false}), only the first
|
||||
segment is given a header and only the last one a trailer. It is forced to
|
||||
@code{false} when @option{write_header_trailer} is @code{false} or when
|
||||
@option{segment_header_filename} is set. Default value is @code{true}.
|
||||
|
||||
@item segment_header_filename @var{name}
|
||||
Write the stream header to a separate file named @var{name} instead of storing
|
||||
it in the segments. Setting it forces @option{write_header_trailer} to
|
||||
@code{true} and @option{individual_header_trailer} to @code{false}, so the
|
||||
header is written only once, to @var{name}. Unset by default.
|
||||
@end table
|
||||
|
||||
Make sure to require a closed GOP when encoding and to set the GOP
|
||||
@@ -3925,76 +3808,6 @@ ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@section wav
|
||||
|
||||
RIFF Wave Audio muxer.
|
||||
|
||||
@subsection Options
|
||||
|
||||
@table @option
|
||||
|
||||
@item rf64 @var{mode}
|
||||
Choose whether to use the RF64 file format instead of RIFF.
|
||||
RF64 allows files larger than 4 gigabytes, but RF64 support is not as
|
||||
universal as RIFF.
|
||||
|
||||
The following modes are recognized:
|
||||
@table @samp
|
||||
@item auto
|
||||
Start writing a standard RIFF file to retain compatibility with non-RF64-aware
|
||||
software, but switch to RF64 if the output file grows larger than 4 gigabytes.
|
||||
Reserves a small amount of extra space in the header using a @code{JUNK} chunk,
|
||||
which should be ignored by all compliant RIFF readers, but some extremely
|
||||
simplistic WAV readers may be confused by this.
|
||||
|
||||
@item always
|
||||
Always use the RF64 format regardless of file size. The output file will only
|
||||
be readable by RF64-compatible software and is no longer a standard RIFF WAVE
|
||||
file.
|
||||
|
||||
@item never
|
||||
Always use plain RIFF, never RF64. This mode is the most compatible with legacy
|
||||
software, but if the output file grows beyond 4 gigabytes, the 32-bit size field
|
||||
in the @code{data} chunk will no longer be able to correctly represent the size,
|
||||
and most audio software will not be able to read some or all of the data.
|
||||
(The @ref{wav} demuxer's @code{ignore_length} option can be used to recover such
|
||||
a file.)
|
||||
This is the default mode.
|
||||
@end table
|
||||
|
||||
@item write_bext @var{bool}
|
||||
Add a Broadcast Wave Format @code{BEXT} chunk containing extended audio
|
||||
metadata if enabled. Defaults to false.
|
||||
|
||||
@item write_peak @var{mode}
|
||||
Add a Peak Envelope chunk (EBU Tech 3285 Supplement 3) if enabled.
|
||||
Defaults to off.
|
||||
|
||||
@table @samp
|
||||
@item off
|
||||
Do not add the Peak Envelope chunk.
|
||||
|
||||
@item on
|
||||
Add the Peak Envelope chunk, calculating the peak values based on the
|
||||
@code{peak_block_size}, @code{peak_format}, and @code{peak_ppv} options.
|
||||
|
||||
@item only
|
||||
Like @code{on}, but skip writing the actual audio data (no @code{data}
|
||||
chunk will be written to the file; only the Peak Envelope and other metadata
|
||||
chunks will be written.)
|
||||
@end table
|
||||
|
||||
@item peak_block_size @var{int}
|
||||
Number of audio samples used to generate each peak frame, up to 65536.
|
||||
Default is 256.
|
||||
|
||||
@item peak_format @var{format}
|
||||
The format of the peak envelope data (1: uint8, 2: uint16). Default is 2 (uint16).
|
||||
|
||||
@item peak_ppv @var{int}
|
||||
Number of peak points per peak value (1 or 2). Default is 2.
|
||||
@end table
|
||||
|
||||
@section webm_chunk
|
||||
|
||||
WebM Live Chunk Muxer.
|
||||
@@ -4138,10 +3951,6 @@ This muxer supports the following options:
|
||||
Set the timeout in milliseconds for ICE and DTLS handshake.
|
||||
Default value is 5000.
|
||||
|
||||
@item timeout @var{integer}
|
||||
Set timeout in seconds for socket I/O operations. Applicable only for HTTP output.
|
||||
Default value is -1.
|
||||
|
||||
@item pkt_size @var{integer}
|
||||
Set the maximum size, in bytes, of RTP packets that send out.
|
||||
Default value is 1200.
|
||||
|
||||
@@ -20,7 +20,7 @@ architecture-specific versions. It is recommended to look at older
|
||||
revisions of the interesting files (web frontends for the various FFmpeg
|
||||
branches are listed at http://ffmpeg.org/download.html).
|
||||
Alternatively, look into the other architecture-specific versions in
|
||||
the x86/, ppc/, aarch64/ subdirectories. Even if you don't exactly
|
||||
the x86/, ppc/, alpha/ subdirectories. Even if you don't exactly
|
||||
comprehend the instructions, it could help understanding the functions
|
||||
and how they can be optimized.
|
||||
|
||||
@@ -191,6 +191,11 @@ __asm__() block.
|
||||
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
|
||||
expansions, add DBG=1 to your make command-line: the input file will be
|
||||
preprocessed, stripped of the debug/empty lines, then compiled, showing the
|
||||
actual lines causing issues.
|
||||
|
||||
Inline asm vs. external asm
|
||||
---------------------------
|
||||
Both inline asm (__asm__("..") in a .c file, handled by a compiler such as gcc)
|
||||
|
||||
+8
-76
@@ -169,7 +169,6 @@ Read angle 2 of playlist 4 from BluRay mounted to /mnt/bluray, start from chapte
|
||||
-playlist 4 -angle 2 -chapter 2 bluray:/mnt/bluray
|
||||
@end example
|
||||
|
||||
@anchor{cache}
|
||||
@section cache
|
||||
|
||||
Caching wrapper for input stream.
|
||||
@@ -344,8 +343,7 @@ time, which is valuable for files on slow medium.
|
||||
If set to 1, the protocol will retry reading at the end of the file, allowing
|
||||
reading files that still are being written. In order for this to terminate,
|
||||
you either need to use the rw_timeout option, or use the interrupt callback
|
||||
(for API users). Setting this option also ignores the file size reported by
|
||||
the file system.
|
||||
(for API users).
|
||||
|
||||
@item seekable
|
||||
Controls if seekability is advertised on the file. 0 means non-seekable, -1
|
||||
@@ -453,16 +451,15 @@ string describing the libavformat build. ("Lavf/<version>")
|
||||
Set the Referer header. Include 'Referer: URL' header in HTTP request.
|
||||
|
||||
@item multiple_requests
|
||||
Force persistent connections if set to 1, or disable if 0. Default is -1,
|
||||
which means auto (implies keep-alive when using -request_size or
|
||||
-initial_request_size).
|
||||
Use persistent connections if set to 1, default is 0.
|
||||
|
||||
@item request_size
|
||||
Limit the size of requests made. This is useful for some pathological servers
|
||||
that throttle unbounded range requests, as well as when expecting to seek
|
||||
frequently. Disabled (set to 0) by default.
|
||||
|
||||
Note that if enabling this option, it's strongly recommended to also set
|
||||
Note that if enabling this option, it's strongly recommended to also enable
|
||||
the @option{multiple_requests} option, as well as setting
|
||||
@option{short_seek_size} to the same value or higher. Doing so allows FFmpeg
|
||||
to reuse a single HTTP connection wherever possible.
|
||||
|
||||
@@ -1572,67 +1569,6 @@ If set to any value, listen for an incoming connection. Outgoing connection is d
|
||||
Set the maximum number of streams. By default no limit is set.
|
||||
@end table
|
||||
|
||||
@section shared
|
||||
|
||||
Thread-safe, persistent, cross-process cache wrapper for input streams. Caches
|
||||
the input stream to a file in the specified directory. This is similar to
|
||||
@ref{cache}, but with a persistent cache on disk that may be shared between
|
||||
multiple processes or demuxers, even concurrently.
|
||||
|
||||
The filename of the cache is obtained by hashing the input URL, so there is
|
||||
some risk of collision if the same URL is used for different content (e.g.
|
||||
as a result of extra POST data being used to select the stream ID). To avoid
|
||||
this, make sure to only use this protocol for URLs that uniquely identify
|
||||
the content; otherwise you may get a garbled mix of sources.
|
||||
|
||||
The accepted options are:
|
||||
@table @option
|
||||
|
||||
@item cache_dir
|
||||
Path to the directory where cache files are stored. This option is required.
|
||||
|
||||
@item block_shift
|
||||
Shift factor (log2) of the block size used for internal reads/writes. Defaults
|
||||
to 15, i.e. 32KB blocks. If this does not match the value that was specified
|
||||
when an existing cache file was created, the previously specified value will
|
||||
be used instead.
|
||||
|
||||
@item read_only
|
||||
If true, use the shared cache for reads but don't write any new blocks to it.
|
||||
Default is false. Note that even with this option enabled, the cache file will
|
||||
be initialized if it does not already exist.
|
||||
|
||||
@item cache_verify
|
||||
If true, verify any data read from the cache against the underlying input
|
||||
stream, and report any mismatches. Note that this will make the cache layer
|
||||
effectively useless. This is purely a debug option.
|
||||
|
||||
@item cache_timeout
|
||||
If set to a nonzero value, specifies the maximum time (in microseconds) to wait
|
||||
for data to become available, if another process is currently trying to fetch
|
||||
and cache the same block at the same time. If this timeout elapses, it's
|
||||
assumed that the other process may have gotten stuck or died in the meantime.
|
||||
|
||||
If set to zero, no waiting is done and all processes will immediately race
|
||||
to try and fetch the same missing blocks themselves. Defaults to 10000 (10 ms).
|
||||
|
||||
@item retry_errors
|
||||
If true (the default), transient read errors from the underlying input stream
|
||||
are ignored and retried again. If false, any blocks that previously failed
|
||||
being read from will be treated as permanently inaccessible.
|
||||
|
||||
@item retry_corrupt
|
||||
If true (the default), blocks whose contents fail the CRC integrity check are
|
||||
re-fetched from the underlying input stream, overwriting the corrupt cached
|
||||
data. If false, cache corruption is treated as a fatal read error.
|
||||
|
||||
@end table
|
||||
|
||||
URL Syntax is
|
||||
@example
|
||||
shared:@var{URL}
|
||||
@end example
|
||||
|
||||
@section srt
|
||||
|
||||
Haivision Secure Reliable Transport Protocol via libsrt.
|
||||
@@ -1921,10 +1857,6 @@ When true, use Timestamp-based Packet Delivery mode. The default behavior
|
||||
depends on the transmission type: enabled in live mode, disabled in file
|
||||
mode.
|
||||
|
||||
@item ipv6only=@var{1|0}
|
||||
Accept IPv4 or not while using the IPv6 wildcard address. This should be set
|
||||
when listening on a IPv6 wildcard address.
|
||||
|
||||
@end table
|
||||
|
||||
For more information see: @url{https://github.com/Haivision/srt}.
|
||||
@@ -2091,8 +2023,8 @@ database, but it does not validate that the certificate actually
|
||||
matches the host name we are trying to connect to. (With other backends,
|
||||
the host name is validated as well.)
|
||||
|
||||
This is enabled by default. Verifying the peer requires a CA database,
|
||||
which in some cases has to be provided by the caller.
|
||||
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.
|
||||
@@ -2163,8 +2095,8 @@ 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 enabled by default. Verifying the peer requires a CA database,
|
||||
which in some cases has to be provided by the caller.
|
||||
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.
|
||||
|
||||
+13
-94
@@ -11,88 +11,48 @@ For programmatic use, they can be set explicitly in the
|
||||
|
||||
@table @option
|
||||
|
||||
@anchor{scaler}
|
||||
@item scaler, scaler_sub
|
||||
Choose the scaling algorithm to use. Default value is @samp{auto} for both.
|
||||
It accepts the following values:
|
||||
|
||||
@table @samp
|
||||
@item auto
|
||||
Aumotic choice. For @samp{scaler_sub}, this means the same algorithm as
|
||||
@samp{scaler}. For @samp{scaler}, this defaults to the scaler flag selected
|
||||
by @samp{sws_flags}.
|
||||
|
||||
@item bilinear
|
||||
Bilinear filter. (AKA triangle filter)
|
||||
|
||||
@item bicubic
|
||||
2-tap cubic BC-spline (AKA Mitchell-Netravali spline). The B and C parameters
|
||||
can be configured by setting @code{param0} and @code{param1}, defaulting to
|
||||
0.0 and 0.6 respectively.
|
||||
|
||||
@item point, neighbor
|
||||
Point sampling (AKA nearest neighbor).
|
||||
|
||||
@item area
|
||||
Area averaging. Equivalent to @samp{bilinear} for upscaling.
|
||||
|
||||
@item gaussian
|
||||
2-tap Gaussian filter approximation. The sharpness parameter can be configured
|
||||
by setting @code{param0}, defaulting to 3.0.
|
||||
|
||||
@item sinc
|
||||
Unwindowed sinc filter.
|
||||
|
||||
@item lanczos
|
||||
Lanczos resampling (sinc windowed sinc). The number of filter taps can
|
||||
be configured by setting @code{param0}, defaulting to 3.
|
||||
|
||||
@item spline
|
||||
Unwindowed natural bicubic spline.
|
||||
@end table
|
||||
|
||||
@anchor{sws_flags}
|
||||
@item sws_flags
|
||||
Set the scaler flags. This is also used to set the scaling
|
||||
algorithm, though this usage is deprecated in favor of setting @samp{scaler}.
|
||||
Only a single algorithm may be selected. Default value is @samp{bicubic}.
|
||||
algorithm. Only a single algorithm should be selected. Default
|
||||
value is @samp{bicubic}.
|
||||
|
||||
It accepts the following values:
|
||||
@table @samp
|
||||
@item fast_bilinear
|
||||
Select fast bilinear scaling algorithm. (Deprecated)
|
||||
Select fast bilinear scaling algorithm.
|
||||
|
||||
@item bilinear
|
||||
Select bilinear scaling algorithm. (Deprecated)
|
||||
Select bilinear scaling algorithm.
|
||||
|
||||
@item bicubic
|
||||
Select bicubic scaling algorithm. (Deprecated)
|
||||
Select bicubic scaling algorithm.
|
||||
|
||||
@item experimental
|
||||
Select experimental scaling algorithm. (Deprecated)
|
||||
Select experimental scaling algorithm.
|
||||
|
||||
@item neighbor
|
||||
Select nearest neighbor rescaling algorithm. (Deprecated)
|
||||
Select nearest neighbor rescaling algorithm.
|
||||
|
||||
@item area
|
||||
Select averaging area rescaling algorithm. (Deprecated)
|
||||
Select averaging area rescaling algorithm.
|
||||
|
||||
@item bicublin
|
||||
Select bicubic scaling algorithm for the luma component, bilinear for
|
||||
chroma components. (Deprecated)
|
||||
chroma components.
|
||||
|
||||
@item gauss
|
||||
Select Gaussian rescaling algorithm. (Deprecated)
|
||||
Select Gaussian rescaling algorithm.
|
||||
|
||||
@item sinc
|
||||
Select sinc rescaling algorithm. (Deprecated)
|
||||
Select sinc rescaling algorithm.
|
||||
|
||||
@item lanczos
|
||||
Select Lanczos rescaling algorithm. The default width (alpha) is 3 and can be
|
||||
changed by setting @code{param0}. (Deprecated)
|
||||
changed by setting @code{param0}.
|
||||
|
||||
@item spline
|
||||
Select natural bicubic spline rescaling algorithm. (Deprecated)
|
||||
Select natural bicubic spline rescaling algorithm.
|
||||
|
||||
@item print_info
|
||||
Enable printing/debug logging.
|
||||
@@ -191,47 +151,6 @@ No blending
|
||||
|
||||
@end table
|
||||
|
||||
@item sws_backends
|
||||
Set the allowed swscale backends. This is a flags option, so multiple backends
|
||||
may be combined.
|
||||
|
||||
@table @samp
|
||||
@item auto
|
||||
Automatic selection. Equal to either @samp{stable} or @samp{all} depending on
|
||||
whether or not the @samp{unstable} flag is set. This is the default value.
|
||||
|
||||
@item stable
|
||||
All stable backends.
|
||||
|
||||
@item unstable
|
||||
All unstable backends.
|
||||
|
||||
@item all
|
||||
All available backends.
|
||||
|
||||
@item legacy
|
||||
Legacy swscale code.
|
||||
|
||||
@item c
|
||||
Template-based reference code.
|
||||
|
||||
@item memcpy
|
||||
Fast path using libc @code{memcpy}.
|
||||
|
||||
@item x86
|
||||
x86 SIMD kernels.
|
||||
|
||||
@item aarch64
|
||||
AArch64 NEON kernels.
|
||||
|
||||
@item spirv
|
||||
Vulkan SPIR-V backend.
|
||||
|
||||
@item glsl
|
||||
Vulkan GLSL backend.
|
||||
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
@c man end SCALER OPTIONS
|
||||
|
||||
+2
-3
@@ -13,9 +13,8 @@ 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_reinit() initially and on format changes,
|
||||
splits interlaced images into separate fields, and calls ff_sws_graph_run()
|
||||
on each.
|
||||
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.
|
||||
|
||||
|
||||
+73
-53
@@ -55,8 +55,7 @@ sub get_formatting_function($$) {
|
||||
|
||||
# determine texinfo version
|
||||
my $package_version = ff_get_conf('PACKAGE_VERSION');
|
||||
$package_version =~ s/\+nc$//;
|
||||
$package_version =~ s/\+?dev$//;
|
||||
$package_version =~ s/\+dev$//;
|
||||
my $program_version_num = version->declare($package_version)->numify;
|
||||
my $program_version_6_8 = $program_version_num >= 6.008000;
|
||||
|
||||
@@ -120,8 +119,29 @@ sub ffmpeg_heading_command($$$$$)
|
||||
}
|
||||
|
||||
my $heading_level;
|
||||
# Never use node for heading
|
||||
if ($cmdname ne 'node') {
|
||||
# node is used as heading if there is nothing else.
|
||||
if ($cmdname eq 'node') {
|
||||
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') {
|
||||
$heading_level = 0;
|
||||
} else {
|
||||
$heading_level = 3;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (defined($command->{'extra'})
|
||||
and defined($command->{'extra'}->{'section_level'})) {
|
||||
$heading_level = $command->{'extra'}->{'section_level'};
|
||||
@@ -133,58 +153,58 @@ sub ffmpeg_heading_command($$$$$)
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($heading_level)) {
|
||||
my $heading = $self->command_text($command);
|
||||
# empty heading corresponds to an empty @top
|
||||
if ($heading ne '') {
|
||||
if ($root_commands{$cmdname}
|
||||
and $sectioning_commands{$cmdname}) {
|
||||
my $content_href = $self->command_contents_href($command, 'contents',
|
||||
$self->{'current_filename'});
|
||||
if ($content_href) {
|
||||
my $this_href = $content_href =~ s/^\#toc-/\#/r;
|
||||
$heading .= '<span class="pull-right">'.
|
||||
'<a class="anchor hidden-xs" '.
|
||||
"href=\"$this_href\" aria-hidden=\"true\">".
|
||||
($ENV{"FA_ICONS"} ? '<i class="fa fa-link"></i>'
|
||||
: '#').
|
||||
'</a> '.
|
||||
'<a class="anchor hidden-xs"'.
|
||||
"href=\"$content_href\" aria-hidden=\"true\">".
|
||||
($ENV{"FA_ICONS"} ? '<i class="fa fa-navicon"></i>'
|
||||
: 'TOC').
|
||||
'</a>'.
|
||||
'</span>';
|
||||
}
|
||||
}
|
||||
my $heading = $self->command_text($command);
|
||||
# $heading not defined may happen if the command is a @node, for example
|
||||
# if there is an error in the node.
|
||||
if (defined($heading) and $heading ne '' and defined($heading_level)) {
|
||||
|
||||
my $in_preformatted;
|
||||
if ($program_version_num >= 7.001090) {
|
||||
$in_preformatted = $self->in_preformatted_context();
|
||||
} else {
|
||||
$in_preformatted = $self->in_preformatted();
|
||||
if ($root_commands{$cmdname}
|
||||
and $sectioning_commands{$cmdname}) {
|
||||
my $content_href = $self->command_contents_href($command, 'contents',
|
||||
$self->{'current_filename'});
|
||||
if ($content_href) {
|
||||
my $this_href = $content_href =~ s/^\#toc-/\#/r;
|
||||
$heading .= '<span class="pull-right">'.
|
||||
'<a class="anchor hidden-xs" '.
|
||||
"href=\"$this_href\" aria-hidden=\"true\">".
|
||||
($ENV{"FA_ICONS"} ? '<i class="fa fa-link"></i>'
|
||||
: '#').
|
||||
'</a> '.
|
||||
'<a class="anchor hidden-xs"'.
|
||||
"href=\"$content_href\" aria-hidden=\"true\">".
|
||||
($ENV{"FA_ICONS"} ? '<i class="fa fa-navicon"></i>'
|
||||
: 'TOC').
|
||||
'</a>'.
|
||||
'</span>';
|
||||
}
|
||||
if ($in_preformatted) {
|
||||
$result .= $heading."\n";
|
||||
} else {
|
||||
# if the level was changed, set the command name right
|
||||
if ($cmdname ne 'node'
|
||||
and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
|
||||
$cmdname
|
||||
= $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
|
||||
}
|
||||
if ($program_version_num >= 7.000000) {
|
||||
$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);
|
||||
}
|
||||
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
|
||||
if ($cmdname ne 'node'
|
||||
and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
|
||||
$cmdname
|
||||
= $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
|
||||
}
|
||||
if ($program_version_num >= 7.000000) {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-17
@@ -1,17 +1,14 @@
|
||||
# Transforms
|
||||
|
||||
The basis transforms used for FFT and various other derived functions are based on the following unrollings.
|
||||
The basis transforms used for FFT and various other derived functions are based
|
||||
on the following unrollings.
|
||||
The functions can be easily adapted to double precision floats as well.
|
||||
|
||||
## Parity permutation
|
||||
|
||||
# Parity permutation
|
||||
The basis transforms described here all use the following permutation:
|
||||
|
||||
``` C
|
||||
void ff_tx_gen_split_radix_parity_revtab(int *revtab, int len, int inv,
|
||||
int basis, int dual_stride);
|
||||
```
|
||||
|
||||
Parity means even and odd complex numbers will be split, e.g. the even
|
||||
coefficients will come first, after which the odd coefficients will be
|
||||
placed. For example, a 4-point transform's coefficients after reordering:
|
||||
@@ -36,8 +33,7 @@ register or 0. This allows to reuse SSE functions as dual-transform
|
||||
functions in AVX mode.
|
||||
If length is smaller than basis/2 this function will not do anything.
|
||||
|
||||
## 4-point FFT transform
|
||||
|
||||
# 4-point FFT transform
|
||||
The only permutation this transform needs is to swap the `z[1]` and `z[2]`
|
||||
elements when performing an inverse transform, which in the assembly code is
|
||||
hardcoded with the function itself being templated and duplicated for each
|
||||
@@ -84,8 +80,7 @@ static void fft4(FFTComplex *z)
|
||||
}
|
||||
```
|
||||
|
||||
## 8-point AVX FFT transform
|
||||
|
||||
# 8-point AVX FFT transform
|
||||
Input must be pre-permuted using the parity lookup table, generated via
|
||||
`ff_tx_gen_split_radix_parity_revtab`.
|
||||
|
||||
@@ -198,8 +193,7 @@ This theme continues throughout the document. Note that in the actual assembly c
|
||||
the paths are interleaved to improve unit saturation and CPU dependency tracking, so
|
||||
to more clearly see them, you'll need to deinterleave the instructions.
|
||||
|
||||
## 8-point SSE/ARM64 FFT transform
|
||||
|
||||
# 8-point SSE/ARM64 FFT transform
|
||||
Input must be pre-permuted using the parity lookup table, generated via
|
||||
`ff_tx_gen_split_radix_parity_revtab`.
|
||||
|
||||
@@ -311,8 +305,7 @@ static void fft8(FFTComplex *z)
|
||||
Most functions here are highly tuned to use x86's addsub instruction to save on
|
||||
external sign mask loading.
|
||||
|
||||
## 16-point AVX FFT transform
|
||||
|
||||
# 16-point AVX FFT transform
|
||||
This version expects the output of the 8 and 4-point transforms to follow the
|
||||
even/odd convention established above.
|
||||
|
||||
@@ -452,8 +445,7 @@ static void fft16(FFTComplex *z)
|
||||
}
|
||||
```
|
||||
|
||||
## AVX split-radix synthesis
|
||||
|
||||
# AVX split-radix synthesis
|
||||
To create larger transforms, the following unrolling of the C split-radix
|
||||
function is used.
|
||||
|
||||
@@ -713,8 +705,8 @@ beginning to overlap, particularly `[o1]` with `[0]` after the second iteration.
|
||||
To iterate further, set `z = &z[16]` via `z += 8` for the second iteration. After
|
||||
the 4th iteration, the layout resets, so repeat the same.
|
||||
|
||||
## 15-point AVX FFT transform
|
||||
|
||||
# 15-point AVX FFT transform
|
||||
The 15-point transform is based on the following unrolling. The input
|
||||
must be permuted via the following loop:
|
||||
|
||||
|
||||
+20
-10
@@ -2,6 +2,14 @@
|
||||
# common bits used by all libraries
|
||||
#
|
||||
|
||||
DEFAULT_X86ASMD=.dbg
|
||||
|
||||
ifeq ($(DBG),1)
|
||||
X86ASMD=$(DEFAULT_X86ASMD)
|
||||
else
|
||||
X86ASMD=
|
||||
endif
|
||||
|
||||
ifndef SUBDIR
|
||||
|
||||
LINK = $(LD) $(1)
|
||||
@@ -27,7 +35,7 @@ M = @$(call ECHO,$(TAG),$@);
|
||||
$(foreach VAR,$(BRIEF), \
|
||||
$(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
|
||||
$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
|
||||
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_PATH)/%=%)); $(INSTALL))
|
||||
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
|
||||
endif
|
||||
|
||||
# Prepend to a recursively expanded variable without making it simply expanded.
|
||||
@@ -97,6 +105,10 @@ COMPILE_LASX = $(call COMPILE,CC,LASXFLAGS)
|
||||
%_host.o: %.c
|
||||
$(COMPILE_HOSTC)
|
||||
|
||||
%$(DEFAULT_X86ASMD).asm: %.asm
|
||||
$(DEPX86ASM) $(X86ASMFLAGS) -M -o $@ $< > $(@:.asm=.d)
|
||||
$(X86ASM) $(X86ASMFLAGS) -e $< | sed '/^%/d;/^$$/d;' > $@
|
||||
|
||||
%.o: %.asm
|
||||
$(COMPILE_X86ASM)
|
||||
-$(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@)
|
||||
@@ -114,8 +126,8 @@ $(BIN2CEXE): ffbuild/bin2c_host.o
|
||||
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS)
|
||||
|
||||
RUN_BIN2C = $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
RUN_GZIP = $(M)mkdir -p $(dir $@) && gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
|
||||
RUN_MINIFY = $(M)mkdir -p $(dir $@) && sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@
|
||||
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
|
||||
|
||||
@@ -185,7 +197,7 @@ endif
|
||||
clean::
|
||||
$(RM) $(BIN2CEXE) $(CLEANSUFFIXES:%=ffbuild/%)
|
||||
|
||||
%.c %.h %.S %.pc %.ver %.version: TAG = GEN
|
||||
%.c %.h %.pc %.ver %.version: TAG = GEN
|
||||
|
||||
# Dummy rule to stop make trying to rebuild removed or renamed headers
|
||||
%.h %_template.c:
|
||||
@@ -205,7 +217,6 @@ OBJS += $(OBJS-yes)
|
||||
SHLIBOBJS += $(SHLIBOBJS-yes)
|
||||
STLIBOBJS += $(STLIBOBJS-yes)
|
||||
FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS)
|
||||
DEVPROGS += $(DEVPROGS-yes)
|
||||
TESTPROGS += $(TESTPROGS-yes)
|
||||
|
||||
LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
|
||||
@@ -214,8 +225,7 @@ FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=
|
||||
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
|
||||
SHLIBOBJS := $(sort $(SHLIBOBJS:%=$(SUBDIR)%))
|
||||
STLIBOBJS := $(sort $(STLIBOBJS:%=$(SUBDIR)%))
|
||||
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o) $(DEVPROGS:%=$(SUBDIR)%.o)
|
||||
DEVPROGS := $(DEVPROGS:%=$(SUBDIR)%$(EXESUF))
|
||||
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o)
|
||||
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)tests/%$(EXESUF))
|
||||
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
|
||||
HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
|
||||
@@ -256,14 +266,14 @@ $(TOOLOBJS): | tools
|
||||
|
||||
OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS))
|
||||
|
||||
CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.gz *.spv.c *.gen.asm *.gen.c *.gen.S *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *~ *.ilk *.pdb
|
||||
CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.gz *.spv.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
|
||||
clean::
|
||||
$(RM) $(DEVPROGS) $(HOSTPROGS) $(TESTPROGS) $(TOOLS)
|
||||
$(RM) $(HOSTPROGS) $(TESTPROGS) $(TOOLS)
|
||||
endef
|
||||
|
||||
$(eval $(RULES))
|
||||
|
||||
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SPVOBJS:.spv.o=.d))
|
||||
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SPVOBJS:.spv.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d)
|
||||
|
||||
+7
-26
@@ -14,15 +14,6 @@ INSTHEADERS := $(INSTHEADERS) $(HEADERS:%=$(SUBDIR)%)
|
||||
all-$(CONFIG_STATIC): $(SUBDIR)$(LIBNAME) $(SUBDIR)lib$(FULLNAME).pc
|
||||
all-$(CONFIG_SHARED): $(SUBDIR)$(SLIBNAME) $(SUBDIR)lib$(FULLNAME).pc
|
||||
|
||||
# Make <4.0 does not support the built-in file function;
|
||||
# versions that do support it should use it, as it's
|
||||
# faster and isn't bound by command line length limits.
|
||||
ifeq (4.0,$(firstword $(sort 4.0 $(MAKE_VERSION))))
|
||||
HAVE_BUILTIN_FILE := yes
|
||||
else
|
||||
HAVE_BUILTIN_FILE := no
|
||||
endif
|
||||
|
||||
LIBOBJS := $(OBJS) $(SHLIBOBJS) $(STLIBOBJS) $(SUBDIR)%.h.o $(TESTOBJS)
|
||||
$(LIBOBJS) $(LIBOBJS:.o=.s) $(LIBOBJS:.o=.i): CPPFLAGS += -DHAVE_AV_CONFIG_H
|
||||
|
||||
@@ -45,11 +36,7 @@ endif
|
||||
$(SUBDIR)$(LIBNAME): $(OBJS) $(STLIBOBJS)
|
||||
$(RM) $@
|
||||
ifeq ($(RESPONSE_FILES),yes)
|
||||
ifeq ($(HAVE_BUILTIN_FILE),yes)
|
||||
$(file >$@.objs,$^)
|
||||
else
|
||||
$(Q)echo $^ > $@.objs
|
||||
endif
|
||||
$(AR) $(ARFLAGS) $(AR_O) @$@.objs
|
||||
else
|
||||
$(AR) $(ARFLAGS) $(AR_O) $^
|
||||
@@ -64,13 +51,15 @@ install-libs-$(CONFIG_SHARED): install-lib$(NAME)-shared
|
||||
|
||||
define RULES
|
||||
$(TOOLS): THISLIB = $(FULLNAME:%=$(LD_LIB))
|
||||
$(TESTPROGS) $(DEVPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
|
||||
$(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
|
||||
|
||||
$(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME)
|
||||
|
||||
$(NAME)LINK_EXE_ARGS = $(LDFLAGS) $(LDEXEFLAGS)
|
||||
$(NAME)LINK_SO_ARGS = $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS)
|
||||
$(NAME)LINK_EXTRA = $(FFEXTRALIBS)
|
||||
|
||||
$(DEVPROGS) $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
|
||||
$(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
|
||||
$$(call LINK,$$(call $(NAME)LINK_EXE_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $$(call $(NAME)LINK_EXTRA) $$(EXTRALIBS-$$(*F)) $$(ELIBS))
|
||||
|
||||
$(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h $(SUBDIR)version_major.h | $(SUBDIR)
|
||||
@@ -86,20 +75,14 @@ $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR)
|
||||
$(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME)
|
||||
|
||||
$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SUBDIR)lib$(NAME).ver
|
||||
$(SLIB_CREATE_DEF_CMD)
|
||||
ifeq ($(RESPONSE_FILES),yes)
|
||||
ifeq ($(HAVE_BUILTIN_FILE),yes)
|
||||
$$(file >$$@.objs,$$(filter %.o,$$^))
|
||||
else
|
||||
$(Q)echo $$(filter %.o,$$^) > $$@.objs
|
||||
endif
|
||||
endif
|
||||
$(Q)$(SLIB_CREATE_DEF_CMD)
|
||||
ifeq ($(RESPONSE_FILES),yes)
|
||||
$$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) @$$@.objs $$(call $(NAME)LINK_EXTRA))
|
||||
else
|
||||
$$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(call $(NAME)LINK_EXTRA))
|
||||
endif
|
||||
$(Q)$(SLIB_EXTRA_CMD)
|
||||
$(SLIB_EXTRA_CMD)
|
||||
-$(RM) $$@.objs
|
||||
|
||||
ifdef SUBDIR
|
||||
@@ -113,9 +96,7 @@ clean::
|
||||
install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME)
|
||||
$(Q)mkdir -p "$(SHLIBDIR)"
|
||||
$$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
|
||||
ifneq ($(STRIPTYPE),nostrip)
|
||||
$$(STRIP) "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
|
||||
endif
|
||||
$(Q)$(foreach F,$(SLIB_INSTALL_LINKS),(cd "$(SHLIBDIR)" && $(LN_S) $(SLIB_INSTALL_NAME) $(F));)
|
||||
$(if $(SLIB_INSTALL_EXTRA_SHLIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_SHLIB:%=$(SUBDIR)%) "$(SHLIBDIR)")
|
||||
$(if $(SLIB_INSTALL_EXTRA_LIB),$(Q)mkdir -p "$(LIBDIR)")
|
||||
@@ -153,6 +134,6 @@ endef
|
||||
$(eval $(RULES))
|
||||
|
||||
$(TOOLS): $(DEP_LIBS) $(SUBDIR)$($(CONFIG_SHARED:yes=S)LIBNAME)
|
||||
$(TESTPROGS) $(DEVPROGS): $(DEP_LIBS) $(SUBDIR)$(LIBNAME)
|
||||
$(TESTPROGS): $(DEP_LIBS) $(SUBDIR)$(LIBNAME)
|
||||
|
||||
testprogs: $(TESTPROGS)
|
||||
|
||||
+1
-1
@@ -1267,7 +1267,7 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
|
||||
break;
|
||||
}
|
||||
}
|
||||
av_fallthrough;
|
||||
// fall-through
|
||||
case STREAM_LIST_GROUP_IDX:
|
||||
if (ss->stream_list == STREAM_LIST_GROUP_IDX &&
|
||||
ss->list_id >= 0 && ss->list_id < s->nb_stream_groups)
|
||||
|
||||
@@ -216,16 +216,6 @@ void term_init(void)
|
||||
#endif
|
||||
|
||||
#if HAVE_TERMIOS_H
|
||||
/* A closed fd 0 is later reused by the first opened input file. read_key()
|
||||
* would then read from that input instead of the terminal and corrupt the
|
||||
* stream, so disable interaction when fd 0 is not an open descriptor.
|
||||
*/
|
||||
if (stdin_interaction && fcntl(0, F_GETFD) == -1) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"fd 0 is not an open file descriptor, stdin interaction disabled\n");
|
||||
stdin_interaction = 0;
|
||||
}
|
||||
|
||||
if (stdin_interaction) {
|
||||
struct termios tty;
|
||||
if (tcgetattr (0, &tty) == 0) {
|
||||
|
||||
+33
-3
@@ -51,6 +51,16 @@
|
||||
|
||||
#include "libswresample/swresample.h"
|
||||
|
||||
// deprecated features
|
||||
#define FFMPEG_OPT_QPHIST 1
|
||||
#define FFMPEG_OPT_ADRIFT_THRESHOLD 1
|
||||
#define FFMPEG_OPT_ENC_TIME_BASE_NUM 1
|
||||
#define FFMPEG_OPT_TOP 1
|
||||
#define FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP 1
|
||||
#define FFMPEG_OPT_VSYNC_DROP 1
|
||||
#define FFMPEG_OPT_VSYNC 1
|
||||
#define FFMPEG_OPT_FILTER_SCRIPT 1
|
||||
|
||||
#define FFMPEG_ERROR_RATE_EXCEEDED FFERRTAG('E', 'R', 'E', 'D')
|
||||
|
||||
enum VideoSyncMethod {
|
||||
@@ -59,6 +69,9 @@ enum VideoSyncMethod {
|
||||
VSYNC_CFR,
|
||||
VSYNC_VFR,
|
||||
VSYNC_VSCFR,
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
VSYNC_DROP,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum EncTimeBase {
|
||||
@@ -205,17 +218,21 @@ typedef struct OptionsContext {
|
||||
SpecifierOptList display_rotations;
|
||||
SpecifierOptList display_hflips;
|
||||
SpecifierOptList display_vflips;
|
||||
SpecifierOptList mastering_displays;
|
||||
SpecifierOptList content_lights;
|
||||
SpecifierOptList rc_overrides;
|
||||
SpecifierOptList intra_matrices;
|
||||
SpecifierOptList inter_matrices;
|
||||
SpecifierOptList chroma_intra_matrices;
|
||||
#if FFMPEG_OPT_TOP
|
||||
SpecifierOptList top_field_first;
|
||||
#endif
|
||||
SpecifierOptList metadata_map;
|
||||
SpecifierOptList presets;
|
||||
SpecifierOptList copy_initial_nonkeyframes;
|
||||
SpecifierOptList copy_prior_start;
|
||||
SpecifierOptList filters;
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
SpecifierOptList filter_scripts;
|
||||
#endif
|
||||
SpecifierOptList reinit_filters;
|
||||
SpecifierOptList drop_changed;
|
||||
SpecifierOptList fix_sub_duration;
|
||||
@@ -417,6 +434,9 @@ enum DecoderFlags {
|
||||
// decoder should override timestamps by fixed framerate
|
||||
// from DecoderOpts.framerate
|
||||
DECODER_FLAG_FRAMERATE_FORCED = (1 << 2),
|
||||
#if FFMPEG_OPT_TOP
|
||||
DECODER_FLAG_TOP_FIELD_FIRST = (1 << 3),
|
||||
#endif
|
||||
DECODER_FLAG_SEND_END_TS = (1 << 4),
|
||||
// force bitexact decoding
|
||||
DECODER_FLAG_BITEXACT = (1 << 5),
|
||||
@@ -480,6 +500,9 @@ typedef struct InputStream {
|
||||
|
||||
/* framerate forced with -r */
|
||||
AVRational framerate;
|
||||
#if FFMPEG_OPT_TOP
|
||||
int top_field_first;
|
||||
#endif
|
||||
|
||||
int fix_sub_duration;
|
||||
|
||||
@@ -581,6 +604,9 @@ typedef struct EncStats {
|
||||
|
||||
enum {
|
||||
KF_FORCE_SOURCE = 1,
|
||||
#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
|
||||
KF_FORCE_SOURCE_NO_DROP = 2,
|
||||
#endif
|
||||
// force keyframe if lavfi.scd.time metadata is set
|
||||
KF_FORCE_SCD_METADATA = 3,
|
||||
};
|
||||
@@ -637,6 +663,10 @@ typedef struct OutputStream {
|
||||
|
||||
Encoder *enc;
|
||||
|
||||
/* video only */
|
||||
#if FFMPEG_OPT_TOP
|
||||
int top_field_first;
|
||||
#endif
|
||||
int bitexact;
|
||||
int bits_per_raw_sample;
|
||||
|
||||
@@ -783,7 +813,7 @@ int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used
|
||||
int assert_file_overwrite(const char *filename);
|
||||
int find_codec(void *logctx, const char *name,
|
||||
enum AVMediaType type, int encoder, const AVCodec **codec);
|
||||
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx);
|
||||
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global);
|
||||
|
||||
int filtergraph_is_simple(const FilterGraph *fg);
|
||||
int fg_create_simple(FilterGraph **pfg,
|
||||
|
||||
@@ -387,6 +387,13 @@ fail:
|
||||
static int video_frame_process(DecoderPriv *dp, AVFrame *frame,
|
||||
unsigned *outputs_mask)
|
||||
{
|
||||
#if FFMPEG_OPT_TOP
|
||||
if (dp->flags & DECODER_FLAG_TOP_FIELD_FIRST) {
|
||||
av_log(dp, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n");
|
||||
frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (frame->format == dp->hwaccel_pix_fmt) {
|
||||
int err = hwaccel_retrieve_data(dp->dec_ctx, frame);
|
||||
if (err < 0)
|
||||
|
||||
+17
-154
@@ -28,7 +28,6 @@
|
||||
#include "libavutil/display.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/mastering_display_metadata.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/parseutils.h"
|
||||
@@ -69,8 +68,6 @@ typedef struct DemuxStream {
|
||||
int autorotate;
|
||||
int apply_cropping;
|
||||
int force_display_matrix;
|
||||
int force_mastering_display;
|
||||
int force_content_light;
|
||||
int drop_changed;
|
||||
|
||||
|
||||
@@ -998,7 +995,11 @@ int ist_use(InputStream *ist, int decoding_needed,
|
||||
|
||||
ds->dec_opts.flags |= (!!ist->fix_sub_duration * DECODER_FLAG_FIX_SUB_DURATION) |
|
||||
(!!is_unreliable * DECODER_FLAG_TS_UNRELIABLE) |
|
||||
(!!(d->loop && is_audio) * DECODER_FLAG_SEND_END_TS);
|
||||
(!!(d->loop && is_audio) * DECODER_FLAG_SEND_END_TS)
|
||||
#if FFMPEG_OPT_TOP
|
||||
| ((ist->top_field_first >= 0) * DECODER_FLAG_TOP_FIELD_FIRST)
|
||||
#endif
|
||||
;
|
||||
|
||||
if (ist->framerate.num) {
|
||||
ds->dec_opts.flags |= DECODER_FLAG_FRAMERATE_FORCED;
|
||||
@@ -1260,125 +1261,6 @@ static int add_display_matrix_to_stream(const OptionsContext *o,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_mastering_display_to_stream(const OptionsContext *o,
|
||||
AVFormatContext *ctx, InputStream *ist)
|
||||
{
|
||||
AVStream *st = ist->st;
|
||||
DemuxStream *ds = ds_from_ist(ist);
|
||||
AVMasteringDisplayMetadata *master_display;
|
||||
AVPacketSideData *sd;
|
||||
const char *p = NULL;
|
||||
const int chroma_den = 50000;
|
||||
const int luma_den = 10000;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
opt_match_per_stream_str(ist, &o->mastering_displays, ctx, st, &p);
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
master_display = av_mastering_display_metadata_alloc_size(&size);
|
||||
if (!master_display)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = sscanf(p,
|
||||
"G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)",
|
||||
(unsigned*)&master_display->display_primaries[1][0].num,
|
||||
(unsigned*)&master_display->display_primaries[1][1].num,
|
||||
(unsigned*)&master_display->display_primaries[2][0].num,
|
||||
(unsigned*)&master_display->display_primaries[2][1].num,
|
||||
(unsigned*)&master_display->display_primaries[0][0].num,
|
||||
(unsigned*)&master_display->display_primaries[0][1].num,
|
||||
(unsigned*)&master_display->white_point[0].num,
|
||||
(unsigned*)&master_display->white_point[1].num,
|
||||
(unsigned*)&master_display->max_luminance.num,
|
||||
(unsigned*)&master_display->min_luminance.num);
|
||||
|
||||
if (ret != 10 ||
|
||||
(unsigned)(master_display->display_primaries[1][0].num | master_display->display_primaries[1][1].num |
|
||||
master_display->display_primaries[2][0].num | master_display->display_primaries[2][1].num |
|
||||
master_display->display_primaries[0][0].num | master_display->display_primaries[0][1].num |
|
||||
master_display->white_point[0].num | master_display->white_point[1].num) > UINT16_MAX ||
|
||||
(unsigned)(master_display->max_luminance.num | master_display->min_luminance.num) > INT_MAX ||
|
||||
master_display->min_luminance.num > master_display->max_luminance.num) {
|
||||
av_freep(&master_display);
|
||||
av_log(ist, AV_LOG_ERROR, "Failed to parse mastering display option\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
master_display->display_primaries[1][0].den = chroma_den;
|
||||
master_display->display_primaries[1][1].den = chroma_den;
|
||||
master_display->display_primaries[2][0].den = chroma_den;
|
||||
master_display->display_primaries[2][1].den = chroma_den;
|
||||
master_display->display_primaries[0][0].den = chroma_den;
|
||||
master_display->display_primaries[0][1].den = chroma_den;
|
||||
master_display->white_point[0].den = chroma_den;
|
||||
master_display->white_point[1].den = chroma_den;
|
||||
master_display->max_luminance.den = luma_den;
|
||||
master_display->min_luminance.den = luma_den;
|
||||
|
||||
master_display->has_primaries = 1;
|
||||
master_display->has_luminance = 1;
|
||||
|
||||
sd = av_packet_side_data_add(&st->codecpar->coded_side_data,
|
||||
&st->codecpar->nb_coded_side_data,
|
||||
AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
|
||||
(uint8_t *)master_display, size, 0);
|
||||
if (!sd) {
|
||||
av_freep(&master_display);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
ds->force_mastering_display = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_content_light_to_stream(const OptionsContext *o,
|
||||
AVFormatContext *ctx, InputStream *ist)
|
||||
{
|
||||
AVStream *st = ist->st;
|
||||
DemuxStream *ds = ds_from_ist(ist);
|
||||
AVContentLightMetadata *cll;
|
||||
AVPacketSideData *sd;
|
||||
const char *p = NULL;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
opt_match_per_stream_str(ist, &o->content_lights, ctx, st, &p);
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
cll = av_content_light_metadata_alloc(&size);
|
||||
if (!cll)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = sscanf(p, "%u,%u",
|
||||
(unsigned*)&cll->MaxCLL,
|
||||
(unsigned*)&cll->MaxFALL);
|
||||
|
||||
if (ret != 2 || (unsigned)(cll->MaxCLL | cll->MaxFALL) > UINT16_MAX) {
|
||||
av_freep(&cll);
|
||||
av_log(ist, AV_LOG_ERROR, "Failed to parse content light option\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
sd = av_packet_side_data_add(&st->codecpar->coded_side_data,
|
||||
&st->codecpar->nb_coded_side_data,
|
||||
AV_PKT_DATA_CONTENT_LIGHT_LEVEL,
|
||||
(uint8_t *)cll, size, 0);
|
||||
if (!sd) {
|
||||
av_freep(&cll);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
ds->force_content_light = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *input_stream_item_name(void *obj)
|
||||
{
|
||||
const DemuxStream *ds = obj;
|
||||
@@ -1432,7 +1314,6 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
||||
const char *bsfs = NULL;
|
||||
char *next;
|
||||
const char *discard_str = NULL;
|
||||
AVBPrint bp;
|
||||
int ret;
|
||||
|
||||
ds = demux_stream_alloc(d, st);
|
||||
@@ -1498,14 +1379,6 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = add_mastering_display_to_stream(o, ic, ist);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = add_content_light_to_stream(o, ic, ist);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
|
||||
opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
|
||||
&hwaccel_output_format);
|
||||
@@ -1623,26 +1496,15 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
||||
av_dict_set_int(&ds->decoder_opts, "apply_cropping",
|
||||
ds->apply_cropping && ds->apply_cropping != CROP_CONTAINER, 0);
|
||||
|
||||
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
|
||||
if (ds->force_display_matrix) {
|
||||
char buf[32];
|
||||
if (av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||
av_bprintf(&bp, ",");
|
||||
av_bprintf(&bp, "displaymatrix");
|
||||
buf[0] = ',';
|
||||
else
|
||||
buf[0] = '\0';
|
||||
av_strlcat(buf, "displaymatrix", sizeof(buf));
|
||||
av_dict_set(&ds->decoder_opts, "side_data_prefer_packet", buf, AV_DICT_APPEND);
|
||||
}
|
||||
if (ds->force_mastering_display) {
|
||||
if (bp.len || av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||
av_bprintf(&bp, ",");
|
||||
av_bprintf(&bp, "mastering_display_metadata");
|
||||
}
|
||||
if (ds->force_content_light) {
|
||||
if (bp.len || av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||
av_bprintf(&bp, ",");
|
||||
av_bprintf(&bp, "content_light_level");
|
||||
}
|
||||
if (bp.len)
|
||||
av_dict_set(&ds->decoder_opts, "side_data_prefer_packet", bp.str, AV_DICT_APPEND);
|
||||
av_bprint_finalize(&bp, NULL);
|
||||
|
||||
/* Attached pics are sparse, therefore we would not want to delay their decoding
|
||||
* till EOF. */
|
||||
if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)
|
||||
@@ -1659,6 +1521,12 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_TOP
|
||||
ist->top_field_first = -1;
|
||||
opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO: {
|
||||
const char *ch_layout_str = NULL;
|
||||
@@ -1804,11 +1672,6 @@ static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStream
|
||||
|
||||
if (tg->nb_tiles == 1)
|
||||
return 0;
|
||||
if (!tg->nb_tiles) {
|
||||
av_log(istg, AV_LOG_FATAL, "A demuxer exported an invalid tile group stream group. "
|
||||
"This is a bug, please report it.\n");
|
||||
return AVERROR_BUG;
|
||||
}
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
|
||||
|
||||
+18
-5
@@ -227,9 +227,6 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||
frame->ch_layout.nb_channels > 0);
|
||||
enc_ctx->sample_fmt = frame->format;
|
||||
enc_ctx->sample_rate = frame->sample_rate;
|
||||
if (!enc_ctx->frame_size && (!(enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ||
|
||||
(enc_ctx->flags2 & AV_CODEC_FLAG2_FIXED_FRAME_SIZE)))
|
||||
enc_ctx->frame_size = frame->nb_samples;
|
||||
ret = av_channel_layout_copy(&enc_ctx->ch_layout, &frame->ch_layout);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -283,8 +280,17 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||
}
|
||||
|
||||
if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) ||
|
||||
(frame->flags & AV_FRAME_FLAG_INTERLACED)) {
|
||||
int top_field_first = !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
|
||||
(frame->flags & AV_FRAME_FLAG_INTERLACED)
|
||||
#if FFMPEG_OPT_TOP
|
||||
|| ost->top_field_first >= 0
|
||||
#endif
|
||||
) {
|
||||
int top_field_first =
|
||||
#if FFMPEG_OPT_TOP
|
||||
ost->top_field_first >= 0 ?
|
||||
ost->top_field_first :
|
||||
#endif
|
||||
!!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
|
||||
|
||||
if (enc->id == AV_CODEC_ID_MJPEG)
|
||||
enc_ctx->field_order = top_field_first ? AV_FIELD_TT : AV_FIELD_BB;
|
||||
@@ -796,6 +802,13 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt)
|
||||
if (type == AVMEDIA_TYPE_VIDEO) {
|
||||
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) {
|
||||
frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
||||
frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * (!!ost->top_field_first);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (!(e->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&
|
||||
e->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) {
|
||||
|
||||
+37
-21
@@ -27,7 +27,6 @@
|
||||
#include "libavfilter/buffersink.h"
|
||||
#include "libavfilter/buffersrc.h"
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/bprint.h"
|
||||
@@ -51,6 +50,8 @@ typedef struct FilterGraphPriv {
|
||||
// true when the filtergraph contains only meta filters
|
||||
// that do not modify the frame data
|
||||
int is_meta;
|
||||
// source filters are present in the graph
|
||||
int have_sources;
|
||||
int disable_conversions;
|
||||
|
||||
unsigned nb_outputs_done;
|
||||
@@ -1037,7 +1038,6 @@ void fg_free(FilterGraph **pfg)
|
||||
av_frame_free(&ifp->opts.fallback);
|
||||
|
||||
av_buffer_unref(&ifp->hw_frames_ctx);
|
||||
av_channel_layout_uninit(&ifp->ch_layout);
|
||||
av_freep(&ifilter->linklabel);
|
||||
av_freep(&ifp->opts.name);
|
||||
av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data);
|
||||
@@ -1143,6 +1143,16 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
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)) ||
|
||||
!strcmp(f->name, "apad")) {
|
||||
fgp->have_sources = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (AVFilterInOut *cur = inputs; cur; cur = cur->next) {
|
||||
InputFilter *const ifilter = ifilter_alloc(fg);
|
||||
|
||||
@@ -1671,10 +1681,7 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
|
||||
av_frame_side_data_remove(&ofp->side_data, &ofp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
}
|
||||
|
||||
if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE) &&
|
||||
// skip add scale for hardware format
|
||||
!(ofp->format != AV_PIX_FMT_NONE &&
|
||||
av_pix_fmt_desc_get(ofp->format)->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
|
||||
if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) {
|
||||
char args[255];
|
||||
AVFilterContext *filter;
|
||||
const AVDictionaryEntry *e = NULL;
|
||||
@@ -1799,8 +1806,10 @@ static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
|
||||
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", ofilter->output_name);
|
||||
ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us,
|
||||
@@ -2257,7 +2266,8 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
||||
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))
|
||||
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL) ||
|
||||
frame->side_data[i]->type == AV_FRAME_DATA_DISPLAYMATRIX)
|
||||
continue;
|
||||
|
||||
ret = av_frame_side_data_clone(&ifp->side_data,
|
||||
@@ -2268,11 +2278,8 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
||||
}
|
||||
|
||||
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
if (sd) {
|
||||
if (sd)
|
||||
memcpy(ifp->displaymatrix, sd->data, sizeof(ifp->displaymatrix));
|
||||
if (ifp->opts.flags & IFILTER_FLAG_AUTOROTATE)
|
||||
av_frame_side_data_remove(&ifp->side_data, &ifp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
}
|
||||
ifp->displaymatrix_present = !!sd;
|
||||
|
||||
/* Copy downmix related side data to InputFilterPriv so it may be propagated
|
||||
@@ -2540,7 +2547,11 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
|
||||
|
||||
if (delta0 < 0 &&
|
||||
delta > 0 &&
|
||||
fps->vsync_method != VSYNC_PASSTHROUGH) {
|
||||
fps->vsync_method != VSYNC_PASSTHROUGH
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
&& fps->vsync_method != VSYNC_DROP
|
||||
#endif
|
||||
) {
|
||||
if (delta0 < -0.6) {
|
||||
av_log(ofp, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0);
|
||||
} else
|
||||
@@ -2558,7 +2569,6 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
|
||||
delta0 = 0;
|
||||
ofp->next_pts = llrint(sync_ipts);
|
||||
}
|
||||
av_fallthrough;
|
||||
case VSYNC_CFR:
|
||||
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
|
||||
if (frame_drop_threshold && delta < frame_drop_threshold && fps->frame_number) {
|
||||
@@ -2579,6 +2589,9 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
|
||||
ofp->next_pts = llrint(sync_ipts);
|
||||
frame->duration = llrint(duration);
|
||||
break;
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
case VSYNC_DROP:
|
||||
#endif
|
||||
case VSYNC_PASSTHROUGH:
|
||||
ofp->next_pts = llrint(sync_ipts);
|
||||
frame->duration = llrint(duration);
|
||||
@@ -2823,10 +2836,8 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt,
|
||||
if (!fgt->got_frame) {
|
||||
ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0) {
|
||||
av_frame_unref(frame);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fd->wallclock[LATENCY_PROBE_FILTER_POST] = av_gettime_relative();
|
||||
@@ -2860,6 +2871,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
AVFrame *frame)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
||||
int did_step = 0;
|
||||
|
||||
// graph not configured, just select the input to request
|
||||
if (!fgt->graph) {
|
||||
@@ -2878,7 +2890,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
return AVERROR_BUG;
|
||||
}
|
||||
|
||||
if (fgp->nb_outputs_done < fg->nb_outputs) {
|
||||
while (fgp->nb_outputs_done < fg->nb_outputs) {
|
||||
int ret;
|
||||
|
||||
/* Reap all buffers present in the buffer sinks */
|
||||
@@ -2893,6 +2905,9 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
@@ -2909,8 +2924,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
}
|
||||
fgt->next_in = fg->nb_inputs;
|
||||
|
||||
// return so that scheduler can rate-control us
|
||||
return 0;
|
||||
did_step = 1;
|
||||
}
|
||||
|
||||
return AVERROR_EOF;
|
||||
@@ -3167,7 +3181,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
const char *color_space_name = av_color_space_name(frame->colorspace);
|
||||
const char *color_range_name = av_color_range_name(frame->color_range);
|
||||
const char *alpha_mode = av_alpha_mode_name(frame->alpha_mode);
|
||||
av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, %s alpha, ",
|
||||
av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, %s alpha,",
|
||||
unknown_if_null(pixel_format_name), unknown_if_null(color_range_name),
|
||||
unknown_if_null(color_space_name), frame->width, frame->height,
|
||||
unknown_if_null(alpha_mode));
|
||||
@@ -3323,6 +3337,8 @@ static int filter_thread(void *arg)
|
||||
|
||||
o = (intptr_t)fgt.frame->opaque;
|
||||
|
||||
o = (intptr_t)fgt.frame->opaque;
|
||||
|
||||
// message on the control stream
|
||||
if (input_idx == fg->nb_inputs) {
|
||||
FilterCommand *fc;
|
||||
|
||||
@@ -139,6 +139,11 @@ static int mux_fixup_ts(Muxer *mux, MuxStream *ms, AVPacket *pkt)
|
||||
{
|
||||
OutputStream *ost = &ms->ost;
|
||||
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
if (ost->type == AVMEDIA_TYPE_VIDEO && ms->ts_drop)
|
||||
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
|
||||
#endif
|
||||
|
||||
// rescale timestamps to the stream timebase
|
||||
if (ost->type == AVMEDIA_TYPE_AUDIO && !ost->enc) {
|
||||
// use av_rescale_delta() for streamcopying audio, to preserve
|
||||
|
||||
@@ -81,6 +81,9 @@ typedef struct MuxStream {
|
||||
int copy_initial_nonkeyframes;
|
||||
int copy_prior_start;
|
||||
int streamcopy_started;
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
int ts_drop;
|
||||
#endif
|
||||
|
||||
AVRational frame_rate;
|
||||
AVRational max_frame_rate;
|
||||
|
||||
+83
-24
@@ -417,19 +417,45 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc,
|
||||
OutputStream *ost, char **dst)
|
||||
{
|
||||
const char *filters = NULL;
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
const char *filters_script = NULL;
|
||||
|
||||
opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
|
||||
#endif
|
||||
opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
|
||||
|
||||
if (!ost->ist) {
|
||||
if (filters) {
|
||||
if (
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
filters_script ||
|
||||
#endif
|
||||
filters) {
|
||||
av_log(ost, AV_LOG_ERROR,
|
||||
"Filtergraph '%s' was specified for a stream fed from a complex "
|
||||
"%s '%s' was specified for a stream fed from a complex "
|
||||
"filtergraph. Simple and complex filtering cannot be used "
|
||||
"together for the same stream.\n", filters);
|
||||
"together for the same stream.\n",
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
filters ? "Filtergraph" : "Filtergraph script",
|
||||
filters ? filters : filters_script
|
||||
#else
|
||||
"Filtergraph", filters
|
||||
#endif
|
||||
);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
if (filters_script && filters) {
|
||||
av_log(ost, AV_LOG_ERROR, "Both -filter and -filter_script set\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (filters_script)
|
||||
*dst = read_file_to_string(filters_script);
|
||||
else
|
||||
#endif
|
||||
if (filters)
|
||||
*dst = av_strdup(filters);
|
||||
else
|
||||
@@ -735,10 +761,21 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
|
||||
|
||||
opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps);
|
||||
|
||||
#if FFMPEG_OPT_TOP
|
||||
ost->top_field_first = -1;
|
||||
opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first);
|
||||
if (ost->top_field_first >= 0)
|
||||
av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n");
|
||||
#endif
|
||||
|
||||
#if FFMPEG_OPT_VSYNC
|
||||
*vsync_method = video_sync_method;
|
||||
#else
|
||||
*vsync_method = VSYNC_AUTO;
|
||||
#endif
|
||||
opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
|
||||
if (fps_mode) {
|
||||
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index);
|
||||
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -773,6 +810,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
|
||||
*vsync_method = VSYNC_VSCFR;
|
||||
}
|
||||
}
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
if (*vsync_method == VSYNC_DROP)
|
||||
ms->ts_drop = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -999,12 +1040,28 @@ static int streamcopy_init(const OptionsContext *o, const Muxer *mux,
|
||||
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 (filters) {
|
||||
if (
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
filters_script ||
|
||||
#endif
|
||||
filters) {
|
||||
av_log(ost, AV_LOG_ERROR,
|
||||
"Filtergraph '%s' was specified, but codec copy was selected. "
|
||||
"Filtering and streamcopy cannot be used together.\n", filters);
|
||||
"%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);
|
||||
}
|
||||
|
||||
@@ -1344,11 +1401,20 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
|
||||
q = (AVRational){ ENC_TIME_BASE_FILTER, 0 };
|
||||
} else {
|
||||
ret = av_parse_ratio(&q, enc_time_base, INT_MAX, 0, NULL);
|
||||
if (ret < 0 || q.den <= 0 || q.num < 0) {
|
||||
if (ret < 0 || q.den <= 0
|
||||
#if !FFMPEG_OPT_ENC_TIME_BASE_NUM
|
||||
|| q.num < 0
|
||||
#endif
|
||||
) {
|
||||
av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base);
|
||||
ret = ret < 0 ? ret : AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
#if FFMPEG_OPT_ENC_TIME_BASE_NUM
|
||||
if (q.num < 0)
|
||||
av_log(ost, AV_LOG_WARNING, "-enc_time_base -1 is deprecated,"
|
||||
" use -enc_time_base demux\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
enc_tb = q;
|
||||
@@ -1465,8 +1531,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc)
|
||||
ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
if (oc->oformat->flags & AVFMT_FIXED_FRAMESIZE && ost->enc)
|
||||
ost->enc->enc_ctx->flags2 |= AV_CODEC_FLAG2_FIXED_FRAME_SIZE;
|
||||
|
||||
opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes,
|
||||
oc, st, &ms->copy_initial_nonkeyframes);
|
||||
@@ -2063,8 +2127,7 @@ 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 && type == AVMEDIA_TYPE_AUDIO &&
|
||||
(!(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ||
|
||||
(ost->enc->enc_ctx->flags2 & AV_CODEC_FLAG2_FIXED_FRAME_SIZE)));
|
||||
!(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);
|
||||
@@ -2489,10 +2552,6 @@ static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const cha
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AV_STREAM_GROUP_PARAMS_LCEVC:
|
||||
case AV_STREAM_GROUP_PARAMS_TREF:
|
||||
case AV_STREAM_GROUP_PARAMS_DOLBY_VISION:
|
||||
break;
|
||||
default:
|
||||
av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type);
|
||||
ret = AVERROR(EINVAL);
|
||||
@@ -2515,10 +2574,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
|
||||
{ .i64 = AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT }, .unit = "type" },
|
||||
{ "iamf_mix_presentation", NULL, 0, AV_OPT_TYPE_CONST,
|
||||
{ .i64 = AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION }, .unit = "type" },
|
||||
{ "lcevc", NULL, 0, AV_OPT_TYPE_CONST,
|
||||
{ .i64 = AV_STREAM_GROUP_PARAMS_LCEVC }, .unit = "type" },
|
||||
{ "tref", NULL, 0, AV_OPT_TYPE_CONST,
|
||||
{ .i64 = AV_STREAM_GROUP_PARAMS_TREF }, .unit = "type" },
|
||||
{ NULL },
|
||||
};
|
||||
const AVClass class = {
|
||||
@@ -2593,10 +2648,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
|
||||
ret = avformat_stream_group_add_stream(stg, oc->streams[idx]);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
OutputStream *ost = mux->of.streams[idx];
|
||||
if (ost->enc && (type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
|
||||
type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION))
|
||||
ost->enc->enc_ctx->flags2 |= AV_CODEC_FLAG2_FIXED_FRAME_SIZE;
|
||||
}
|
||||
while (e = av_dict_get(dict, "stg", e, 0)) {
|
||||
char *endptr;
|
||||
@@ -2621,6 +2672,8 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
|
||||
ret = of_parse_iamf_submixes(mux, stg, ptr);
|
||||
break;
|
||||
default:
|
||||
av_log(mux, AV_LOG_FATAL, "Unknown group type %d.\n", type);
|
||||
ret = AVERROR(EINVAL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3227,6 +3280,12 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
|
||||
// parse it only for static kf timings
|
||||
} else if (!strcmp(forced_keyframes, "source")) {
|
||||
ost->kf.type = KF_FORCE_SOURCE;
|
||||
#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
|
||||
} else if (!strcmp(forced_keyframes, "source_no_drop")) {
|
||||
av_log(ost, AV_LOG_WARNING, "The 'source_no_drop' value for "
|
||||
"-force_key_frames is deprecated, use just 'source'\n");
|
||||
ost->kf.type = KF_FORCE_SOURCE;
|
||||
#endif
|
||||
} else if (!strcmp(forced_keyframes, "scd_metadata")) {
|
||||
ost->kf.type = KF_FORCE_SCD_METADATA;
|
||||
} else {
|
||||
|
||||
+109
-11
@@ -56,6 +56,9 @@ char *vstats_filename;
|
||||
float dts_delta_threshold = 10;
|
||||
float dts_error_threshold = 3600*30;
|
||||
|
||||
#if FFMPEG_OPT_VSYNC
|
||||
enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
|
||||
#endif
|
||||
float frame_drop_threshold = 0;
|
||||
int do_benchmark = 0;
|
||||
int do_benchmark_all = 0;
|
||||
@@ -356,17 +359,38 @@ int view_specifier_parse(const char **pspec, ViewSpecifier *vs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx)
|
||||
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global)
|
||||
{
|
||||
if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR;
|
||||
else if (!av_strcasecmp(arg, "vfr")) *vsync_var = VSYNC_VFR;
|
||||
else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;
|
||||
else if (!av_strcasecmp(arg, "auto")) *vsync_var = VSYNC_AUTO;
|
||||
else {
|
||||
#if FFMPEG_OPT_VSYNC_DROP
|
||||
else if (!av_strcasecmp(arg, "drop")) {
|
||||
av_log(NULL, AV_LOG_WARNING, "-vsync/fps_mode drop is deprecated\n");
|
||||
*vsync_var = VSYNC_DROP;
|
||||
}
|
||||
#endif
|
||||
else if (!is_global && !av_strcasecmp(arg, "auto")) *vsync_var = VSYNC_AUTO;
|
||||
else if (!is_global) {
|
||||
av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_VSYNC
|
||||
if (is_global && *vsync_var == VSYNC_AUTO) {
|
||||
int ret;
|
||||
double num;
|
||||
|
||||
ret = parse_number("vsync", arg, OPT_TYPE_INT, VSYNC_AUTO, VSYNC_VFR, &num);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
video_sync_method = num;
|
||||
av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
|
||||
" use a string argument as described in the manual.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -621,7 +645,6 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
for (i = 0; i < o->nb_stream_maps; i++) {
|
||||
m = &o->stream_maps[i];
|
||||
if (file_idx == m->file_index &&
|
||||
!m->linklabel &&
|
||||
m->stream_index >= 0 &&
|
||||
m->stream_index < input_files[m->file_index]->nb_streams &&
|
||||
stream_specifier_match(&ss,
|
||||
@@ -1210,6 +1233,14 @@ static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
|
||||
return parse_option(o, "filter:a", arg, options);
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_VSYNC
|
||||
static int opt_vsync(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use -fps_mode\n");
|
||||
return parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int opt_timecode(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
OptionsContext *o = optctx;
|
||||
@@ -1250,6 +1281,31 @@ static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
GlobalOptionsContext *go = optctx;
|
||||
char *graph_desc;
|
||||
int ret;
|
||||
|
||||
graph_desc = read_file_to_string(arg);
|
||||
if (!graph_desc)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -/filter_complex %s instead\n",
|
||||
opt, arg);
|
||||
|
||||
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
|
||||
|
||||
void show_help_default(const char *opt, const char *arg)
|
||||
{
|
||||
int show_advanced = 0, show_avoptions = 0;
|
||||
@@ -1540,6 +1596,22 @@ int opt_timelimit(void *optctx, const char *opt, const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FFMPEG_OPT_QPHIST
|
||||
static int opt_qphist(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
av_log(NULL, AV_LOG_WARNING, "Option -%s is deprecated and has no effect\n", opt);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FFMPEG_OPT_ADRIFT_THRESHOLD
|
||||
static int opt_adrift_threshold(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
av_log(NULL, AV_LOG_WARNING, "Option -%s is deprecated and has no effect\n", opt);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 };
|
||||
@@ -1746,6 +1818,11 @@ const OptionDef options[] = {
|
||||
{ "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) },
|
||||
"deprecated, use -/filter", "filename" },
|
||||
#endif
|
||||
{ "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
|
||||
{ .off = OFFSET(reinit_filters) },
|
||||
"reinit filtergraph on input parameter changes", "" },
|
||||
@@ -1761,6 +1838,11 @@ const OptionDef options[] = {
|
||||
{ "lavfi", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
|
||||
{ .func_arg = opt_filter_complex },
|
||||
"create a complex filtergraph", "graph_description" },
|
||||
#if FFMPEG_OPT_FILTER_SCRIPT
|
||||
{ "filter_complex_script", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
|
||||
{ .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" },
|
||||
@@ -1860,12 +1942,6 @@ const OptionDef options[] = {
|
||||
{ .off = OFFSET(display_vflips) },
|
||||
"set display vertical flip for stream(s) "
|
||||
"(overrides any display rotation if it is not set)"},
|
||||
{ "mastering_display", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
|
||||
{ .off = OFFSET(mastering_displays) },
|
||||
"set SMPTE2084 mastering display color volume info" },
|
||||
{ "content_light", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
|
||||
{ .off = OFFSET(content_lights) },
|
||||
"set SMPTE2084 Max CLL and Max FALL values" },
|
||||
{ "vn", OPT_TYPE_BOOL, OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,
|
||||
{ .off = OFFSET(video_disable) },
|
||||
"disable video" },
|
||||
@@ -1913,7 +1989,7 @@ const OptionDef options[] = {
|
||||
.u1.name_canon = "tag", },
|
||||
{ "fps_mode", OPT_TYPE_STRING, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT,
|
||||
{ .off = OFFSET(fps_mode) },
|
||||
"set framerate mode for matching video streams" },
|
||||
"set framerate mode for matching video streams; overrides vsync" },
|
||||
{ "force_fps", OPT_TYPE_BOOL, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT,
|
||||
{ .off = OFFSET(force_fps) },
|
||||
"force the selected framerate, disable the best supported framerate selection" },
|
||||
@@ -2098,5 +2174,27 @@ const OptionDef options[] = {
|
||||
{ .func_arg = opt_filter_hw_device },
|
||||
"set hardware device used when filtering", "device" },
|
||||
|
||||
// deprecated options
|
||||
#if FFMPEG_OPT_ADRIFT_THRESHOLD
|
||||
{ "adrift_threshold", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
|
||||
{ .func_arg = opt_adrift_threshold },
|
||||
"deprecated, does nothing", "threshold" },
|
||||
#endif
|
||||
#if FFMPEG_OPT_TOP
|
||||
{ "top", OPT_TYPE_INT, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_INPUT | OPT_OUTPUT,
|
||||
{ .off = OFFSET(top_field_first) },
|
||||
"deprecated, use the setfield video filter", "" },
|
||||
#endif
|
||||
#if FFMPEG_OPT_QPHIST
|
||||
{ "qphist", OPT_TYPE_FUNC, OPT_VIDEO | OPT_EXPERT,
|
||||
{ .func_arg = opt_qphist },
|
||||
"deprecated, does nothing" },
|
||||
#endif
|
||||
#if FFMPEG_OPT_VSYNC
|
||||
{ "vsync", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
|
||||
{ .func_arg = opt_vsync },
|
||||
"set video sync method globally; deprecated, use -fps_mode", "" },
|
||||
#endif
|
||||
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
+53
-164
@@ -32,7 +32,6 @@
|
||||
#include "libavcodec/packet.h"
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/container_fifo.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/frame.h"
|
||||
@@ -87,7 +86,6 @@ typedef struct SchDec {
|
||||
unsigned nb_outputs;
|
||||
|
||||
SchTask task;
|
||||
SchWaiter waiter;
|
||||
// Queue for receiving input packets, one stream.
|
||||
ThreadQueue *queue;
|
||||
|
||||
@@ -97,9 +95,6 @@ typedef struct SchDec {
|
||||
|
||||
// temporary storage used by sch_dec_send()
|
||||
AVFrame *send_frame;
|
||||
|
||||
// internal queue of undecoded packets used by sch_dec_receive()
|
||||
AVContainerFifo *overflow;
|
||||
} SchDec;
|
||||
|
||||
typedef struct SchSyncQueue {
|
||||
@@ -440,7 +435,7 @@ static void task_init(Scheduler *sch, SchTask *task, enum SchedulerNodeType type
|
||||
task->func_arg = func_arg;
|
||||
}
|
||||
|
||||
static int64_t trailing_dts(const Scheduler *sch)
|
||||
static int64_t trailing_dts(const Scheduler *sch, int count_finished)
|
||||
{
|
||||
int64_t min_dts = INT64_MAX;
|
||||
|
||||
@@ -450,7 +445,7 @@ static int64_t trailing_dts(const Scheduler *sch)
|
||||
for (unsigned j = 0; j < mux->nb_streams; j++) {
|
||||
const SchMuxStream *ms = &mux->streams[j];
|
||||
|
||||
if (ms->source_finished)
|
||||
if (ms->source_finished && !count_finished)
|
||||
continue;
|
||||
if (ms->last_dts == AV_NOPTS_VALUE)
|
||||
return AV_NOPTS_VALUE;
|
||||
@@ -462,26 +457,6 @@ static int64_t trailing_dts(const Scheduler *sch)
|
||||
return min_dts == INT64_MAX ? AV_NOPTS_VALUE : min_dts;
|
||||
}
|
||||
|
||||
static int64_t progressing_dts(const Scheduler *sch, int count_finished)
|
||||
{
|
||||
int64_t max_dts = INT64_MIN;
|
||||
|
||||
for (unsigned i = 0; i < sch->nb_mux; i++) {
|
||||
const SchMux *mux = &sch->mux[i];
|
||||
|
||||
for (unsigned j = 0; j < mux->nb_streams; j++) {
|
||||
const SchMuxStream *ms = &mux->streams[j];
|
||||
|
||||
if (ms->source_finished && !count_finished)
|
||||
continue;
|
||||
if (ms->last_dts != AV_NOPTS_VALUE)
|
||||
max_dts = FFMAX(max_dts, ms->last_dts);
|
||||
}
|
||||
}
|
||||
|
||||
return max_dts == INT64_MIN ? AV_NOPTS_VALUE : max_dts;
|
||||
}
|
||||
|
||||
void sch_remove_filtergraph(Scheduler *sch, int idx)
|
||||
{
|
||||
SchFilterGraph *fg = &sch->filters[idx];
|
||||
@@ -553,7 +528,6 @@ void sch_free(Scheduler **psch)
|
||||
tq_free(&dec->queue);
|
||||
|
||||
av_thread_message_queue_free(&dec->queue_end_ts);
|
||||
av_container_fifo_free(&dec->overflow);
|
||||
|
||||
for (unsigned j = 0; j < dec->nb_outputs; j++) {
|
||||
SchDecOutput *o = &dec->outputs[j];
|
||||
@@ -565,8 +539,6 @@ void sch_free(Scheduler **psch)
|
||||
av_freep(&dec->outputs);
|
||||
|
||||
av_frame_free(&dec->send_frame);
|
||||
|
||||
waiter_uninit(&dec->waiter);
|
||||
}
|
||||
av_freep(&sch->dec);
|
||||
|
||||
@@ -817,14 +789,6 @@ int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dec->overflow = av_container_fifo_alloc_avpacket(0);
|
||||
if (!dec->overflow)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = waiter_init(&dec->waiter);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -1318,15 +1282,7 @@ int sch_mux_sub_heartbeat_add(Scheduler *sch, unsigned mux_idx, unsigned stream_
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
UNCHOKE_DEMUX = (1 << 0),
|
||||
UNCHOKE_FILTER = (1 << 1),
|
||||
UNCHOKE_DECODE = (1 << 2),
|
||||
|
||||
UNCHOKE_ALL = UNCHOKE_DEMUX | UNCHOKE_FILTER | UNCHOKE_DECODE,
|
||||
};
|
||||
|
||||
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags);
|
||||
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src);
|
||||
|
||||
// Unchoke any filter graphs that are downstream of this node, to prevent it
|
||||
// from getting stuck trying to push data to a full queue
|
||||
@@ -1338,10 +1294,8 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
|
||||
switch (dst->type) {
|
||||
case SCH_NODE_TYPE_DEC:
|
||||
dec = &sch->dec[dst->idx];
|
||||
if (!dec->waiter.choked_next) {
|
||||
for (int i = 0; i < dec->nb_outputs; i++)
|
||||
unchoke_downstream(sch, dec->outputs[i].dst);
|
||||
}
|
||||
for (int i = 0; i < dec->nb_outputs; i++)
|
||||
unchoke_downstream(sch, dec->outputs[i].dst);
|
||||
break;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
enc = &sch->enc[dst->idx];
|
||||
@@ -1357,8 +1311,8 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
|
||||
fg->waiter.choked_next = 0;
|
||||
} else {
|
||||
// ensure that this filter graph is not stuck waiting for
|
||||
// input from a different upstream source
|
||||
unchoke_for_stream(sch, fg->inputs[fg->best_input].src, UNCHOKE_ALL);
|
||||
// input from a different upstream demuxer
|
||||
unchoke_for_stream(sch, fg->inputs[fg->best_input].src);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1367,30 +1321,23 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
|
||||
}
|
||||
}
|
||||
|
||||
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags)
|
||||
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
|
||||
{
|
||||
while (1) {
|
||||
SchFilterGraph *fg;
|
||||
SchDemux *demux;
|
||||
SchDec *dec;
|
||||
switch (src.type) {
|
||||
case SCH_NODE_TYPE_DEMUX:
|
||||
// fed directly by a demuxer (i.e. not through a filtergraph)
|
||||
demux = &sch->demux[src.idx];
|
||||
if (demux->waiter.choked_next == 0)
|
||||
return; // prevent infinite loop
|
||||
if (flags & UNCHOKE_DEMUX) {
|
||||
demux->waiter.choked_next = 0;
|
||||
for (int i = 0; i < demux->nb_streams; i++)
|
||||
unchoke_downstream(sch, demux->streams[i].dst);
|
||||
}
|
||||
demux->waiter.choked_next = 0;
|
||||
for (int i = 0; i < demux->nb_streams; i++)
|
||||
unchoke_downstream(sch, demux->streams[i].dst);
|
||||
return;
|
||||
case SCH_NODE_TYPE_DEC:
|
||||
dec = &sch->dec[src.idx];
|
||||
if (!(flags & UNCHOKE_DECODE))
|
||||
return;
|
||||
dec->waiter.choked_next = 0;
|
||||
src = dec->src;
|
||||
src = sch->dec[src.idx].src;
|
||||
continue;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
src = sch->enc[src.idx].src;
|
||||
@@ -1400,8 +1347,7 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags)
|
||||
// the filtergraph contains internal sources and
|
||||
// requested to be scheduled directly
|
||||
if (fg->best_input == fg->nb_inputs) {
|
||||
if (flags & UNCHOKE_FILTER)
|
||||
fg->waiter.choked_next = 0;
|
||||
fg->waiter.choked_next = 0;
|
||||
return;
|
||||
}
|
||||
src = fg->inputs[fg->best_input].src;
|
||||
@@ -1453,23 +1399,17 @@ static void schedule_update_locked(Scheduler *sch)
|
||||
if (atomic_load(&sch->terminate))
|
||||
return;
|
||||
|
||||
dts = trailing_dts(sch);
|
||||
dts = trailing_dts(sch, 0);
|
||||
|
||||
atomic_store(&sch->last_dts, progressing_dts(sch, 0));
|
||||
atomic_store(&sch->last_dts, dts);
|
||||
|
||||
// initialize our internal state
|
||||
#define RESET_WAITER(field) \
|
||||
do { \
|
||||
for (unsigned i = 0; i < sch->nb_##field; i++) { \
|
||||
SchWaiter *w = &sch->field[i].waiter; \
|
||||
w->choked_prev = atomic_load(&w->choked); \
|
||||
w->choked_next = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
RESET_WAITER(demux);
|
||||
RESET_WAITER(filters);
|
||||
RESET_WAITER(dec);
|
||||
for (unsigned type = 0; type < 2; type++)
|
||||
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
|
||||
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
|
||||
w->choked_prev = atomic_load(&w->choked);
|
||||
w->choked_next = 1;
|
||||
}
|
||||
|
||||
// figure out the sources that are allowed to proceed
|
||||
for (unsigned i = 0; i < sch->nb_mux; i++) {
|
||||
@@ -1480,18 +1420,15 @@ static void schedule_update_locked(Scheduler *sch)
|
||||
|
||||
// unblock sources for output streams that are not finished
|
||||
// and not too far ahead of the trailing stream
|
||||
if (ms->source_finished) {
|
||||
// still allow decoders to drain
|
||||
unchoke_for_stream(sch, ms->src, UNCHOKE_DECODE);
|
||||
if (ms->source_finished)
|
||||
continue;
|
||||
}
|
||||
if (dts == AV_NOPTS_VALUE && ms->last_dts != AV_NOPTS_VALUE)
|
||||
continue;
|
||||
if (dts != AV_NOPTS_VALUE && ms->last_dts - dts >= SCHEDULE_TOLERANCE)
|
||||
continue;
|
||||
|
||||
// resolve the source to unchoke
|
||||
unchoke_for_stream(sch, ms->src, UNCHOKE_ALL);
|
||||
unchoke_for_stream(sch, ms->src);
|
||||
have_unchoked = 1;
|
||||
}
|
||||
}
|
||||
@@ -1504,41 +1441,33 @@ static void schedule_update_locked(Scheduler *sch)
|
||||
for (unsigned j = 0; j < fg->nb_inputs; j++) {
|
||||
SchFilterIn *fi = &fg->inputs[j];
|
||||
if (fi->receive_finished && !fi->send_finished)
|
||||
unchoke_for_stream(sch, fi->src, UNCHOKE_ALL);
|
||||
unchoke_for_stream(sch, fi->src);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure to unchoke at least one source, if still available
|
||||
#define UNCHOKE_ONCE(field) \
|
||||
do { \
|
||||
for (unsigned i = 0; !have_unchoked && i < sch->nb_##field; i++) { \
|
||||
SchWaiter *w = &sch->field[i].waiter; \
|
||||
if (!sch->field[i].task_exited) { \
|
||||
w->choked_next = 0; \
|
||||
have_unchoked = 1; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
for (unsigned type = 0; !have_unchoked && type < 2; type++)
|
||||
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
|
||||
int exited = type ? sch->filters[i].task_exited : sch->demux[i].task_exited;
|
||||
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
|
||||
if (!exited) {
|
||||
w->choked_next = 0;
|
||||
have_unchoked = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNCHOKE_ONCE(demux);
|
||||
UNCHOKE_ONCE(filters);
|
||||
for (unsigned type = 0; type < 2; type++) {
|
||||
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
|
||||
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
|
||||
if (w->choked_prev != w->choked_next) {
|
||||
waiter_set(w, w->choked_next);
|
||||
if (!type)
|
||||
choke_demux(sch, i, w->choked_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define UPDATE_WAITER(field) \
|
||||
do { \
|
||||
for (unsigned i = 0; i < sch->nb_##field; i++) { \
|
||||
SchWaiter *w = &sch->field[i].waiter; \
|
||||
if (w->choked_prev != w->choked_next) { \
|
||||
waiter_set(w, w->choked_next); \
|
||||
if (offsetof(Scheduler, field) == offsetof(Scheduler, demux)) \
|
||||
choke_demux(sch, i, w->choked_next); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
UPDATE_WAITER(demux);
|
||||
UPDATE_WAITER(filters);
|
||||
UPDATE_WAITER(dec);
|
||||
}
|
||||
|
||||
enum {
|
||||
@@ -2257,7 +2186,7 @@ int sch_mux_receive(Scheduler *sch, unsigned mux_idx, AVPacket *pkt)
|
||||
av_assert0(mux_idx < sch->nb_mux);
|
||||
mux = &sch->mux[mux_idx];
|
||||
|
||||
ret = tq_receive(mux->queue, &stream_idx, pkt, 0);
|
||||
ret = tq_receive(mux->queue, &stream_idx, pkt);
|
||||
pkt->stream_index = stream_idx;
|
||||
return ret;
|
||||
}
|
||||
@@ -2341,12 +2270,6 @@ int sch_dec_receive(Scheduler *sch, unsigned dec_idx, AVPacket *pkt)
|
||||
av_assert0(dec_idx < sch->nb_dec);
|
||||
dec = &sch->dec[dec_idx];
|
||||
|
||||
retry:
|
||||
// Pull a packet from the overflow FIFO while unchoked or expecting EOF ts
|
||||
if (av_container_fifo_can_read(dec->overflow) &&
|
||||
(!atomic_load(&dec->waiter.choked) || dec->expect_end_ts))
|
||||
return av_container_fifo_read(dec->overflow, pkt, 0);
|
||||
|
||||
// the decoder should have given us post-flush end timestamp in pkt
|
||||
if (dec->expect_end_ts) {
|
||||
Timestamp ts = (Timestamp){ .ts = pkt->pts, .tb = pkt->time_base };
|
||||
@@ -2357,32 +2280,14 @@ retry:
|
||||
dec->expect_end_ts = 0;
|
||||
}
|
||||
|
||||
ret = tq_receive(dec->queue, &dummy, pkt, 0);
|
||||
ret = tq_receive(dec->queue, &dummy, pkt);
|
||||
av_assert0(dummy <= 0);
|
||||
|
||||
// drain packets from overflow queue before returning EOF
|
||||
if (ret == AVERROR_EOF && av_container_fifo_can_read(dec->overflow)) {
|
||||
int terminate = waiter_wait(sch, &dec->waiter);
|
||||
if (terminate)
|
||||
return ret;
|
||||
return av_container_fifo_read(dec->overflow, pkt, 0);
|
||||
} else if (ret < 0)
|
||||
return ret;
|
||||
|
||||
// got a flush packet, on the next call to this function the decoder
|
||||
// should give us post-flush end timestamp (after draining overflow fifo)
|
||||
if (!pkt->data && !pkt->side_data_elems && dec->queue_end_ts)
|
||||
// will give us post-flush end timestamp
|
||||
if (ret >= 0 && !pkt->data && !pkt->side_data_elems && dec->queue_end_ts)
|
||||
dec->expect_end_ts = 1;
|
||||
|
||||
// we got a packet, but we're currently choked or have existing overflow
|
||||
// packets; so push it to the FIFO first
|
||||
if (atomic_load(&dec->waiter.choked) || av_container_fifo_can_read(dec->overflow)) {
|
||||
ret = av_container_fifo_write(dec->overflow, pkt, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2516,7 +2421,7 @@ int sch_enc_receive(Scheduler *sch, unsigned enc_idx, AVFrame *frame)
|
||||
av_assert0(enc_idx < sch->nb_enc);
|
||||
enc = &sch->enc[enc_idx];
|
||||
|
||||
ret = tq_receive(enc->queue, &dummy, frame, 0);
|
||||
ret = tq_receive(enc->queue, &dummy, frame);
|
||||
av_assert0(dummy <= 0);
|
||||
|
||||
return ret;
|
||||
@@ -2605,7 +2510,6 @@ int sch_filter_receive(Scheduler *sch, unsigned fg_idx,
|
||||
unsigned *in_idx, AVFrame *frame)
|
||||
{
|
||||
SchFilterGraph *fg;
|
||||
int ret, idx;
|
||||
|
||||
av_assert0(fg_idx < sch->nb_filters);
|
||||
fg = &sch->filters[fg_idx];
|
||||
@@ -2626,20 +2530,14 @@ int sch_filter_receive(Scheduler *sch, unsigned fg_idx,
|
||||
}
|
||||
|
||||
if (*in_idx == fg->nb_inputs) {
|
||||
// drain incoming frames before waiting, to avoid blocking downstream
|
||||
ret = tq_receive(fg->queue, &idx, frame, THREAD_QUEUE_FLAG_NO_BLOCK);
|
||||
if (ret >= 0) {
|
||||
av_assert0(idx >= 0);
|
||||
*in_idx = idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int terminate = waiter_wait(sch, &fg->waiter);
|
||||
return terminate ? AVERROR_EOF : AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ret = tq_receive(fg->queue, &idx, frame, 0);
|
||||
int ret, idx;
|
||||
|
||||
ret = tq_receive(fg->queue, &idx, frame);
|
||||
if (idx < 0)
|
||||
return AVERROR_EOF;
|
||||
else if (ret >= 0) {
|
||||
@@ -2826,10 +2724,6 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
|
||||
|
||||
atomic_store(&sch->terminate, 1);
|
||||
|
||||
// Ensure no other thread is currently in schedule_update_locked while
|
||||
// we are choking all demuxers
|
||||
pthread_mutex_lock(&sch->schedule_lock);
|
||||
|
||||
for (unsigned type = 0; type < 2; type++)
|
||||
for (unsigned i = 0; i < (type ? sch->nb_demux : sch->nb_filters); i++) {
|
||||
SchWaiter *w = type ? &sch->demux[i].waiter : &sch->filters[i].waiter;
|
||||
@@ -2838,11 +2732,6 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
|
||||
choke_demux(sch, i, 0); // unfreeze to allow draining
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < sch->nb_dec; i++)
|
||||
waiter_set(&sch->dec[i].waiter, 0); // unfreeze to allow draining
|
||||
|
||||
pthread_mutex_unlock(&sch->schedule_lock);
|
||||
|
||||
for (unsigned i = 0; i < sch->nb_demux; i++) {
|
||||
SchDemux *d = &sch->demux[i];
|
||||
|
||||
@@ -2879,7 +2768,7 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
|
||||
}
|
||||
|
||||
if (finish_ts)
|
||||
*finish_ts = progressing_dts(sch, 1);
|
||||
*finish_ts = trailing_dts(sch, 1);
|
||||
|
||||
sch->state = SCH_STATE_STOPPED;
|
||||
|
||||
|
||||
+15
-18
@@ -3007,7 +3007,6 @@ static int read_thread(void *arg)
|
||||
// initial metadata as update.
|
||||
st->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
|
||||
}
|
||||
ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
|
||||
for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
|
||||
if (wanted_stream_spec[i] && st_index[i] == -1) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
|
||||
@@ -3176,24 +3175,16 @@ static int read_thread(void *arg)
|
||||
is->eof = 0;
|
||||
}
|
||||
|
||||
if (show_status) {
|
||||
if (ic->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
|
||||
fprintf(stderr, "\x1b[2K\r");
|
||||
dump_dictionary(NULL, ic->metadata,
|
||||
"\r New metadata", " ", AV_LOG_INFO);
|
||||
}
|
||||
if (ic->streams[pkt->stream_index]->event_flags &
|
||||
AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
|
||||
fprintf(stderr, "\x1b[2K\r");
|
||||
snprintf(metadata_description,
|
||||
sizeof(metadata_description),
|
||||
"\r New metadata for stream %d",
|
||||
pkt->stream_index);
|
||||
dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata,
|
||||
metadata_description, " ", AV_LOG_INFO);
|
||||
}
|
||||
if (show_status && ic->streams[pkt->stream_index]->event_flags &
|
||||
AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
|
||||
fprintf(stderr, "\x1b[2K\r");
|
||||
snprintf(metadata_description,
|
||||
sizeof(metadata_description),
|
||||
"\r New metadata for stream %d",
|
||||
pkt->stream_index);
|
||||
dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata,
|
||||
metadata_description, " ", AV_LOG_INFO);
|
||||
}
|
||||
ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
|
||||
ic->streams[pkt->stream_index]->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
|
||||
|
||||
/* check if packet is in play range specified by user, then queue, otherwise discard */
|
||||
@@ -3883,6 +3874,12 @@ int main(int argc, char **argv)
|
||||
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
|
||||
if (audio_disable)
|
||||
flags &= ~SDL_INIT_AUDIO;
|
||||
else {
|
||||
/* Try to work around an occasional ALSA buffer underflow issue when the
|
||||
* period size is NPOT due to ALSA resampling by forcing the buffer size. */
|
||||
if (!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
|
||||
SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE","1", 1);
|
||||
}
|
||||
if (display_disable)
|
||||
flags &= ~SDL_INIT_VIDEO;
|
||||
if (SDL_Init (flags)) {
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
#include "ffplay_renderer.h"
|
||||
|
||||
#if (SDL_VERSION_ATLEAST(2, 0, 6) && CONFIG_LIBPLACEBO)
|
||||
#define HAVE_VULKAN_RENDERER 1
|
||||
/* Get PL_API_VER */
|
||||
#include <libplacebo/config.h>
|
||||
#define HAVE_VULKAN_RENDERER (PL_API_VER >= 278)
|
||||
#else
|
||||
#define HAVE_VULKAN_RENDERER 0
|
||||
#endif
|
||||
|
||||
+54
-187
@@ -39,7 +39,6 @@
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/downmix_info.h"
|
||||
#include "libavutil/display.h"
|
||||
#include "libavutil/film_grain_params.h"
|
||||
#include "libavutil/hdr_dynamic_metadata.h"
|
||||
@@ -216,8 +215,6 @@ typedef enum {
|
||||
SECTION_ID_STREAM_GROUP_SUBPIECE,
|
||||
SECTION_ID_STREAM_GROUP_BLOCKS,
|
||||
SECTION_ID_STREAM_GROUP_BLOCK,
|
||||
SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST,
|
||||
SECTION_ID_STREAM_GROUP_SIDE_DATA,
|
||||
SECTION_ID_STREAM_GROUP_STREAMS,
|
||||
SECTION_ID_STREAM_GROUP_STREAM,
|
||||
SECTION_ID_STREAM_GROUP_DISPOSITION,
|
||||
@@ -301,7 +298,7 @@ static const AVTextFormatSection sections[] = {
|
||||
[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", 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_SIDE_DATA_LIST, 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_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" },
|
||||
@@ -310,8 +307,6 @@ static const AVTextFormatSection sections[] = {
|
||||
[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_SIDE_DATA_LIST] = { SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_group_side_data_list" },
|
||||
[SECTION_ID_STREAM_GROUP_SIDE_DATA] = { SECTION_ID_STREAM_GROUP_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE|AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_group_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_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" },
|
||||
@@ -345,11 +340,12 @@ static const char *print_input_filename;
|
||||
static const AVInputFormat *iformat = NULL;
|
||||
static const char *output_filename = NULL;
|
||||
|
||||
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";
|
||||
|
||||
static unsigned int nb_streams;
|
||||
static int nb_streams;
|
||||
static uint64_t *nb_streams_packets;
|
||||
static uint64_t *nb_streams_frames;
|
||||
static int *selected_streams;
|
||||
@@ -436,8 +432,8 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
|
||||
|
||||
#define print_list_fmt(k, f, n, m, ...) do { \
|
||||
av_bprint_clear(&pbuf); \
|
||||
for (unsigned int idx = 0; idx < n; idx++) { \
|
||||
for (unsigned int idx2 = 0; idx2 < m; idx2++) { \
|
||||
for (int idx = 0; idx < n; idx++) { \
|
||||
for (int idx2 = 0; idx2 < m; idx2++) { \
|
||||
if (idx > 0 || idx2 > 0) \
|
||||
av_bprint_chars(&pbuf, ' ', 1); \
|
||||
av_bprintf(&pbuf, f, __VA_ARGS__); \
|
||||
@@ -455,9 +451,7 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
|
||||
#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, AV_TEXTFORMAT_VALUE_FMT_INT, u)
|
||||
#define print_int_fmt(k, v, f, u) avtext_print_unit_integer(tfc, k, v, f, u)
|
||||
#define print_decibel(k, v) avtext_print_unit_double(tfc, k, v, AV_TEXTFORMAT_VALUE_FMT_DECIBEL, 0)
|
||||
#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u)
|
||||
|
||||
static void print_integers(AVTextFormatContext *tfc, const char *key,
|
||||
const void *data, int size, const char *format,
|
||||
@@ -509,30 +503,6 @@ static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int se
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_downmix_info(AVTextFormatContext *tfc,
|
||||
const AVDownmixInfo *downmix_info)
|
||||
{
|
||||
switch (downmix_info->preferred_downmix_type) {
|
||||
case AV_DOWNMIX_TYPE_LORO:
|
||||
print_str("preferred_downmix_type", "loro");
|
||||
break;
|
||||
case AV_DOWNMIX_TYPE_LTRT:
|
||||
print_str("preferred_downmix_type", "ltrt");
|
||||
break;
|
||||
case AV_DOWNMIX_TYPE_DPLII:
|
||||
print_str("preferred_downmix_type", "dplII");
|
||||
break;
|
||||
default:
|
||||
print_str("preferred_downmix_type", "unknown");
|
||||
break;
|
||||
}
|
||||
print_decibel("center_mix_level_db", downmix_info->center_mix_level);
|
||||
print_decibel("center_mix_level_ltrt_db", downmix_info->center_mix_level_ltrt);
|
||||
print_decibel("surround_mix_level_db", downmix_info->surround_mix_level);
|
||||
print_decibel("surround_mix_level_ltrt_db", downmix_info->surround_mix_level_ltrt);
|
||||
print_decibel("lfe_mix_level_db", downmix_info->lfe_mix_level);
|
||||
}
|
||||
|
||||
static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9])
|
||||
{
|
||||
double rotation = av_display_rotation_get(matrix);
|
||||
@@ -831,62 +801,6 @@ static void print_dynamic_hdr10_plus(AVTextFormatContext *tfc, const AVDynamicHD
|
||||
}
|
||||
}
|
||||
|
||||
static void print_dynamic_hdr_smpte2094_app5(AVTextFormatContext *tfc, const AVDynamicHDRSmpte2094App5 *metadata)
|
||||
{
|
||||
if (!metadata)
|
||||
return;
|
||||
print_int("application_version", metadata->application_version);
|
||||
print_int("minimum_application_version", metadata->minimum_application_version);
|
||||
print_int("has_custom_hdr_reference_white_flag", metadata->has_custom_hdr_reference_white_flag);
|
||||
print_int("has_adaptive_tone_map_flag", metadata->has_adaptive_tone_map_flag);
|
||||
|
||||
if (metadata->has_custom_hdr_reference_white_flag)
|
||||
print_int("hdr_reference_white", metadata->hdr_reference_white);
|
||||
|
||||
if (!metadata->has_adaptive_tone_map_flag)
|
||||
return;
|
||||
|
||||
print_int("baseline_hdr_headroom", metadata->baseline_hdr_headroom);
|
||||
print_int("use_reference_white_tone_mapping_flag", metadata->use_reference_white_tone_mapping_flag);
|
||||
|
||||
if (metadata->use_reference_white_tone_mapping_flag)
|
||||
return;
|
||||
|
||||
print_int("num_alternate_images", metadata->num_alternate_images);
|
||||
print_int("gain_application_space_chromaticities_flag", metadata->gain_application_space_chromaticities_flag);
|
||||
print_int("has_common_component_mix_params_flag", metadata->has_common_component_mix_params_flag);
|
||||
print_int("has_common_curve_params_flag", metadata->has_common_curve_params_flag);
|
||||
|
||||
if (metadata->gain_application_space_chromaticities_flag == 3) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
print_int("gain_application_space_chromaticities", metadata->gain_application_space_chromaticities[i]);
|
||||
}
|
||||
|
||||
for (int a = 0; a < metadata->num_alternate_images; a++) {
|
||||
print_int("alternate_hdr_headroom", metadata->alternate_hdr_headrooms[a]);
|
||||
|
||||
print_int("component_mixing_type", metadata->component_mixing_type[a]);
|
||||
if (metadata->component_mixing_type[a] == 3) {
|
||||
for (int k = 0; k < 6; k++) {
|
||||
print_int("has_component_mixing_coefficient_flag", metadata->has_component_mixing_coefficient_flag[a][k]);
|
||||
if (metadata->has_component_mixing_coefficient_flag[a][k])
|
||||
print_int("component_mixing_coefficient", metadata->component_mixing_coefficient[a][k]);
|
||||
}
|
||||
}
|
||||
|
||||
print_int("gain_curve_num_control_points_minus_1", metadata->gain_curve_num_control_points_minus_1[a]);
|
||||
print_int("gain_curve_use_pchip_slope_flag", metadata->gain_curve_use_pchip_slope_flag[a]);
|
||||
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
|
||||
print_int("gain_curve_control_point_x", metadata->gain_curve_control_points_x[a][c]);
|
||||
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
|
||||
print_int("gain_curve_control_point_y", metadata->gain_curve_control_points_y[a][c]);
|
||||
if (!metadata->gain_curve_use_pchip_slope_flag[a]) {
|
||||
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
|
||||
print_int("gain_curve_control_point_theta", metadata->gain_curve_control_points_theta[a][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_dynamic_hdr_vivid(AVTextFormatContext *tfc, const AVDynamicHDRVivid *metadata)
|
||||
{
|
||||
if (!metadata)
|
||||
@@ -1028,7 +942,7 @@ static void print_film_grain_params(AVTextFormatContext *tfc,
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
|
||||
for (unsigned uv = 0; uv < 2; uv++) {
|
||||
for (int uv = 0; uv < 2; uv++) {
|
||||
if (!aom->num_uv_points[uv] && !aom->chroma_scaling_from_luma)
|
||||
continue;
|
||||
|
||||
@@ -1094,8 +1008,7 @@ static void print_film_grain_params(AVTextFormatContext *tfc,
|
||||
}
|
||||
|
||||
static void print_pkt_side_data(AVTextFormatContext *tfc,
|
||||
int width,
|
||||
int height,
|
||||
AVCodecParameters *par,
|
||||
const AVPacketSideData *sd,
|
||||
SectionID id_data)
|
||||
{
|
||||
@@ -1121,7 +1034,7 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
|
||||
print_int("padding", spherical->padding);
|
||||
} else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
|
||||
size_t l, t, r, b;
|
||||
av_spherical_tile_bounds(spherical, width, height,
|
||||
av_spherical_tile_bounds(spherical, par->width, par->height,
|
||||
&l, &t, &r, &b);
|
||||
print_int("bound_left", l);
|
||||
print_int("bound_top", t);
|
||||
@@ -1368,7 +1281,7 @@ static void show_packet(AVTextFormatContext *tfc, InputFile *ifile, AVPacket *pk
|
||||
print_time("dts_time", pkt->dts, &st->time_base);
|
||||
print_duration_ts("duration", pkt->duration);
|
||||
print_duration_time("duration_time", pkt->duration, &st->time_base);
|
||||
print_int_fmt("size", pkt->size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
|
||||
print_val("size", pkt->size, unit_byte_str);
|
||||
if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
|
||||
else print_str_opt("pos", "N/A");
|
||||
print_fmt("flags", "%c%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
|
||||
@@ -1392,7 +1305,7 @@ static void show_packet(AVTextFormatContext *tfc, InputFile *ifile, AVPacket *pk
|
||||
|
||||
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(tfc, st->codecpar->width, st->codecpar->height, &pkt->side_data[i],
|
||||
print_pkt_side_data(tfc, st->codecpar, &pkt->side_data[i],
|
||||
SECTION_ID_PACKET_SIDE_DATA);
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
@@ -1428,9 +1341,6 @@ static void show_subtitle(AVTextFormatContext *tfc, AVSubtitle *sub, AVStream *s
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *name,
|
||||
const AVIAMFParamDefinition *param, SectionID section_id);
|
||||
|
||||
static void print_frame_side_data(AVTextFormatContext *tfc,
|
||||
const AVFrame *frame,
|
||||
const AVStream *stream)
|
||||
@@ -1444,9 +1354,7 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
|
||||
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_DOWNMIX_INFO) {
|
||||
print_downmix_info(tfc, (AVDownmixInfo *)sd->data);
|
||||
} else if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
|
||||
if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
|
||||
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);
|
||||
@@ -1471,9 +1379,6 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
|
||||
} else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
|
||||
AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
|
||||
print_dynamic_hdr10_plus(tfc, metadata);
|
||||
} else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5) {
|
||||
AVDynamicHDRSmpte2094App5 *metadata = (AVDynamicHDRSmpte2094App5 *)sd->data;
|
||||
print_dynamic_hdr_smpte2094_app5(tfc, metadata);
|
||||
} else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
|
||||
print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
|
||||
} else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
|
||||
@@ -1495,11 +1400,6 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
|
||||
print_int("view_id", *(int*)sd->data);
|
||||
} else if (sd->type == AV_FRAME_DATA_EXIF) {
|
||||
print_int("size", sd->size);
|
||||
} else if (sd->type == AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM ||
|
||||
sd->type == AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM ||
|
||||
sd->type == AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM) {
|
||||
const AVIAMFParamDefinition *param = (AVIAMFParamDefinition *)sd->data;
|
||||
print_iamf_param_definition(tfc, NULL, param, SECTION_ID_FRAME_SIDE_DATA);
|
||||
}
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
@@ -1533,7 +1433,7 @@ static void show_frame(AVTextFormatContext *tfc, AVFrame *frame, AVStream *strea
|
||||
print_duration_time("duration_time", frame->duration, &stream->time_base);
|
||||
if (fd && fd->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, fd->pkt_pos);
|
||||
else print_str_opt("pkt_pos", "N/A");
|
||||
if (fd && fd->pkt_size != -1) print_int_fmt("pkt_size", fd->pkt_size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
|
||||
if (fd && fd->pkt_size != -1) print_val ("pkt_size", fd->pkt_size, unit_byte_str);
|
||||
else print_str_opt("pkt_size", "N/A");
|
||||
|
||||
switch (stream->codecpar->codec_type) {
|
||||
@@ -1796,10 +1696,12 @@ static int read_interval_packets(AVTextFormatContext *tfc, InputFile *ifile,
|
||||
}
|
||||
av_packet_unref(pkt);
|
||||
//Flush remaining frames that are cached in the decoder
|
||||
for (int i = 0; i < ifile->nb_streams; i++) {
|
||||
for (i = 0; i < ifile->nb_streams; i++) {
|
||||
pkt->stream_index = i;
|
||||
if (do_read_frames) {
|
||||
while (process_frame(tfc, ifile, frame, pkt, &(int){1}) > 0);
|
||||
if (ifile->streams[i].dec_ctx)
|
||||
avcodec_flush_buffers(ifile->streams[i].dec_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1813,33 +1715,17 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flush_buffers(InputFile *ifile)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!do_read_frames)
|
||||
return;
|
||||
for (i = 0; i < ifile->nb_streams; i++) {
|
||||
if (ifile->streams[i].dec_ctx)
|
||||
avcodec_flush_buffers(ifile->streams[i].dec_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_packets(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
int64_t cur_ts = fmt_ctx->start_time;
|
||||
|
||||
if (read_intervals_nb == 0) {
|
||||
ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
|
||||
ret = read_interval_packets(tfc, ifile, &interval, &cur_ts);
|
||||
} else {
|
||||
for (int i = 0; i < read_intervals_nb; i++) {
|
||||
/* flushing buffers can reset parts of the private context which may be
|
||||
* read by show_streams(), so only flush between each read_interval */
|
||||
if (i)
|
||||
flush_buffers(ifile);
|
||||
for (i = 0; i < read_intervals_nb; i++) {
|
||||
ret = read_interval_packets(tfc, ifile, &read_intervals[i], &cur_ts);
|
||||
if (ret < 0)
|
||||
break;
|
||||
@@ -1852,7 +1738,7 @@ static int read_packets(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
static void print_dispositions(AVTextFormatContext *tfc, uint32_t disposition, SectionID section_id)
|
||||
{
|
||||
avtext_print_section_header(tfc, NULL, section_id);
|
||||
for (unsigned i = 0; i < sizeof(disposition) * CHAR_BIT; i++) {
|
||||
for (int i = 0; i < sizeof(disposition) * CHAR_BIT; i++) {
|
||||
const char *disposition_str = av_disposition_to_string(1U << i);
|
||||
|
||||
if (disposition_str)
|
||||
@@ -2075,7 +1961,7 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
|
||||
if (stream->codecpar->nb_coded_side_data) {
|
||||
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(tfc, stream->codecpar->width, stream->codecpar->height, &stream->codecpar->coded_side_data[i],
|
||||
print_pkt_side_data(tfc, stream->codecpar, &stream->codecpar->coded_side_data[i],
|
||||
SECTION_ID_STREAM_SIDE_DATA);
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
@@ -2092,10 +1978,10 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
|
||||
static int show_streams(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMS);
|
||||
for (int i = 0; i < ifile->nb_streams; i++)
|
||||
for (i = 0; i < ifile->nb_streams; i++)
|
||||
if (selected_streams[i]) {
|
||||
ret = show_stream(tfc, fmt_ctx, i, &ifile->streams[i], 0);
|
||||
if (ret < 0)
|
||||
@@ -2109,7 +1995,7 @@ static int show_streams(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *program)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM);
|
||||
print_int("program_id", program->id);
|
||||
@@ -2123,7 +2009,7 @@ static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *p
|
||||
goto end;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_STREAMS);
|
||||
for (unsigned i = 0; i < program->nb_stream_indexes; i++) {
|
||||
for (i = 0; i < program->nb_stream_indexes; i++) {
|
||||
if (selected_streams[program->stream_index[i]]) {
|
||||
ret = show_stream(tfc, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM);
|
||||
if (ret < 0)
|
||||
@@ -2140,10 +2026,10 @@ end:
|
||||
static int show_programs(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAMS);
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_programs; i++) {
|
||||
for (i = 0; i < fmt_ctx->nb_programs; i++) {
|
||||
AVProgram *program = fmt_ctx->programs[i];
|
||||
if (!program)
|
||||
continue;
|
||||
@@ -2167,7 +2053,7 @@ static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup
|
||||
print_int("width", tile_grid->width);
|
||||
print_int("height", tile_grid->height);
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS);
|
||||
for (unsigned i = 0; i < tile_grid->nb_tiles; i++) {
|
||||
for (int i = 0; i < tile_grid->nb_tiles; i++) {
|
||||
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);
|
||||
@@ -2175,15 +2061,6 @@ static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
avtext_print_section_footer(tfc);
|
||||
if (tile_grid->nb_coded_side_data) {
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST);
|
||||
for (int i = 0; i < tile_grid->nb_coded_side_data; i++) {
|
||||
print_pkt_side_data(tfc, tile_grid->width, tile_grid->height, &tile_grid->coded_side_data[i],
|
||||
SECTION_ID_STREAM_GROUP_SIDE_DATA);
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
|
||||
@@ -2191,21 +2068,12 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
|
||||
const AVIAMFParamDefinition *param, SectionID section_id)
|
||||
{
|
||||
SectionID subsection_id, parameter_section_id;
|
||||
if (section_id == SECTION_ID_FRAME_SIDE_DATA)
|
||||
subsection_id = SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST;
|
||||
else {
|
||||
av_assert0(sections[section_id].children_ids[0] != -1);
|
||||
subsection_id = sections[section_id].children_ids[0];
|
||||
}
|
||||
av_assert0(sections[subsection_id].children_ids[0] != -1);
|
||||
subsection_id = sections[section_id].children_ids[0];
|
||||
av_assert0(subsection_id != -1);
|
||||
parameter_section_id = sections[subsection_id].children_ids[0];
|
||||
|
||||
// When printing as part of side-data, skip opening a section
|
||||
if (section_id != SECTION_ID_FRAME_SIDE_DATA)
|
||||
avtext_print_section_header(tfc, "IAMF Param Definition", section_id);
|
||||
|
||||
if (name)
|
||||
print_str("name", name);
|
||||
av_assert0(parameter_section_id != -1);
|
||||
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);
|
||||
print_int("parameter_id", param->parameter_id);
|
||||
@@ -2214,7 +2082,7 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
|
||||
print_int("constant_subblock_duration", param->constant_subblock_duration);
|
||||
if (param->nb_subblocks > 0)
|
||||
avtext_print_section_header(tfc, NULL, subsection_id);
|
||||
for (unsigned i = 0; i < param->nb_subblocks; i++) {
|
||||
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: {
|
||||
@@ -2248,9 +2116,7 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
|
||||
}
|
||||
if (param->nb_subblocks > 0)
|
||||
avtext_print_section_footer(tfc); // subsection_id
|
||||
|
||||
if (section_id != SECTION_ID_FRAME_SIDE_DATA)
|
||||
avtext_print_section_footer(tfc); // section_id
|
||||
avtext_print_section_footer(tfc); // section_id
|
||||
}
|
||||
|
||||
static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVStreamGroup *stg,
|
||||
@@ -2265,7 +2131,7 @@ static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVSt
|
||||
print_int("audio_element_type", audio_element->audio_element_type);
|
||||
print_int("default_w", audio_element->default_w);
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS);
|
||||
for (unsigned i = 0; i < audio_element->nb_layers; i++) {
|
||||
for (int i = 0; i < audio_element->nb_layers; i++) {
|
||||
const AVIAMFLayer *layer = audio_element->layers[i];
|
||||
char val_str[128];
|
||||
avtext_print_section_header(tfc, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT);
|
||||
@@ -2301,7 +2167,7 @@ static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmi
|
||||
print_int("nb_layouts", submix->nb_layouts);
|
||||
print_q("default_mix_gain", submix->default_mix_gain, '/');
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_PIECES);
|
||||
for (unsigned i = 0; i < submix->nb_elements; i++) {
|
||||
for (int i = 0; i < submix->nb_elements; i++) {
|
||||
const AVIAMFSubmixElement *element = submix->elements[i];
|
||||
avtext_print_section_header(tfc, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE);
|
||||
print_int("stream_id", element->audio_element_id);
|
||||
@@ -2324,7 +2190,7 @@ static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmi
|
||||
if (submix->output_mix_config)
|
||||
print_iamf_param_definition(tfc, "output_mix_config", submix->output_mix_config,
|
||||
SECTION_ID_STREAM_GROUP_PIECE);
|
||||
for (unsigned i = 0; i < submix->nb_layouts; i++) {
|
||||
for (int i = 0; i < submix->nb_layouts; i++) {
|
||||
const AVIAMFSubmixLayout *layout = submix->layouts[i];
|
||||
char val_str[128];
|
||||
avtext_print_section_header(tfc, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE);
|
||||
@@ -2354,7 +2220,7 @@ static void print_iamf_mix_presentation_params(AVTextFormatContext *tfc, const A
|
||||
print_str(annotation->key, annotation->value);
|
||||
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
|
||||
}
|
||||
for (unsigned i = 0; i < mix_presentation->nb_submixes; i++)
|
||||
for (int i = 0; i < mix_presentation->nb_submixes; i++)
|
||||
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
|
||||
@@ -2376,7 +2242,7 @@ static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStrea
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
AVBPrint pbuf;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP);
|
||||
@@ -2401,7 +2267,7 @@ static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStrea
|
||||
goto end;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_STREAMS);
|
||||
for (unsigned i = 0; i < stg->nb_streams; i++) {
|
||||
for (i = 0; i < stg->nb_streams; i++) {
|
||||
if (selected_streams[stg->streams[i]->index]) {
|
||||
ret = show_stream(tfc, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP);
|
||||
if (ret < 0)
|
||||
@@ -2419,10 +2285,10 @@ end:
|
||||
static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUPS);
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_stream_groups; i++) {
|
||||
for (i = 0; i < fmt_ctx->nb_stream_groups; i++) {
|
||||
AVStreamGroup *stg = fmt_ctx->stream_groups[i];
|
||||
|
||||
ret = show_stream_group(tfc, ifile, stg);
|
||||
@@ -2436,10 +2302,10 @@ static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
static int show_chapters(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
{
|
||||
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTERS);
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_chapters; i++) {
|
||||
for (i = 0; i < fmt_ctx->nb_chapters; i++) {
|
||||
AVChapter *chapter = fmt_ctx->chapters[i];
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTER);
|
||||
@@ -2476,7 +2342,7 @@ static int show_format(AVTextFormatContext *tfc, InputFile *ifile)
|
||||
}
|
||||
print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
|
||||
print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
|
||||
if (size >= 0) print_int_fmt("size", size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
|
||||
if (size >= 0) print_val ("size", size, unit_byte_str);
|
||||
else print_str_opt("size", "N/A");
|
||||
if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
|
||||
else print_str_opt("bit_rate", "N/A");
|
||||
@@ -2559,7 +2425,7 @@ static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream
|
||||
static int open_input_file(InputFile *ifile, const char *filename,
|
||||
const char *print_filename)
|
||||
{
|
||||
int err;
|
||||
int err, i;
|
||||
AVFormatContext *fmt_ctx = NULL;
|
||||
const AVDictionaryEntry *t = NULL;
|
||||
int scan_all_pmts_set = 0;
|
||||
@@ -2600,7 +2466,7 @@ static int open_input_file(InputFile *ifile, const char *filename,
|
||||
|
||||
err = avformat_find_stream_info(fmt_ctx, opts);
|
||||
|
||||
for (int i = 0; i < orig_nb_streams; i++)
|
||||
for (i = 0; i < orig_nb_streams; i++)
|
||||
av_dict_free(&opts[i]);
|
||||
av_freep(&opts);
|
||||
|
||||
@@ -2618,7 +2484,7 @@ static int open_input_file(InputFile *ifile, const char *filename,
|
||||
ifile->nb_streams = fmt_ctx->nb_streams;
|
||||
|
||||
/* bind a decoder to each input stream */
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_streams; i++) {
|
||||
for (i = 0; i < fmt_ctx->nb_streams; i++) {
|
||||
InputStream *ist = &ifile->streams[i];
|
||||
AVStream *stream = fmt_ctx->streams[i];
|
||||
const AVCodec *codec;
|
||||
@@ -2676,9 +2542,10 @@ static int open_input_file(InputFile *ifile, const char *filename,
|
||||
|
||||
static void close_input_file(InputFile *ifile)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* close decoder for each stream */
|
||||
for (int i = 0; i < ifile->nb_streams; i++)
|
||||
for (i = 0; i < ifile->nb_streams; i++)
|
||||
avcodec_free_context(&ifile->streams[i].dec_ctx);
|
||||
|
||||
av_freep(&ifile->streams);
|
||||
@@ -2691,7 +2558,7 @@ static int probe_file(AVTextFormatContext *tfc, const char *filename,
|
||||
const char *print_filename)
|
||||
{
|
||||
InputFile ifile = { 0 };
|
||||
int ret;
|
||||
int ret, i;
|
||||
int section_id;
|
||||
|
||||
do_analyze_frames = do_analyze_frames && do_show_streams;
|
||||
@@ -2711,7 +2578,7 @@ static int probe_file(AVTextFormatContext *tfc, const char *filename,
|
||||
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 (unsigned i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
|
||||
for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
|
||||
if (stream_specifier) {
|
||||
ret = avformat_match_stream_specifier(ifile.fmt_ctx,
|
||||
ifile.fmt_ctx->streams[i],
|
||||
@@ -2929,9 +2796,9 @@ static inline void mark_section_show_entries(SectionID section_id,
|
||||
static int match_section(const char *section_name,
|
||||
int show_all_entries, AVDictionary *entries)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
|
||||
const struct AVTextFormatSection *section = §ions[i];
|
||||
if (!strcmp(section_name, section->name) ||
|
||||
(section->unique_name && !strcmp(section_name, section->unique_name))) {
|
||||
|
||||
@@ -141,7 +141,7 @@ typedef struct GraphPrintContext {
|
||||
#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, AV_TEXTFORMAT_VALUE_FMT_INT, u)
|
||||
#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); \
|
||||
|
||||
+9
-20
@@ -68,11 +68,6 @@ enum show_muxdemuxers {
|
||||
SHOW_MUXERS,
|
||||
};
|
||||
|
||||
enum show_codec {
|
||||
SHOW_DECODER,
|
||||
SHOW_ENCODER,
|
||||
};
|
||||
|
||||
static FILE *report_file;
|
||||
static int report_file_level = AV_LOG_DEBUG;
|
||||
|
||||
@@ -326,12 +321,6 @@ static void print_codec(const AVCodec *c)
|
||||
printf("hardware ");
|
||||
if (c->capabilities & AV_CODEC_CAP_HYBRID)
|
||||
printf("hybrid ");
|
||||
if (c->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)
|
||||
printf("reorderedopaque ");
|
||||
if (c->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)
|
||||
printf("flush ");
|
||||
if (c->capabilities & AV_CODEC_CAP_ENCODER_RECON_FRAME)
|
||||
printf("reconframe ");
|
||||
if (!c->capabilities)
|
||||
printf("none");
|
||||
printf("\n");
|
||||
@@ -602,9 +591,9 @@ int show_help(void *optctx, const char *opt, const char *arg)
|
||||
if (!*topic) {
|
||||
show_help_default(topic, par);
|
||||
} else if (!strcmp(topic, "decoder")) {
|
||||
show_help_codec(par, SHOW_DECODER);
|
||||
show_help_codec(par, 0);
|
||||
} else if (!strcmp(topic, "encoder")) {
|
||||
show_help_codec(par, SHOW_ENCODER);
|
||||
show_help_codec(par, 1);
|
||||
} else if (!strcmp(topic, "demuxer")) {
|
||||
show_help_demuxer(par);
|
||||
} else if (!strcmp(topic, "muxer")) {
|
||||
@@ -719,16 +708,16 @@ int show_codecs(void *optctx, const char *opt, const char *arg)
|
||||
|
||||
/* print decoders/encoders when there's more than one or their
|
||||
* names are different from codec name */
|
||||
while ((codec = next_codec_for_id(desc->id, &iter, SHOW_DECODER))) {
|
||||
while ((codec = next_codec_for_id(desc->id, &iter, 0))) {
|
||||
if (strcmp(codec->name, desc->name)) {
|
||||
print_codecs_for_id(desc->id, SHOW_DECODER);
|
||||
print_codecs_for_id(desc->id, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter = NULL;
|
||||
while ((codec = next_codec_for_id(desc->id, &iter, SHOW_ENCODER))) {
|
||||
while ((codec = next_codec_for_id(desc->id, &iter, 1))) {
|
||||
if (strcmp(codec->name, desc->name)) {
|
||||
print_codecs_for_id(desc->id, SHOW_ENCODER);
|
||||
print_codecs_for_id(desc->id, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -785,12 +774,12 @@ static int print_codecs(int encoder)
|
||||
|
||||
int show_decoders(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
return print_codecs(SHOW_DECODER);
|
||||
return print_codecs(0);
|
||||
}
|
||||
|
||||
int show_encoders(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
return print_codecs(SHOW_ENCODER);
|
||||
return print_codecs(1);
|
||||
}
|
||||
|
||||
int show_bsfs(void *optctx, const char *opt, const char *arg)
|
||||
@@ -887,7 +876,7 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg,
|
||||
const char *name = NULL;
|
||||
const char *long_name = NULL;
|
||||
|
||||
if (muxdemuxers != SHOW_DEMUXERS) {
|
||||
if (muxdemuxers !=SHOW_DEMUXERS) {
|
||||
ofmt_opaque = NULL;
|
||||
while ((ofmt = av_muxer_iterate(&ofmt_opaque))) {
|
||||
is_dev = is_device(ofmt->priv_class);
|
||||
|
||||
@@ -18,21 +18,19 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/base64.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/hash.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/macros.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "avtextformat.h"
|
||||
@@ -240,7 +238,12 @@ fail:
|
||||
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)
|
||||
{
|
||||
@@ -364,30 +367,24 @@ struct unit_value {
|
||||
int64_t i;
|
||||
} val;
|
||||
|
||||
AVTextFormatValueFormat fmt;
|
||||
const char *unit;
|
||||
};
|
||||
|
||||
static const char float_fmt_full[] = "%f";
|
||||
static const char float_fmt_singledigit[] = "%.1f";
|
||||
static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv)
|
||||
{
|
||||
double vald;
|
||||
int64_t vali = 0;
|
||||
const char *float_fmt = 0;
|
||||
int show_float = 0;
|
||||
|
||||
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_DECIBEL) {
|
||||
vald = 20 * log10(uv.val.d);
|
||||
float_fmt = float_fmt_singledigit;
|
||||
} else if (uv.fmt >= AV_TEXTFORMAT_VALUE_FMT_DOUBLE) {
|
||||
if (uv.unit == unit_second_str) {
|
||||
vald = uv.val.d;
|
||||
float_fmt = float_fmt_full;
|
||||
show_float = 1;
|
||||
} else {
|
||||
vald = (double)uv.val.i;
|
||||
vali = uv.val.i;
|
||||
}
|
||||
|
||||
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_SECOND && tctx->opts.use_value_sexagesimal_format) {
|
||||
if (uv.unit == unit_second_str && tctx->opts.use_value_sexagesimal_format) {
|
||||
double secs;
|
||||
int hours, mins;
|
||||
secs = vald;
|
||||
@@ -402,7 +399,7 @@ static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_si
|
||||
if (tctx->opts.use_value_prefix && vald > 1) {
|
||||
int64_t index;
|
||||
|
||||
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_BYTE && tctx->opts.use_byte_value_binary_prefix) {
|
||||
if (uv.unit == unit_byte_str && tctx->opts.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;
|
||||
@@ -416,46 +413,29 @@ static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_si
|
||||
vali = (int64_t)vald;
|
||||
}
|
||||
|
||||
if (float_fmt || (tctx->opts.use_value_prefix && vald != (int64_t)vald))
|
||||
snprintf(buf, buf_size, float_fmt ? float_fmt : "%f", vald);
|
||||
if (show_float || (tctx->opts.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->opts.show_value_unit && uv.unit && *uv.unit ? " " : "",
|
||||
prefix_string, tctx->opts.show_value_unit && uv.unit ? uv.unit : "");
|
||||
av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || tctx->opts.show_value_unit ? " " : "",
|
||||
prefix_string, tctx->opts.show_value_unit ? uv.unit : "");
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, AVTextFormatValueFormat fmt, const char *unit)
|
||||
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit)
|
||||
{
|
||||
char val_str[128];
|
||||
struct unit_value uv;
|
||||
|
||||
av_assert0(fmt < AV_TEXTFORMAT_VALUE_FMT_DOUBLE);
|
||||
|
||||
uv.val.i = val;
|
||||
uv.fmt = fmt;
|
||||
uv.unit = unit;
|
||||
avtext_print_string(tctx, key, value_string(tctx, val_str, sizeof(val_str), uv), 0);
|
||||
}
|
||||
|
||||
|
||||
void avtext_print_unit_double(AVTextFormatContext *tctx, const char *key, double val, AVTextFormatValueFormat fmt, const char *unit)
|
||||
{
|
||||
char val_str[128];
|
||||
struct unit_value uv;
|
||||
|
||||
av_assert0(fmt >= AV_TEXTFORMAT_VALUE_FMT_DOUBLE);
|
||||
|
||||
uv.val.d = val;
|
||||
uv.fmt = fmt;
|
||||
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;
|
||||
@@ -515,7 +495,6 @@ void avtext_print_time(AVTextFormatContext *tctx, const char *key,
|
||||
double d = av_q2d(*time_base) * ts;
|
||||
struct unit_value uv;
|
||||
uv.val.d = d;
|
||||
uv.fmt = AV_TEXTFORMAT_VALUE_FMT_SECOND;
|
||||
uv.unit = unit_second_str;
|
||||
value_string(tctx, buf, sizeof(buf), uv);
|
||||
avtext_print_string(tctx, key, buf, 0);
|
||||
|
||||
@@ -161,14 +161,6 @@ struct AVTextFormatContext {
|
||||
unsigned int string_validation_utf8_flags;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
AV_TEXTFORMAT_VALUE_FMT_INT,
|
||||
AV_TEXTFORMAT_VALUE_FMT_BYTE,
|
||||
AV_TEXTFORMAT_VALUE_FMT_DOUBLE = 0x100,
|
||||
AV_TEXTFORMAT_VALUE_FMT_SECOND,
|
||||
AV_TEXTFORMAT_VALUE_FMT_DECIBEL,
|
||||
} AVTextFormatValueFormat;
|
||||
|
||||
#define AV_TEXTFORMAT_PRINT_STRING_OPTIONAL 1
|
||||
#define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2
|
||||
|
||||
@@ -186,9 +178,7 @@ void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va
|
||||
|
||||
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, AVTextFormatValueFormat fmt, const char *unit);
|
||||
|
||||
void avtext_print_unit_double(AVTextFormatContext *tctx, const char *key, double val, AVTextFormatValueFormat fmt, const char *unit);
|
||||
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);
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/opt.h"
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "tf_internal.h"
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "tf_internal.h"
|
||||
@@ -73,7 +74,7 @@ static char *ini_escape_str(AVBPrint *dst, const char *src)
|
||||
case '=':
|
||||
case ':':
|
||||
av_bprint_chars(dst, '\\', 1);
|
||||
av_fallthrough;
|
||||
/* fallthrough */
|
||||
default:
|
||||
if ((unsigned char)c < 32)
|
||||
av_bprintf(dst, "\\x00%02x", (unsigned char)c);
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avtextformat.h"
|
||||
#include "libavutil/bprint.h"
|
||||
|
||||
@@ -194,7 +194,7 @@ static int receive_locked(ThreadQueue *tq, int *stream_idx,
|
||||
return nb_finished == tq->nb_streams ? AVERROR_EOF : AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags)
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -211,7 +211,7 @@ int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags)
|
||||
if (can_read != av_container_fifo_can_read(tq->fifo))
|
||||
pthread_cond_broadcast(&tq->cond);
|
||||
|
||||
if (ret == AVERROR(EAGAIN) && !(flags & THREAD_QUEUE_FLAG_NO_BLOCK)) {
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
pthread_cond_wait(&tq->cond, &tq->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-10
@@ -26,12 +26,6 @@ enum ThreadQueueType {
|
||||
THREAD_QUEUE_PACKETS,
|
||||
};
|
||||
|
||||
enum ThreadQueueFlags {
|
||||
/* When set, tq_receive() will return AVERROR(EAGAIN) instead of blocking
|
||||
* when the queue is empty or choked. */
|
||||
THREAD_QUEUE_FLAG_NO_BLOCK = (1 << 0),
|
||||
};
|
||||
|
||||
typedef struct ThreadQueue ThreadQueue;
|
||||
|
||||
/**
|
||||
@@ -80,8 +74,6 @@ void tq_choke(ThreadQueue *tq, int choked);
|
||||
* written here
|
||||
* @param data the data item will be written here on success using the
|
||||
* callback provided to tq_alloc()
|
||||
* @param flags combination of THREAD_QUEUE_FLAG_*
|
||||
*
|
||||
* @return
|
||||
* - 0 a data item was successfully read; *stream_idx contains a non-negative
|
||||
* stream index
|
||||
@@ -89,8 +81,7 @@ void tq_choke(ThreadQueue *tq, int choked);
|
||||
* side has marked the given stream as finished. This will happen at most once
|
||||
* for each stream. When *stream_idx is -1, all streams are done.
|
||||
*/
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags);
|
||||
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data);
|
||||
/**
|
||||
* Mark the given stream finished from the receiving side.
|
||||
*/
|
||||
|
||||
+15
-14
@@ -115,9 +115,10 @@ 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
|
||||
OBJS-$(CONFIG_HEVC_SEI) += h2645_sei.o aom_film_grain.o \
|
||||
dynamic_hdr_vivid.o
|
||||
OBJS-$(CONFIG_HPELDSP) += hpeldsp.o
|
||||
OBJS-$(CONFIG_HUFFMAN) += huffman.o
|
||||
OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o
|
||||
@@ -125,12 +126,11 @@ OBJS-$(CONFIG_HUFFYUVENCDSP) += huffyuvencdsp.o
|
||||
OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o
|
||||
OBJS-$(CONFIG_INFLATE_WRAPPER) += zlib_wrapper.o
|
||||
OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4_vc1_data.o
|
||||
OBJS-$(CONFIG_ITUT_T35) += itut35.o aom_film_grain.o dynamic_hdr_vivid.o
|
||||
OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o
|
||||
OBJS-$(CONFIG_JNI) += ffjni.o jni.o
|
||||
OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o
|
||||
OBJS-$(CONFIG_LCMS2) += fflcms2.o
|
||||
OBJS-$(CONFIG_LIBLCEVC_DEC) += lcevcdec.o lcevctab.o
|
||||
OBJS-$(CONFIG_LIBLCEVC_DEC) += lcevcdec.o
|
||||
OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o
|
||||
OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o
|
||||
OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o
|
||||
@@ -203,7 +203,7 @@ OBJS-$(CONFIG_AAC_FIXED_DECODER) += aactab.o \
|
||||
sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o \
|
||||
$(if $(!CONFIG_HARDCODED_TABLES), cbrt_tablegen_common.o)
|
||||
OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \
|
||||
aacpsy.o aactab.o aacencdsp.o \
|
||||
aacpsy.o aactab.o \
|
||||
aacenc_is.o \
|
||||
aacenc_tns.o \
|
||||
psymodel.o kbdwin.o \
|
||||
@@ -252,7 +252,6 @@ 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_APV_VULKAN_ENCODER) += apv_encode_vulkan.o
|
||||
OBJS-$(CONFIG_ARBC_DECODER) += arbc.o
|
||||
OBJS-$(CONFIG_ARGO_DECODER) += argo.o
|
||||
OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o
|
||||
@@ -443,6 +442,7 @@ 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
|
||||
OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o
|
||||
@@ -461,7 +461,7 @@ 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) += h274.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
|
||||
@@ -587,6 +587,7 @@ OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o
|
||||
OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o
|
||||
OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
|
||||
OBJS-$(CONFIG_MPEG4_MEDIACODEC_ENCODER) += mediacodecenc.o
|
||||
OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o
|
||||
OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o
|
||||
OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER) += v4l2_m2m_enc.o
|
||||
OBJS-$(CONFIG_MPL2_DECODER) += mpl2dec.o ass.o
|
||||
@@ -625,7 +626,6 @@ OBJS-$(CONFIG_PBM_ENCODER) += pnmenc.o
|
||||
OBJS-$(CONFIG_PCX_DECODER) += pcx.o
|
||||
OBJS-$(CONFIG_PCX_ENCODER) += pcxenc.o
|
||||
OBJS-$(CONFIG_PDV_DECODER) += pdvdec.o
|
||||
OBJS-$(CONFIG_PDV_ENCODER) += pdvenc.o
|
||||
OBJS-$(CONFIG_PFM_DECODER) += pnmdec.o pnm.o
|
||||
OBJS-$(CONFIG_PFM_ENCODER) += pnmenc.o
|
||||
OBJS-$(CONFIG_PGM_DECODER) += pnmdec.o pnm.o
|
||||
@@ -723,6 +723,9 @@ OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.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
|
||||
OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o
|
||||
OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhqdec.o speedhq.o mpeg12.o \
|
||||
mpeg12data.o
|
||||
OBJS-$(CONFIG_SPEEDHQ_ENCODER) += speedhq.o mpeg12data.o mpeg12enc.o speedhqenc.o
|
||||
@@ -833,7 +836,7 @@ 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 h274.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
|
||||
@@ -842,7 +845,6 @@ OBJS-$(CONFIG_WBMP_DECODER) += wbmpdec.o
|
||||
OBJS-$(CONFIG_WBMP_ENCODER) += wbmpenc.o
|
||||
OBJS-$(CONFIG_WCMV_DECODER) += wcmv.o
|
||||
OBJS-$(CONFIG_WEBP_DECODER) += webp.o
|
||||
OBJS-$(CONFIG_WEBP_ANIM_DECODER) += webp.o
|
||||
OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o
|
||||
OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o
|
||||
OBJS-$(CONFIG_WMALOSSLESS_DECODER) += wmalosslessdec.o wma_common.o
|
||||
@@ -1044,7 +1046,6 @@ OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
|
||||
OBJS-$(CONFIG_VDPAU) += vdpau.o
|
||||
OBJS-$(CONFIG_VULKAN) += vulkan.o vulkan_video.o
|
||||
|
||||
OBJS-$(CONFIG_APV_VULKAN_HWACCEL) += vulkan_decode.o vulkan_apv.o
|
||||
OBJS-$(CONFIG_AV1_D3D11VA_HWACCEL) += dxva2_av1.o
|
||||
OBJS-$(CONFIG_AV1_DXVA2_HWACCEL) += dxva2_av1.o
|
||||
OBJS-$(CONFIG_AV1_D3D12VA_HWACCEL) += dxva2_av1.o d3d12va_av1.o
|
||||
@@ -1126,7 +1127,7 @@ OBJS-$(CONFIG_FITS_DEMUXER) += fits.o
|
||||
OBJS-$(CONFIG_TAK_DEMUXER) += tak.o
|
||||
|
||||
# libavformat dependencies for static builds
|
||||
STLIBOBJS-$(CONFIG_AVFORMAT) += h2645_parse.o lcevctab.o to_upper4.o
|
||||
STLIBOBJS-$(CONFIG_AVFORMAT) += to_upper4.o
|
||||
STLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o
|
||||
STLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o
|
||||
STLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o
|
||||
@@ -1170,6 +1171,7 @@ OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o
|
||||
OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o
|
||||
OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o
|
||||
OBJS-$(CONFIG_LIBARIBCAPTION_DECODER) += libaribcaption.o ass.o
|
||||
OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o
|
||||
OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o
|
||||
OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o
|
||||
OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d.o av1_parse.o
|
||||
@@ -1328,7 +1330,6 @@ SKIPHEADERS += %_tablegen.h \
|
||||
%_tables.h \
|
||||
tableprint.h \
|
||||
tableprint_vlc.h \
|
||||
aaccoder_nmr.h \
|
||||
aaccoder_twoloop.h \
|
||||
aaccoder_trellis.h \
|
||||
aacenc_quantization.h \
|
||||
@@ -1366,7 +1367,6 @@ TESTPROGS = avcodec \
|
||||
bitstream_be \
|
||||
bitstream_le \
|
||||
codec_desc \
|
||||
encinfo \
|
||||
htmlsubtitles \
|
||||
jpeg2000dwt \
|
||||
mathops \
|
||||
@@ -1379,6 +1379,7 @@ TESTPROGS-$(CONFIG_GOLOMB) += golomb
|
||||
TESTPROGS-$(CONFIG_IDCTDSP) += dct
|
||||
TESTPROGS-$(CONFIG_DXV_ENCODER) += hashtable
|
||||
TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman
|
||||
TESTPROGS-$(HAVE_MMX) += motion
|
||||
TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate
|
||||
TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels
|
||||
TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels
|
||||
|
||||
+17
-104
@@ -676,7 +676,6 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[type][elem_id] = ac->che[type][elem_id];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 13:
|
||||
if (ac->tags_mapped > 3 && ((type == TYPE_CPE && elem_id < 8) ||
|
||||
(type == TYPE_SCE && elem_id < 6) ||
|
||||
@@ -684,20 +683,17 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[type][elem_id] = ac->che[type][elem_id];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 12:
|
||||
case 7:
|
||||
if (ac->tags_mapped == 3 && type == TYPE_CPE) {
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][2];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 11:
|
||||
if (ac->tags_mapped == 3 && type == TYPE_SCE) {
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 6:
|
||||
/* Some streams incorrectly code 5.1 audio as
|
||||
* SCE[0] CPE[0] CPE[1] SCE[1]
|
||||
@@ -715,13 +711,11 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 5:
|
||||
if (ac->tags_mapped == 2 && type == TYPE_CPE) {
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 4:
|
||||
/* Some streams incorrectly code 4.0 audio as
|
||||
* SCE[0] CPE[0] LFE[0]
|
||||
@@ -745,7 +739,6 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 3:
|
||||
case 2:
|
||||
if (ac->tags_mapped == (ac->oc[1].m4ac.chan_config != 2) &&
|
||||
@@ -757,13 +750,11 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
|
||||
}
|
||||
av_fallthrough;
|
||||
case 1:
|
||||
if (!ac->tags_mapped && type == TYPE_SCE) {
|
||||
ac->tags_mapped++;
|
||||
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][0];
|
||||
}
|
||||
av_fallthrough;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -831,8 +822,8 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
||||
sampling_index = get_bits(gb, 4);
|
||||
if (m4ac->sampling_index != sampling_index)
|
||||
av_log(avctx, AV_LOG_WARNING,
|
||||
"Sample rate index (%d) in program config element does not "
|
||||
"match the sample rate index (%d) configured by the container.\n", sampling_index, m4ac->sampling_index);
|
||||
"Sample rate index in program config element does not "
|
||||
"match the sample rate index configured by the container.\n");
|
||||
|
||||
num_front = get_bits(gb, 4);
|
||||
num_side = get_bits(gb, 4);
|
||||
@@ -875,91 +866,6 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
||||
av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
// Height extension
|
||||
int height_ext = 0;
|
||||
if (comment_len >= 16 + (num_front * 2 + num_side * 2 + num_back * 2))
|
||||
height_ext = show_bits(gb, 8) == 0xAC;
|
||||
if (height_ext) {
|
||||
uint8_t height_map[4 /* ChannelPosition */][16 /* Channel */]; // 0 == base, 1 == top, 2 == bottom.
|
||||
uint8_t tag[6 /* ChannelPosition */ ][16 /* Channel */][3];
|
||||
int i, invalid = 0, height_tags = 0;
|
||||
|
||||
skip_bits(gb, 8);
|
||||
|
||||
// Read height extension bits to height_map, which define which layer each element belongs to.
|
||||
// Also make a copy of layout_map that will then be used to rearrange it.
|
||||
for (i = 0; i < num_front; i++) {
|
||||
int height = get_bits(gb, 2);
|
||||
invalid |= height > 2;
|
||||
height_map [AAC_CHANNEL_FRONT][i] = height;
|
||||
memcpy(&tag[AAC_CHANNEL_FRONT][i], layout_map + height_tags, sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
for (i = 0; i < num_side; i++) {
|
||||
int height = get_bits(gb, 2);
|
||||
invalid |= height > 2;
|
||||
height_map [AAC_CHANNEL_SIDE][i] = height;
|
||||
memcpy(&tag[AAC_CHANNEL_SIDE][i], layout_map + height_tags, sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
for (i = 0; i < num_back; i++) {
|
||||
int height = get_bits(gb, 2);
|
||||
invalid |= height > 2;
|
||||
height_map [AAC_CHANNEL_BACK][i] = height;
|
||||
memcpy(&tag[AAC_CHANNEL_BACK][i], layout_map + height_tags, sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
for (i = 0; i < num_lfe; i++) {
|
||||
memcpy(&tag[AAC_CHANNEL_LFE][i], layout_map + height_tags, sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
for (i = 0; i < num_cc; i++) {
|
||||
memcpy(&tag[AAC_CHANNEL_CC][i], layout_map + height_tags, sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
av_assert0(height_tags == tags);
|
||||
|
||||
if (!invalid) {
|
||||
height_tags = 0;
|
||||
// For each height layer, check that an element belongs to it and copy it back to layout_map.
|
||||
// We need to take into account LFE and CC elements that may be present.
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < num_front; j++) {
|
||||
if (height_map[AAC_CHANNEL_FRONT][j] == i) {
|
||||
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_FRONT][j], sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < num_side; j++) {
|
||||
if (height_map[AAC_CHANNEL_SIDE][j] == i) {
|
||||
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_SIDE][j], sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < num_back; j++) {
|
||||
if (height_map[AAC_CHANNEL_BACK][j] == i) {
|
||||
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_BACK][j], sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
}
|
||||
if (i == 0) { // Base height, copy LFE and CC elements before moving to Top and Bottom
|
||||
for (int j = 0; j < num_lfe; j++) {
|
||||
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_LFE][j], sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
for (int j = 0; j < num_cc; j++) {
|
||||
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_CC][j], sizeof(*layout_map));
|
||||
height_tags++;
|
||||
}
|
||||
}
|
||||
}
|
||||
av_assert0(height_tags == tags);
|
||||
}
|
||||
|
||||
comment_len -= 8 + (num_front * 2 + num_side * 2 + num_back * 2);
|
||||
}
|
||||
|
||||
skip_bits_long(gb, comment_len);
|
||||
return tags;
|
||||
}
|
||||
@@ -983,6 +889,12 @@ static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx,
|
||||
int tags = 0;
|
||||
|
||||
m4ac->frame_length_short = get_bits1(gb);
|
||||
if (m4ac->frame_length_short && m4ac->sbr == 1) {
|
||||
avpriv_report_missing_feature(avctx, "SBR with 960 frame length");
|
||||
if (ac) ac->warned_960_sbr = 1;
|
||||
m4ac->sbr = 0;
|
||||
m4ac->ps = 0;
|
||||
}
|
||||
|
||||
if (get_bits1(gb)) // dependsOnCoreCoder
|
||||
skip_bits(gb, 14); // coreCoderDelay
|
||||
@@ -1334,7 +1246,7 @@ av_cold int ff_aac_decode_init(AVCodecContext *avctx)
|
||||
ac->oc[1].m4ac.chan_config = i;
|
||||
|
||||
if (ac->oc[1].m4ac.chan_config) {
|
||||
ret = ff_aac_set_default_channel_config(ac, avctx, layout_map,
|
||||
int ret = ff_aac_set_default_channel_config(ac, avctx, layout_map,
|
||||
&layout_map_tags,
|
||||
ac->oc[1].m4ac.chan_config);
|
||||
if (!ret)
|
||||
@@ -2034,11 +1946,17 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn
|
||||
switch (type) { // extension type
|
||||
case EXT_SBR_DATA_CRC:
|
||||
crc_flag++;
|
||||
av_fallthrough;
|
||||
case EXT_SBR_DATA:
|
||||
if (!che) {
|
||||
av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first channel element.\n");
|
||||
return res;
|
||||
} else if (ac->oc[1].m4ac.frame_length_short) {
|
||||
if (!ac->warned_960_sbr)
|
||||
avpriv_report_missing_feature(ac->avctx,
|
||||
"SBR with 960 frame length");
|
||||
ac->warned_960_sbr = 1;
|
||||
skip_bits_long(gb, 8 * cnt - 4);
|
||||
return res;
|
||||
} else if (!ac->oc[1].m4ac.sbr) {
|
||||
av_log(ac->avctx, AV_LOG_ERROR, "SBR signaled to be not-present but was found in the bitstream.\n");
|
||||
skip_bits_long(gb, 8 * cnt - 4);
|
||||
@@ -2059,8 +1977,7 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn
|
||||
ac->avctx->profile = AV_PROFILE_AAC_HE;
|
||||
}
|
||||
|
||||
ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type,
|
||||
ac->oc[1].m4ac.frame_length_short);
|
||||
ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type);
|
||||
|
||||
if (ac->oc[1].m4ac.ps == 1 && !ac->warned_he_aac_mono) {
|
||||
av_log(ac->avctx, AV_LOG_VERBOSE, "Treating HE-AAC mono as stereo.\n");
|
||||
@@ -2170,7 +2087,6 @@ static void spectral_to_sample(AACDecContext *ac, int samples)
|
||||
}
|
||||
if (ac->oc[1].m4ac.sbr > 0) {
|
||||
ac->proc.sbr_apply(ac, che, type,
|
||||
ac->oc[1].m4ac.frame_length_short,
|
||||
che->ch[0].output,
|
||||
che->ch[1].output);
|
||||
}
|
||||
@@ -2648,9 +2564,6 @@ static const AVOption options[] = {
|
||||
{ "coded", "order in which the channels are coded in the bitstream",
|
||||
0, AV_OPT_TYPE_CONST, { .i64 = CHANNEL_ORDER_CODED }, .flags = AACDEC_FLAGS, .unit = "channel_order" },
|
||||
|
||||
{ "target_level", "Target output loudness in dBFS for xHE-AAC normalization (0 = disabled)",
|
||||
OFF(target_level), AV_OPT_TYPE_INT, { .i64 = 0 }, -70, 0, AACDEC_FLAGS },
|
||||
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
||||
+4
-31
@@ -98,12 +98,6 @@ enum AACUSACLoudnessExt {
|
||||
UNIDRCLOUDEXT_EQ = 0x1,
|
||||
};
|
||||
|
||||
enum AACUSACDRCExt {
|
||||
UNIDRCCONFEXT_TERM = 0x0,
|
||||
UNIDRCCONFEXT_PARAM_DRC = 0x1,
|
||||
UNIDRCCONFEXT_V1 = 0x2,
|
||||
};
|
||||
|
||||
// Supposed to be equal to AAC_RENAME() in case of USE_FIXED.
|
||||
#define RENAME_FIXED(name) name ## _fixed
|
||||
|
||||
@@ -308,7 +302,6 @@ typedef struct ChannelElement {
|
||||
|
||||
typedef struct AACUSACLoudnessInfo {
|
||||
uint8_t drc_set_id : 6;
|
||||
uint8_t eq_set_id : 6; /* loudnessInfoV1() only, 0 otherwise */
|
||||
uint8_t downmix_id : 7;
|
||||
struct {
|
||||
uint16_t lvl : 12;
|
||||
@@ -384,13 +377,6 @@ typedef struct AACUsacElemConfig {
|
||||
uint32_t pl_data_offset;
|
||||
uint8_t *pl_buf;
|
||||
} ext;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
int lower;
|
||||
int upper;
|
||||
} loudness;
|
||||
} drc;
|
||||
} AACUsacElemConfig;
|
||||
|
||||
typedef struct AACUSACConfig {
|
||||
@@ -406,13 +392,6 @@ typedef struct AACUSACConfig {
|
||||
AACUSACLoudnessInfo album_info[64];
|
||||
uint8_t nb_info;
|
||||
AACUSACLoudnessInfo info[64];
|
||||
|
||||
/**
|
||||
* Raw bsMethodValue (μ) of the program/anchor-loudness measurement
|
||||
* selected for normalization at config time. -1 == none found.
|
||||
* L_LKFS = -57.75 + 0.25 * input_method_val.
|
||||
*/
|
||||
int input_method_val;
|
||||
} loudness;
|
||||
} AACUSACConfig;
|
||||
|
||||
@@ -454,9 +433,9 @@ typedef struct AACDecProc {
|
||||
|
||||
int (*sbr_ctx_alloc_init)(AACDecContext *ac, ChannelElement **che, int id_aac);
|
||||
int (*sbr_decode_extension)(AACDecContext *ac, ChannelElement *che,
|
||||
GetBitContext *gb, int crc, int cnt, int id_aac, int fl960);
|
||||
void (*sbr_apply)(AACDecContext *ac, ChannelElement *che, int id_aac, int fl960,
|
||||
void /* INTFLOAT */ *L, void /* INTFLOAT */ *R);
|
||||
GetBitContext *gb, int crc, int cnt, int id_aac);
|
||||
void (*sbr_apply)(AACDecContext *ac, ChannelElement *che,
|
||||
int id_aac, void /* INTFLOAT */ *L, void /* INTFLOAT */ *R);
|
||||
void (*sbr_ctx_close)(ChannelElement *che);
|
||||
} AACDecProc;
|
||||
|
||||
@@ -576,15 +555,9 @@ struct AACDecContext {
|
||||
|
||||
enum AACOutputChannelOrder output_channel_order;
|
||||
|
||||
/**
|
||||
* Target output loudness in dBFS, used for xHE-AAC loudness normalization
|
||||
* based on the parsed loudnessInfoSet() metadata. 0 disables normalization.
|
||||
*/
|
||||
int target_level;
|
||||
int warned_loudness_missing;
|
||||
|
||||
OutputConfiguration oc[2];
|
||||
int warned_num_aac_frames;
|
||||
int warned_960_sbr;
|
||||
unsigned warned_71_wide;
|
||||
int warned_gain_control;
|
||||
int warned_he_aac_mono;
|
||||
|
||||
@@ -75,7 +75,7 @@ const uint8_t ff_aac_channel_layout_map[16][16][3] = {
|
||||
const int16_t ff_aac_channel_map[3][4][6] = {
|
||||
{
|
||||
{ AV_CHAN_FRONT_CENTER, AV_CHAN_FRONT_LEFT_OF_CENTER, AV_CHAN_FRONT_RIGHT_OF_CENTER, AV_CHAN_FRONT_LEFT, AV_CHAN_FRONT_RIGHT, AV_CHAN_NONE },
|
||||
{ AV_CHAN_UNUSED, AV_CHAN_SIDE_LEFT, AV_CHAN_SIDE_RIGHT, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
|
||||
{ AV_CHAN_UNUSED, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
|
||||
{ AV_CHAN_UNUSED, AV_CHAN_SIDE_LEFT, AV_CHAN_SIDE_RIGHT, AV_CHAN_BACK_LEFT, AV_CHAN_BACK_RIGHT, AV_CHAN_BACK_CENTER },
|
||||
{ AV_CHAN_LOW_FREQUENCY, AV_CHAN_LOW_FREQUENCY_2, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
|
||||
},
|
||||
|
||||
+20
-251
@@ -49,7 +49,7 @@ static inline uint32_t get_escaped_value(GetBitContext *gb, int nb1, int nb2, in
|
||||
return val;
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-3, Table 74: bsOutputChannelPos */
|
||||
/* ISO/IEC 23003-3, Table 74 — bsOutputChannelPos */
|
||||
static const enum AVChannel usac_ch_pos_to_av[64] = {
|
||||
[0] = AV_CHAN_FRONT_LEFT,
|
||||
[1] = AV_CHAN_FRONT_RIGHT,
|
||||
@@ -85,23 +85,10 @@ static const enum AVChannel usac_ch_pos_to_av[64] = {
|
||||
[31] = AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS
|
||||
};
|
||||
|
||||
/* ISO/IEC 23003-4, Table A.48: bit width of bsMethodValue depends on methodDef. */
|
||||
static int methodvalue_width(int method_def)
|
||||
{
|
||||
switch (method_def) {
|
||||
case 7: return 5; /* mixing level */
|
||||
case 8: return 2; /* room type */
|
||||
default: return 8; /* loudness (0..6, 9) + reserved */
|
||||
}
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 58/60: loudnessInfo(), loudnessInfoV1().
|
||||
* The only difference in V1 is the added eqSetId field. */
|
||||
static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
|
||||
GetBitContext *gb, int v1)
|
||||
GetBitContext *gb)
|
||||
{
|
||||
info->drc_set_id = get_bits(gb, 6);
|
||||
info->eq_set_id = v1 ? get_bits(gb, 6) : 0;
|
||||
info->downmix_id = get_bits(gb, 7);
|
||||
|
||||
if ((info->sample_peak.present = get_bits1(gb))) /* samplePeakLevelPresent */
|
||||
@@ -116,8 +103,7 @@ static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
|
||||
info->nb_measurements = get_bits(gb, 4);
|
||||
for (int i = 0; i < info->nb_measurements; i++) {
|
||||
info->measurements[i].method_def = get_bits(gb, 4);
|
||||
info->measurements[i].method_val =
|
||||
get_bits(gb, methodvalue_width(info->measurements[i].method_def));
|
||||
info->measurements[i].method_val = get_unary(gb, 0, 8);
|
||||
info->measurements[i].measurement = get_bits(gb, 4);
|
||||
info->measurements[i].reliability = get_bits(gb, 2);
|
||||
}
|
||||
@@ -125,56 +111,6 @@ static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 61: loudnessInfoSetExtension(), UNIDRCLOUDEXT_EQ */
|
||||
static int decode_loudness_set_v1(AACDecContext *ac, AACUSACConfig *usac,
|
||||
GetBitContext *gb)
|
||||
{
|
||||
int ret;
|
||||
int nb_album = get_bits(gb, 6); /* loudnessInfoV1AlbumCount */
|
||||
int nb_info = get_bits(gb, 6); /* loudnessInfoV1Count */
|
||||
|
||||
for (int i = 0; i < nb_album; i++) {
|
||||
AACUSACLoudnessInfo tmp;
|
||||
ret = decode_loudness_info(ac, &tmp, gb, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (usac->loudness.nb_album < FF_ARRAY_ELEMS(usac->loudness.album_info))
|
||||
usac->loudness.album_info[usac->loudness.nb_album++] = tmp;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nb_info; i++) {
|
||||
AACUSACLoudnessInfo tmp;
|
||||
ret = decode_loudness_info(ac, &tmp, gb, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (usac->loudness.nb_info < FF_ARRAY_ELEMS(usac->loudness.info))
|
||||
usac->loudness.info[usac->loudness.nb_info++] = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pick the bsMethodValue of a program- or anchor-loudness measurement.
|
||||
* Per ISO/IEC 23003-4 6.1.2.5, downmixId, drcSetId and eqSetId identify the
|
||||
* signal a loudnessInfo() applies to; only downmixId == 0 (base layout)
|
||||
* together with drcSetId == 0 and eqSetId == 0 (no DRC/EQ) describes the
|
||||
* unprocessed signal we output, so measurements for any other
|
||||
* downmix/DRC/EQ set must not be used. */
|
||||
static int select_loudness_measurement(const AACUSACConfig *usac)
|
||||
{
|
||||
for (int i = 0; i < usac->loudness.nb_info; i++) {
|
||||
const AACUSACLoudnessInfo *info = &usac->loudness.info[i];
|
||||
if (info->downmix_id != 0 || info->drc_set_id != 0 || info->eq_set_id != 0)
|
||||
continue;
|
||||
for (int j = 0; j < info->nb_measurements; j++) {
|
||||
int method = info->measurements[j].method_def;
|
||||
if (method == 1 || method == 2)
|
||||
return info->measurements[j].method_val;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
|
||||
GetBitContext *gb)
|
||||
{
|
||||
@@ -184,13 +120,13 @@ static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
|
||||
usac->loudness.nb_info = get_bits(gb, 6); /* loudnessInfoCount */
|
||||
|
||||
for (int i = 0; i < usac->loudness.nb_album; i++) {
|
||||
ret = decode_loudness_info(ac, &usac->loudness.album_info[i], gb, 0);
|
||||
ret = decode_loudness_info(ac, &usac->loudness.album_info[i], gb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < usac->loudness.nb_info; i++) {
|
||||
ret = decode_loudness_info(ac, &usac->loudness.info[i], gb, 0);
|
||||
ret = decode_loudness_info(ac, &usac->loudness.info[i], gb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -198,25 +134,16 @@ static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
|
||||
if (get_bits1(gb)) { /* loudnessInfoSetExtPresent */
|
||||
enum AACUSACLoudnessExt type;
|
||||
while ((type = get_bits(gb, 4)) != UNIDRCLOUDEXT_TERM) {
|
||||
uint8_t size_bits = get_bits(gb, 4) + 4; /* bitSizeLen */
|
||||
uint32_t bit_size = get_bits_long(gb, size_bits) + 1; /* bitSize */
|
||||
int start = get_bits_count(gb);
|
||||
int skip;
|
||||
uint8_t size_bits = get_bits(gb, 4) + 4;
|
||||
uint8_t bit_size = get_bits(gb, size_bits) + 1;
|
||||
switch (type) {
|
||||
case UNIDRCLOUDEXT_EQ:
|
||||
ret = decode_loudness_set_v1(ac, usac, gb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
avpriv_report_missing_feature(ac->avctx, "loudnessInfoV1");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
default:
|
||||
break;
|
||||
for (int i = 0; i < bit_size; i++)
|
||||
skip_bits1(gb);
|
||||
}
|
||||
/* The extension size is explicit, so unparsed (or unknown)
|
||||
* data can be skipped without desynchronizing. */
|
||||
skip = bit_size - (get_bits_count(gb) - start);
|
||||
if (skip < 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
skip_bits_long(gb, skip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +227,7 @@ static int decode_usac_element_pair(AACDecContext *ac,
|
||||
e->mps.phase_coding = get_bits1(gb); /* bsPhaseCoding */
|
||||
|
||||
e->mps.otts_bands_phase_present = get_bits1(gb);
|
||||
int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109: Default value of bsOttBandsPhase
|
||||
int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109 — Default value of bsOttBandsPhase
|
||||
if (e->mps.otts_bands_phase_present) { /* bsOttBandsPhasePresent */
|
||||
otts_bands_phase = get_bits(gb, 5); /* bsOttBandsPhase */
|
||||
if (otts_bands_phase > numBands)
|
||||
@@ -326,114 +253,6 @@ static int decode_usac_element_pair(AACDecContext *ac,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 62: channelLayout() */
|
||||
static int decode_drc_channel_layout(GetBitContext *gb)
|
||||
{
|
||||
int base_channel_count = get_bits(gb, 7); /* baseChannelCount */
|
||||
if (get_bits1(gb)) { /* layoutSignallingPresent */
|
||||
if (get_bits(gb, 8) == 0) /* definedLayout == 0 */
|
||||
for (int i = 0; i < base_channel_count; i++)
|
||||
skip_bits(gb, 7); /* speakerPosition */
|
||||
}
|
||||
return base_channel_count;
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 63: downmixInstructions() */
|
||||
static void skip_drc_downmix_instructions(GetBitContext *gb, int base_channel_count)
|
||||
{
|
||||
int target_channel_count;
|
||||
skip_bits(gb, 7); /* downmixId */
|
||||
target_channel_count = get_bits(gb, 7); /* targetChannelCount */
|
||||
skip_bits(gb, 8); /* targetLayout */
|
||||
if (get_bits1(gb)) /* downmixCoefficientsPresent */
|
||||
skip_bits_long(gb, 4 * target_channel_count * base_channel_count);
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 70: drcInstructionsBasic(), common with the
|
||||
* uniDrc variant up to the loudness-target fields. */
|
||||
static void decode_drc_instructions_basic(AACUsacElemConfig *e, GetBitContext *gb)
|
||||
{
|
||||
int set_effects;
|
||||
|
||||
skip_bits(gb, 6); /* drcSetId */
|
||||
skip_bits(gb, 4); /* drcLocation */
|
||||
skip_bits(gb, 7); /* downmixId */
|
||||
if (get_bits1(gb)) { /* additionalDownmixIdPresent */
|
||||
int add_downmix_cnt = get_bits(gb, 3); /* additionalDownmixIdCount */
|
||||
for (int j = 0; j < add_downmix_cnt; j++)
|
||||
skip_bits(gb, 7); /* additionalDownmixId */
|
||||
}
|
||||
|
||||
set_effects = get_bits(gb, 16); /* drcSetEffect */
|
||||
if ((set_effects & (3 << 10)) == 0) {
|
||||
if (get_bits1(gb)) /* limiterPeakTargetPresent */
|
||||
skip_bits(gb, 8); /* bsLimiterPeakTarget */
|
||||
}
|
||||
|
||||
if (get_bits1(gb)) { /* drcSetTargetLoudnessPresent */
|
||||
e->drc.loudness.upper = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueUpper */
|
||||
if (get_bits1(gb)) /* drcSetTargetLoudnessValueLowerPresent */
|
||||
e->drc.loudness.lower = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueLower */
|
||||
}
|
||||
}
|
||||
|
||||
/* ISO/IEC 23003-4, Table 57: uniDrcConfig() */
|
||||
static int decode_drc_config(AACDecContext *ac, AACUsacElemConfig *e,
|
||||
GetBitContext *gb)
|
||||
{
|
||||
int nb_downmix_instr, nb_coeff_basic = 0, nb_instr_basic = 0;
|
||||
int nb_coeff_uni, nb_instr_uni;
|
||||
int base_channel_count;
|
||||
|
||||
e->drc.loudness.lower = -1;
|
||||
e->drc.loudness.upper = -1;
|
||||
|
||||
if (get_bits1(gb)) /* sampleRatePresent */
|
||||
skip_bits(gb, 18); /* bsSampleRate */
|
||||
|
||||
nb_downmix_instr = get_bits(gb, 7); /* downmixInstructionsCount */
|
||||
|
||||
if (get_bits1(gb)) { /* drcDescriptionBasicPresent */
|
||||
nb_coeff_basic = get_bits(gb, 3); /* drcCoefficientsBasicCount */
|
||||
nb_instr_basic = get_bits(gb, 4); /* drcInstructionsBasicCount */
|
||||
}
|
||||
|
||||
nb_coeff_uni = get_bits(gb, 3); /* drcCoefficientsUniDrcCount */
|
||||
nb_instr_uni = get_bits(gb, 6); /* drcInstructionsUniDrcCount */
|
||||
|
||||
if (nb_coeff_uni || nb_instr_uni) {
|
||||
avpriv_report_missing_feature(ac->avctx,
|
||||
"AAC USAC uniDrc DRC processing");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
base_channel_count = decode_drc_channel_layout(gb);
|
||||
|
||||
for (int i = 0; i < nb_downmix_instr; i++)
|
||||
skip_drc_downmix_instructions(gb, base_channel_count);
|
||||
|
||||
for (int i = 0; i < nb_coeff_basic; i++)
|
||||
skip_bits(gb, 4 + 7); /* drcLocation, drcCharacteristic */
|
||||
|
||||
for (int i = 0; i < nb_instr_basic; i++)
|
||||
decode_drc_instructions_basic(e, gb);
|
||||
|
||||
if (get_bits1(gb)) { /* uniDrcConfigExtPresent */
|
||||
enum AACUSACDRCExt type;
|
||||
while ((type = get_bits(gb, 4)) != UNIDRCCONFEXT_TERM) {
|
||||
uint8_t size_bits = get_bits(gb, 4) + 4; /* bitSizeLen */
|
||||
uint32_t bit_size = get_bits_long(gb, size_bits) + 1; /* extBitSize */
|
||||
switch (type) {
|
||||
default:
|
||||
skip_bits_long(gb, bit_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e,
|
||||
GetBitContext *gb)
|
||||
{
|
||||
@@ -457,25 +276,9 @@ static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e,
|
||||
break;
|
||||
case ID_EXT_ELE_SAOC:
|
||||
break;
|
||||
#endif
|
||||
case ID_EXT_ELE_UNI_DRC: {
|
||||
int start = get_bits_count(gb);
|
||||
int ret = decode_drc_config(ac, e, gb);
|
||||
int skip = 8*ext_config_len - (get_bits_count(gb) - start);
|
||||
if (ret == AVERROR_PATCHWELCOME) {
|
||||
/* Unsupported uniDrcConfig(): ignore the DRC metadata and treat
|
||||
* the element as fill so the stream stays decodable. */
|
||||
e->ext.type = ID_EXT_ELE_FILL;
|
||||
ret = 0;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (skip < 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
/* The config is byte-padded to usacExtElementConfigLength */
|
||||
skip_bits_long(gb, skip);
|
||||
case ID_EXT_ELE_UNI_DRC:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case ID_EXT_ELE_FILL:
|
||||
break; /* This is what the spec does */
|
||||
case ID_EXT_ELE_AUDIOPREROLL:
|
||||
@@ -570,7 +373,6 @@ int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx,
|
||||
return AVERROR_PATCHWELCOME;
|
||||
|
||||
memset(usac, 0, sizeof(*usac));
|
||||
usac->loudness.input_method_val = -1;
|
||||
|
||||
freq_idx = get_bits(gb, 5); /* usacSamplingFrequencyIndex */
|
||||
if (freq_idx == 0x1f) {
|
||||
@@ -770,13 +572,6 @@ int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx,
|
||||
|
||||
ac->avctx->profile = AV_PROFILE_AAC_USAC;
|
||||
|
||||
usac->loudness.input_method_val = select_loudness_measurement(usac);
|
||||
if (usac->loudness.input_method_val >= 0)
|
||||
av_log(avctx, AV_LOG_VERBOSE,
|
||||
"USAC input loudness: %.2f LKFS (bsMethodValue=%d)\n",
|
||||
-57.75f + 0.25f * usac->loudness.input_method_val,
|
||||
usac->loudness.input_method_val);
|
||||
|
||||
ret = ff_aac_usac_reset_state(ac, oc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -1549,13 +1344,13 @@ static void spectrum_decode(AACDecContext *ac, AACUSACConfig *usac,
|
||||
|
||||
/* Save coefficients and alpha values for prediction reasons */
|
||||
if (nb_channels > 1) {
|
||||
AACUsacStereo *us2 = &cpe->us;
|
||||
AACUsacStereo *us = &cpe->us;
|
||||
for (int ch = 0; ch < nb_channels; ch++) {
|
||||
SingleChannelElement *sce = &cpe->ch[ch];
|
||||
memcpy(sce->prev_coeffs, sce->coeffs, sizeof(sce->coeffs));
|
||||
}
|
||||
memcpy(us2->prev_alpha_q_re, us2->alpha_q_re, sizeof(us2->alpha_q_re));
|
||||
memcpy(us2->prev_alpha_q_im, us2->alpha_q_im, sizeof(us2->alpha_q_im));
|
||||
memcpy(us->prev_alpha_q_re, us->alpha_q_re, sizeof(us->alpha_q_re));
|
||||
memcpy(us->prev_alpha_q_im, us->alpha_q_im, sizeof(us->alpha_q_im));
|
||||
}
|
||||
|
||||
for (int ch = 0; ch < nb_channels; ch++) {
|
||||
@@ -1877,7 +1672,7 @@ static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac,
|
||||
spectrum_decode(ac, usac, che, core_nb_channels);
|
||||
|
||||
if (ac->oc[1].m4ac.sbr > 0) {
|
||||
ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE, 0,
|
||||
ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE,
|
||||
che->ch[0].output,
|
||||
che->ch[1].output);
|
||||
}
|
||||
@@ -1941,8 +1736,8 @@ static int parse_audio_preroll(AACDecContext *ac, GetBitContext *gb)
|
||||
}
|
||||
|
||||
/* Byte alignment is not guaranteed. */
|
||||
for (int j = 0; j < au_len; j++)
|
||||
tmp_buf[j] = get_bits(gb, 8);
|
||||
for (int i = 0; i < au_len; i++)
|
||||
tmp_buf[i] = get_bits(gb, 8);
|
||||
|
||||
ret = init_get_bits8(&gbc, tmp_buf, au_len);
|
||||
if (ret < 0)
|
||||
@@ -2033,10 +1828,6 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e,
|
||||
case ID_EXT_ELE_AUDIOPREROLL:
|
||||
ret = parse_audio_preroll(ac, gb2);
|
||||
break;
|
||||
case ID_EXT_ELE_UNI_DRC:
|
||||
/* uniDrcGain() payload: DRC is not applied, just consume the
|
||||
* bits via skip_bits_long below. */
|
||||
break;
|
||||
default:
|
||||
/* This should never happen */
|
||||
av_assert0(0);
|
||||
@@ -2171,28 +1962,6 @@ int ff_aac_usac_decode_frame(AVCodecContext *avctx, AACDecContext *ac,
|
||||
*got_frame_ptr = 0;
|
||||
}
|
||||
|
||||
if (samples && ac->target_level) {
|
||||
int method_val = usac->loudness.input_method_val;
|
||||
if (method_val < 0) {
|
||||
if (!ac->warned_loudness_missing) {
|
||||
av_log(avctx, AV_LOG_WARNING,
|
||||
"target_level set but no program/anchor loudness "
|
||||
"measurement available; normalization skipped\n");
|
||||
ac->warned_loudness_missing = 1;
|
||||
}
|
||||
} else {
|
||||
/* Per ISO/IEC 23003-4 Table A.48: L = -57.75 + 0.25 * μ */
|
||||
float input_loudness = -57.75f + 0.25f * method_val;
|
||||
float gain_dB = (float)ac->target_level - input_loudness;
|
||||
float gain = powf(10.0f, gain_dB / 20.0f);
|
||||
|
||||
for (int ch = 0; ch < frame->ch_layout.nb_channels; ch++)
|
||||
ac->fdsp->vector_fmul_scalar((float *)frame->extended_data[ch],
|
||||
(float *)frame->extended_data[ch],
|
||||
gain, frame->nb_samples);
|
||||
}
|
||||
}
|
||||
|
||||
/* for dual-mono audio (SCE + SCE) */
|
||||
is_dmono = ac->dmono_mode && elem_id[0] == 2 &&
|
||||
!av_channel_layout_compare(&ac->oc[1].ch_layout,
|
||||
|
||||
@@ -240,7 +240,7 @@ static void huff_data_2d(GetBitContext *gb, int16_t *part0_data[2], int16_t (*da
|
||||
0, 2*esc_cnt, 0, (2*lav + 1));
|
||||
for (i = 0; i < esc_cnt; i++) {
|
||||
data[esc_idx[i]][0] = esc_data[0][i] - lav;
|
||||
data[esc_idx[i]][1] = esc_data[1][i] - lav;
|
||||
data[esc_idx[i]][0] = esc_data[0][i] - lav;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -858,7 +858,7 @@ int ff_aac_map_index_data(AACMPSLosslessData *ld,
|
||||
for (int i = 0; i < nb_param_sets; i++) {
|
||||
if (ld->coarse_quant_no[i] == 1) {
|
||||
coarse_to_fine(tmp_idx_data[i], data_type, start_band,
|
||||
stop_band);
|
||||
stop_band - start_band);
|
||||
ld->coarse_quant_no[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-23
@@ -59,7 +59,6 @@
|
||||
#define NOISE_LAMBDA_REPLACE 1.948f
|
||||
|
||||
#include "libavcodec/aaccoder_trellis.h"
|
||||
#include "libavcodec/aaccoder_nmr.h"
|
||||
|
||||
typedef float (*quantize_and_encode_band_func)(struct AACEncContext *s, PutBitContext *pb,
|
||||
const float *in, float *quant, const float *scaled,
|
||||
@@ -503,12 +502,25 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne
|
||||
const float dist_bias = av_clipf(4.f * 120 / lambda, 0.25f, 4.0f);
|
||||
const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f);
|
||||
|
||||
int prev = -1000, prev_sf = -1;
|
||||
int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
|
||||
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
|
||||
* (lambda / 120.f);
|
||||
|
||||
/** Keep this in sync with twoloop's cutoff selection */
|
||||
float rate_bandwidth_multiplier = 1.5f;
|
||||
int prev = -1000, prev_sf = -1;
|
||||
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
|
||||
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
|
||||
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
|
||||
|
||||
frame_bit_rate *= 1.15f;
|
||||
|
||||
if (avctx->cutoff > 0) {
|
||||
bandwidth = avctx->cutoff;
|
||||
} else {
|
||||
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
|
||||
}
|
||||
|
||||
/* PNS candidacy must use the coder's actual coding bandwidth (s->bandwidth,
|
||||
* fixed at init), not a separate heuristic, or it evaluates a different band
|
||||
* range than the coder later codes. */
|
||||
bandwidth = s->bandwidth;
|
||||
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
|
||||
|
||||
memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type));
|
||||
@@ -627,10 +639,24 @@ static void mark_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelEleme
|
||||
const float spread_threshold = FFMIN(0.75f, NOISE_SPREAD_THRESHOLD*FFMAX(0.5f, lambda/100.f));
|
||||
const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f);
|
||||
|
||||
/* PNS candidacy must use the coder's actual coding bandwidth (s->bandwidth,
|
||||
* fixed at init), not a separate heuristic, or it evaluates a different band
|
||||
* range than the coder later codes (NMR relies on this output directly). */
|
||||
bandwidth = s->bandwidth;
|
||||
int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
|
||||
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
|
||||
* (lambda / 120.f);
|
||||
|
||||
/** Keep this in sync with twoloop's cutoff selection */
|
||||
float rate_bandwidth_multiplier = 1.5f;
|
||||
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
|
||||
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
|
||||
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
|
||||
|
||||
frame_bit_rate *= 1.15f;
|
||||
|
||||
if (avctx->cutoff > 0) {
|
||||
bandwidth = avctx->cutoff;
|
||||
} else {
|
||||
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
|
||||
}
|
||||
|
||||
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
|
||||
|
||||
memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type));
|
||||
@@ -841,17 +867,4 @@ const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
|
||||
search_for_ms,
|
||||
ff_aac_search_for_is,
|
||||
},
|
||||
[AAC_CODER_NMR] = {
|
||||
search_for_quantizers_nmr,
|
||||
codebook_trellis_rate,
|
||||
quantize_and_encode_band,
|
||||
ff_aac_encode_tns_info,
|
||||
ff_aac_apply_tns,
|
||||
set_special_band_scalefactors,
|
||||
NULL, /* PNS decided in the trellis (search_for_quantizers_nmr) */
|
||||
mark_pns,
|
||||
ff_aac_search_for_tns,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,700 +0,0 @@
|
||||
/*
|
||||
* AAC encoder NMR (noise-to-mask ratio) scalefactor coder
|
||||
* Copyright (c) 2026 Lynne <dev@lynne.ee>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* AAC encoder NMR scalefactor coder.
|
||||
*
|
||||
* Optimizes the same noise-to-mask objective as the two-loop coder, but with an
|
||||
* optimal Viterbi search over scalefactors instead of a heuristic loop. For each
|
||||
* coded band the per-scalefactor distortion/bits curve is precomputed, then a
|
||||
* trellis over the (window-group, band) coding sequence minimizes
|
||||
* sum_g = dist_g(sf_g)/threshold_g +
|
||||
* lambda * (spectral_bits_g(sf_g) + scalefactor_differential_bits)
|
||||
* with |sf_g - sf_{g-1}| <= SCALE_MAX_DIFF as a constraint, and lambda
|
||||
* binary-searched so the coded size meets the per-frame bit budget
|
||||
*
|
||||
* Perceptual noise substitution (PNS) is integrated into the same objective: once
|
||||
* the trellis settles on its operating lambda, each noise-like band (flagged by
|
||||
* mark_pns) is offered a terminal "code as noise" candidate whose cost is
|
||||
* nmr_pns + lambda*NMR_PNS_BITS. Because NMR_PNS_BITS is far below a band's spectral bit
|
||||
* count, this candidate only wins when lambda is large, i.e. when the encoder is
|
||||
* struggling to hold the bitrate. The bits freed by the chosen PNS bands are
|
||||
* then re-spent by a second trellis pass over the remaining bands.
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_AACCODER_NMR_H
|
||||
#define AVCODEC_AACCODER_NMR_H
|
||||
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "libavutil/mathematics.h"
|
||||
#include "mathops.h"
|
||||
#include "avcodec.h"
|
||||
#include "put_bits.h"
|
||||
#include "aac.h"
|
||||
#include "aacenc.h"
|
||||
#include "aactab.h"
|
||||
#include "aacenctab.h"
|
||||
|
||||
/* differential scalefactor coding cost, clamped to the legal delta range */
|
||||
#define NMR_SFBITS(d) ff_aac_scalefactor_bits[av_clip((d) + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF)]
|
||||
|
||||
#define NMR_ITERS 14 /* lambda binary-search iters */
|
||||
#define NMR_IFINE 9 /* fine-pass lambda iters */
|
||||
#define NMR_CITERS 7 /* coarse-pass lambda iters */
|
||||
#define NMR_CWARM 5 /* coarse-pass iters when warm-started off the previous frame's
|
||||
* lambda: the bracket spans 10 octaves instead of ~43, so fewer
|
||||
* bisection steps reach the same resolution */
|
||||
#define NMR_COARSE 8 /* two-pass coarse->fine grid step, cuts the Viterbi ncand^2 with no
|
||||
* quality loss, 0 disables it (single full-resolution pass) */
|
||||
#define NMR_STEP 1 /* fine-pass scalefactor candidate granularity */
|
||||
|
||||
#define NMR_PNS_BITS 9 /* approx cost in bits of signalling PNS */
|
||||
|
||||
/* Spectral-hole fill: noise-like bands the trellis left mostly empty are filled with
|
||||
* energy-matched noise (PNS); an audible hole sounds worse than matched noise. */
|
||||
#define NMR_PNS_HOLE_FRAC 0.5f
|
||||
#define NMR_PNS_HOLE_SPREAD 0.5f
|
||||
|
||||
/* RC servo gain: scale the corridor centre by exp2(-K*fill/R) each frame to hold
|
||||
* the long-run mean rate; without it a bad centre drifts for dozens of frames. */
|
||||
#define NMR_RC_K_CBR 0.5f
|
||||
|
||||
#define NMR_RC_ITERS 8 /* lambda bisection iters when clamping an over-cap frame */
|
||||
/* Corridor: bisect within [lam_rc/NMR_RC_CORR, lam_rc*NMR_RC_CORR] so quality stays
|
||||
* smooth while per-frame demand is tracked; 1.5 cuts lambda jitter ~25%. */
|
||||
#define NMR_RC_CORR 1.5f
|
||||
|
||||
/* Leaky-bucket half-depth (bits/ch); 512 is the sweet spot — tighter rebounds as
|
||||
* frames cannot hit the narrow window. Clamped to the 6144 bits/ch decoder buffer. */
|
||||
#define NMR_CBR_BUF 512
|
||||
#define NMR_RC_CITERS 3 /* corridor coarse-pass iters */
|
||||
|
||||
/* Transient bit-burst: an isolated onset (preceded by >= NMR_BURST_GAP long frames)
|
||||
* is coded NMR_BURST_GAIN x finer, held uniform across the run, repaid from steady stretches. */
|
||||
#define NMR_BURST_GAP 10
|
||||
#define NMR_BURST_GAIN 8.0f
|
||||
#define NMR_RC_FITERS 4 /* corridor fine-pass iters */
|
||||
#define NMR_RC_TRACK 0.1f /* per-frame pull of the corridor centre toward the realized lambda */
|
||||
|
||||
/* PNS noise-distortion gate: only bands coded well above the masking floor become noise. */
|
||||
#define NMR_PNS_NDGATE 4.0f
|
||||
|
||||
/* Energy/threshold cap for PNS: loud bands (energy >> mask) yield clipping random peaks;
|
||||
* only near-masked bands are safe substitution targets. */
|
||||
#define NMR_PNS_MAX_ET 8.0f
|
||||
|
||||
/* Operating-lambda floor for PNS: below it the encoder is not struggling, so
|
||||
* substituting real texture for 9 signalling bits is net-negative. */
|
||||
#define NMR_PNS_LAM 100.0f
|
||||
|
||||
/**
|
||||
* Viterbi over the coding sequence act[0..nact-1] (indices into the per-band
|
||||
* curves nd/nb), with lambda binary-searched so the coded size ~ destbits.
|
||||
* Fills chosen[band] for every band referenced by act. Returns the operating
|
||||
* lambda. node cost = dist/threshold + lambda*spectral_bits;
|
||||
* edge cost = lambda*sf_differential_bits; |delta sf| <= SCALE_MAX_DIFF hard.
|
||||
*/
|
||||
static float nmr_solve(AACEncContext *s,
|
||||
const float (*nd)[NMR_NCAND], const int (*nb)[NMR_NCAND],
|
||||
const int *blo, const int *bnc, int step,
|
||||
const int *act, int nact, int destbits, int *chosen,
|
||||
float lo_l, float hi_l, int iters)
|
||||
{
|
||||
float dp[NMR_NCAND], dpp[NMR_NCAND], node[NMR_NCAND];
|
||||
float lamsf[2*SCALE_MAX_DIFF + 1]; /* lam*sfdiff bit cost, per lambda */
|
||||
uint8_t bp[128][NMR_NCAND];
|
||||
float lam = 1.0f;
|
||||
|
||||
if (nact <= 0)
|
||||
return lam;
|
||||
|
||||
for (int it = 0; it < iters; it++) {
|
||||
lam = sqrtf(lo_l * hi_l);
|
||||
for (int i = 0; i <= 2*SCALE_MAX_DIFF; i++)
|
||||
lamsf[i] = lam * ff_aac_scalefactor_bits[i]; /* edge cost for this lambda */
|
||||
|
||||
int b0 = act[0];
|
||||
for (int o = 0; o < bnc[b0]; o++)
|
||||
dp[o] = nd[b0][o] + lam * nb[b0][o]; /* anchor band node cost */
|
||||
|
||||
for (int k = 1; k < nact; k++) {
|
||||
int b = act[k], pb = act[k-1];
|
||||
memcpy(dpp, dp, sizeof(dp));
|
||||
for (int o = 0; o < bnc[b]; o++)
|
||||
node[o] = nd[b][o] + lam * nb[b][o];
|
||||
/* dp[o] = node[o] + min_op(dpp[op] + edge cost) */
|
||||
s->aacdsp.nmr_trellis_step(dp, bp[k], dpp, node, lamsf,
|
||||
bnc[b], bnc[pb], blo[b] - blo[pb], step,
|
||||
SCALE_MAX_DIFF);
|
||||
}
|
||||
|
||||
/* backtrack */
|
||||
int beo = 0, b = act[nact-1];
|
||||
float bec = FLT_MAX;
|
||||
for (int o = 0; o < bnc[b]; o++)
|
||||
if (dp[o] < bec) { bec = dp[o]; beo = o; }
|
||||
chosen[b] = beo;
|
||||
for (int k = nact-1; k > 0; k--)
|
||||
chosen[act[k-1]] = bp[k][chosen[act[k]]];
|
||||
|
||||
/* calc cost */
|
||||
int total = 0;
|
||||
for (int k = 0; k < nact; k++)
|
||||
total += nb[act[k]][chosen[act[k]]];
|
||||
for (int k = 1; k < nact; k++)
|
||||
total += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*step) - (blo[act[k-1]]+chosen[act[k-1]]*step));
|
||||
|
||||
if (it == iters - 1)
|
||||
break;
|
||||
|
||||
/* check if we went over budget, go coarser if we did */
|
||||
if (total > destbits)
|
||||
lo_l = lam;
|
||||
else
|
||||
hi_l = lam;
|
||||
}
|
||||
return lam;
|
||||
}
|
||||
|
||||
/* Build one coded band's (dist/threshold, bits) cost curve, candidates sf = lo + o*step
|
||||
* for o in [0,maxn), stopping when the band would drop (cb <= 0). Returns the bit count. */
|
||||
static int nmr_band_curve(AACEncContext *s, SingleChannelElement *sce, int w, int g,
|
||||
int start, int lo, int step, int maxn, float invthr,
|
||||
float maxval, float *nd_row, int *nb_row)
|
||||
{
|
||||
int ncand = 0;
|
||||
for (int o = 0; o < maxn && lo + o*step <= SCALE_MAX_POS; o++) {
|
||||
int sf = lo + o*step, btot = 0, cb = find_min_book(maxval, sf);
|
||||
float dist = 0.0f;
|
||||
if (cb <= 0)
|
||||
break;
|
||||
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
|
||||
int bb;
|
||||
dist += quantize_band_cost_cached(s, w + w2, g, sce->coeffs + start + w2*128,
|
||||
s->scoefs + start + w2*128, sce->ics.swb_sizes[g],
|
||||
sf, cb, 1.0f, INFINITY, &bb, NULL, 0);
|
||||
btot += bb;
|
||||
}
|
||||
nd_row[ncand] = (dist - btot) * invthr;
|
||||
nb_row[ncand] = btot;
|
||||
ncand++;
|
||||
}
|
||||
return ncand;
|
||||
}
|
||||
|
||||
static void search_for_quantizers_nmr(AVCodecContext *avctx,
|
||||
AACEncContext *s,
|
||||
SingleChannelElement *sce,
|
||||
const float lambda)
|
||||
{
|
||||
int bch = ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels);
|
||||
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / bch * (lambda / 120.f);
|
||||
int allz = 0, cutoff = 1024, nbnd = 0;
|
||||
|
||||
float thr[128]; /* allocation-law effective threshold (drives the trellis) */
|
||||
float thr_real[128]; /* real masking threshold (perceptual gates: PNS) */
|
||||
float pener[128]; /* band energy (for PNS noise target) */
|
||||
float pspread[128]; /* band tonality spread (1 = noise) */
|
||||
int minsf[128];
|
||||
float maxvals[128];
|
||||
|
||||
/* coded-band trellis state (indexed 0..nbnd-1) */
|
||||
int bidx[128]; /* sce band index (w*16+g) */
|
||||
int bw[128], bg[128], bst[128]; /* window group, swb, coef start per coded band */
|
||||
int blo[128]; /* finest candidate scalefactor */
|
||||
int bnc[128]; /* number of candidates */
|
||||
int chosen[128];
|
||||
int act[128]; /* active (non-PNS) band coding order */
|
||||
uint8_t is_pns[128]; /* trellis band coded as noise */
|
||||
|
||||
float (*nd)[NMR_NCAND] = s->nmr->nd; /* dist / threshold per candidate (heap) */
|
||||
int (*nb)[NMR_NCAND] = s->nmr->nb; /* spectral bits per candidate (heap) */
|
||||
|
||||
/* two-pass coarse->fine grid step (see NMR_COARSE), the lambda search runs on
|
||||
* the cheap coarse grid, PASS 2 refines the winner at NMR_STEP granularity */
|
||||
const int cstep = NMR_COARSE > 0 ? NMR_COARSE : NMR_STEP;
|
||||
|
||||
s->nmr->counted[s->cur_channel] = 0;
|
||||
|
||||
/* Global-lambda RC: one solve per frame at a servoed centre lambda; the reservoir
|
||||
* holds the long-run mean rate. Bypassed for VBR (-q:a) and the bootstrap frame. */
|
||||
int rc_eligible = !(avctx->flags & AV_CODEC_FLAG_QSCALE) && avctx->bit_rate > 0 &&
|
||||
avctx->bit_rate_tolerance != 0;
|
||||
/* Leaky-bucket reservoir: rc_fill (signed +-rc_bmax); the spend-floor/cap below force
|
||||
* lambda so no frame banks past +rc_bmax or borrows past -rc_bmax. */
|
||||
int rc_rate_frame = avctx->bit_rate * 1024.0 / avctx->sample_rate;
|
||||
int rc_bmax = FFMIN(FFMAX(6144 * s->channels - rc_rate_frame, 256), NMR_CBR_BUF * s->channels);
|
||||
if (rc_eligible && avctx->frame_num != s->nmr->rc_frame_num) {
|
||||
if (s->nmr->rc_frame_num > 0 && s->nmr->lam_rc > 0.0f)
|
||||
s->nmr->rc_fill = av_clip(s->nmr->rc_fill + rc_rate_frame - s->last_frame_pb_count,
|
||||
-rc_bmax, rc_bmax);
|
||||
s->nmr->rc_frame_num = avctx->frame_num;
|
||||
|
||||
/* Transient burst run state: set at run start and held across the run so
|
||||
* coding stays uniform; repaid from the reservoir's steady stretches. */
|
||||
int is_short = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
|
||||
if (is_short) {
|
||||
if (!s->nmr->prev_was_short) /* run start */
|
||||
s->nmr->run_burst = s->nmr->frames_since_short >= NMR_BURST_GAP
|
||||
? NMR_BURST_GAIN : 1.0f;
|
||||
s->nmr->frames_since_short = 0;
|
||||
} else {
|
||||
s->nmr->run_burst = 1.0f;
|
||||
s->nmr->frames_since_short++;
|
||||
}
|
||||
s->nmr->prev_was_short = is_short;
|
||||
}
|
||||
int rc_global = rc_eligible && s->nmr->lam_rc > 0.0f;
|
||||
|
||||
if (s->psy.bitres.alloc >= 0)
|
||||
destbits = s->psy.bitres.alloc *
|
||||
(lambda / (avctx->global_quality ? avctx->global_quality : 120));
|
||||
if (rc_global && s->psy.bitres.alloc >= 0)
|
||||
/* uniform CBR target: nominal rate plus fast reservoir repayment */
|
||||
destbits = (avctx->bit_rate * 1024.0 / avctx->sample_rate
|
||||
+ s->nmr->rc_fill / 2.0) / s->channels;
|
||||
destbits = FFMIN(destbits, 5800);
|
||||
/* honest budget: subtract the measured non-trellis overhead (section data, ICS,
|
||||
* sf/PNS signalling), which is rate-dependent hence adaptive. */
|
||||
if (s->nmr->side_inited)
|
||||
destbits = av_clip(destbits - (int)(s->nmr->side_ema / s->channels), 64, 5800);
|
||||
|
||||
/* Apply the held transient burst factor (set in the run-state machine above). */
|
||||
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE && s->nmr->run_burst > 1.0f)
|
||||
destbits = av_clip((int)(destbits * s->nmr->run_burst), 64, 6800);
|
||||
|
||||
/* band cutoff index for this frame's window size; the bandwidth is fixed
|
||||
* at init and shared with the psy model */
|
||||
cutoff = s->bandwidth * 2 * (1024 / sce->ics.num_windows) / avctx->sample_rate;
|
||||
|
||||
/* Short-block transient noise shaping (pairs with short-block TNS): temporal
|
||||
* premasking clamps each window's threshold toward the preceding windows'
|
||||
* (Apple's preEchoReduction), and flat-residual flattens each window's thresholds
|
||||
* to their per-window mean so TNS synthesis has a white floor to concentrate. */
|
||||
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
||||
const float pm_p1 = 0.1f, pm_p2 = 2.0f, pm_p3 = 4.0f;
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
float t1 = FLT_MAX, t2 = FLT_MAX; /* original thr of w-1, w-2 */
|
||||
for (int w = 0; w < sce->ics.num_windows; w++) {
|
||||
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
|
||||
float t = b->threshold;
|
||||
float c = FFMIN(t, FFMIN(t1*pm_p2, t2*pm_p3));
|
||||
b->threshold = FFMAX(c, t*pm_p1);
|
||||
t2 = t1; t1 = t;
|
||||
}
|
||||
}
|
||||
{
|
||||
for (int w = 0; w < sce->ics.num_windows; w++) {
|
||||
float sum = 0.0f; int n = 0;
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
|
||||
if (b->energy > b->threshold && b->threshold > 0.0f) { sum += b->threshold; n++; }
|
||||
}
|
||||
if (n > 0) {
|
||||
float mean = sum / n;
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
|
||||
if (b->energy > b->threshold && b->threshold > 0.0f)
|
||||
b->threshold = mean;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocation curve to favour high frequencies */
|
||||
const float a_ae = 0.443f, a_at = 0.111f;
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
|
||||
int start = 0;
|
||||
for (int g = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) {
|
||||
float uplim = 0.0f, ener = 0.0f, spread = 2.0f;
|
||||
int nz = 0;
|
||||
if (sce->band_type[w*16+g] == INTENSITY_BT ||
|
||||
sce->band_type[w*16+g] == INTENSITY_BT2) {
|
||||
/* pre-decided intensity band (right channel): keep its
|
||||
* signalling, it is not trellis-coded */
|
||||
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
|
||||
sce->zeroes[(w+w2)*16+g] = 0;
|
||||
continue;
|
||||
}
|
||||
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
|
||||
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
|
||||
ener += band->energy;
|
||||
spread = FFMIN(spread, band->spread);
|
||||
if (start >= cutoff || band->energy <= band->threshold || band->threshold == 0.0f) {
|
||||
sce->zeroes[(w+w2)*16+g] = 1;
|
||||
continue;
|
||||
}
|
||||
uplim += band->threshold;
|
||||
nz = 1;
|
||||
}
|
||||
sce->zeroes[w*16+g] = !nz;
|
||||
thr_real[w*16+g] = uplim; /* real mask, before the allocation law (PNS gate) */
|
||||
if (nz && ener > 0.0f && uplim > 0.0f)
|
||||
uplim = expf(a_ae * logf(ener) + a_at * logf(uplim));
|
||||
thr[w*16+g] = uplim;
|
||||
pener[w*16+g] = ener;
|
||||
pspread[w*16+g] = spread;
|
||||
allz |= nz;
|
||||
}
|
||||
}
|
||||
if (!allz)
|
||||
goto bail;
|
||||
|
||||
s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024);
|
||||
ff_quantize_band_cost_cache_init(s);
|
||||
|
||||
/* finest codeable scalefactor and max value per band */
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
|
||||
int start = w*128;
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs + start);
|
||||
minsf[w*16+g] = maxvals[w*16+g] > 0 ? coef2minsf(maxvals[w*16+g]) : 0;
|
||||
start += sce->ics.swb_sizes[g];
|
||||
}
|
||||
}
|
||||
|
||||
/* PASS 1:
|
||||
* precompute each coded band's cost curve at the coarse candidate step
|
||||
* (the lambda search runs on this cheap grid, PASS 2 refines the winner) */
|
||||
{
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
|
||||
int start = w*128;
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
if (!sce->zeroes[w*16+g] && maxvals[w*16+g] > 0 && nbnd < 128) {
|
||||
int lo = av_clip(minsf[w*16+g], 0, SCALE_MAX_POS);
|
||||
float invthr = 1.0f / FFMAX(thr[w*16+g], 1e-9f);
|
||||
int ncand = nmr_band_curve(s, sce, w, g, start, lo, cstep, NMR_NCAND,
|
||||
invthr, maxvals[w*16+g], nd[nbnd], nb[nbnd]);
|
||||
if (ncand == 0) {
|
||||
/* nothing codeable -> drop the whole group band. The
|
||||
* subwindow flags must be cleared too: the encoder later
|
||||
* re-derives the group flag by ANDing them, which would
|
||||
* resurrect the band with a never-assigned scalefactor. */
|
||||
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
|
||||
sce->zeroes[(w+w2)*16+g] = 1;
|
||||
} else {
|
||||
bidx[nbnd] = w*16+g;
|
||||
bw[nbnd] = w;
|
||||
bg[nbnd] = g;
|
||||
bst[nbnd] = start;
|
||||
blo[nbnd] = lo;
|
||||
bnc[nbnd] = ncand;
|
||||
nbnd++;
|
||||
}
|
||||
}
|
||||
start += sce->ics.swb_sizes[g];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nbnd)
|
||||
goto bail;
|
||||
|
||||
/* solve the trellis over all coded bands, then offer PNS at the operating
|
||||
* lambda and re-solve over the survivors with the freed budget */
|
||||
{
|
||||
int nact = nbnd, pns_count = 0;
|
||||
float lam0 = s->nmr->lam[s->cur_channel];
|
||||
float lam;
|
||||
|
||||
for (int b = 0; b < nbnd; b++) {
|
||||
act[b] = b;
|
||||
is_pns[b] = 0;
|
||||
}
|
||||
if (rc_global) {
|
||||
/* bisect to this frame's bit demand within the corridor around the
|
||||
* servoed lambda: per-frame psy demand is tracked, but lambda cannot
|
||||
* jump, which keeps quality smooth across frames */
|
||||
float lo = s->nmr->lam_rc / NMR_RC_CORR;
|
||||
/* Transient burst: widen the lower lambda bound so the bisection can actually
|
||||
* pour the boosted destbits into an onset frame (finer coding kills the
|
||||
* pre-echo); reservoir servo repays it from the steady frames. run_burst==1 on
|
||||
* non-onset frames leaves the corridor unchanged. */
|
||||
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE && s->nmr->run_burst > 1.0f)
|
||||
lo /= s->nmr->run_burst;
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
|
||||
lo, s->nmr->lam_rc * NMR_RC_CORR,
|
||||
NMR_RC_CITERS);
|
||||
|
||||
int tot = 0;
|
||||
for (int k = 0; k < nact; k++)
|
||||
tot += nb[act[k]][chosen[act[k]]];
|
||||
for (int k = 1; k < nact; k++)
|
||||
tot += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*cstep) - (blo[act[k-1]]+chosen[act[k-1]]*cstep));
|
||||
int hardcap = av_clip((int)(5800.f * FFMIN(1.f, lambda / 120.f)), 256, 5800);
|
||||
/* leaky-bucket window: don't borrow past -rc_bmax (cap) or bank past +rc_bmax (floor) */
|
||||
int rc_cap = FFMIN(hardcap, (s->nmr->rc_fill + rc_rate_frame + rc_bmax) / s->channels);
|
||||
int rc_floor = FFMAX(0, (s->nmr->rc_fill + rc_rate_frame - rc_bmax) / s->channels);
|
||||
if (tot > rc_cap)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, rc_cap, chosen,
|
||||
lam, 1e4f, NMR_CITERS);
|
||||
else if (tot < rc_floor)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, rc_floor, chosen,
|
||||
1e-9f, lam, NMR_CITERS);
|
||||
} else if (NMR_COARSE > 0 && lam0 > 0.0f) {
|
||||
/* per-frame bisection; lambda is strongly frame-correlated, so when a
|
||||
* previous frame's operating lambda exists, bisect a narrow bracket
|
||||
* around it. A result near the bracket edge means the budget crossing
|
||||
* lies outside (hard content transition) == redo the full search. */
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
|
||||
lam0/32.0f, lam0*32.0f, NMR_CWARM);
|
||||
if (lam < lam0/16.0f || lam > lam0*16.0f)
|
||||
lam0 = 0.0f;
|
||||
}
|
||||
if (!rc_global && lam0 <= 0.0f)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
|
||||
1e-9f, 1e4f, NMR_COARSE > 0 ? NMR_CITERS : NMR_ITERS);
|
||||
|
||||
/* PASS 2:
|
||||
* refine each band at full granularity (NMR_STEP) in a +/-cstep window
|
||||
* around the coarse pick, then re-solve. Recovers single-pass quality while the
|
||||
* lambda search stayed cheap on the coarse grid. */
|
||||
if (NMR_COARSE > 0) {
|
||||
/* nmr_speed, 0 = slowest/best, higher = faster. It narrows the fine
|
||||
* refine +/-window (scalefactors) below NMR_COARSE: at speed 0 the window
|
||||
* spans the whole coarse-grid gap, so the two-pass result matches the
|
||||
* exhaustive single-pass search.
|
||||
* Each speed level shaves one sf off the window.
|
||||
* At @64k mono (Zim / xRT): speed 0 -> 0.00095/15x,
|
||||
* 2 -> 0.00096/18x, 3 -> 0.00100/20x, 4 -> 0.00103/22x */
|
||||
int win = NMR_COARSE - av_clip(s->options.nmr_speed, 0, 4);
|
||||
for (int b = 0; b < nbnd; b++) {
|
||||
int center = blo[b] + chosen[b]*cstep;
|
||||
int flo = av_clip(center - win, av_clip(minsf[bidx[b]], 0, SCALE_MAX_POS), SCALE_MAX_POS);
|
||||
int maxn = FFMIN(NMR_NCAND, 2*win/NMR_STEP + 1);
|
||||
float invthr = 1.0f / FFMAX(thr[bidx[b]], 1e-9f);
|
||||
int ncand = nmr_band_curve(s, sce, bw[b], bg[b], bst[b], flo, NMR_STEP, maxn,
|
||||
invthr, maxvals[bidx[b]], nd[b], nb[b]);
|
||||
blo[b] = flo;
|
||||
bnc[b] = FFMAX(1, ncand);
|
||||
}
|
||||
/* fine pass: narrow corridor around the coarse solve */
|
||||
if (rc_global)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, destbits, chosen,
|
||||
lam/2.0f, lam*2.0f, NMR_RC_FITERS);
|
||||
else
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, destbits, chosen,
|
||||
lam/16.0f, lam*16.0f, NMR_IFINE);
|
||||
}
|
||||
|
||||
if (rc_global) {
|
||||
/* leaky-bucket clamp: keep the frame within [rc_floor, rc_cap] so the reservoir
|
||||
* stays in +-rc_bmax -- clamp lambda UP if it would borrow past the cap, DOWN if it
|
||||
* would bank past the floor (spend-floor). The hard cap follows the encoder's outer
|
||||
* lambda so the (rare) hard-overflow re-encode -- which shrinks that lambda -- always
|
||||
* converges; on the first pass lambda is nominal and this is 5800. */
|
||||
int hardcap = av_clip((int)(5800.f * FFMIN(1.f, lambda / 120.f)), 256, 5800);
|
||||
int tot = 0;
|
||||
for (int k = 0; k < nact; k++)
|
||||
tot += nb[act[k]][chosen[act[k]]];
|
||||
for (int k = 1; k < nact; k++)
|
||||
tot += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*NMR_STEP) - (blo[act[k-1]]+chosen[act[k-1]]*NMR_STEP));
|
||||
int rc_cap = FFMIN(hardcap, (s->nmr->rc_fill + rc_rate_frame + rc_bmax) / s->channels);
|
||||
int rc_floor = FFMAX(0, (s->nmr->rc_fill + rc_rate_frame - rc_bmax) / s->channels);
|
||||
if (tot > rc_cap)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, rc_cap, chosen,
|
||||
lam, 1e4f, NMR_RC_ITERS);
|
||||
else if (tot < rc_floor)
|
||||
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, rc_floor, chosen,
|
||||
1e-9f, lam, NMR_RC_ITERS);
|
||||
}
|
||||
|
||||
s->nmr->lam[s->cur_channel] = lam; /* warm start for the next frame */
|
||||
if (rc_global) {
|
||||
/* drag the corridor centre toward the realized lambda so it follows
|
||||
* content drift faster than the reservoir term alone */
|
||||
float c = s->nmr->lam_rc * powf(lam / s->nmr->lam_rc, NMR_RC_TRACK);
|
||||
/* then servo the centre off the reservoir error so the long-run rate
|
||||
* returns to nominal. rc_fill>0 = bits banked (undershooting) -> lower
|
||||
* lambda to spend them; <0 -> raise it. This is what holds the mean;
|
||||
* the corridor tracking alone has no rate authority and a bad centre
|
||||
* would otherwise drift for dozens of frames, starving each one. */
|
||||
float R = avctx->bit_rate * 1024.0 / avctx->sample_rate;
|
||||
c *= exp2f(-NMR_RC_K_CBR * s->nmr->rc_fill / R);
|
||||
s->nmr->lam_rc = av_clipf(c, 1e-6f, 1e4f);
|
||||
} else if (rc_eligible && nbnd >= 8) {
|
||||
/* bootstrap the servo off the first substantive frame; near-silent
|
||||
* lead-in frames have degenerate budgets that rail the bisection to
|
||||
* a nonsense lambda and would poison the whole stream */
|
||||
s->nmr->lam_rc = av_clipf(lam, 1e-4f, 10.0f);
|
||||
}
|
||||
|
||||
{ /* PNS */
|
||||
const float pns_lam = NMR_PNS_LAM;
|
||||
/* band 0 (lowest freq) is kept as the global-gain / sf-chain anchor */
|
||||
for (int b = 1; b < nbnd; b++) {
|
||||
int bi = bidx[b];
|
||||
float spread = pspread[bi];
|
||||
float nmr_pns, cost_keep, cost_pns, frac;
|
||||
if (!sce->can_pns[bi])
|
||||
continue;
|
||||
|
||||
/* Loud-band guard: never substitute a band whose energy is far above the
|
||||
* masking threshold -- energy-matched noise on a dominant band clips/pops
|
||||
* (and is audibly wrong). PNS is for near-masked noise only. */
|
||||
if (pener[bi] > NMR_PNS_MAX_ET * thr_real[bi])
|
||||
continue;
|
||||
|
||||
/* Struggle gate: no PNS at all unless the encoder is genuinely under bit
|
||||
* pressure (high operating lambda). */
|
||||
if (lam <= pns_lam)
|
||||
continue;
|
||||
|
||||
/* Spectral-hole fill: a noise-like band the trellis left mostly empty */
|
||||
frac = nd[b][chosen[b]] * thr[bi] / FFMAX(pener[bi], 1e-9f);
|
||||
if (spread > NMR_PNS_HOLE_SPREAD && frac > NMR_PNS_HOLE_FRAC) {
|
||||
is_pns[b] = 1;
|
||||
pns_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only replace a band that is being coded audibly badly */
|
||||
if (nd[b][chosen[b]] * thr[bi] <= NMR_PNS_NDGATE * thr_real[bi])
|
||||
continue;
|
||||
|
||||
/* perceptual cost of replacing the band with energy-matched noise:
|
||||
* the non-noise-like fraction of its energy, in dist/threshold units */
|
||||
nmr_pns = FFMAX(0.0f, pener[bi] * (1.0f - spread*spread))
|
||||
/ FFMAX(thr[bi], 1e-9f);
|
||||
cost_keep = nd[b][chosen[b]] + lam * nb[b][chosen[b]];
|
||||
cost_pns = nmr_pns + lam * NMR_PNS_BITS;
|
||||
if (cost_pns < cost_keep) {
|
||||
is_pns[b] = 1;
|
||||
pns_count++;
|
||||
}
|
||||
}
|
||||
if (pns_count) {
|
||||
int budget2 = destbits - pns_count * NMR_PNS_BITS;
|
||||
nact = 0;
|
||||
for (int b = 0; b < nbnd; b++)
|
||||
if (!is_pns[b])
|
||||
act[nact++] = b;
|
||||
/* re-solve over the survivors: at fixed lambda the allocation is
|
||||
* the same except for the repaired sf-delta chain; in bisection
|
||||
* mode re-spend the freed budget */
|
||||
if (rc_global)
|
||||
nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, budget2, chosen,
|
||||
lam, lam, 1);
|
||||
else
|
||||
nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, budget2, chosen,
|
||||
1e-9f, 1e4f, NMR_ITERS);
|
||||
}
|
||||
}
|
||||
for (int b = 0; b < nbnd; b++) {
|
||||
int bi = bidx[b];
|
||||
if (is_pns[b]) {
|
||||
sce->band_type[bi] = NOISE_BT;
|
||||
sce->zeroes[bi] = 0;
|
||||
sce->pns_ener[bi] = pener[bi] * FFMIN(1.0f, pspread[bi]*pspread[bi]);
|
||||
} else {
|
||||
sce->sf_idx[bi] = av_clip(blo[b] + chosen[b]*NMR_STEP, 0, SCALE_MAX_POS);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* record the bits this solve accounted for; the encoder compares them
|
||||
* against the channel's real output to keep the budget honest */
|
||||
int tot = 0, prevb = -1;
|
||||
for (int b = 0; b < nbnd; b++) {
|
||||
if (is_pns[b])
|
||||
continue;
|
||||
tot += nb[b][chosen[b]];
|
||||
if (prevb >= 0)
|
||||
tot += NMR_SFBITS((blo[b]+chosen[b]*NMR_STEP) - (blo[prevb]+chosen[prevb]*NMR_STEP));
|
||||
prevb = b;
|
||||
}
|
||||
s->nmr->counted[s->cur_channel] = tot;
|
||||
}
|
||||
}
|
||||
|
||||
/* SCALE_MAX_DIFF condition:
|
||||
* re-clamp, codebook fixup, drop uncodeable, set global gain
|
||||
* NOISE_BT bands keep their own scalefactor chain via set_special_band_scalefactors) */
|
||||
{
|
||||
uint8_t nextband[128];
|
||||
int prev = -1;
|
||||
ff_init_nextband_map(sce, nextband);
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
if (sce->band_type[w*16+g] == NOISE_BT ||
|
||||
sce->band_type[w*16+g] == INTENSITY_BT ||
|
||||
sce->band_type[w*16+g] == INTENSITY_BT2)
|
||||
continue;
|
||||
if (sce->zeroes[w*16+g]) {
|
||||
sce->band_type[w*16+g] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev != -1)
|
||||
sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], prev - SCALE_MAX_DIFF, prev + SCALE_MAX_DIFF);
|
||||
sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
|
||||
if (sce->band_type[w*16+g] <= 0) {
|
||||
if (!ff_sfdelta_can_remove_band(sce, nextband, prev, w*16+g)) {
|
||||
sce->band_type[w*16+g] = 1;
|
||||
} else {
|
||||
/* drop subwindow flags too, see the PASS 1 drop above */
|
||||
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
|
||||
sce->zeroes[(w+w2)*16+g] = 1;
|
||||
sce->band_type[w*16+g] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (prev == -1)
|
||||
sce->sf_idx[0] = sce->sf_idx[w*16+g]; /* global gain */
|
||||
prev = sce->sf_idx[w*16+g];
|
||||
}
|
||||
}
|
||||
|
||||
/* Every band, coded or not, must carry a chain-legal scalefactor: the
|
||||
* codebook trellis (encode_window_bands_info) may later absorb a dropped
|
||||
* band into a nonzero section, resurrecting it, and its sf then gets
|
||||
* coded. Forward-fill with the previous coded sf (delta 0, cheapest);
|
||||
* leading bands get the global gain. */
|
||||
if (prev != -1) {
|
||||
int last = sce->sf_idx[0];
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
|
||||
for (int g = 0; g < sce->ics.num_swb; g++) {
|
||||
if (!sce->zeroes[w*16+g] && sce->band_type[w*16+g] != NOISE_BT &&
|
||||
sce->band_type[w*16+g] < RESERVED_BT)
|
||||
last = sce->sf_idx[w*16+g];
|
||||
else if (sce->band_type[w*16+g] < RESERVED_BT && (w*16+g) > 0)
|
||||
sce->sf_idx[w*16+g] = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
bail:
|
||||
/* Nothing codeable in this channel. Leave a fully consistent state: any
|
||||
* stale nonzero band_type acts as a codebook lower bound in the encoder's
|
||||
* section trellis (encode_window_bands_info), which would forbid the zero
|
||||
* section and resurrect the band with a stale, chain-illegal scalefactor.
|
||||
* Pre-decided intensity bands keep their signalling. */
|
||||
for (int i = 0; i < 128; i++) {
|
||||
if (sce->band_type[i] == INTENSITY_BT || sce->band_type[i] == INTENSITY_BT2)
|
||||
continue;
|
||||
sce->zeroes[i] = 1;
|
||||
sce->band_type[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* AVCODEC_AACCODER_NMR_H */
|
||||
@@ -71,6 +71,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
|
||||
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
|
||||
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
|
||||
* (lambda / 120.f);
|
||||
int refbits = destbits;
|
||||
int toomanybits, toofewbits;
|
||||
char nzs[128];
|
||||
uint8_t nextband[128];
|
||||
@@ -171,8 +172,32 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
|
||||
/** and zero out above cutoff frequency */
|
||||
{
|
||||
int wlen = 1024 / sce->ics.num_windows;
|
||||
/* the bandwidth is fixed at init and shared with the psy model */
|
||||
cutoff = s->bandwidth * 2 * wlen / avctx->sample_rate;
|
||||
int bandwidth;
|
||||
|
||||
/**
|
||||
* Scale, psy gives us constant quality, this LP only scales
|
||||
* bitrate by lambda, so we save bits on subjectively unimportant HF
|
||||
* rather than increase quantization noise. Adjust nominal bitrate
|
||||
* to effective bitrate according to encoding parameters,
|
||||
* AAC_CUTOFF_FROM_BITRATE is calibrated for effective bitrate.
|
||||
*/
|
||||
float rate_bandwidth_multiplier = 1.5f;
|
||||
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
|
||||
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
|
||||
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
|
||||
|
||||
/** Compensate for extensions that increase efficiency */
|
||||
if (s->options.pns || s->options.intensity_stereo)
|
||||
frame_bit_rate *= 1.15f;
|
||||
|
||||
if (avctx->cutoff > 0) {
|
||||
bandwidth = avctx->cutoff;
|
||||
} else {
|
||||
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
|
||||
s->psy.cutoff = bandwidth;
|
||||
}
|
||||
|
||||
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
|
||||
pns_start_pos = NOISE_LOW_LIMIT * 2 * wlen / avctx->sample_rate;
|
||||
}
|
||||
|
||||
|
||||
+148
-496
@@ -123,40 +123,40 @@ static const AACPCEInfo aac_pce_configs[] = {
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_SURROUND,
|
||||
.num_ele = { 2, 0, 0, 0 },
|
||||
.pairing = { { 0, 1 }, },
|
||||
.pairing = { { 1, 0 }, },
|
||||
.index = { { 0, 0 }, },
|
||||
.config_map = { 2, TYPE_SCE, TYPE_CPE },
|
||||
.reorder_map = { 2, 0, 1 },
|
||||
.config_map = { 2, TYPE_CPE, TYPE_SCE, },
|
||||
.reorder_map = { 0, 1, 2 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_3POINT1,
|
||||
.num_ele = { 2, 0, 0, 1 },
|
||||
.pairing = { { 0, 1 }, },
|
||||
.pairing = { { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, },
|
||||
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 3 },
|
||||
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE },
|
||||
.reorder_map = { 0, 1, 2, 3 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_4POINT0,
|
||||
.num_ele = { 2, 0, 1, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 0 }, },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 0 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 } },
|
||||
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 2, 0, 1, 3 },
|
||||
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_4POINT1,
|
||||
.num_ele = { 2, 0, 1, 1 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 0 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 4, 3 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 0 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 2 }, { 0 } },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_2_2,
|
||||
.num_ele = { 1, 0, 1, 0 },
|
||||
.pairing = { { 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0 }, { 0 }, { 1 } },
|
||||
.num_ele = { 1, 1, 0, 0 },
|
||||
.pairing = { { 1 }, { 1 }, },
|
||||
.index = { { 0 }, { 1 }, },
|
||||
.config_map = { 2, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3 },
|
||||
},
|
||||
@@ -170,131 +170,158 @@ static const AACPCEInfo aac_pce_configs[] = {
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_5POINT0,
|
||||
.num_ele = { 2, 0, 1, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1 } },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 } },
|
||||
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 2, 0, 1, 3, 4 },
|
||||
.num_ele = { 2, 1, 0, 0 },
|
||||
.pairing = { { 1, 0 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 1 } },
|
||||
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_5POINT1,
|
||||
.num_ele = { 2, 0, 1, 1 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 4, 5, 3 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1 } },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_5POINT0_BACK,
|
||||
.num_ele = { 2, 0, 1, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1 } },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1 } },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 } },
|
||||
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 2, 0, 1, 3, 4 },
|
||||
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_5POINT1_BACK,
|
||||
.num_ele = { 2, 0, 1, 1 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 4, 5, 3 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1 } },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_6POINT0,
|
||||
.num_ele = { 2, 0, 2, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 0 } },
|
||||
.index = { { 0, 0 }, { 0 }, { 1, 1 } },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 2, 0, 1, 4, 5, 3 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 1 }, { 0 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1 } },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_6POINT0_FRONT,
|
||||
.num_ele = { 2, 0, 1, 0 },
|
||||
.pairing = { { 1, 1 }, { 0 }, { 1 } },
|
||||
.index = { { 0, 1 }, { 0 }, { 2 }, },
|
||||
.num_ele = { 2, 1, 0, 0 },
|
||||
.pairing = { { 1, 1 }, { 1 } },
|
||||
.index = { { 1, 0 }, { 2 }, },
|
||||
.config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, },
|
||||
.reorder_map = { 2, 3, 0, 1, 4, 5 },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_HEXAGONAL,
|
||||
.num_ele = { 2, 0, 2, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 0 } },
|
||||
.index = { { 0, 0 }, { 0 }, { 1, 1 } },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 2, 0, 1, 3, 4, 5 },
|
||||
.pairing = { { 1, 0 },{ 0 },{ 1, 0 }, },
|
||||
.index = { { 0, 0 },{ 0 },{ 1, 1 } },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_6POINT1,
|
||||
.num_ele = { 2, 0, 2, 1 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1, 1 }, { 0 } },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 5, 6, 4, 3 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 },{ 0 },{ 1, 0 }, },
|
||||
.index = { { 0, 0 },{ 1 },{ 1, 2 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_6POINT1_BACK,
|
||||
.num_ele = { 2, 0, 2, 1 },
|
||||
.pairing = { { 0, 1 },{ 0 },{ 1, 0 }, },
|
||||
.index = { { 0, 0 },{ 0 },{ 1, 1 },{ 0 } },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 4, 5, 6, 3 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1, 2 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_6POINT1_FRONT,
|
||||
.num_ele = { 2, 0, 1, 1 },
|
||||
.pairing = { { 1, 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 1 }, { 0 }, { 2 }, { 0 }, },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE, },
|
||||
.reorder_map = { 3, 4, 0, 1, 5, 6, 2 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1, 2 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_7POINT0,
|
||||
.num_ele = { 2, 0, 2, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 1 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 2, 1 }, },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 2, 0, 1, 3, 4, 5, 6 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 1 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 2 }, },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_7POINT0_FRONT,
|
||||
.num_ele = { 3, 0, 1, 0 },
|
||||
.pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0, 1 }, { 0 }, { 2 }, },
|
||||
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 2, 3, 4, 0, 1, 5, 6 },
|
||||
.num_ele = { 2, 1, 1, 0 },
|
||||
.pairing = { { 1, 0 }, { 1 }, { 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 2 }, },
|
||||
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_7POINT1,
|
||||
.num_ele = { 2, 0, 2, 1 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 1 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 2, 1 }, { 0 } },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 0, 1, 4, 5, 6, 7, 3 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1, 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE,
|
||||
.num_ele = { 3, 0, 1, 1 },
|
||||
.pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
|
||||
.index = { { 0, 0, 1 }, { 0 }, { 2 }, { 0 }, },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 4, 5, 0, 1, 6, 7, 3 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 },{ 1, 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK,
|
||||
.num_ele = { 3, 0, 1, 1 },
|
||||
.pairing = { { 0, 1, 1 }, { 0 }, { 1 } },
|
||||
.index = { { 0, 0, 1 }, { 0 }, { 2 }, { 0 } },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
|
||||
.reorder_map = { 2, 6, 7, 0, 1, 4, 5, 3 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 0 }, { 1, 1 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_OCTAGONAL,
|
||||
.num_ele = { 2, 0, 3, 0 },
|
||||
.pairing = { { 0, 1 }, { 0 }, { 1, 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 0 }, { 1, 2, 1 }, },
|
||||
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 2, 0, 1, 6, 7, 3, 4, 5 },
|
||||
.num_ele = { 2, 1, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 1 }, { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 1 }, { 2, 1 } },
|
||||
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
},
|
||||
{ /* Meant for order 2/mixed ambisonics */
|
||||
.layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 9,
|
||||
.u.mask = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER },
|
||||
.num_ele = { 2, 2, 2, 0 },
|
||||
.pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, },
|
||||
.index = { { 0, 0 }, { 1, 1 }, { 2, 2 } },
|
||||
.config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
|
||||
},
|
||||
{ /* Meant for order 2/mixed ambisonics */
|
||||
.layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 10,
|
||||
.u.mask = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER |
|
||||
AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER },
|
||||
.num_ele = { 2, 2, 2, 0 },
|
||||
.pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, },
|
||||
.index = { { 0, 1 }, { 2, 0 }, { 3, 1 } },
|
||||
.config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
},
|
||||
{
|
||||
.layout = AV_CHANNEL_LAYOUT_HEXADECAGONAL,
|
||||
.num_ele = { 4, 2, 4, 0 },
|
||||
.pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, },
|
||||
.index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } },
|
||||
.config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
|
||||
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -339,10 +366,11 @@ static void put_pce(PutBitContext *pb, AVCodecContext *avctx)
|
||||
* Make AAC audio config object.
|
||||
* @see 1.6.2.1 "Syntax - AudioSpecificConfig"
|
||||
*/
|
||||
static int put_audio_specific_config(AVCodecContext *avctx, int chcfg)
|
||||
static int put_audio_specific_config(AVCodecContext *avctx)
|
||||
{
|
||||
PutBitContext pb;
|
||||
AACEncContext *s = avctx->priv_data;
|
||||
int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0));
|
||||
const int max_size = 32;
|
||||
|
||||
avctx->extradata = av_mallocz(max_size);
|
||||
@@ -352,7 +380,7 @@ static int put_audio_specific_config(AVCodecContext *avctx, int chcfg)
|
||||
init_put_bits(&pb, avctx->extradata, max_size);
|
||||
put_bits(&pb, 5, s->profile+1); //profile
|
||||
put_bits(&pb, 4, s->samplerate_index); //sample rate index
|
||||
put_bits(&pb, 4, chcfg);
|
||||
put_bits(&pb, 4, channels);
|
||||
//GASpecificConfig
|
||||
put_bits(&pb, 1, 0); //frame length - 1024 samples
|
||||
put_bits(&pb, 1, 0); //does not depend on core coder
|
||||
@@ -577,222 +605,6 @@ static void apply_intensity_stereo(ChannelElement *cpe)
|
||||
}
|
||||
}
|
||||
|
||||
/* Intensity stereo is only allowed when its irreducible image error */
|
||||
#define NMR_IS_IMG_GATE 0.5f
|
||||
|
||||
/* Frequency in Hz for the lower limit of intensity stereo */
|
||||
#define NMR_IS_LOW_LIMIT 6100
|
||||
|
||||
/* Rate ceiling (bits/sample/channel) above which intensity is skipped, ~145kbps */
|
||||
#define NMR_IS_MAXBPS 1.52f
|
||||
|
||||
/* The rate ceiling is lifted on hard-to-code frames. The signal is the bit
|
||||
* reservoir going into deficit: a negative fill means the trellis is spending
|
||||
* more than the nominal rate to hold quality (operating lambda has climbed). */
|
||||
#define NMR_IS_FILLGAIN 0.27f
|
||||
#define NMR_IS_FILLMAX 0.40f
|
||||
|
||||
/* M/S thresholds: a band is recoded as mid+side when the side is negligible */
|
||||
#define NMR_MS_EQUIV 0.01f
|
||||
#define NMR_MS_MASK 0.0f
|
||||
|
||||
/* PNS-stereo decorrelation gate: a band may be noise-substituted in a CPE only if its
|
||||
* side energy is at least this fraction of its mid energy, i.e. the image is genuinely
|
||||
* wide (channels decorrelated). PNS renders uncorrelated noise per channel, so it only
|
||||
* preserves the image on already-wide bands; a much stricter bar than I/S (which can
|
||||
* collapse correlated bands). Lower = more PNS / more imaging risk. */
|
||||
#define NMR_PNS_STEREO_DECORR 0.6f
|
||||
|
||||
/* Recode one band's window group as mid+side in place, updating the psy band
|
||||
* energies/thresholds to the M/S spectra. The threshold is halved as a coarse guard
|
||||
* against L/R unmasking of the independently-quantized M/S noise (M/S is a lossless
|
||||
* rotation but lossy coding). Used for the M/S decision and the intensity fallback. */
|
||||
static void nmr_apply_ms_band(AACEncContext *s, ChannelElement *cpe,
|
||||
int w, int g, int start, int len, int gl)
|
||||
{
|
||||
SingleChannelElement *sce0 = &cpe->ch[0];
|
||||
SingleChannelElement *sce1 = &cpe->ch[1];
|
||||
cpe->ms_mask[w*16+g] = 1;
|
||||
for (int w2 = 0; w2 < gl; w2++) {
|
||||
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
|
||||
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
|
||||
float *L = sce0->coeffs + start + (w+w2)*128;
|
||||
float *R = sce1->coeffs + start + (w+w2)*128;
|
||||
float em = 0.0f, es = 0.0f;
|
||||
for (int i = 0; i < len; i++) {
|
||||
float m = (L[i] + R[i]) * 0.5f;
|
||||
R[i] = m - R[i]; L[i] = m;
|
||||
em += L[i]*L[i]; es += R[i]*R[i];
|
||||
}
|
||||
b0->threshold = b1->threshold = FFMIN(b0->threshold, b1->threshold) * 0.5f;
|
||||
b0->energy = em; b1->energy = es;
|
||||
}
|
||||
}
|
||||
|
||||
/* Intensity-stereo perceptual test for one band's window group: collapse the pair
|
||||
* to a single carrier (L + p*R)*scale that the decoder rescales per channel, and
|
||||
* check that the irreducible image error, which no bit budget can reduce, is
|
||||
* masked in both channels. On success returns 1 and fills the carrier scale, the
|
||||
* decoder's R/carrier ratio sr_, and the phase p. The caller restricts this to HF
|
||||
* bands with energy in both channels. */
|
||||
static int nmr_is_image_masked(AACEncContext *s, ChannelElement *cpe,
|
||||
int w, int g, int start, int len, int gl,
|
||||
float ener0, float ener1, float dot,
|
||||
float minthr0, float minthr1,
|
||||
float *scale_out, float *sr_out, int *p_out)
|
||||
{
|
||||
int p = dot >= 0.0f ? 1 : -1;
|
||||
float ener01 = ener0 + ener1 + 2*p*dot; /* energy of L + p*R */
|
||||
if (ener01 <= FLT_MIN)
|
||||
return 0;
|
||||
float scale = sqrtf(ener0 / ener01); /* carrier = (L + p*R)*scale */
|
||||
float sr_ = sqrtf(ener1 / ener0); /* decoder: R = p*sr_*carrier */
|
||||
float img0 = 0.0f, img1 = 0.0f;
|
||||
for (int w2 = 0; w2 < gl; w2++) {
|
||||
const float *L = cpe->ch[0].coeffs + start + (w+w2)*128;
|
||||
const float *R = cpe->ch[1].coeffs + start + (w+w2)*128;
|
||||
for (int i = 0; i < len; i++) {
|
||||
float c = (L[i] + p*R[i]) * scale;
|
||||
float dl = L[i] - c, dr = R[i] - p*sr_*c;
|
||||
img0 += dl*dl; img1 += dr*dr;
|
||||
}
|
||||
}
|
||||
if (img0 >= NMR_IS_IMG_GATE * minthr0 * gl ||
|
||||
img1 >= NMR_IS_IMG_GATE * minthr1 * gl)
|
||||
return 0;
|
||||
*scale_out = scale; *sr_out = sr_; *p_out = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Recode one band's window group as intensity stereo in place: replace L with the
|
||||
* carrier, zero R, signal the phase via the side channel's band type, and fold the
|
||||
* pair's masking into the surviving (carrier) channel. */
|
||||
static void nmr_apply_is_band(AACEncContext *s, ChannelElement *cpe,
|
||||
int w, int g, int start, int len, int gl,
|
||||
float scale, float sr_, int p,
|
||||
float ener0, float ener1)
|
||||
{
|
||||
cpe->is_mask[w*16+g] = 1;
|
||||
cpe->ch[0].is_ener[w*16+g] = scale;
|
||||
cpe->ch[1].is_ener[w*16+g] = ener0 / ener1;
|
||||
cpe->ch[1].band_type[w*16+g] = p > 0 ? INTENSITY_BT : INTENSITY_BT2;
|
||||
for (int w2 = 0; w2 < gl; w2++) {
|
||||
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
|
||||
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
|
||||
float *L = cpe->ch[0].coeffs + start + (w+w2)*128;
|
||||
float *R = cpe->ch[1].coeffs + start + (w+w2)*128;
|
||||
float ec = 0.0f;
|
||||
for (int i = 0; i < len; i++) {
|
||||
L[i] = (L[i] + p*R[i]) * scale;
|
||||
R[i] = 0.0f;
|
||||
ec += L[i]*L[i];
|
||||
}
|
||||
b0->threshold = FFMIN(b0->threshold, b1->threshold / FFMAX(sr_*sr_, 1e-9f));
|
||||
b0->energy = ec; b1->energy = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Per-band stereo-mode decision (L/R vs M/S vs intensity) for the NMR coder,
|
||||
* made before quantization from the psychoacoustic model alone, so the
|
||||
* quantizer search allocates natively on the spectra that are actually coded.
|
||||
*/
|
||||
static void nmr_decide_stereo(AACEncContext *s, ChannelElement *cpe)
|
||||
{
|
||||
SingleChannelElement *sce0 = &cpe->ch[0];
|
||||
SingleChannelElement *sce1 = &cpe->ch[1];
|
||||
IndividualChannelStream *ics = &sce0->ics;
|
||||
const AVCodecContext *avctx = s->psy.avctx;
|
||||
const float freq_mult = avctx->sample_rate / (1024.0f / ics->num_windows) / 2.0f;
|
||||
const float bps = avctx->bit_rate > 0 ?
|
||||
(float)avctx->bit_rate / avctx->sample_rate / avctx->ch_layout.nb_channels : 0.0f;
|
||||
int is_count = 0;
|
||||
|
||||
/* Stereo decision, with no bitrate dependence. Start from full L/R and depart from
|
||||
* it only where the change is inaudible. M/S and I/S differ in what they trade:
|
||||
* M/S recodes the pair as mid+side -- an invertible rotation, but the M and S
|
||||
* are quantized independently, so it is lossy coding whose noise un-mixes
|
||||
* back to L/R. Used where it barely changes the result (the side is
|
||||
* negligible vs the mid, so it is ~equivalent to L/R at the same rate) --
|
||||
* OR where the doubled side energy is masked.
|
||||
* I/S drops the side phase and keeps its energy, where the residual image error
|
||||
* is masked. Used for the decorrelated HF that M/S cannot help.
|
||||
* Both tests are content/perceptual and frame-stable, so the image holds. */
|
||||
|
||||
/* I/S rate gate: eligible at/below ~128 kbps, with the ceiling lifted on hard
|
||||
* frames (bit reservoir in deficit) so a starved high-rate passage can still
|
||||
* call on intensity. Where an I/S candidate is found but IS is not eligible, fall
|
||||
* back to M/S: not free, but ~equivalent to L/R there and it lets the energy
|
||||
* compact into the mid. */
|
||||
const float rate_frame = avctx->bit_rate * 1024.0f / FFMAX(avctx->sample_rate, 1);
|
||||
const float deficit = (s->nmr && rate_frame > 0.0f)
|
||||
? FFMAX(0.0f, -(float)s->nmr->rc_fill / rate_frame) : 0.0f;
|
||||
const float is_bonus = FFMIN(NMR_IS_FILLMAX, NMR_IS_FILLGAIN * deficit);
|
||||
const int allow_is = s->options.intensity_stereo && bps < NMR_IS_MAXBPS + is_bonus;
|
||||
|
||||
for (int w = 0; w < ics->num_windows; w += ics->group_len[w]) {
|
||||
int start = 0;
|
||||
for (int g = 0; g < ics->num_swb; start += ics->swb_sizes[g++]) {
|
||||
int len = ics->swb_sizes[g], gl = ics->group_len[w];
|
||||
float ener0 = 0.0f, ener1 = 0.0f, dot = 0.0f, es_tot = 0.0f, em_tot = 0.0f;
|
||||
float minthr0 = FLT_MAX, minthr1 = FLT_MAX;
|
||||
|
||||
cpe->is_mask[w*16+g] = 0;
|
||||
cpe->ms_mask[w*16+g] = 0;
|
||||
|
||||
for (int w2 = 0; w2 < gl; w2++) {
|
||||
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
|
||||
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
|
||||
const float *L = sce0->coeffs + start + (w+w2)*128;
|
||||
const float *R = sce1->coeffs + start + (w+w2)*128;
|
||||
float el = 0.0f, er = 0.0f, em = 0.0f, es = 0.0f, d = 0.0f;
|
||||
for (int i = 0; i < len; i++) {
|
||||
float m = (L[i] + R[i]) * 0.5f;
|
||||
float sv = m - R[i];
|
||||
el += L[i]*L[i]; er += R[i]*R[i];
|
||||
em += m*m; es += sv*sv; d += L[i]*R[i];
|
||||
}
|
||||
ener0 += el; ener1 += er; dot += d; es_tot += es; em_tot += em;
|
||||
minthr0 = FFMIN(minthr0, b0->threshold);
|
||||
minthr1 = FFMIN(minthr1, b1->threshold);
|
||||
}
|
||||
float thr_g = FFMIN(minthr0, minthr1) * gl; /* group masking budget */
|
||||
|
||||
/* PNS-stereo reservation. Reserve a band for noise substitution only if it
|
||||
* is noise-like in both channels (intersected can_pns) and clearly
|
||||
* decorrelated (wide image). */
|
||||
if (cpe->ch[0].can_pns[w*16+g] && cpe->ch[1].can_pns[w*16+g] &&
|
||||
es_tot > NMR_PNS_STEREO_DECORR * em_tot)
|
||||
continue;
|
||||
cpe->ch[0].can_pns[w*16+g] = cpe->ch[1].can_pns[w*16+g] = 0;
|
||||
|
||||
int ms_ok = s->options.mid_side &&
|
||||
(s->options.mid_side == 1 ||
|
||||
es_tot < NMR_MS_EQUIV * em_tot ||
|
||||
es_tot < NMR_MS_MASK * thr_g);
|
||||
float scale, sr_; int p;
|
||||
int is_ok = !ms_ok &&
|
||||
start * freq_mult > NMR_IS_LOW_LIMIT &&
|
||||
ener0 > FLT_MIN && ener1 > FLT_MIN &&
|
||||
nmr_is_image_masked(s, cpe, w, g, start, len, gl,
|
||||
ener0, ener1, dot, minthr0, minthr1,
|
||||
&scale, &sr_, &p);
|
||||
|
||||
if (ms_ok) {
|
||||
nmr_apply_ms_band(s, cpe, w, g, start, len, gl);
|
||||
} else if (is_ok && allow_is) {
|
||||
nmr_apply_is_band(s, cpe, w, g, start, len, gl,
|
||||
scale, sr_, p, ener0, ener1);
|
||||
is_count++;
|
||||
} else if (is_ok && s->options.mid_side) {
|
||||
nmr_apply_ms_band(s, cpe, w, g, start, len, gl);
|
||||
}
|
||||
/* else: keep full L/R stereo */
|
||||
}
|
||||
}
|
||||
cpe->is_mode = !!is_count;
|
||||
}
|
||||
|
||||
static void apply_mid_side_stereo(ChannelElement *cpe)
|
||||
{
|
||||
int w, w2, g, i;
|
||||
@@ -1166,6 +978,12 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
|
||||
s->psy.bitres.alloc /= chans;
|
||||
}
|
||||
s->cur_type = tag;
|
||||
for (ch = 0; ch < chans; ch++) {
|
||||
s->cur_channel = start_ch + ch;
|
||||
if (s->options.pns && s->coder->mark_pns)
|
||||
s->coder->mark_pns(s, avctx, &cpe->ch[ch]);
|
||||
s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda);
|
||||
}
|
||||
if (chans > 1
|
||||
&& wi[0].window_type[0] == wi[1].window_type[0]
|
||||
&& wi[0].window_shape == wi[1].window_shape) {
|
||||
@@ -1178,75 +996,26 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int use_tns = s->options.tns && s->coder->search_for_tns &&
|
||||
s->coder->apply_tns_filt;
|
||||
|
||||
/* The NMR coder rate-controls itself and never re-quantizes, so TNS must run
|
||||
* before the quantizer */
|
||||
const int tns_first = s->options.coder == AAC_CODER_NMR;
|
||||
if (tns_first && use_tns) {
|
||||
for (ch = 0; ch < chans; ch++) {
|
||||
sce = &cpe->ch[ch];
|
||||
s->cur_channel = start_ch + ch;
|
||||
/* mono: mark_pns before TNS so the region cap sees PNS bands. Stereo
|
||||
* PNS is marked in its own block (below) after the stereo decision. */
|
||||
if (chans == 1 && s->options.pns && s->coder->mark_pns)
|
||||
s->coder->mark_pns(s, avctx, sce);
|
||||
s->coder->search_for_tns(s, sce);
|
||||
s->coder->apply_tns_filt(s, sce);
|
||||
if (sce->tns.present)
|
||||
tns_mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* NMR stereo PNS (imaging-safe). Mark each channel's noise-like bands on the
|
||||
* original L/R psy, then keep PNS only where BOTH channels are noise-like. */
|
||||
if (chans == 2 && cpe->common_window && tns_first &&
|
||||
s->options.pns && s->coder->mark_pns) {
|
||||
s->cur_channel = start_ch; s->coder->mark_pns(s, avctx, &cpe->ch[0]);
|
||||
s->cur_channel = start_ch + 1; s->coder->mark_pns(s, avctx, &cpe->ch[1]);
|
||||
for (int b = 0; b < 128; b++)
|
||||
if (!cpe->ch[0].can_pns[b] || !cpe->ch[1].can_pns[b])
|
||||
cpe->ch[0].can_pns[b] = cpe->ch[1].can_pns[b] = 0;
|
||||
}
|
||||
|
||||
/* The NMR coder decides I/S and M/S BEFORE quantization, from the psy model,
|
||||
* and the trellis then allocates natively on the coeffs actually coded. */
|
||||
if (chans == 2 && cpe->common_window && s->options.coder == AAC_CODER_NMR &&
|
||||
(s->options.mid_side || s->options.intensity_stereo)) {
|
||||
s->cur_channel = start_ch;
|
||||
nmr_decide_stereo(s, cpe);
|
||||
}
|
||||
for (ch = 0; ch < chans; ch++) {
|
||||
s->cur_channel = start_ch + ch;
|
||||
/* NMR PNS is mono-only */
|
||||
if (s->options.pns && s->coder->mark_pns && !tns_first)
|
||||
s->coder->mark_pns(s, avctx, &cpe->ch[ch]);
|
||||
s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda);
|
||||
}
|
||||
for (ch = 0; ch < chans; ch++) { /* TNS (non-NMR) and PNS */
|
||||
for (ch = 0; ch < chans; ch++) { /* TNS and PNS */
|
||||
sce = &cpe->ch[ch];
|
||||
s->cur_channel = start_ch + ch;
|
||||
if (!tns_first && use_tns) {
|
||||
if (s->options.tns && s->coder->search_for_tns)
|
||||
s->coder->search_for_tns(s, sce);
|
||||
if (s->options.tns && s->coder->apply_tns_filt)
|
||||
s->coder->apply_tns_filt(s, sce);
|
||||
if (sce->tns.present)
|
||||
tns_mode = 1;
|
||||
}
|
||||
if (sce->tns.present)
|
||||
tns_mode = 1;
|
||||
if (s->options.pns && s->coder->search_for_pns)
|
||||
s->coder->search_for_pns(s, avctx, sce);
|
||||
}
|
||||
s->cur_channel = start_ch;
|
||||
if (s->options.intensity_stereo) { /* Intensity Stereo */
|
||||
if (s->options.coder != AAC_CODER_NMR) { /* NMR: decided pre-search */
|
||||
if (s->coder->search_for_is)
|
||||
s->coder->search_for_is(s, avctx, cpe);
|
||||
apply_intensity_stereo(cpe);
|
||||
}
|
||||
if (s->coder->search_for_is)
|
||||
s->coder->search_for_is(s, avctx, cpe);
|
||||
if (cpe->is_mode) is_mode = 1;
|
||||
apply_intensity_stereo(cpe);
|
||||
}
|
||||
if (s->options.mid_side && s->options.coder != AAC_CODER_NMR) { /* Mid/Side stereo */
|
||||
if (s->options.mid_side) { /* Mid/Side stereo */
|
||||
if (s->options.mid_side == -1 && s->coder->search_for_ms)
|
||||
s->coder->search_for_ms(s, cpe);
|
||||
else if (cpe->common_window)
|
||||
@@ -1274,19 +1043,11 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
|
||||
break;
|
||||
}
|
||||
|
||||
frame_bits = put_bits_count(&s->pb);
|
||||
|
||||
/* The NMR coder rate-controls itself (global-lambda reservoir servo):
|
||||
* per-frame bits intentionally float around the nominal rate, so skip
|
||||
* the lambda rate loop and only intervene on a hard overflow. */
|
||||
if (s->options.coder == AAC_CODER_NMR && avctx->bit_rate_tolerance != 0 &&
|
||||
frame_bits < 6144 * s->channels - 3)
|
||||
break;
|
||||
|
||||
/* rate control stuff
|
||||
* allow between the nominal bitrate, and what psy's bit reservoir says to target
|
||||
* but drift towards the nominal bitrate always
|
||||
*/
|
||||
frame_bits = put_bits_count(&s->pb);
|
||||
rate_bits = avctx->bit_rate * 1024 / avctx->sample_rate;
|
||||
rate_bits = FFMIN(rate_bits, 6144 * s->channels - 3);
|
||||
too_many_bits = FFMAX(target_bits, rate_bits);
|
||||
@@ -1350,80 +1111,18 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
|
||||
}
|
||||
} while (1);
|
||||
|
||||
/* tool-usage stats over the final per-band decisions of this frame */
|
||||
for (i = 0; i < s->chan_map[0]; i++) {
|
||||
int etag = s->chan_map[i + 1], echans = etag == TYPE_CPE ? 2 : 1;
|
||||
ChannelElement *ce = &s->cpe[i];
|
||||
IndividualChannelStream *ics = &ce->ch[0].ics;
|
||||
for (ch = 0; ch < echans; ch++) { /* per-channel frame stats */
|
||||
int is_short = ce->ch[ch].ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
|
||||
s->stat_chans++;
|
||||
if (is_short)
|
||||
s->stat_short++;
|
||||
if (ce->ch[ch].tns.present) {
|
||||
if (is_short) s->stat_tns_short++;
|
||||
else s->stat_tns_long++;
|
||||
}
|
||||
}
|
||||
for (w = 0; w < ics->num_windows; w += ics->group_len[w]) {
|
||||
for (int g = 0; g < ics->num_swb; g++) {
|
||||
int idx = w*16 + g, coded = 0;
|
||||
for (ch = 0; ch < echans; ch++) {
|
||||
SingleChannelElement *sce = &ce->ch[ch];
|
||||
if (sce->zeroes[idx] && sce->band_type[idx] == 0)
|
||||
continue;
|
||||
s->stat_ch_bands++;
|
||||
if (sce->band_type[idx] == NOISE_BT)
|
||||
s->stat_pns++;
|
||||
coded = 1;
|
||||
}
|
||||
if (etag == TYPE_CPE && coded) {
|
||||
s->stat_cpe_bands++;
|
||||
if (ce->ms_mask[idx]) s->stat_ms++;
|
||||
if (ce->is_mask[idx]) s->stat_is++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put_bits(&s->pb, 3, TYPE_END);
|
||||
flush_put_bits(&s->pb);
|
||||
|
||||
s->last_frame_pb_count = put_bits_count(&s->pb);
|
||||
|
||||
/* NMR rate accounting: how many bits the frame really took beyond what the
|
||||
* trellis counted; feeds the next frame's budget correction */
|
||||
if (s->nmr) {
|
||||
int counted = 0;
|
||||
for (i = 0; i < s->channels; i++)
|
||||
counted += s->nmr->counted[i];
|
||||
if (counted > 0) {
|
||||
float side = (float)s->last_frame_pb_count - counted;
|
||||
if (s->nmr->side_inited) {
|
||||
s->nmr->side_ema += 0.125f * (side - s->nmr->side_ema);
|
||||
} else {
|
||||
s->nmr->side_ema = side;
|
||||
s->nmr->side_inited = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
avpkt->size = put_bytes_output(&s->pb);
|
||||
|
||||
s->lambda_sum += (s->nmr && s->nmr->lam_rc > 0.0f) ? s->nmr->lam_rc : s->lambda;
|
||||
s->lambda_sum += s->lambda;
|
||||
s->lambda_count++;
|
||||
|
||||
ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
|
||||
&avpkt->duration);
|
||||
|
||||
int discard_padding = avctx->frame_size - ff_samples_from_time_base(avctx, avpkt->duration);
|
||||
if (discard_padding > 0) {
|
||||
uint8_t *side_data =
|
||||
av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
|
||||
if (!side_data)
|
||||
return AVERROR(ENOMEM);
|
||||
AV_WL32(side_data + 4, discard_padding);
|
||||
}
|
||||
|
||||
avpkt->flags |= AV_PKT_FLAG_KEY;
|
||||
|
||||
*got_packet_ptr = 1;
|
||||
@@ -1434,15 +1133,7 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
|
||||
{
|
||||
AACEncContext *s = avctx->priv_data;
|
||||
|
||||
av_log(avctx, AV_LOG_INFO,
|
||||
"Qavg: %.3f Tr: %.1f%% TNS(L): %.1f%% TNS(S): %.1f%% M/S: %.1f%% I/S: %.1f%% PNS: %.1f%%\n",
|
||||
s->lambda_count ? s->lambda_sum / s->lambda_count : NAN,
|
||||
s->stat_chans ? 100.0 * s->stat_short / s->stat_chans : 0.0,
|
||||
s->stat_chans - s->stat_short ? 100.0 * s->stat_tns_long / (s->stat_chans - s->stat_short) : 0.0,
|
||||
s->stat_short ? 100.0 * s->stat_tns_short / s->stat_short : 0.0,
|
||||
s->stat_cpe_bands ? 100.0 * s->stat_ms / s->stat_cpe_bands : 0.0,
|
||||
s->stat_cpe_bands ? 100.0 * s->stat_is / s->stat_cpe_bands : 0.0,
|
||||
s->stat_ch_bands ? 100.0 * s->stat_pns / s->stat_ch_bands : 0.0);
|
||||
av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_count ? s->lambda_sum / s->lambda_count : NAN);
|
||||
|
||||
av_tx_uninit(&s->mdct1024);
|
||||
av_tx_uninit(&s->mdct128);
|
||||
@@ -1451,7 +1142,6 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
|
||||
av_freep(&s->buffer.samples);
|
||||
av_freep(&s->cpe);
|
||||
av_freep(&s->fdsp);
|
||||
av_freep(&s->nmr);
|
||||
ff_af_queue_close(&s->afq);
|
||||
return 0;
|
||||
}
|
||||
@@ -1485,12 +1175,6 @@ static av_cold int alloc_buffers(AVCodecContext *avctx, AACEncContext *s)
|
||||
for(ch = 0; ch < s->channels; ch++)
|
||||
s->planar_samples[ch] = s->buffer.samples + 3 * 1024 * ch;
|
||||
|
||||
if (s->options.coder == AAC_CODER_NMR) {
|
||||
s->nmr = av_mallocz(sizeof(*s->nmr));
|
||||
if (!s->nmr)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1498,7 +1182,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
{
|
||||
AACEncContext *s = avctx->priv_data;
|
||||
int i, ret = 0;
|
||||
int chcfg;
|
||||
const uint8_t *sizes[2];
|
||||
uint8_t grouping[AAC_MAX_CHANNELS];
|
||||
int lengths[2];
|
||||
@@ -1513,8 +1196,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
s->channels = avctx->ch_layout.nb_channels;
|
||||
|
||||
s->needs_pce = 1;
|
||||
for (chcfg = 1; chcfg < FF_ARRAY_ELEMS(aac_normal_chan_layouts); chcfg++) {
|
||||
if (!av_channel_layout_compare(&avctx->ch_layout, &aac_normal_chan_layouts[chcfg])) {
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(aac_normal_chan_layouts); i++) {
|
||||
if (!av_channel_layout_compare(&avctx->ch_layout, &aac_normal_chan_layouts[i])) {
|
||||
s->needs_pce = s->options.pce;
|
||||
break;
|
||||
}
|
||||
@@ -1534,10 +1217,9 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
s->pce = aac_pce_configs[i];
|
||||
s->reorder_map = s->pce.reorder_map;
|
||||
s->chan_map = s->pce.config_map;
|
||||
chcfg = 0;
|
||||
} else {
|
||||
s->reorder_map = aac_chan_maps[chcfg - 1];
|
||||
s->chan_map = aac_chan_configs[chcfg - 1];
|
||||
s->reorder_map = aac_chan_maps[s->channels - 1];
|
||||
s->chan_map = aac_chan_configs[s->channels - 1];
|
||||
}
|
||||
|
||||
if (!avctx->bit_rate) {
|
||||
@@ -1587,34 +1269,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
if (s->channels > 3)
|
||||
s->options.mid_side = 0;
|
||||
|
||||
/* Coding bandwidth, fixed at init time */
|
||||
if (avctx->cutoff > 0) {
|
||||
s->bandwidth = avctx->cutoff;
|
||||
} else {
|
||||
int frame_br = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
|
||||
(avctx->bit_rate / 2.0f * (s->lambda / 120.f) * 1.5f) :
|
||||
(avctx->bit_rate / avctx->ch_layout.nb_channels);
|
||||
|
||||
/* For NMR, the rate to bandwidth conversion was tuned to maximize metrics
|
||||
* over a variable cutoff x bitrate combo */
|
||||
if (s->options.coder == AAC_CODER_NMR && frame_br >= 32000) {
|
||||
static const int rates[] = { 32000, 48000, 64000, 96000, 192000 };
|
||||
static const int bws[] = { 14000, 15000, 16000, 18000, 20000 };
|
||||
int bw_i = 0;
|
||||
for (; bw_i < FF_ARRAY_ELEMS(rates) - 2 && frame_br > rates[bw_i + 1]; bw_i++);
|
||||
s->bandwidth = bws[bw_i] + (int)((int64_t)(bws[bw_i + 1] - bws[bw_i]) *
|
||||
(frame_br - rates[bw_i]) / (rates[bw_i + 1] - rates[bw_i]));
|
||||
s->bandwidth = FFMIN3(s->bandwidth, 22000, avctx->sample_rate / 2);
|
||||
} else {
|
||||
if (s->options.pns || s->options.intensity_stereo)
|
||||
frame_br *= 1.15f;
|
||||
s->bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_br, 1,
|
||||
avctx->sample_rate));
|
||||
}
|
||||
|
||||
s->bandwidth = FFMIN(FFMAX(s->bandwidth, 8000), avctx->sample_rate / 2);
|
||||
}
|
||||
|
||||
// Initialize static tables
|
||||
ff_aac_float_common_init();
|
||||
|
||||
@@ -1624,7 +1278,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
if ((ret = alloc_buffers(avctx, s)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = put_audio_specific_config(avctx, chcfg)))
|
||||
if ((ret = put_audio_specific_config(avctx)))
|
||||
return ret;
|
||||
|
||||
sizes[0] = ff_aac_swb_size_1024[s->samplerate_index];
|
||||
@@ -1634,7 +1288,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
for (i = 0; i < s->chan_map[0]; i++)
|
||||
grouping[i] = s->chan_map[i + 1] == TYPE_CPE;
|
||||
if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths,
|
||||
s->chan_map[0], grouping, s->bandwidth)) < 0)
|
||||
s->chan_map[0], grouping)) < 0)
|
||||
return ret;
|
||||
ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON);
|
||||
s->random_state = 0x1f2e3d4c;
|
||||
@@ -1648,16 +1302,14 @@ 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_NMR}, 0, AAC_CODER_NB-1, AACENC_FLAGS, .unit = "coder"},
|
||||
{"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"},
|
||||
{"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"},
|
||||
{"nmr", "Noise-to-mask ratio scalefactor trellis", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_NMR}, 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_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
|
||||
{"aac_nmr_speed", "NMR coder speed level: 0 = slowest/best, higher trades quality for speed", offsetof(AACEncContext, options.nmr_speed), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, AACENC_FLAGS},
|
||||
FF_AAC_PROFILE_OPTS
|
||||
{NULL}
|
||||
};
|
||||
|
||||
+3
-35
@@ -44,7 +44,6 @@
|
||||
typedef enum AACCoder {
|
||||
AAC_CODER_TWOLOOP,
|
||||
AAC_CODER_FAST,
|
||||
AAC_CODER_NMR,
|
||||
|
||||
AAC_CODER_NB,
|
||||
}AACCoder;
|
||||
@@ -70,7 +69,6 @@ typedef struct AACEncOptions {
|
||||
int pce;
|
||||
int mid_side;
|
||||
int intensity_stereo;
|
||||
int nmr_speed; ///< NMR coder speed level: 0 = slowest/best, higher is faster
|
||||
} AACEncOptions;
|
||||
|
||||
/**
|
||||
@@ -167,33 +165,11 @@ typedef struct AACQuantizeBandCostCacheEntry {
|
||||
uint16_t generation;
|
||||
} AACQuantizeBandCostCacheEntry;
|
||||
|
||||
/** per-band scalefactor candidates above the finest codeable sf (NMR coder) */
|
||||
#define NMR_NCAND 96
|
||||
|
||||
/**
|
||||
* NMR coder per-band candidate cost curves (~96 KiB) and rate-control carry-over
|
||||
*/
|
||||
typedef struct AACNMRCurves {
|
||||
float nd[128][NMR_NCAND]; ///< dist / threshold per candidate
|
||||
int nb[128][NMR_NCAND]; ///< spectral bits per candidate
|
||||
float lam[16]; ///< per-channel operating lambda of the previous frame, 0 = none yet
|
||||
int counted[16]; ///< per-channel bits the trellis accounted for in the last solve
|
||||
float side_ema; ///< running estimate of real-minus-counted bits per frame
|
||||
int side_inited; ///< side_ema holds a measurement
|
||||
|
||||
int64_t rc_frame_num; ///< frame the reservoir was last advanced for
|
||||
float lam_rc; ///< global-lambda rate control: operating lambda, 0 until bootstrapped
|
||||
int rc_fill; ///< virtual bit reservoir fill, + = bits saved vs nominal
|
||||
int frames_since_short; ///< long-block frames since the last short run (the "gap"): large = isolated transient
|
||||
int prev_was_short; ///< previous frame was a short block (for run-start detection)
|
||||
float run_burst; ///< transient bit-burst factor, set at run start and held across the short run
|
||||
} AACNMRCurves;
|
||||
|
||||
typedef struct AACPCEInfo {
|
||||
AVChannelLayout layout;
|
||||
uint8_t num_ele[4]; ///< front, side, back, lfe
|
||||
uint8_t pairing[3][8]; ///< front, side, back
|
||||
uint8_t index[4][8]; ///< front, side, back, lfe
|
||||
int num_ele[4]; ///< front, side, back, lfe
|
||||
int pairing[3][8]; ///< front, side, back
|
||||
int index[4][8]; ///< front, side, back, lfe
|
||||
uint8_t config_map[16]; ///< configs the encoder's channel specific settings
|
||||
uint8_t reorder_map[16]; ///< maps channels from lavc to aac order
|
||||
} AACPCEInfo;
|
||||
@@ -218,7 +194,6 @@ typedef struct AACEncContext {
|
||||
LPCContext lpc; ///< used by TNS
|
||||
int samplerate_index; ///< MPEG-4 samplerate index
|
||||
int channels; ///< channel count
|
||||
int bandwidth; ///< coding bandwidth in Hz, fixed at init; the psy model and the coders' band cutoff agree on it
|
||||
const uint8_t *reorder_map; ///< lavc to aac reorder map
|
||||
const uint8_t *chan_map; ///< channel configuration map
|
||||
|
||||
@@ -231,12 +206,6 @@ typedef struct AACEncContext {
|
||||
int last_frame_pb_count; ///< number of bits for the previous frame
|
||||
float lambda_sum; ///< sum(lambda), for Qvg reporting
|
||||
int lambda_count; ///< count(lambda), for Qvg reporting
|
||||
/* tool-usage stats, reported at close: per-coded-band for PNS (channel bands),
|
||||
* per-coded-pair-band for M/S and I/S (CPE bands) */
|
||||
uint64_t stat_ch_bands, stat_pns; ///< coded channel-bands, of which PNS
|
||||
uint64_t stat_cpe_bands, stat_ms, stat_is; ///< coded CPE pair-bands, of which M/S, I/S
|
||||
uint64_t stat_chans, stat_short; ///< coded channels, of which short-block (transient)
|
||||
uint64_t stat_tns_long, stat_tns_short; ///< TNS-active channels among long / short blocks
|
||||
enum RawDataBlockType cur_type; ///< channel group type cur_channel belongs to
|
||||
|
||||
AudioFrameQueue afq;
|
||||
@@ -247,7 +216,6 @@ typedef struct AACEncContext {
|
||||
AACQuantizeBandCostCacheEntry quantize_band_cost_cache[256][128]; ///< memoization area for quantize_band_cost
|
||||
|
||||
AACEncDSPContext aacdsp;
|
||||
AACNMRCurves *nmr; ///< NMR coder scratch (NULL unless coder == nmr)
|
||||
|
||||
struct {
|
||||
float *samples;
|
||||
|
||||
+52
-135
@@ -41,13 +41,9 @@
|
||||
/* We really need the bits we save here elsewhere */
|
||||
#define TNS_ENABLE_COEF_COMPRESSION
|
||||
|
||||
/* Apple-derived TNS: weighted-spectrum predictor, accepted only if the measured
|
||||
* post-quantization prediction gain clears a block-type-dependent bar (Apple RE). */
|
||||
#define TNS_PREDGAIN_GATE 1.4f /* first gate: predicted LPC gain */
|
||||
#define TNS_PG_C1_LONG 1.4f /* min measured gain, long blocks */
|
||||
#define TNS_PG_C1_SHORT 3.2f /* min measured gain, short blocks */
|
||||
#define TNS_PG_CLAMP 6.0f /* upper bound: poles near unit circle → noise blowup */
|
||||
#define TNS_WEIGHT_FLOOR 0.01f /* per-bin masking floor for the weighted spectrum */
|
||||
/* TNS will only be used if the LPC gain is within these margins */
|
||||
#define TNS_GAIN_THRESHOLD_LOW 1.4f
|
||||
#define TNS_GAIN_THRESHOLD_HIGH 1.16f*TNS_GAIN_THRESHOLD_LOW
|
||||
|
||||
static inline int compress_coeffs(int *coef, int order, int c_bits)
|
||||
{
|
||||
@@ -66,7 +62,11 @@ static inline int compress_coeffs(int *coef, int order, int c_bits)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Encode TNS data. */
|
||||
/**
|
||||
* Encode TNS data.
|
||||
* Coefficient compression is simply not lossless as it should be
|
||||
* on any decoder tested and as such is not active.
|
||||
*/
|
||||
void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
|
||||
{
|
||||
TemporalNoiseShaping *tns = &sce->tns;
|
||||
@@ -98,28 +98,15 @@ void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
|
||||
}
|
||||
}
|
||||
|
||||
/* Cap the TNS band range at the first PNS band to avoid TNS+PNS conflicts. */
|
||||
static int tns_max_nonpns(const SingleChannelElement *sce, int mmm)
|
||||
{
|
||||
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w])
|
||||
for (int g = 0; g < mmm; g++)
|
||||
if (sce->band_type[w*16+g] == NOISE_BT) { mmm = g; break; }
|
||||
return mmm;
|
||||
}
|
||||
|
||||
/* Apply TNS filter */
|
||||
void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
|
||||
{
|
||||
TemporalNoiseShaping *tns = &sce->tns;
|
||||
IndividualChannelStream *ics = &sce->ics;
|
||||
int w, filt, m, i, top, order, bottom, start, end, size, inc;
|
||||
const int mmm = tns_max_nonpns(sce, FFMIN(ics->tns_max_bands, ics->max_sfb));
|
||||
const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb);
|
||||
float lpc[TNS_MAX_ORDER];
|
||||
|
||||
/* TNS predicts from the post-M/S and post-I/S coefficients. */
|
||||
float hist[1024];
|
||||
memcpy(hist, sce->coeffs, sizeof(hist));
|
||||
|
||||
for (w = 0; w < ics->num_windows; w++) {
|
||||
bottom = ics->num_swb;
|
||||
for (filt = 0; filt < tns->n_filt[w]; filt++) {
|
||||
@@ -147,7 +134,7 @@ void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
|
||||
/* AR filter */
|
||||
for (m = 0; m < size; m++, start += inc) {
|
||||
for (i = 1; i <= FFMIN(m, order); i++) {
|
||||
sce->coeffs[start] += lpc[i-1]*hist[start - i*inc];
|
||||
sce->coeffs[start] += lpc[i-1]*sce->pcoeffs[start - i*inc];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,8 +161,9 @@ static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order,
|
||||
void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
|
||||
{
|
||||
TemporalNoiseShaping *tns = &sce->tns;
|
||||
int w, count = 0;
|
||||
const int mmm = tns_max_nonpns(sce, FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb));
|
||||
int w, g, count = 0;
|
||||
double gain, coefs[MAX_LPC_ORDER];
|
||||
const int mmm = FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb);
|
||||
const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
|
||||
const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
|
||||
const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm);
|
||||
@@ -186,127 +174,56 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
|
||||
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;
|
||||
const int ord_g = order / n_filt;
|
||||
|
||||
/* Apple's accept bar (minimum measured prediction gain): higher on short blocks,
|
||||
* where a weak filter's shaped-noise tail spreads across the 50% overlap. */
|
||||
const float c1 = is8 ? TNS_PG_C1_SHORT : TNS_PG_C1_LONG;
|
||||
FFPsyBand *const psy_bands = &s->psy.ch[s->cur_channel].psy_bands[0];
|
||||
|
||||
if (coef_len <= 0 || sfb_len <= 0) {
|
||||
sce->tns.present = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* time-domain window length backing one coding window: a long MDCT block is
|
||||
* fed 2048 windowed samples (current 1024 + overlap), each short block 256. */
|
||||
const int tlen = is8 ? 256 : 2048;
|
||||
|
||||
for (w = 0; w < sce->ics.num_windows; w++) {
|
||||
int filt, any = 0;
|
||||
float en[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int oc_start = 0;
|
||||
int coef_start = sce->ics.swb_offset[sfb_start];
|
||||
|
||||
/* The filter gets ran in the direction of the signal's *temporal* energy,
|
||||
* so the quantization noise stays in the loud masked part rather than spilling
|
||||
* into the quiet part. */
|
||||
const float *tw = sce->ret_buf + w*tlen;
|
||||
float e_early = 0.0f, e_late = 0.0f;
|
||||
int ti;
|
||||
for (ti = 0; ti < tlen/2; ti++)
|
||||
e_early += tw[ti]*tw[ti];
|
||||
for (; ti < tlen; ti++)
|
||||
e_late += tw[ti]*tw[ti];
|
||||
const int tdir = e_early > e_late;
|
||||
|
||||
/* Walk the frequency regions exactly as the decoder does: filter 0 is the
|
||||
* topmost band region, each subsequent filter covers the next region down,
|
||||
* clamped to mmm. Each filter gets its own LPC over its own region. */
|
||||
int top_sfb = sce->ics.num_swb;
|
||||
for (filt = 0; filt < n_filt; filt++) {
|
||||
double coefs[MAX_LPC_ORDER];
|
||||
float wspec[1024], tmp[1024], lpc_q[TNS_MAX_ORDER];
|
||||
int len_sfb = (filt == n_filt - 1) ? sfb_len - filt*(sfb_len/n_filt)
|
||||
: sfb_len/n_filt;
|
||||
int bot_sfb = FFMAX(0, top_sfb - len_sfb);
|
||||
int g_lo = FFMIN(bot_sfb, mmm), g_hi = FFMIN(top_sfb, mmm);
|
||||
int c_lo = sce->ics.swb_offset[g_lo];
|
||||
int c_hi = sce->ics.swb_offset[g_hi];
|
||||
int clen = c_hi - c_lo;
|
||||
const int dir = slant != 2 ? slant : tdir;
|
||||
float gain, orig_e = 0.0f, filt_e = 0.0f;
|
||||
int m, i, g, inc, st;
|
||||
|
||||
tns->length[w][filt] = len_sfb;
|
||||
tns->order[w][filt] = 0; /* default: region carries no filter */
|
||||
top_sfb = bot_sfb;
|
||||
|
||||
if (clen <= 2*ord_g) /* too short for a stable order-ord_g LPC */
|
||||
continue;
|
||||
|
||||
/* Fit LPC on the perceptually-weighted spectrum X/sqrt(thr), floored
|
||||
* to avoid a near-zero threshold blowing up a single bin (Apple). */
|
||||
{
|
||||
float maxrms = 0.0f, floorrms;
|
||||
int k;
|
||||
for (g = g_lo; g < g_hi; g++) {
|
||||
int s0 = sce->ics.swb_offset[g], s1 = sce->ics.swb_offset[g+1];
|
||||
float rms = sqrtf(FFMAX(psy_bands[w*16 + g].threshold, 0.0f) /
|
||||
FFMAX(s1 - s0, 1));
|
||||
maxrms = FFMAX(maxrms, rms);
|
||||
}
|
||||
floorrms = FFMAX(maxrms * TNS_WEIGHT_FLOOR, 1e-9f);
|
||||
for (g = g_lo; g < g_hi; g++) {
|
||||
int s0 = sce->ics.swb_offset[g], s1 = sce->ics.swb_offset[g+1];
|
||||
float rms = sqrtf(FFMAX(psy_bands[w*16 + g].threshold, 0.0f) /
|
||||
FFMAX(s1 - s0, 1));
|
||||
float wgt = 1.0f / FFMAX(rms, floorrms);
|
||||
for (k = s0; k < s1; k++)
|
||||
wspec[k - c_lo] = sce->coeffs[w*128 + k] * wgt;
|
||||
}
|
||||
/* Short blocks: unwindowed fit; Hann window zeros the edges of the
|
||||
* tiny region, wrecking the LPC. Long blocks keep the window. */
|
||||
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, wspec, clen, ord_g, coefs, !is8);
|
||||
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 */
|
||||
}
|
||||
/* Reject below the first gate and above the clamp (poles near unit circle). */
|
||||
if (!isfinite(gain) || gain < TNS_PREDGAIN_GATE || gain > TNS_PG_CLAMP)
|
||||
continue;
|
||||
/* Negate: ff_lpc_calc_ref_coefs_f sign convention is opposite to what
|
||||
* ff_aac_apply_tns's MA filter needs; fed unnegated, it anti-whitens. */
|
||||
for (i = 0; i < ord_g; i++)
|
||||
coefs[i] = -coefs[i];
|
||||
|
||||
/* Quantize, then build the decoder's direct-form LPC. */
|
||||
quantize_coefs(coefs, tns->coef_idx[w][filt], tns->coef[w][filt],
|
||||
ord_g, c_bits);
|
||||
compute_lpc_coefs(tns->coef[w][filt], 0, ord_g, lpc_q, 0, 0, 0, NULL);
|
||||
|
||||
/* Apply the quantized filter to the weighted spectrum and measure gain. */
|
||||
const float *msrc = wspec;
|
||||
inc = dir ? -1 : 1;
|
||||
st = dir ? clen - 1 : 0;
|
||||
for (m = 0; m < clen; m++) {
|
||||
int idx = st + m*inc;
|
||||
float acc = msrc[idx];
|
||||
for (i = 1; i <= FFMIN(m, ord_g); i++)
|
||||
acc += lpc_q[i-1] * msrc[idx - i*inc];
|
||||
tmp[idx] = acc;
|
||||
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 */
|
||||
}
|
||||
for (m = 0; m < clen; m++) {
|
||||
orig_e += msrc[m]*msrc[m];
|
||||
filt_e += tmp[m]*tmp[m];
|
||||
}
|
||||
filt_e = FFMAX(filt_e, 1e-9f);
|
||||
|
||||
/* Keep only if measured post-quantization gain clears C1 (Apple's outcome gate). */
|
||||
if (orig_e < c1*filt_e)
|
||||
continue;
|
||||
|
||||
tns->order[w][filt] = ord_g;
|
||||
tns->direction[w][filt] = dir;
|
||||
any = 1;
|
||||
en[3] = en[0];
|
||||
}
|
||||
tns->n_filt[w] = any ? n_filt : 0;
|
||||
if (any)
|
||||
count++;
|
||||
|
||||
/* LPC */
|
||||
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[w*128 + coef_start],
|
||||
coef_len, order, coefs);
|
||||
|
||||
if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH)
|
||||
continue;
|
||||
|
||||
tns->n_filt[w] = n_filt;
|
||||
for (g = 0; g < tns->n_filt[w]; 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],
|
||||
tns->order[w][g], c_bits);
|
||||
oc_start += tns->order[w][g];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
sce->tns.present = !!count;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user