Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 894da5ca7d | |||
| 4c788cb200 | |||
| 9c4d3a7add | |||
| b5fb8749b9 | |||
| 946407193a | |||
| 27def36203 | |||
| 6777ab8e88 | |||
| 0831f98933 | |||
| 719171a375 | |||
| 6157fafd8a | |||
| 6a1bb9c09f | |||
| 58efabb076 | |||
| b833558b76 | |||
| c1b57e2102 | |||
| cfc6fe6400 | |||
| 915272f5c7 | |||
| 5a6e2b0ab1 | |||
| a048a80554 | |||
| 68e61becf9 | |||
| bc680e230c | |||
| 89c5d8bdab | |||
| bb680a9d53 | |||
| dd062bfaf3 | |||
| a130ed479b | |||
| 8b42ed314a | |||
| 67ed7fddac | |||
| 71ecb3d626 | |||
| dcf7f9b70c | |||
| 716cf25eb8 | |||
| aad0a7d8f6 | |||
| 1cac745f2d | |||
| ac0a59de51 | |||
| 9f6c98a32e | |||
| a7f9caa662 | |||
| 8674f8c3cd | |||
| bb0e3e7a7c | |||
| 277384f039 | |||
| 4a73c79ad5 | |||
| 7d741cc3b4 | |||
| 520570dbeb | |||
| 8e8c1f498d | |||
| 5630394ebf | |||
| cb570f824d | |||
| 2790dd608c | |||
| 22d0f10943 | |||
| 44bfe0da61 | |||
| b660192fb8 | |||
| 71007e6c12 | |||
| 24205bc657 | |||
| 7cbc26267b | |||
| d8049e01d7 | |||
| adc819773b | |||
| b784c3eb6d | |||
| bb65f51fce | |||
| d1f31a829d | |||
| 1e56c51d3b | |||
| 45fcd5567a | |||
| 558994b051 | |||
| dd00a614e1 | |||
| 046a8293e1 | |||
| d961a634fb | |||
| d8605a6b55 | |||
| c9b8e5999b | |||
| b9adbf0fcc | |||
| e322e2e5d9 | |||
| 61c50407fd | |||
| b9dd25b80a | |||
| 0ca188e0d6 | |||
| d3265e15ee | |||
| a2179be5e9 | |||
| 4f8b3891ee | |||
| e0a971a8fa | |||
| 7cc24cee16 | |||
| e4e57bef31 | |||
| 08a81b090b | |||
| 1c9d70c4af | |||
| e219c8f77b | |||
| 140fd653ae | |||
| 09f15530e5 | |||
| af310e68db | |||
| c3747e011e | |||
| f258c9a8e5 | |||
| a6c578ef65 | |||
| efa64c2acc | |||
| 9c5f654e44 | |||
| 5494973d28 | |||
| 15cb74fc68 | |||
| 9ddd245b09 | |||
| c1a7f4040a | |||
| 17f4cc0992 | |||
| eeff85f15d | |||
| bc88c1d62e | |||
| 3b8fe34a30 | |||
| ac8cbf2ad7 | |||
| 30b308f7a8 | |||
| afc8c20946 | |||
| debbeb006b | |||
| 8c117d7fec | |||
| 5f8cb575e8 | |||
| abf123b744 | |||
| e97babf6bc | |||
| 9bc89a2605 | |||
| ac5ff0ae89 | |||
| a2e445918e | |||
| 34c39367aa | |||
| 3cab009519 | |||
| 3e05b89590 | |||
| 4a3e5ea8d2 | |||
| 263e819aa4 | |||
| 23655160ea | |||
| f2507dba3b | |||
| da3f5273fc | |||
| 6049800a10 | |||
| e726f7af17 | |||
| de76fb27a6 | |||
| 995d329cf9 | |||
| 81dcb67813 | |||
| bde02336a4 | |||
| 6b1f994e43 | |||
| 5051753833 | |||
| a676267a2c | |||
| bd55bf8300 | |||
| 64c71cbe4e | |||
| 2feaad5cb9 | |||
| 048f6f4bd5 | |||
| 4558ad6a77 | |||
| 937d9ed849 | |||
| 13b161cd24 | |||
| 7c92f740ee | |||
| 057b94649f | |||
| 26da3d0069 | |||
| a8fdfddedb | |||
| 89849ca92a | |||
| 370cff8b33 | |||
| 9fd3869212 | |||
| 0a167141d0 |
+7
-176
@@ -12,173 +12,45 @@
|
||||
# =======
|
||||
libavcodec/.*aac.* @lynne
|
||||
libavcodec/.*ac3.* @lynne
|
||||
libavcodec/.*adpcm.* @zane @pross
|
||||
libavcodec/anm.* @pross
|
||||
libavcodec/amf.* @OvchinnikovDmitrii @ArazIusubov
|
||||
libavcodec/ansi.* @pross
|
||||
libavcodec/aom_film_grain.* @haasn
|
||||
libavcodec/.*atrac9.* @lynne
|
||||
libavcodec/bink.* @pross
|
||||
libavcodec/bintext.* @pross
|
||||
libavcodec/.*bitpacked.* @lynne
|
||||
libavcodec/.*d3d12va.* @jianhuaw @tong1wu @younengxiao
|
||||
libavcodec/.*d3d12va.* @jianhuaw
|
||||
libavcodec/.*dirac.* @lynne
|
||||
libavcodec/.*dovi_rpu.* @haasn
|
||||
libavcodec/dpx.* @pross
|
||||
libavcodec/dsd.* @pross
|
||||
libavcodec/eacmv.* @pross
|
||||
libavcodec/eaidct.* @pross
|
||||
libavcodec/eamad.* @pross
|
||||
libavcodec/eat.* @pross
|
||||
libavcodec/.*exif.* @Traneptora
|
||||
libavcodec/.*ffv1.* @lynne @michaelni
|
||||
libavcodec/g728.* @pross
|
||||
libavcodec/gem.* @pross
|
||||
libavcodec/golomb.* @michaelni
|
||||
libavcodec/.*h266.* @frankplow @NuoMi @jianhuaw
|
||||
libavcodec/h26x/.* @frankplow @NuoMi @jianhuaw
|
||||
libavcodec/.*h274.* @haasn
|
||||
libavcodec/iff.* @pross
|
||||
libavcodec/.*jpegxl.* @lynne @Traneptora
|
||||
libavcodec/jpeg2000htdec.* @cae
|
||||
libavcodec/jv.* @pross
|
||||
libavcodec/.*jxl.* @lynne @Traneptora
|
||||
libavcodec/.*lcms2.* @haasn
|
||||
libavcodec/lead.* @pross
|
||||
libavcodec/mediacodec* @quink
|
||||
libavcodec/mjpeg* @michaelni
|
||||
libavcodec/mmvideo.* @pross
|
||||
libavcodec/msp2.* @pross
|
||||
libavcodec/mvc.* @pross
|
||||
libavcodec/oh* @quink
|
||||
libavcodec/.*jpegxl.* @lynne
|
||||
libavcodec/.*jxl.* @lynne
|
||||
libavcodec/.*opus.* @lynne
|
||||
libavcodec/pictor.* @pross
|
||||
libavcodec/.*png.* @Traneptora
|
||||
libavcodec/.*prores.* @lynne
|
||||
libavcodec/rangecoder.* @michaelni
|
||||
libavcodec/ratecontrol.* @michaelni
|
||||
libavcodec/rkmpp* @quink
|
||||
libavcodec/rv60.* @pross
|
||||
libavcodec/sgirle.* @pross
|
||||
libavcodec/.*siren.* @lynne
|
||||
libavcodec/smpte_436m.* @programmerjake
|
||||
libavcodec/svq1.* @pross
|
||||
libavcodec/svq3.* @pross
|
||||
libavcodec/.*vc2.* @lynne
|
||||
libavcodec/videotoolbox.* @ePirat
|
||||
libavcodec/vp3.* @pross
|
||||
libavcodec/vp4.* @pross
|
||||
libavcodec/vp5.* @pross
|
||||
libavcodec/vp6.* @pross
|
||||
libavcodec/vp8.* @rbultje @pross
|
||||
libavcodec/vp9.* @rbultje
|
||||
libavcodec/vpx.* @rbultje @pross
|
||||
libavcodec/vqc.* @pross
|
||||
libavcodec/.*vvc.* @frankplow @NuoMi @jianhuaw
|
||||
libavcodec/wmavoice.* @rbultje
|
||||
libavcodec/wbmp.* @pross
|
||||
|
||||
# bitstream filters
|
||||
libavcodec/bsf/eia608_to_smpte436m.* @programmerjake
|
||||
libavcodec/bsf/smpte436m_to_eia608.* @programmerjake
|
||||
|
||||
# architecture-specific
|
||||
libavcodec/aarch64/.* @lynne @mstorsjo
|
||||
libavcodec/arm/.* @mstorsjo
|
||||
libavcodec/ppc/.* @sean_mcg
|
||||
libavcodec/riscv/.* @Courmisch
|
||||
libavcodec/wasm/hevc/.* @quink
|
||||
libavcodec/x86/.* @lynne
|
||||
libavcodec/x86/vp8.* @rbultje
|
||||
libavcodec/x86/vp9.* @rbultje
|
||||
libavcodec/x86/vpx.* @rbultje
|
||||
|
||||
# avfilter
|
||||
# =======
|
||||
libavfilter/af_loudnorm.* @kylophone
|
||||
libavfilter/aarch64/.* @mstorsjo
|
||||
libavfilter/af_whisper.* @vpalmisano
|
||||
libavfilter/.*_amf* @OvchinnikovDmitrii @ArazIusubov
|
||||
libavfilter/avfiltergraph.* @haasn
|
||||
libavfilter/colorspace.* @rbultje
|
||||
libavfilter/formats.* @haasn
|
||||
libavfilter/.*f_ebur128.* @haasn
|
||||
libavfilter/vf_blackdetect.* @haasn
|
||||
libavfilter/vf_colordetect.* @haasn
|
||||
libavfilter/vf_colorspace.* @rbultje
|
||||
libavfilter/.*drawvg.* @ayosec
|
||||
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
|
||||
libavfilter/vf_thumbnail.* @haasn
|
||||
libavfilter/vf_transpose_vt.* @quink
|
||||
libavfilter/vf_yadif.* @michaelni
|
||||
libavfilter/vsrc_mandelbrot.* @michaelni
|
||||
|
||||
libavfilter/aarch64/.* @mstorsjo
|
||||
libavfilter/riscv/.* @Courmisch
|
||||
libavfilter/x86/colorspace.* @rbultje
|
||||
libavfilter/x86/scene_sad.* @haasn
|
||||
|
||||
# avformat
|
||||
# =======
|
||||
libavformat/alp.* @zane
|
||||
libavformat/amv.* @zane
|
||||
libavformat/anm.* @pross
|
||||
libavformat/apm.* @zane
|
||||
libavformat/argo_.* @zane
|
||||
libavformat/bink.* @pross
|
||||
libavformat/bintext.* @pross
|
||||
libavformat/caf.* @pross
|
||||
libavformat/cine.* @pross
|
||||
libavformat/dsf.* @pross
|
||||
libavformat/eacdata.* @pross
|
||||
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
|
||||
libavformat/iff.* @pross
|
||||
libavformat/.*jpegxl.* @Traneptora
|
||||
libavformat/jv.* @pross
|
||||
libavformat/.*jxl.* @Traneptora
|
||||
libavformat/kvag.* @zane
|
||||
libavformat/mccdec.* @programmerjake
|
||||
libavformat/mccenc.* @programmerjake
|
||||
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
|
||||
libavformat/scd.* @zane
|
||||
libavformat/tty.* @pross
|
||||
libavformat/whip.c @JackLau
|
||||
libavformat/wsd.* @pross
|
||||
libavformat/wtv.* @pross
|
||||
|
||||
# avutil
|
||||
# ======
|
||||
libavutil/.*_amf* @OvchinnikovDmitrii @ArazIusubov
|
||||
libavutil/.*crc.* @lynne @michaelni
|
||||
libavutil/.*d3d12va.* @jianhuaw @tong1wu @younengxiao
|
||||
libavutil/csp.* @rbultje @haasn
|
||||
libavutil/.*d3d12va.* @jianhuaw
|
||||
libavutil/eval.* @michaelni
|
||||
libavutil/film_grain.* @haasn
|
||||
libavutil/dovi_meta.* @haasn
|
||||
libavutil/hwcontext_oh.* @quink
|
||||
libavutil/hwcontext_mediacodec.* @quink
|
||||
libavutil/hwcontext_videotoolbox.* @ePirat
|
||||
libavutil/iamf.* @jamrial
|
||||
libavutil/integer.* @michaelni
|
||||
libavutil/lfg.* @michaelni
|
||||
@@ -197,8 +69,6 @@ libavutil/tx.* @lynne
|
||||
libavutil/aarch64/.* @lynne @mstorsjo
|
||||
libavutil/arm/.* @mstorsjo
|
||||
libavutil/ppc/.* @sean_mcg
|
||||
libavutil/riscv/.* @Courmisch
|
||||
libavutil/wasm/.* @quink
|
||||
libavutil/x86/.* @lynne
|
||||
|
||||
# swresample
|
||||
@@ -212,13 +82,6 @@ libswresample/.* @michaelni
|
||||
libswscale/aarch64/.* @mstorsjo
|
||||
libswscale/arm/.* @mstorsjo
|
||||
libswscale/ppc/.* @sean_mcg
|
||||
libswscale/riscv/.* @Courmisch
|
||||
libswscale/.* @haasn
|
||||
|
||||
# tools
|
||||
# =====
|
||||
fftools/ffplay_renderer.* @haasn
|
||||
tools/target_dec_fuzzer.c @michaelni
|
||||
|
||||
# doc
|
||||
# ===
|
||||
@@ -226,37 +89,5 @@ doc/.* @GyanD
|
||||
|
||||
# Frameworks
|
||||
# ==========
|
||||
.*d3d12va.* @jianhuaw @tong1wu @younengxiao
|
||||
.*vulkan.* @lynne @haasn
|
||||
|
||||
# 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
|
||||
# =======
|
||||
.forgejo/CODEOWNERS @michaelni
|
||||
|
||||
# /
|
||||
# =
|
||||
MAINTAINERS @michaelni
|
||||
.*d3d12va.* @jianhuaw
|
||||
.*vulkan.* @lynne
|
||||
|
||||
@@ -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,7 +1,6 @@
|
||||
module.exports = async ({github, context}) => {
|
||||
const title = (context.payload.pull_request?.title || context.payload.issue?.title || '').toLowerCase();
|
||||
const labels = [];
|
||||
const issueNumber = context.payload.pull_request?.number || context.payload.issue?.number;
|
||||
|
||||
const kwmap = {
|
||||
'avcodec': 'avcodec',
|
||||
@@ -11,55 +10,18 @@ module.exports = async ({github, context}) => {
|
||||
'avutil': 'avutil',
|
||||
'swresample': 'swresample',
|
||||
'swscale': 'swscale',
|
||||
'fftools': 'CLI',
|
||||
'vulkan': 'vulkan'
|
||||
'fftools': 'CLI'
|
||||
};
|
||||
|
||||
async function isOrgMember(username) {
|
||||
try {
|
||||
const response = await github.rest.orgs.checkMembershipForUser({
|
||||
org: context.repo.owner,
|
||||
username: username
|
||||
});
|
||||
return response.status === 204;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (context.payload.action === 'closed' ||
|
||||
(context.payload.action !== 'opened' && (
|
||||
context.payload.action === 'assigned' ||
|
||||
context.payload.action === 'label_updated' ||
|
||||
context.payload.action === 'labeled' ||
|
||||
context.payload.comment) &&
|
||||
await isOrgMember(context.payload.sender.login))
|
||||
) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
// this should say 'new', but forgejo deviates from GitHub API here and expects the ID
|
||||
name: '41'
|
||||
});
|
||||
console.log('Removed "new" label');
|
||||
} catch (error) {
|
||||
if (error.status !== 404 && error.status !== 410) {
|
||||
console.log('Could not remove "new" label');
|
||||
}
|
||||
}
|
||||
} else if (context.payload.action === 'opened') {
|
||||
if (context.payload.action === 'opened') {
|
||||
labels.push('new');
|
||||
console.log('Detected label: new');
|
||||
}
|
||||
|
||||
if ((context.payload.action === 'opened' || context.payload.action === 'edited') && context.eventName !== 'issue_comment') {
|
||||
for (const [kw, label] of Object.entries(kwmap)) {
|
||||
if (title.includes(kw)) {
|
||||
labels.push(label);
|
||||
console.log('Detected label: ' + label);
|
||||
}
|
||||
for (const [kw, label] of Object.entries(kwmap)) {
|
||||
if (title.includes(kw)) {
|
||||
labels.push(label);
|
||||
console.log('Detected label: ' + label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +29,7 @@ module.exports = async ({github, context}) => {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
issue_number: context.payload.pull_request?.number || context.payload.issue?.number,
|
||||
labels: labels,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
avcodec:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libavcodec/**'
|
||||
- any-glob-to-any-file: libavcodec/**
|
||||
|
||||
avdevice:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libavdevice/**'
|
||||
- any-glob-to-any-file: libavdevice/**
|
||||
|
||||
avfilter:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libavfilter/**'
|
||||
- any-glob-to-any-file: libavfilter/**
|
||||
|
||||
avformat:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libavformat/**'
|
||||
- any-glob-to-any-file: libavformat/**
|
||||
|
||||
avutil:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libavutil/**'
|
||||
- any-glob-to-any-file: libavutil/**
|
||||
|
||||
swresample:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libswresample/**'
|
||||
- any-glob-to-any-file: libswresample/**
|
||||
|
||||
swscale:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'libswscale/**'
|
||||
- any-glob-to-any-file: libswscale/**
|
||||
|
||||
CLI:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'fftools/**'
|
||||
|
||||
vulkan:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*vulkan*'
|
||||
- any-glob-to-any-file: fftools/**
|
||||
|
||||
@@ -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
|
||||
@@ -27,20 +18,6 @@ repos:
|
||||
- id: fix-byte-order-marker
|
||||
- id: mixed-line-ending
|
||||
- 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$
|
||||
language: script
|
||||
entry: ./tools/check_arm_indent.sh --apply
|
||||
pass_filenames: false
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
@@ -48,4 +25,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
|
||||
|
||||
@@ -1,30 +1,23 @@
|
||||
name: Autolabel
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, edited, synchronize, closed, assigned, labeled, unlabeled]
|
||||
types: [opened, edited, synchronize]
|
||||
issues:
|
||||
types: [opened, edited, closed, assigned, labeled, unlabeled]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
types: [opened, edited]
|
||||
|
||||
jobs:
|
||||
pr_labeler:
|
||||
name: Labeler
|
||||
runs-on: utilities
|
||||
if: ${{ github.event.sender.login != 'ffmpeg-devel' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
- name: Label by file-changes
|
||||
uses: actions/labeler@v6
|
||||
uses: https://github.com/actions/labeler@v5
|
||||
if: ${{ forge.event_name == 'pull_request_target' }}
|
||||
with:
|
||||
configuration-path: .forgejo/labeler/labeler.yml
|
||||
repo-token: ${{ secrets.AUTOLABELER_TOKEN }}
|
||||
sync-labels: true
|
||||
- name: Label by title-match
|
||||
uses: actions/github-script@v8
|
||||
uses: https://github.com/actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const script = require('.forgejo/labeler/labeler.js')
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ forge.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Pre-Commit
|
||||
runs-on: utilities
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Rebase onto target branch
|
||||
uses: ./.forgejo/actions/rebase-pr
|
||||
uses: actions/checkout@v4
|
||||
- name: Install pre-commit CI
|
||||
id: install
|
||||
run: |
|
||||
@@ -26,7 +18,7 @@ jobs:
|
||||
~/pre-commit/bin/pip install pre-commit
|
||||
echo "envhash=$({ python3 --version && cat .forgejo/pre-commit/config.yaml; } | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
|
||||
- name: Cache
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-${{ steps.install.outputs.envhash }}
|
||||
|
||||
+13
-99
@@ -1,49 +1,26 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ forge.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
run_fate:
|
||||
name: Fate (${{ matrix.runner }}, ${{ matrix.shared }}, ${{ matrix.bits }} bit)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
runner: [linux-aarch64]
|
||||
shared: ['static']
|
||||
bits: ['64']
|
||||
include:
|
||||
- runner: linux-amd64
|
||||
shared: 'static'
|
||||
bits: '32'
|
||||
- runner: linux-amd64
|
||||
shared: 'shared'
|
||||
bits: '64'
|
||||
runner: [linux-amd64,linux-aarch64]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Rebase onto target branch
|
||||
uses: ./.forgejo/actions/rebase-pr
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 \
|
||||
$([ "${{ matrix.bits }}" != "32" ] || echo --arch=x86_32 --extra-cflags=-m32 --extra-cxxflags=-m32 --extra-ldflags=-m32) \
|
||||
$([ "${{ matrix.shared }}" != "shared" ] || echo --enable-shared --disable-static) \
|
||||
|| CFGRES=$?
|
||||
cat ffbuild/config.log
|
||||
exit ${CFGRES:-0}
|
||||
run: ./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2
|
||||
- name: Build
|
||||
run: make -j$(nproc)
|
||||
- name: Restore Cached Fate-Suite
|
||||
id: cache
|
||||
uses: actions/cache/restore@v5
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite
|
||||
@@ -53,93 +30,30 @@ jobs:
|
||||
id: fate
|
||||
run: |
|
||||
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
|
||||
echo "hash=$(find fate-suite -type f | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
|
||||
- name: Cache Fate-Suite
|
||||
uses: actions/cache/save@v5
|
||||
uses: actions/cache/save@v4
|
||||
if: ${{ format('fate-suite-{0}', steps.fate.outputs.hash) != steps.cache.outputs.cache-matched-key }}
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite-${{ steps.fate.outputs.hash }}
|
||||
- name: 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 }})
|
||||
run: make fate SAMPLES=$PWD/fate-suite -j$(nproc)
|
||||
compile_only:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: ['ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest']
|
||||
target_exec: ['wine']
|
||||
image: ["ghcr.io/btbn/ffmpeg-builds/win64-gpl:latest"]
|
||||
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
|
||||
uses: actions/checkout@v4
|
||||
- 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" \
|
||||
--enable-memory-poisoning --assert-level=2 --target-exec="${{ matrix.target_exec }}" \
|
||||
--enable-hardcoded-tables \
|
||||
|| CFGRES=$?
|
||||
cat ffbuild/config.log
|
||||
exit ${CFGRES:-0}
|
||||
--extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" --extra-ldexeflags="$FF_LDEXEFLAGS"
|
||||
- name: Build
|
||||
run: make -C build -j$(nproc)
|
||||
- name: Restore Cached Fate-Suite
|
||||
id: cache
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite
|
||||
restore-keys: |
|
||||
fate-suite-
|
||||
- name: Sync Fate-Suite
|
||||
id: fate
|
||||
run: |
|
||||
make -C build 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
|
||||
if: ${{ format('fate-suite-{0}', steps.fate.outputs.hash) != steps.cache.outputs.cache-matched-key }}
|
||||
with:
|
||||
path: fate-suite
|
||||
key: fate-suite-${{ steps.fate.outputs.hash }}
|
||||
- name: 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=$?
|
||||
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: make -j$(nproc)
|
||||
|
||||
-10
@@ -23,12 +23,6 @@
|
||||
*.metal.air
|
||||
*.metallib
|
||||
*.metallib.c
|
||||
*.spv
|
||||
*.spv.c
|
||||
*.spv.gz
|
||||
*.gen.asm
|
||||
*.gen.c
|
||||
*.gen.S
|
||||
*.ptx
|
||||
*.ptx.c
|
||||
*.ptx.gz
|
||||
@@ -40,12 +34,8 @@
|
||||
/ffmpeg
|
||||
/ffplay
|
||||
/ffprobe
|
||||
/checkasm_config_generated.asm
|
||||
/checkasm_config_generated.h
|
||||
/checkasm_header_config_generated.h
|
||||
/config.asm
|
||||
/config.h
|
||||
/config_components.asm
|
||||
/config_components.h
|
||||
/coverage.info
|
||||
/lcov/
|
||||
|
||||
+1
-2
@@ -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**.
|
||||
Patches should be submitted to 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,69 +1,89 @@
|
||||
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 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:
|
||||
- ffprobe -codec option
|
||||
- EXIF Metadata Parsing
|
||||
- gfxcapture: Windows.Graphics.Capture based window/monitor capture
|
||||
- hxvs demuxer for HXVS/HXVT IP camera format
|
||||
- MPEG-H 3D Audio decoding via mpeghdec
|
||||
- D3D12 H.264 encoder
|
||||
- drawvg filter via libcairo
|
||||
- ffmpeg CLI tiled HEIF support
|
||||
- D3D12 AV1 encoder
|
||||
- ProRes Vulkan hwaccel
|
||||
- DPX Vulkan hwaccel
|
||||
- Rockchip H.264/HEVC hardware encoder
|
||||
- Add vf_scale_d3d12 filter
|
||||
- JPEG-XS parser
|
||||
- JPEG-XS decoder and encoder through libsvtjpegxs
|
||||
- JPEG-XS raw bitstream muxer and demuxer
|
||||
- IAMF Projection mode Ambisonic Audio Elements muxing and demuxing
|
||||
- Add vf_mestimate_d3d12 filter
|
||||
- xHE-AAC Mps212 decoding support (experimental)
|
||||
- Remove the old HLS protocol handler
|
||||
- Vulkan compute codec optimizations
|
||||
- swscale Vulkan support
|
||||
- LCEVC metadata bitstream filter
|
||||
- Add vf_deinterlace_d3d12 filter
|
||||
- ffprobe: only show refs field in stream section when reading frames
|
||||
- ProRes Vulkan encoder
|
||||
- LCEVC parser
|
||||
- LCEVC enhancement layer exporting in MPEG-TS
|
||||
|
||||
version 8.0.1:
|
||||
avutil/common: cast GET_BYTE/GET_16BIT returned value
|
||||
avfilter/vf_drawtext: fix call GET_UTF8 with invalid argument
|
||||
avfilter/vf_drawtext: fix incorrect text length
|
||||
Update for 8.0.1
|
||||
avfilter/vf_drawtext: Account for bbox text seperator
|
||||
avcodec/mediacodecdec_common: Check that the input to mediacodec_wrap_sw_audio_buffer() contains channel * sample_size
|
||||
avcodec/rv60dec: Clear blk_info
|
||||
avformat/whip: Fix rtp_ctx->streams access
|
||||
avcodec/utvideodec: Set B for the width= 1 case in restore_median_planar_il()
|
||||
avcodec/osq: Fix 32bit sample overflow
|
||||
avformat/rtpdec_rfc4175: Only change PayloadContext on success
|
||||
avformat/rtpdec_rfc4175: Check dimensions
|
||||
avformat/rtpdec_rfc4175: Fix memleak of sampling
|
||||
avformat/http: Fix off by 1 error
|
||||
avcodec/exr: spelling
|
||||
avcodec/rv60dec: add upper bound check for qp
|
||||
avcodec/exr: use tile dimensions in pxr24 UINT case
|
||||
avcodec/exr: Simple check for available channels
|
||||
avformat/sctp: Check size in sctp_write()
|
||||
avformat/rtmpproto: consider command line argument lengths
|
||||
avformat/rtmpproto_ Check tcurl and flashver length
|
||||
avcodec/g723_1enc: Make min_err 64bit
|
||||
avcodec/vlc: Clear val8/16 in vlc_multi_gen() by av_mallocz()
|
||||
avformat/rtpenc_h264_hevc: Check space for nal_length_size in ff_rtp_send_h264_hevc()
|
||||
avcodec/ffv1enc: Consider variation in slice sizes
|
||||
libavcodec/cbs_apv_syntax_template: limit tile to 2gb
|
||||
swscale/output: Fix unsigned cast position in yuv2*
|
||||
swscale/output: Fix integer overflow in yuv2ya16_X_c_template()
|
||||
avcodec/exr: Check that DWA has 3 channels
|
||||
avcodec/exr: check ac_size
|
||||
avcodec/exr: Round dc_w/h up
|
||||
avcodec/mjpegdec: Explain buf_size/width/height check
|
||||
configure: strip non numeric trailer from gcc version
|
||||
avformat/dhav: Fix off by length of read element error
|
||||
avformat/aviobuf: Keep checksum_ptr consistent in avio_seek()
|
||||
doc/examples/vaapi_encode: fix invalid check on fwrite
|
||||
avcodec/librsvgdec: fix compilation with librsvg 2.50.3
|
||||
avcodec/mfenc: fix memory leak with D3D11 input surfaces
|
||||
swscale/graph: fix double-free when legacy pass fails initializing
|
||||
libavformat/udp: Fix call to recvfrom(2)
|
||||
avfilter/f_ebur128: Fix incorrect ebur128 peak calculation.
|
||||
avformat/udp: fix warning about unused varible
|
||||
avdevice/lavfi: stop setting deprecated buffersink options
|
||||
configure: unbreak glslang build
|
||||
swscale/range_convert: fix truncation bias in range conversion
|
||||
lavc/aarch64: Fix addp overflow in ff_pred16x16_plane_neon_10
|
||||
avcodec/mlpdec: don't depend on context channel layout when setting substream masks
|
||||
avformat/demux: pass new extradata to the parser
|
||||
avfilter/af_whisper: fix srt index
|
||||
avfilter/af_whisper: fix int64 printf format
|
||||
avfilter/af_whisper: fix srt file format
|
||||
avfilter/whisper: correct option formatting
|
||||
avfilter/af_whisper: fix broken output for multibyte character
|
||||
avformat/rtsp: fix leading space in RTSP reason
|
||||
avformat/rtsp: do not log invalid values
|
||||
avformat/http: Handle IPv6 Zone ID in hostname
|
||||
avformat/dump: fix log level passed to av_log when printing stream group side data
|
||||
avcodec/hevc/sei: don't attempt to use stale values in HEVCSEITDRDI
|
||||
avcodec/hevc/sei: prevent storing a potentially bogus num_ref_displays value in HEVCSEITDRDI
|
||||
avcodec/hevc/refs: don't unconditionally discard non-IRAP frames if no IRAP frame was seen before
|
||||
libavutil/arm: Rename the HWCAP defines
|
||||
libavutil/arm: Make use of elf_aux_info() on FreeBSD/OpenBSD
|
||||
fftools/ffmpeg: fix gracefully shutdown
|
||||
avcodec/decode: sync initial_pict_type and intra_only_flag with thread worker's avctx
|
||||
avcodec/x86/pngdsp: add missing emms at the end of add_png_paeth_prediction
|
||||
avcodec/videotoolboxenc: ensure bitrate is set in low_delay mode
|
||||
avcodec/videotoolboxenc: allow low latency RC with HEVC
|
||||
avcodec/videotoolboxenc: support global_quality without qscale
|
||||
avcodec/videotoolboxenc: fix the loss of precision when calculating quality
|
||||
fftools/ffmpeg_demux: ensure the display_rotation option is honored
|
||||
avcodec/mjpegdec: use ff_frame_new_side_data() to export display matrix
|
||||
avutil/tests/aes_ctr: extend the test to cover payloads smaller than a block
|
||||
avutil/aes_ctr: reintroduce the block offset state
|
||||
avfilter/vf_lcevc: support LCEVCdec version 4
|
||||
avcodec/lcevcdec: support LCEVCdec version 4
|
||||
movenc: ensure chapters track extradata is not null and populated
|
||||
|
||||
version 8.0:
|
||||
- Whisper filter
|
||||
- Drop support for OpenSSL < 1.1.0
|
||||
- Enable TLS peer certificate verification by default (on next major version bump)
|
||||
- Drop support for OpenSSL < 1.1.1
|
||||
- yasm support dropped, users need to use nasm
|
||||
- VVC VAAPI decoder
|
||||
- RealVideo 6.0 decoder
|
||||
@@ -92,8 +112,6 @@ version 8.0:
|
||||
- AV1 Vulkan encoder
|
||||
- ProRes RAW decoder
|
||||
- ProRes RAW Vulkan hwaccel
|
||||
- ffprobe -codec option
|
||||
- HDR10+ metadata passthrough when decoding/encoding with libaom-av1
|
||||
|
||||
|
||||
version 7.1:
|
||||
|
||||
+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.
|
||||
|
||||
+11
-23
@@ -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
|
||||
@@ -153,13 +152,13 @@ Codecs:
|
||||
adpcm.c Zane van Iperen
|
||||
alacenc.c Jaikrishnan Menon
|
||||
alsdec.c Thilo Borgmann, Umair Khan
|
||||
amfdec*,amfenc* [2] Dmitrii Ovchinnikov, Araz Iusubov
|
||||
amfenc* Dmitrii Ovchinnikov
|
||||
aptx.c Aurelien Jacobs
|
||||
ass* Aurelien Jacobs
|
||||
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
|
||||
@@ -212,7 +211,7 @@ Codecs:
|
||||
libkvazaar.c Arttu Ylä-Outinen
|
||||
libopenh264enc.c Martin Storsjo, Linjie Fu
|
||||
libopenjpegenc.c Michael Bradshaw
|
||||
libtheoraenc.c [0]
|
||||
libtheoraenc.c David Conrad
|
||||
libvorbis.c David Conrad
|
||||
libvpx* James Zern
|
||||
libxavs.c 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
|
||||
@@ -279,7 +278,6 @@ Codecs:
|
||||
xface Stefano Sabatini
|
||||
|
||||
Hardware acceleration:
|
||||
amf* [2] Dmitrii Ovchinnikov, Araz Iusubov
|
||||
dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme
|
||||
d3d11va* Steve Lhomme
|
||||
d3d12va* Wu Jianhua
|
||||
@@ -318,10 +316,6 @@ libavfilter
|
||||
===========
|
||||
|
||||
Generic parts:
|
||||
|
||||
Framework and orphaned filters Nicolas George
|
||||
(except hardware acceleration)
|
||||
|
||||
graphdump.c Nicolas George
|
||||
|
||||
motion_estimation.c Davinder Singh
|
||||
@@ -353,9 +347,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 +405,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 +441,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
|
||||
@@ -492,7 +482,6 @@ Muxers/Demuxers:
|
||||
webm dash (matroskaenc.c) Vignesh Venkatasubramanian
|
||||
webvtt* Matthew J Heaney
|
||||
westwood.c Mike Melanson
|
||||
whip.c [2] Jack Lau
|
||||
wtv.c Peter Ross
|
||||
|
||||
Protocols:
|
||||
@@ -532,7 +521,7 @@ LoongArch [2] Shiyou Yin
|
||||
Darwin (macOS, iOS) [2] Marvin Scholz
|
||||
Mac OS X / PowerPC [0]
|
||||
Amiga / PowerPC Colin Ward
|
||||
Linux / PowerPC [2] Sean McGovern (CC <gseanmcg@gmail.com>), Lauri Kasanen
|
||||
Linux / PowerPC [1] Lauri Kasanen
|
||||
RISC-V [2] Rémi Denis-Courmont
|
||||
Windows MinGW Alex Beregszaszi, Ramiro Polla
|
||||
Windows Cygwin Victor Paesa
|
||||
@@ -628,7 +617,6 @@ Reinhard Tartler 9300 5DC2 7E87 6C37 ED7B CA9A 9808 3544 9453 48A4
|
||||
Reynaldo H. Verdejo Pinochet 6E27 CD34 170C C78E 4D4F 5F40 C18E 077F 3114 452A
|
||||
Robert Swain EE7A 56EA 4A81 A7B5 2001 A521 67FA 362D A2FC 3E71
|
||||
Sascha Sommer 38A0 F88B 868E 9D3A 97D4 D6A0 E823 706F 1E07 0D3C
|
||||
Sean McGovern (Sean_McG) 6D03 BC60 3A33 E615 6E2E 06AD 8C06 8175 6F59 8684
|
||||
Stefano Sabatini 0D0B AD6B 5330 BBAD D3D6 6A0C 719C 2839 FC43 2D5F
|
||||
Steinar H. Gunderson C2E9 004F F028 C18E 4EAD DB83 7F61 7561 7797 8F76
|
||||
Stephan Hilb 4F38 0B3A 5F39 B99B F505 E562 8D5C 5554 4E17 8863
|
||||
|
||||
@@ -11,8 +11,6 @@ vpath %.asm $(SRC_PATH)
|
||||
vpath %.rc $(SRC_PATH)
|
||||
vpath %.v $(SRC_PATH)
|
||||
vpath %.texi $(SRC_PATH)
|
||||
vpath %.glsl $(SRC_PATH)
|
||||
vpath %.spv $(SRC_PATH)
|
||||
vpath %.cu $(SRC_PATH)
|
||||
vpath %.ptx $(SRC_PATH)
|
||||
vpath %.metal $(SRC_PATH)
|
||||
@@ -55,31 +53,31 @@ FF_DEP_LIBS := $(DEP_LIBS)
|
||||
FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS)
|
||||
|
||||
$(TOOLS): %$(EXESUF): %.o
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(filter-out $(FF_DEP_LIBS), $^) $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(filter-out $(FF_DEP_LIBS), $^) $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS)
|
||||
|
||||
target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
target_enc_%_fuzzer$(EXESUF): target_enc_%_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/target_bsf_%_fuzzer$(EXESUF): tools/target_bsf_%_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
target_dem_%_fuzzer$(EXESUF): target_dem_%_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/target_sws_fuzzer$(EXESUF): tools/target_sws_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/target_swr_fuzzer$(EXESUF): tools/target_swr_fuzzer.o $(FF_DEP_LIBS)
|
||||
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
|
||||
|
||||
tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS)
|
||||
tools/enum_options$(EXESUF): $(FF_DEP_LIBS)
|
||||
@@ -106,14 +104,13 @@ 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 \
|
||||
ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \
|
||||
MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \
|
||||
MMI-OBJS LSX-OBJS LASX-OBJS RV-OBJS RVV-OBJS RVVB-OBJS \
|
||||
OBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS SIMD128-OBJS \
|
||||
SVE-OBJS SVE2-OBJS SME-OBJS SME2-OBJS
|
||||
OBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS SIMD128-OBJS
|
||||
|
||||
define RESET
|
||||
$(1) :=
|
||||
@@ -143,13 +140,11 @@ 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))
|
||||
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)
|
||||
|
||||
VERSION_SH = $(SRC_PATH)/ffbuild/version.sh
|
||||
ifeq ($(VERSION_TRACKING),yes)
|
||||
@@ -189,8 +184,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.h mapfile \
|
||||
ffbuild/.config ffbuild/config.* libavutil/avconfig.h \
|
||||
version.h libavutil/ffversion.h libavcodec/codec_names.h \
|
||||
libavcodec/bsf_list.c libavformat/protocol_list.c \
|
||||
@@ -205,8 +199,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.0 "Huffman" │
|
||||
└────────────────────────────────────────┘
|
||||
|
||||
The FFmpeg Project proudly presents FFmpeg 8.0 "Huffman", about 11
|
||||
months after the release of FFmpeg 7.1.
|
||||
|
||||
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.
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Android Binder handler
|
||||
*
|
||||
* Copyright (c) 2025 Dmitrii Okunev
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libavutil/log.h"
|
||||
#include "binder.h"
|
||||
|
||||
#define THREAD_POOL_SIZE 1
|
||||
|
||||
static void *dlopen_libbinder_ndk(void)
|
||||
{
|
||||
/*
|
||||
* libbinder_ndk.so often does not contain the functions we need, so making
|
||||
* this dependency optional, thus using dlopen/dlsym instead of linking.
|
||||
*
|
||||
* See also: https://source.android.com/docs/core/architecture/aidl/aidl-backends
|
||||
*/
|
||||
|
||||
void *h = dlopen("libbinder_ndk.so", RTLD_NOW | RTLD_LOCAL);
|
||||
if (h != NULL)
|
||||
return h;
|
||||
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"android/binder: unable to load libbinder_ndk.so: '%s'; skipping binder threadpool init (MediaCodec likely won't work)\n",
|
||||
dlerror());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void android_binder_threadpool_init(void)
|
||||
{
|
||||
typedef int (*set_thread_pool_max_fn)(uint32_t);
|
||||
typedef void (*start_thread_pool_fn)(void);
|
||||
|
||||
set_thread_pool_max_fn set_thread_pool_max = NULL;
|
||||
start_thread_pool_fn start_thread_pool = NULL;
|
||||
|
||||
void *h = dlopen_libbinder_ndk();
|
||||
if (h == NULL)
|
||||
return;
|
||||
|
||||
unsigned thead_pool_size = THREAD_POOL_SIZE;
|
||||
|
||||
set_thread_pool_max =
|
||||
(set_thread_pool_max_fn) dlsym(h,
|
||||
"ABinderProcess_setThreadPoolMaxThreadCount");
|
||||
start_thread_pool =
|
||||
(start_thread_pool_fn) dlsym(h, "ABinderProcess_startThreadPool");
|
||||
|
||||
if (start_thread_pool == NULL) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"android/binder: ABinderProcess_startThreadPool not found; skipping threadpool init (MediaCodec likely won't work)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_thread_pool_max != NULL) {
|
||||
int ok = set_thread_pool_max(thead_pool_size);
|
||||
av_log(NULL, AV_LOG_DEBUG,
|
||||
"android/binder: ABinderProcess_setThreadPoolMaxThreadCount(%u) => %s\n",
|
||||
thead_pool_size, ok ? "ok" : "fail");
|
||||
} else {
|
||||
av_log(NULL, AV_LOG_DEBUG,
|
||||
"android/binder: ABinderProcess_setThreadPoolMaxThreadCount is unavailable; using the library default\n");
|
||||
}
|
||||
|
||||
start_thread_pool();
|
||||
av_log(NULL, AV_LOG_DEBUG,
|
||||
"android/binder: ABinderProcess_startThreadPool() called\n");
|
||||
}
|
||||
|
||||
void android_binder_threadpool_init_if_required(void)
|
||||
{
|
||||
#if __ANDROID_API__ >= 24
|
||||
if (android_get_device_api_level() < 35) {
|
||||
// the issue with the thread pool was introduced in Android 15 (API 35)
|
||||
av_log(NULL, AV_LOG_DEBUG,
|
||||
"android/binder: API<35, thus no need to initialize a thread pool\n");
|
||||
return;
|
||||
}
|
||||
android_binder_threadpool_init();
|
||||
#else
|
||||
// android_get_device_api_level was introduced in API 24, so we cannot use it
|
||||
// to detect the API level in API<24. For simplicity we just assume
|
||||
// libbinder_ndk.so on the system running this code would have API level < 35;
|
||||
av_log(NULL, AV_LOG_DEBUG,
|
||||
"android/binder: is built with API<24, assuming this is not Android 15+\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __ANDROID__ */
|
||||
@@ -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); }
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ static int optind = 1;
|
||||
static int optopt;
|
||||
static char *optarg;
|
||||
|
||||
static int getopt(int argc, char *argv[], const char *opts)
|
||||
static int getopt(int argc, char *argv[], char *opts)
|
||||
{
|
||||
static int sp = 1;
|
||||
int c;
|
||||
|
||||
+6
-41
@@ -44,9 +44,8 @@
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/time.h"
|
||||
#include "libavutil/wchar_filename.h"
|
||||
|
||||
typedef struct w32pthread_t {
|
||||
typedef struct pthread_t {
|
||||
void *handle;
|
||||
void *(*func)(void* arg);
|
||||
void *arg;
|
||||
@@ -72,7 +71,7 @@ typedef CONDITION_VARIABLE pthread_cond_t;
|
||||
#define THREADFUNC_RETTYPE unsigned
|
||||
#endif
|
||||
|
||||
av_unused static THREADFUNC_RETTYPE
|
||||
static av_unused THREADFUNC_RETTYPE
|
||||
__stdcall attribute_align_arg win32thread_worker(void *arg)
|
||||
{
|
||||
pthread_t h = (pthread_t)arg;
|
||||
@@ -80,12 +79,12 @@ __stdcall attribute_align_arg win32thread_worker(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
av_unused static int pthread_create(pthread_t *thread, const void *unused_attr,
|
||||
static av_unused int pthread_create(pthread_t *thread, const void *unused_attr,
|
||||
void *(*start_routine)(void*), void *arg)
|
||||
{
|
||||
pthread_t ret;
|
||||
|
||||
ret = (pthread_t)av_mallocz(sizeof(*ret));
|
||||
ret = av_mallocz(sizeof(*ret));
|
||||
if (!ret)
|
||||
return EAGAIN;
|
||||
|
||||
@@ -109,7 +108,7 @@ av_unused static int pthread_create(pthread_t *thread, const void *unused_attr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
av_unused static int pthread_join(pthread_t thread, void **value_ptr)
|
||||
static av_unused int pthread_join(pthread_t thread, void **value_ptr)
|
||||
{
|
||||
DWORD ret = WaitForSingleObject(thread->handle, INFINITE);
|
||||
if (ret != WAIT_OBJECT_0) {
|
||||
@@ -149,7 +148,7 @@ static inline int pthread_mutex_unlock(pthread_mutex_t *m)
|
||||
typedef INIT_ONCE pthread_once_t;
|
||||
#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
|
||||
|
||||
av_unused static int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
|
||||
static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
|
||||
{
|
||||
BOOL pending = FALSE;
|
||||
InitOnceBeginInitialize(once_control, 0, &pending, NULL);
|
||||
@@ -210,38 +209,4 @@ static inline int pthread_setcancelstate(int state, int *oldstate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int win32_thread_setname(const char *name)
|
||||
{
|
||||
#if !HAVE_UWP
|
||||
typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR);
|
||||
|
||||
// Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016,
|
||||
// Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in
|
||||
// kernelbase.dll. So, load it from there for maximum coverage.
|
||||
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
|
||||
if (!kernelbase)
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
SetThreadDescriptionFn pSetThreadDescription =
|
||||
(SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription");
|
||||
if (!pSetThreadDescription)
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
wchar_t *wname;
|
||||
if (utf8towchar(name, &wname) < 0)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname);
|
||||
av_free(wname);
|
||||
return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL);
|
||||
#else
|
||||
// UWP is not supported because we cannot use LoadLibrary/GetProcAddress to
|
||||
// detect the availability of the SetThreadDescription API. There is a small
|
||||
// gap in Windows builds 1507-1607 where it was not available. UWP allows
|
||||
// querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it
|
||||
// requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that.
|
||||
return AVERROR(ENOSYS);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* COMPAT_W32PTHREADS_H */
|
||||
|
||||
+5
-25
@@ -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
|
||||
@@ -53,13 +48,7 @@ trap 'rm -f -- $libname' EXIT
|
||||
if [ -n "$AR" ]; then
|
||||
$AR rcs ${libname} $@ >/dev/null
|
||||
else
|
||||
machine_flag=""
|
||||
case "$LDFLAGS" in
|
||||
*"machine:arm64ec"*)
|
||||
machine_flag="-machine:arm64ec"
|
||||
;;
|
||||
esac
|
||||
lib.exe ${machine_flag} -out:${libname} $@ >/dev/null
|
||||
lib.exe -out:${libname} $@ >/dev/null
|
||||
fi
|
||||
if [ $? != 0 ]; then
|
||||
echo "Could not create temporary library." >&2
|
||||
@@ -117,21 +106,12 @@ if [ -n "$NM" ]; then
|
||||
grep -v : |
|
||||
grep -v ^$ |
|
||||
cut -d' ' -f3 |
|
||||
sed -e "s/^${prefix}//" -e "s/^#//" |
|
||||
grep -v '\$entry_thunk' |
|
||||
grep -v '\$exit_thunk')
|
||||
sed -e "s/^${prefix}//")
|
||||
else
|
||||
member=1
|
||||
case "$LDFLAGS" in
|
||||
*"machine:arm64ec"*)
|
||||
member=32
|
||||
;;
|
||||
esac
|
||||
dump=$(dumpbin.exe -linkermember:${member} ${libname} |
|
||||
sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e 's/^[[:space:]]*[0-9A-Fa-f]\{1,\}[[:space:]]\{1,\}//' -e "s/^${prefix}//" -e 's/^#//' |
|
||||
dump=$(dumpbin.exe -linkermember:1 ${libname} |
|
||||
sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' |
|
||||
tail -n +2 |
|
||||
grep -v '\$entry_thunk' |
|
||||
grep -v '\$exit_thunk')
|
||||
cut -d' ' -f3)
|
||||
fi
|
||||
|
||||
rm ${libname}
|
||||
|
||||
+1
-207
@@ -1,213 +1,7 @@
|
||||
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
|
||||
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.
|
||||
|
||||
2026-03-07 - f37cfb370f8 - lavc 62.25.100 - avcodec.h
|
||||
Deprecate AVCodecContext.intra_dc_precision.
|
||||
|
||||
2026-02-26 - 26d6ac56c10 - lsws 9.4.100 - swscale.h
|
||||
Add sws_test_hw_format().
|
||||
|
||||
2026-02-19 - ca011ee7547 - lavf 62.10.100 - avformat.h
|
||||
Add demuxer command API consisting of:
|
||||
- Add avformat_send_command().
|
||||
- Add avformat_receive_command_reply().
|
||||
- Add enum AVFormatCommandID.
|
||||
|
||||
2026-02-13 - 66766bb1c76 - lavu 60.25.100 - avassert.h
|
||||
Deprecate av_assert0_fpu() and av_assert2_fpu() without replacement.
|
||||
|
||||
2026-02-09 - f2b13f783ac - lavf 62.9.100 - avformat.h
|
||||
Add AVFormatContext.name.
|
||||
|
||||
2026-01-26 - 714152dd9a0 - lavu 60.24.100 - hwcontext_d3d11va.h
|
||||
Add BindFlags and MiscFlags to AVD3D11VADeviceContext
|
||||
|
||||
2026-01-04 - 0645c484537 - lavu 60.23.100 - cpu.h
|
||||
Add AV_CPU_FLAG_ARM_CRC.
|
||||
|
||||
2026-01-04 - e382772e4a1 - lavu 60.22.100 - cpu.h
|
||||
Add AV_CPU_FLAG_CLMUL.
|
||||
|
||||
2025-12-29 - a6e5fa3fbb5 - lavu 60.21.100 - iamf.h
|
||||
Add nb_demixing_matrix to AVIAMFLayer
|
||||
|
||||
2025-12-13 - b8ee68cffe - lavc 62.23.100 - codec_id.h
|
||||
Add AV_CODEC_ID_JPEGXS.
|
||||
|
||||
2025-12-12 - c9b5e145b71 - lavf 62.7.100 - avformat.h
|
||||
Add av_mime_codec_str
|
||||
|
||||
2025-12-08 - 212eb8413a6 - lavu 60.20.100 - hwcontext_vulkan.h
|
||||
Add av_vk_get_optional_instance_extensions().
|
||||
Add av_vk_get_optional_device_extensions().
|
||||
|
||||
2025-12-07 - 00caeba050d - lavc 62.22.101 - avcodec.h
|
||||
Add avcodec_receive_frame_flags().
|
||||
Add AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS.
|
||||
|
||||
2025-11-26 - 623669a02cd - lavfi 11.10.100 - buffersrc.h
|
||||
Add av_buffersrc_get_status().
|
||||
|
||||
2025-11-18 - 140b4f28c30 - lavu 60.19.100 - hwcontext_amf.h
|
||||
avutil/hwcontext_amf: add lock and unlock for AVAMFDeviceContext.
|
||||
|
||||
2025-11-16 - 643e2e10f98 - lavu 60.18.100 - cpu.h
|
||||
Deprecate AV_CPU_FLAG_FORCE without replacement.
|
||||
|
||||
2025-11-01 - 8a322c956f3 - lavc 62.19.100 - avcodec.h
|
||||
Schedule AVCodecParser and av_parser_init() to use enum AVCodecID
|
||||
for codec ids on the next major version bump.
|
||||
|
||||
2025-11-01 - e0b0ca81112 - lavc 62.18.100 - avcodec.h
|
||||
Deprecate AVCodecParser fields priv_data_size, parser_init,
|
||||
parser_parse, parser_close, and split with no replacement.
|
||||
|
||||
2025-10-30 - 6879c8ee5dd - lavc 62.17.100 - packet.h
|
||||
Add av_packet_side_data_from_frame() and av_packet_side_data_to_frame().
|
||||
|
||||
2025-10-28 - 71c7b9156bd - lavu 60.16.100 - pixfmt.h
|
||||
Add AVCOL_TRC_EXT_BASE, AVCOL_TRC_V_LOG,
|
||||
AVCOL_PRI_EXT_BASE and AVCOL_PRI_V_GAMUT.
|
||||
|
||||
2025-10-24 - 00e43619cd3 - lavu 60.14.100 - csp.h
|
||||
Add av_csp_approximate_eotf_gamma().
|
||||
|
||||
2025-08-xx - xxxxxxxxxx - lavf 62.6.100 - oggparsevorbis.h oggparseopus.h oggparseflac.h
|
||||
Drop header packets from secondary chained ogg/{flac, opus, vorbis} streams
|
||||
from demuxer output.
|
||||
|
||||
2025-09-08 - 1b97966199f - lavu 60.13.100 - hwcontext_d3d12va.h
|
||||
Add resource_flags and heap_flags to AVD3D12VADeviceContext
|
||||
Add heap_flags to AVD3D12VAFramesContext
|
||||
|
||||
2025-09-05 - 9458a6f8ec2 - lavf 62.5.100 - avformat.h
|
||||
Add AV_FRAME_FILENAME_FLAGS_IGNORE_TRUNCATION
|
||||
|
||||
2025-09-03 - c2ce3873859 - lavu 60.12.100 - hwcontext_d3d12va.h
|
||||
Add support for texture array mode AVD3D12VAFrame.subresource_index,
|
||||
AVD3D12VAFramesContext.texture_array
|
||||
Add enum AVD3D12VAFrameFlags to define the behaviours of frame allocation.
|
||||
Renanme AVD3D12VAFramesContext.flags to AVD3D12VAFramesContext.resource_flags.
|
||||
Add flags to AVD3D12VAFramesContext
|
||||
Add flags to AVD3D12VAFrame
|
||||
|
||||
2025-09-02 - de297ae2fca - lavfi 11.8.100 - buffersrc.h
|
||||
Add AVBufferSrcParameters.alpha_mode.
|
||||
|
||||
2025-09-02 - 0fbd90d78f8 - lavfi 11.7.100 - buffersink.h
|
||||
Add av_buffersink_get_alpha_mode().
|
||||
|
||||
2025-09-02 - ecebf9c6935 - lavc 62.15.100 - avcodec.h codec_par.h
|
||||
Add AVCodecContext.alpha_mode, AVCodecParameters.alpha_mode, and
|
||||
AV_CODEC_CONFIG_ALPHA_MODE.
|
||||
|
||||
2025-09-02 - eea99a77eda - lavfi 11.6.100 - avfilter.h
|
||||
Add AVFilterLink.alpha_mode.
|
||||
|
||||
2025-09-02 - 22929bd044c - lavu 60.11.100 - frame.h pixfmt.h
|
||||
Add AVAlphaMode, AVFrame.alpha_mode, av_alpha_mode_name() and
|
||||
av_alpha_mode_from_name().
|
||||
|
||||
2025-09-01 - ce0938da8cd - lsws 9.3.100 - swscale.h
|
||||
Add SWS_UNSTABLE flag.
|
||||
|
||||
2025-09-01 - 4ffd621523e - lavc 62.14.100 - packet.h
|
||||
Add AV_PKT_DATA_EXIF
|
||||
|
||||
2025-08-24 - 368b5e0ffc2 - lavc 62.13.101 - exif.h
|
||||
Add AV_EXIF_FLAG_RECURSIVE
|
||||
|
||||
2025-08-19 - ad77345a5d1..fe496b0308f - lavc 62.13.100 - exif.h
|
||||
Add:
|
||||
- enum AVTiffDataType, enum AVExifHeaderMode
|
||||
- struct AVExifMetadata, struct AVExifEntry
|
||||
- av_exif_get_tag_name, av_exif_get_tag_id,
|
||||
av_exif_set_entry, av_exif_get_entry,
|
||||
av_exif_remove_entry, av_exif_parse_buffer,
|
||||
av_exif_write, av_exif_free,
|
||||
av_exif_ifd_to_dict, av_exif_clone_ifd,
|
||||
av_exif_matrix_to_orientation,
|
||||
av_exif_orientation_to_matrix,
|
||||
|
||||
2025-08-19 - bb90b262d6d - lavu 60.10.100 - frame.h
|
||||
Add AV_FRAME_DATA_EXIF.
|
||||
|
||||
-------- 8< --------- FFmpeg 8.0 was cut here -------- 8< ---------
|
||||
|
||||
2025-07-29 - 1c85a3832af - lavc 62.10.100 - smpte_436m.h
|
||||
Add a new public header smpte_436m.h with API for
|
||||
manipulating AV_CODEC_ID_SMPTE_436M_ANC data.
|
||||
|
||||
@@ -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
|
||||
+2
-2
@@ -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.0.1
|
||||
|
||||
# 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
|
||||
@@ -295,7 +295,7 @@ MARKDOWN_SUPPORT = YES
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word
|
||||
# be prevented in individual cases by by putting a % sign in front of the word
|
||||
# or globally by setting AUTOLINK_SUPPORT to NO.
|
||||
# The default value is: YES.
|
||||
|
||||
|
||||
+3
-4
@@ -28,7 +28,6 @@ HTMLPAGES = $(AVPROGS-yes:%=doc/%.html) $(AVPROGS-yes:%=doc/%-all.html) $(COMP
|
||||
doc/mailing-list-faq.html \
|
||||
doc/nut.html \
|
||||
doc/platform.html \
|
||||
doc/drawvg-reference.html \
|
||||
$(SRC_PATH)/doc/bootstrap.min.css \
|
||||
$(SRC_PATH)/doc/style.min.css \
|
||||
$(SRC_PATH)/doc/default.css \
|
||||
@@ -54,7 +53,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 +68,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
|
||||
@@ -940,8 +913,6 @@ Set expressions for PTS, DTS or both.
|
||||
Set expression for duration.
|
||||
@item time_base
|
||||
Set output time base.
|
||||
@item prescale
|
||||
Set whether to convert time fields to user-set output time base before evaluation of expressions. Defaults to 0.
|
||||
@end table
|
||||
|
||||
The expressions are evaluated through the eval API and can contain the following
|
||||
@@ -1002,7 +973,7 @@ The next input PTS.
|
||||
The next input duration.
|
||||
|
||||
@item TB
|
||||
The timebase in which time fields are denominated. The user-set output timebase if prescale is enabled, else the input timebase.
|
||||
The timebase of stream packet belongs.
|
||||
|
||||
@item TB_OUT
|
||||
The output timebase.
|
||||
|
||||
@@ -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})
|
||||
@@ -915,14 +913,6 @@ Possible values:
|
||||
|
||||
@end table
|
||||
|
||||
@item alpha_mode @var{integer} (@emph{decoding/encoding,video})
|
||||
Possible values:
|
||||
@table @samp
|
||||
@item premultiplied
|
||||
@item straight
|
||||
@end table
|
||||
|
||||
|
||||
@item log_level_offset @var{integer}
|
||||
Set the log level offset.
|
||||
|
||||
|
||||
+18
-9
@@ -119,6 +119,16 @@ The following options are supported by the libdav1d wrapper.
|
||||
|
||||
@table @option
|
||||
|
||||
@item framethreads
|
||||
Set amount of frame threads to use during decoding. The default value is 0 (autodetect).
|
||||
This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the
|
||||
option @code{max_frame_delay} and the global option @code{threads} instead.
|
||||
|
||||
@item tilethreads
|
||||
Set amount of tile threads to use during decoding. The default value is 0 (autodetect).
|
||||
This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the
|
||||
global option @code{threads} instead.
|
||||
|
||||
@item max_frame_delay
|
||||
Set max amount of frames the decoder may buffer internally. The default value is 0
|
||||
(autodetect).
|
||||
@@ -307,6 +317,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.
|
||||
@@ -338,15 +356,6 @@ value is 0 (disabled).
|
||||
|
||||
@end table
|
||||
|
||||
@section libmpeghdec
|
||||
|
||||
libmpeghdec decoder wrapper.
|
||||
|
||||
libmpeghdec allows libmpeghdec to decode the MPEG-H 3D audio codec.
|
||||
Requires the presence of the libmpeghdec headers and library during
|
||||
configuration. You need to explicitly configure the build with
|
||||
@code{--enable-libmpeghdec --enable-nonfree}.
|
||||
|
||||
@section libopencore-amrnb
|
||||
|
||||
libopencore-amrnb decoder wrapper.
|
||||
|
||||
+24
-64
@@ -281,11 +281,7 @@ This demuxer accepts the following option:
|
||||
@table @option
|
||||
|
||||
@item cenc_decryption_key
|
||||
Default 16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
|
||||
@item cenc_decryption_keys
|
||||
Dictionary of 16-byte key ID => 16-byte key, both in hex, to decrypt files encrypted using ISO Common Encryption
|
||||
(CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
|
||||
@end table
|
||||
|
||||
@@ -668,9 +664,30 @@ Select a glob wildcard pattern type.
|
||||
|
||||
The pattern is interpreted like a @code{glob()} pattern. This is only
|
||||
selectable if libavformat was compiled with globbing support.
|
||||
|
||||
@item glob_sequence @emph{(deprecated, will be removed)}
|
||||
Select a mixed glob wildcard/sequence pattern.
|
||||
|
||||
If your version of libavformat was compiled with globbing support, and
|
||||
the provided pattern contains at least one glob meta character among
|
||||
@code{%*?[]@{@}} that is preceded by an unescaped "%", the pattern is
|
||||
interpreted like a @code{glob()} pattern, otherwise it is interpreted
|
||||
like a sequence pattern.
|
||||
|
||||
All glob special characters @code{%*?[]@{@}} must be prefixed
|
||||
with "%". To escape a literal "%" you shall use "%%".
|
||||
|
||||
For example the pattern @code{foo-%*.jpeg} will match all the
|
||||
filenames prefixed by "foo-" and terminating with ".jpeg", and
|
||||
@code{foo-%?%?%?.jpeg} will match all the filenames prefixed with
|
||||
"foo-", followed by a sequence of three characters, and terminating
|
||||
with ".jpeg".
|
||||
|
||||
This pattern type is deprecated in favor of @var{glob} and
|
||||
@var{sequence}.
|
||||
@end table
|
||||
|
||||
Default value is @var{sequence}.
|
||||
Default value is @var{glob_sequence}.
|
||||
@item pixel_format
|
||||
Set the pixel format of the images to read. If not specified the pixel
|
||||
format is guessed from the first image file in the sequence.
|
||||
@@ -944,11 +961,7 @@ Fixed key used for handling Audible AAX/AAX+ files. It has been pre-set so shoul
|
||||
specify.
|
||||
|
||||
@item decryption_key
|
||||
Default 16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
|
||||
@item decryption_keys
|
||||
Dictionary of 16-byte key ID => 16-byte key, both in hex, to decrypt files encrypted using ISO Common Encryption
|
||||
(CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
16-byte key, in hex, to decrypt files encrypted using ISO Common Encryption (CENC/AES-128 CTR; ISO/IEC 23001-7).
|
||||
|
||||
@item max_stts_delta
|
||||
Very high sample deltas written in a trak's stts box may occasionally be intended but usually they are written in
|
||||
@@ -1043,11 +1056,6 @@ Set input video frame rate. Default value is 25.
|
||||
@item pixel_format
|
||||
Set the input video pixel format. Default value is @code{yuv420p}.
|
||||
|
||||
@item stride
|
||||
Set frame line size in bytes, only required if there are extra padding.
|
||||
For multiplane formats, @option{stride} is a list of line size for each
|
||||
plane.
|
||||
|
||||
@item video_size
|
||||
Set the input video size. This value must be specified explicitly.
|
||||
@end table
|
||||
@@ -1060,13 +1068,6 @@ the command:
|
||||
ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw
|
||||
@end example
|
||||
|
||||
Read a rawvideo with @command{ffplay}, assuming a pixel format of @code{yuv420p},
|
||||
a video size of @code{1080x1920}, has 8 bytes of padding in each line of Y plane,
|
||||
and 4 bytes of padding with UV plane,
|
||||
@example
|
||||
ffplay -f rawvideo -pixel_format yuv420p -video_size 1080x1920 -stride 1088,544,544 input.raw
|
||||
@end example
|
||||
|
||||
@anchor{rcwtdec}
|
||||
@section rcwt
|
||||
|
||||
@@ -1181,51 +1182,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
-38
@@ -45,7 +45,6 @@ maintained and developed.
|
||||
@end itemize
|
||||
|
||||
All proposed code changes should be submitted for review to
|
||||
@url{https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls, Forgejo} or
|
||||
@url{mailto:ffmpeg-devel@@ffmpeg.org, the development mailing list}, as
|
||||
described in more detail in the @ref{Submitting patches} chapter. The code
|
||||
should comply with the @ref{Development Policy} and follow the @ref{Coding Rules}.
|
||||
@@ -225,25 +224,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,
|
||||
@@ -386,9 +366,6 @@ symbols. If in doubt, just avoid names starting with @code{_} altogether.
|
||||
@item
|
||||
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.
|
||||
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
|
||||
|
||||
@anchor{Development Policy}
|
||||
@@ -488,25 +465,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
|
||||
@@ -755,8 +722,7 @@ and has no lrint()')
|
||||
Also please if you send several patches, send each patch as a separate mail,
|
||||
do not attach several unrelated patches to the same mail.
|
||||
|
||||
Patches should be posted to
|
||||
@uref{https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls, Forgejo} or the
|
||||
Patches should be posted to the
|
||||
@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel}
|
||||
mailing list. Use @code{git send-email} when possible since it will properly
|
||||
send patches without requiring extra care. If you cannot, then send patches
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-138
@@ -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
|
||||
@@ -2000,49 +1996,6 @@ by ":". See the SVT-AV1 encoder user guide for a list of accepted parameters.
|
||||
|
||||
@end table
|
||||
|
||||
@section libsvtjpegxs
|
||||
|
||||
SVT-JPEG-XS encoder wrapper.
|
||||
|
||||
Requires the presence of the SVT-JPEG-XS headers and library during configuration.
|
||||
You need to explicitly configure the build with @code{--enable-libsvtjpegxs}.
|
||||
|
||||
@subsection Options
|
||||
|
||||
@table @option
|
||||
@item decomp_v
|
||||
Set vertical decomposition level
|
||||
@item decomp_h
|
||||
Set horizontal decomposition level
|
||||
|
||||
@item quantization
|
||||
Set the quantization algorithm.
|
||||
@table @samp
|
||||
@item deadzone
|
||||
@item uniform
|
||||
@end table
|
||||
|
||||
@item coding-signs
|
||||
Enable Signs handling strategy
|
||||
@table @samp
|
||||
@item disable
|
||||
@item fast
|
||||
@item full
|
||||
@end table
|
||||
|
||||
@item coding-sigf
|
||||
Enable Significance coding
|
||||
|
||||
@item coding-vpred
|
||||
Enable Vertical Prediction coding
|
||||
@table @samp
|
||||
@item disable
|
||||
@item no_residuals
|
||||
@item no_coeffs
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
@section libjxl
|
||||
|
||||
libjxl JPEG XL encoder wrapper.
|
||||
@@ -3087,10 +3040,6 @@ Quantizer curve compression factor
|
||||
Normally, when forcing a I-frame type, the encoder can select any type
|
||||
of I-frame. This option forces it to choose an IDR-frame.
|
||||
|
||||
@item x265-stats
|
||||
Specify the file name for 2-pass stats. This is set automatically when using
|
||||
the @option{-passlogfile} option.
|
||||
|
||||
@item udu_sei @var{boolean}
|
||||
Import user data unregistered SEI if available into output. Default is 0 (off).
|
||||
|
||||
@@ -3464,97 +3413,12 @@ Maximum quantization parameter for B frame.
|
||||
|
||||
@section MediaFoundation
|
||||
|
||||
The following wrappers for encoders in the MediaFoundation framework are
|
||||
available:
|
||||
|
||||
@itemize
|
||||
@item h264_mf
|
||||
@item hevc_mf
|
||||
@item av1_mf
|
||||
@end itemize
|
||||
|
||||
These support both software and hardware encoding.
|
||||
|
||||
This provides wrappers to encoders (both audio and video) in the
|
||||
MediaFoundation framework. It can access both SW and HW encoders.
|
||||
Video encoders can take input in either of nv12 or yuv420p form
|
||||
(some encoders support both, some support only either - in practice,
|
||||
nv12 is the safer choice, especially among HW encoders).
|
||||
|
||||
Hardware-accelerated encoding requires D3D11, including hardware
|
||||
scaling capabilities through the scale_d3d11 filter.
|
||||
|
||||
To list all available options for the MediaFoundation encoders, use:
|
||||
@command{ffmpeg -h encoder=<encoder>} e.g. @command{ffmpeg -h encoder=h264_mf}
|
||||
|
||||
@subsection Options
|
||||
|
||||
@table @option
|
||||
@item rate_control
|
||||
Select rate control mode. Available modes:
|
||||
|
||||
@table @samp
|
||||
@item default
|
||||
Default mode
|
||||
@item cbr
|
||||
CBR mode
|
||||
@item pc_vbr
|
||||
Peak constrained VBR mode
|
||||
@item u_vbr
|
||||
Unconstrained VBR mode
|
||||
@item quality
|
||||
Quality mode
|
||||
@item ld_vbr
|
||||
Low delay VBR mode (requires Windows 8+)
|
||||
@item g_vbr
|
||||
Global VBR mode (requires Windows 8+)
|
||||
@item gld_vbr
|
||||
Global low delay VBR mode (requires Windows 8+)
|
||||
@end table
|
||||
|
||||
@item scenario
|
||||
Select usage scenario. Available scenarios:
|
||||
|
||||
@table @samp
|
||||
@item default
|
||||
Default scenario
|
||||
@item display_remoting
|
||||
Display remoting scenario
|
||||
@item video_conference
|
||||
Video conference scenario
|
||||
@item archive
|
||||
Archive scenario
|
||||
@item live_streaming
|
||||
Live streaming scenario
|
||||
@item camera_record
|
||||
Camera record scenario
|
||||
@item display_remoting_with_feature_map
|
||||
Display remoting with feature map scenario
|
||||
@end table
|
||||
|
||||
@item quality
|
||||
Set encoding quality (0-100). -1 means default quality.
|
||||
|
||||
@item hw_encoding
|
||||
Force hardware encoding (0-1). Default is 0 (disabled).
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
|
||||
Hardware encoding:
|
||||
@example
|
||||
ffmpeg -i input.mp4 -c:v h264_mf -hw_encoding 1 output.mp4
|
||||
@end example
|
||||
|
||||
Hardware-accelerated decoding with hardware encoding:
|
||||
@example
|
||||
ffmpeg -hwaccel d3d11va -i input.mp4 -c:v h264_mf -hw_encoding 1 output.mp4
|
||||
@end example
|
||||
|
||||
Hardware-accelerated decoding, HW scaling and encoding with quality setting:
|
||||
@example
|
||||
ffmpeg -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -vf scale_d3d11=1920:1080 -c:v hevc_mf -hw_encoding 1 -quality 80 output.mp4
|
||||
@end example
|
||||
|
||||
@section Microsoft RLE
|
||||
|
||||
Microsoft RLE aka MSRLE encoder.
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
* file to be played with ffplay.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavfilter/buffersink.h>
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
* @example decode_filter_video.c
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 600 /* for usleep */
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -36,7 +38,6 @@
|
||||
#include <libavfilter/buffersrc.h>
|
||||
#include <libavutil/mem.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/time.h>
|
||||
|
||||
const char *filter_descr = "scale=78:24,transpose=cclock";
|
||||
/* other way:
|
||||
@@ -194,7 +195,7 @@ static void display_frame(const AVFrame *frame, AVRational time_base)
|
||||
delay = av_rescale_q(frame->pts - last_pts,
|
||||
time_base, AV_TIME_BASE_Q);
|
||||
if (delay > 0 && delay < 1000000)
|
||||
av_usleep(delay);
|
||||
usleep(delay);
|
||||
}
|
||||
last_pts = frame->pts;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -109,7 +109,6 @@ static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
|
||||
ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to copy codec parameters to codec context\n");
|
||||
avcodec_free_context(&dec_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -216,10 +215,8 @@ int main(int argc, char *argv[])
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
video = input_ctx->streams[video_stream];
|
||||
if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) {
|
||||
avcodec_free_context(&decoder_ctx);
|
||||
if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
decoder_ctx->get_format = get_hw_format;
|
||||
|
||||
@@ -233,10 +230,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);
|
||||
|
||||
@@ -351,10 +351,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
setting_number = (argc - 5) / 2;
|
||||
dynamic_setting = av_malloc(setting_number * sizeof(*dynamic_setting));
|
||||
if (!dynamic_setting) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
current_setting_number = 0;
|
||||
for (int i = 0; i < setting_number; i++) {
|
||||
dynamic_setting[i].frame_number = atoi(argv[i*2 + 5]);
|
||||
@@ -430,9 +426,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);
|
||||
|
||||
+18
-38
@@ -42,60 +42,41 @@ targets and variables.
|
||||
|
||||
@chapter Using FATE from your FFmpeg source directory
|
||||
|
||||
If you want to run FATE on your machine, FFmpeg needs to be configured first.
|
||||
You may specify the location of samples during configuration by adding the
|
||||
argument @code{--samples=/path/to/fate-suite}.
|
||||
If you want to run FATE on your machine you need to have the samples
|
||||
in place. You can get the samples via the build target fate-rsync.
|
||||
Use this command from the top-level source directory:
|
||||
|
||||
@example
|
||||
./configure --enable-somelib --samples=/path/to/fate-suite
|
||||
make fate-rsync SAMPLES=fate-suite/
|
||||
make fate SAMPLES=fate-suite/
|
||||
@end example
|
||||
|
||||
After successful configuration, you need to add and/or update the samples in place:
|
||||
The above commands set the samples location by passing a makefile
|
||||
variable via command line. It is also possible to set the samples
|
||||
location at source configuration time by invoking configure with
|
||||
@option{--samples=<path to the samples directory>}. Afterwards you can
|
||||
invoke the makefile targets without setting the @var{SAMPLES} makefile
|
||||
variable. This is illustrated by the following commands:
|
||||
|
||||
@example
|
||||
make fate-rsync
|
||||
@end example
|
||||
|
||||
Now you are ready to run FATE:
|
||||
|
||||
@example
|
||||
make fate
|
||||
@end example
|
||||
|
||||
See @ref{makefile variables} for a list of arguments that can be added.
|
||||
|
||||
If you did not set the samples path during configuration, or if you wish to
|
||||
override it just before starting FATE, you can do so in one of three ways.
|
||||
|
||||
Either by setting a make variable:
|
||||
|
||||
@example
|
||||
make fate-rsync SAMPLES=/path/to/fate-suite
|
||||
make fate SAMPLES=/path/to/fate-suite
|
||||
@end example
|
||||
|
||||
or by setting an environment variable for the current session:
|
||||
|
||||
@example
|
||||
export FATE_SAMPLES=/path/to/fate-suite
|
||||
./configure --samples=fate-suite/
|
||||
make fate-rsync
|
||||
make fate
|
||||
@end example
|
||||
|
||||
or in isolation for a single command by prepending it:
|
||||
Yet another way to tell FATE about the location of the sample
|
||||
directory is by making sure the environment variable FATE_SAMPLES
|
||||
contains the path to your samples directory. This can be achieved
|
||||
by e.g. putting that variable in your shell profile or by setting
|
||||
it in your interactive session.
|
||||
|
||||
@example
|
||||
FATE_SAMPLES=/path/to/fate-suite make fate-rsync
|
||||
FATE_SAMPLES=/path/to/fate-suite make fate
|
||||
FATE_SAMPLES=fate-suite/ make fate
|
||||
@end example
|
||||
|
||||
This variable can also be set in your shell profile to make it permanent.
|
||||
|
||||
@float NOTE
|
||||
Do not put a '~' character in the samples path to indicate a home
|
||||
directory. Because of shell nuances, this will cause FATE to fail.
|
||||
Also, on Windows the path has to be relative to the build path
|
||||
which in this case is the FFmpeg source directory.
|
||||
@end float
|
||||
|
||||
Beware that some assertions are disabled by default, so mind setting
|
||||
@@ -239,7 +220,6 @@ Run the FATE test suite (requires the fate-suite dataset).
|
||||
@end table
|
||||
|
||||
@section Makefile variables
|
||||
@anchor{makefile variables}
|
||||
|
||||
@table @env
|
||||
@item V
|
||||
|
||||
@@ -6,28 +6,21 @@ workdir= # directory in which to do all the work
|
||||
#fate_recv="ssh -T fate@fate.ffmpeg.org" # command to submit report
|
||||
comment= # optional description
|
||||
build_only= # set to "yes" for a compile-only instance that skips tests
|
||||
skip_clean= # set to "yes" to preserve build/install directories
|
||||
ignore_tests=
|
||||
|
||||
# the following are optional and map to configure options
|
||||
arch=
|
||||
cpu=
|
||||
toolchain=
|
||||
cross_prefix=
|
||||
ar=
|
||||
as=
|
||||
cc=
|
||||
cxx=
|
||||
ld=
|
||||
nm=
|
||||
target_os=
|
||||
sysroot=
|
||||
target_exec=
|
||||
target_path=
|
||||
target_samples=
|
||||
extra_cflags=
|
||||
extra_cxxflags=
|
||||
extra_objcflags=
|
||||
extra_ldflags=
|
||||
extra_libs=
|
||||
extra_conf= # extra configure options not covered above
|
||||
|
||||
+13
-37
@@ -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}
|
||||
@@ -1686,7 +1665,6 @@ Force video tag/fourcc. This is an alias for @code{-tag:v}.
|
||||
@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
|
||||
@item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream})
|
||||
@item -force_key_frames[:@var{stream_specifier}] source (@emph{output,per-stream})
|
||||
@item -force_key_frames[:@var{stream_specifier}] scd_metadata (@emph{output,per-stream})
|
||||
|
||||
@var{force_key_frames} can take arguments of the following form:
|
||||
|
||||
@@ -1750,14 +1728,6 @@ the current frame being encoded is marked as a key frame in its source.
|
||||
In cases where this particular source frame has to be dropped,
|
||||
enforce the next available frame to become a key frame instead.
|
||||
|
||||
@item scd_metadata
|
||||
If the argument is @code{scd_metadata}, ffmpeg will force a key frame if
|
||||
the current frame contains a metadata entry with the key @code{lavfi.scd.time}.
|
||||
The metadata can be added by filters like @code{scdet} and @code{scdet_vulkan}.
|
||||
Avoid inserting filters that duplicate frames after @code{scdet}, as this can
|
||||
cause duplicate metadata for multiple frames and repeated insertion of key
|
||||
frames.
|
||||
|
||||
@end table
|
||||
|
||||
Note that forcing too many keyframes is very harmful for the lookahead
|
||||
@@ -2388,19 +2358,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 +2406,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.
|
||||
|
||||
+4
-10
@@ -208,14 +208,6 @@ Vulkan configuration using a list of @var{key}=@var{value} pairs separated by
|
||||
Use HW accelerated decoding. Enable this option will enable vulkan renderer
|
||||
automatically.
|
||||
|
||||
@item -video_bg @var{pattern}
|
||||
Set the video background pattern used for transparent videos. For solid color
|
||||
patterns you can use the color name or color code as specified in the
|
||||
@ref{color syntax,,Color section in the ffmpeg-utils(1) manual,ffmpeg-utils}.
|
||||
You can also use the special @code{tiles} keyword for a checker board style
|
||||
pattern. This is also the default. The @code{none} pattern does rendering
|
||||
without alpha blending effectively ignoring alpha channel.
|
||||
|
||||
@end table
|
||||
|
||||
@section While playing
|
||||
@@ -259,13 +251,15 @@ Pause if the stream is not already paused, step to the next video
|
||||
frame, and pause.
|
||||
|
||||
@item left/right
|
||||
Seek backward/forward by 10 seconds or a custom interval if -seek_interval is set.
|
||||
Seek backward/forward 10 seconds.
|
||||
|
||||
@item down/up
|
||||
Seek backward/forward 1 minute.
|
||||
|
||||
@item page down/page up
|
||||
Seek to previous/next chapter or backward/forward 10 minutes if no chapters.
|
||||
Seek to the previous/next chapter.
|
||||
or if there are no chapters
|
||||
Seek backward/forward 10 minutes.
|
||||
|
||||
@item right mouse click
|
||||
Seek to percentage in file corresponding to fraction of width.
|
||||
|
||||
+1
-13
@@ -117,8 +117,7 @@ ffprobe -show_packets -select_streams v:1 INPUT
|
||||
@end example
|
||||
|
||||
@item -show_data
|
||||
Show payload data, as a hexadecimal and ASCII dump (other formats can be
|
||||
selected using @option{-data_dump_format}). Coupled with
|
||||
Show payload data, as a hexadecimal and ASCII dump. Coupled with
|
||||
@option{-show_packets}, it will dump the packets' data. Coupled with
|
||||
@option{-show_streams}, it will dump the codec extradata.
|
||||
|
||||
@@ -128,11 +127,6 @@ The dump is printed as the "data" field. It may contain newlines.
|
||||
Show a hash of payload data, for packets with @option{-show_packets} and for
|
||||
codec extradata with @option{-show_streams}.
|
||||
|
||||
@item -data_dump_format @var{format}
|
||||
Select a format used for the data dumps enabled with the @option{-show_data}
|
||||
option. The default is @code{xxd} which is a hexdump format compatible with the
|
||||
well-known @command{xxd} program. @code{base64} is also supported.
|
||||
|
||||
@item -show_error
|
||||
Show information about the error found when trying to probe the input.
|
||||
|
||||
@@ -374,12 +368,6 @@ Read @var{input_url}.
|
||||
Write output to @var{output_url}. If not specified, the output is sent
|
||||
to stdout.
|
||||
|
||||
@item -c:@var{media_specifier} @var{codec_name}
|
||||
@itemx -codec:@var{media_specifier} @var{codec_name}
|
||||
Force a specific decoder implementation for the stream identified by
|
||||
@var{media_specifier}, which can assume the values @code{a} (audio),
|
||||
@code{v} (video), @code{s} (subtitle), and @code{d} (data).
|
||||
|
||||
@end table
|
||||
@c man end
|
||||
|
||||
|
||||
@@ -276,7 +276,6 @@
|
||||
<xsd:attribute name="extradata" type="xsd:string" />
|
||||
<xsd:attribute name="extradata_size" type="xsd:int" />
|
||||
<xsd:attribute name="extradata_hash" type="xsd:string" />
|
||||
<xsd:attribute name="mime_codec_string" type="xsd:string" />
|
||||
|
||||
<!-- video attributes -->
|
||||
<xsd:attribute name="width" type="xsd:int"/>
|
||||
@@ -357,7 +356,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>
|
||||
|
||||
@@ -98,7 +98,7 @@ These options are shared amongst the ff* tools.
|
||||
|
||||
@table @option
|
||||
|
||||
@item -L, -license
|
||||
@item -L
|
||||
Show license.
|
||||
|
||||
@item -h, -?, -help, --help [@var{arg}]
|
||||
|
||||
+418
-1012
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -283,14 +250,6 @@ Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the
|
||||
instructions for installing the library.
|
||||
Then pass @code{--enable-libfdk-aac} to configure to enable it.
|
||||
|
||||
@subsection Fraunhofer MPEG-H 3D Audio decoder library
|
||||
|
||||
FFmpeg can make use of the Fraunhofer MPEG-H decoder library for MPEG-H 3DA decoding.
|
||||
|
||||
Go to @url{https://github.com/Fraunhofer-IIS/mpeghdec} and follow the
|
||||
instructions for installing the library.
|
||||
Then pass @code{--enable-libmpeghdec --enable-nonfree} to configure to enable it.
|
||||
|
||||
@subsection LC3 library
|
||||
|
||||
FFmpeg can make use of the Google LC3 library for LC3 decoding & encoding.
|
||||
@@ -336,15 +295,6 @@ Go to @url{https://gitlab.com/AOMediaCodec/SVT-AV1/} and follow the instructions
|
||||
for installing the library. Then pass @code{--enable-libsvtav1} to configure to
|
||||
enable it.
|
||||
|
||||
@section SVT-JPEG-XS
|
||||
|
||||
FFmpeg can make use of the Scalable Video Technology for JPEG-XS library for JPEG-XS
|
||||
decoding and encoding.
|
||||
|
||||
Go to @url{https://github.com/OpenVisualCloud/SVT-JPEG-XS} and follow the instructions
|
||||
for installing the library. Then pass @code{--enable-libsvtjpegxs} to configure to
|
||||
enable it.
|
||||
|
||||
@section TwoLAME
|
||||
|
||||
FFmpeg can make use of the TwoLAME library for MP2 encoding.
|
||||
@@ -861,8 +811,6 @@ following image formats are supported:
|
||||
@tab Progressive JPEG is not supported.
|
||||
@item JPEG 2000 @tab X @tab X
|
||||
@item JPEG-LS @tab X @tab X
|
||||
@item JPEG-XS @tab E @tab E
|
||||
@tab Supported through external library libsvtjpegxs
|
||||
@item LJPEG @tab X @tab
|
||||
@tab Lossless JPEG
|
||||
@item Media 100 @tab @tab X
|
||||
@@ -1328,6 +1276,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
|
||||
@@ -1394,8 +1344,6 @@ following image formats are supported:
|
||||
@item MP3 (MPEG audio layer 3) @tab E @tab IX
|
||||
@tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported
|
||||
@item MPEG-4 Audio Lossless Coding (ALS) @tab @tab X
|
||||
@item MPEG-H 3D Audio @tab @tab E
|
||||
@tab decoding supported through external library libmpeghdec
|
||||
@item MobiClip FastAudio @tab @tab X
|
||||
@item Musepack SV7 @tab @tab X
|
||||
@item Musepack SV8 @tab @tab X
|
||||
|
||||
@@ -4,4 +4,3 @@ ffmpeg-formats mono ./ffmpeg-formats.html
|
||||
ffmpeg-resampler mono ./ffmpeg-resampler.html
|
||||
ffmpeg-scaler mono ./ffmpeg-scaler.html
|
||||
ffmpeg-utils mono ./ffmpeg-utils.html
|
||||
drawvg-reference mono ./drawvg-reference.html
|
||||
|
||||
+1
-22
@@ -24,26 +24,6 @@ Our Main server is hosted at telepoint.bg
|
||||
for more details see: https://www.ffmpeg.org/#thanks_sponsor_0001
|
||||
Nothing runs on our main server directly, instead several VMs run on it.
|
||||
|
||||
Main server security:
|
||||
---------------------
|
||||
Telepoint is one of the largest Bulgarian DC providers with multiple sibling companies offering
|
||||
Internet, SDH, DWDM, peering exchange and hosting. They have multiple DC buildings in Sofia and
|
||||
FFmpeg is hosted in XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. The building is locked down and accessible
|
||||
only with personal key cards that are registered. People who are granted access to a rack have
|
||||
to go through the access center with their ID to get logged and receive a one-time access card
|
||||
that can open the service elevator and only the hall where the destination rack is. All racks are
|
||||
locked, once access is granted to someone they will get a key for the rack for the duration of
|
||||
their visit. There are security cameras everywhere and personnel in the access center 24/7. As for
|
||||
software security, our BIOS and IPMI are protected by password and encrypted connection, and
|
||||
the machines can be accessed only by root administrators with their SSH keys. They're using
|
||||
a Ubuntu LTS release and get regular security updates as they are released. We also get
|
||||
notified by email for various security related events (e.g. failed sudo).
|
||||
|
||||
Side note - Telepoint provides the rack and physical infrastructure, their sibling company called
|
||||
Telehouse which is an ISP provides the connectivity, they are directly connected with
|
||||
over 15 tier-1 service providers and have over 100 PoPs (points of presence)
|
||||
in various cities. You can see more on www.telehouse.bg
|
||||
|
||||
|
||||
ffmpeg.org VM:
|
||||
--------------
|
||||
@@ -52,8 +32,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:
|
||||
|
||||
@@ -341,7 +341,7 @@ recommended.
|
||||
Avoid sending the same message to multiple mailing lists.
|
||||
|
||||
@item
|
||||
Please follow our @url{https://ffmpeg.org/community.html#Code-of-Conduct, Code of Conduct}.
|
||||
Please follow our @url{https://ffmpeg.org/community.html#Code-of-conduct, Code of Conduct}.
|
||||
@end itemize
|
||||
|
||||
@chapter Help
|
||||
|
||||
+5
-212
@@ -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,29 +3951,9 @@ 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.
|
||||
|
||||
@item ts_buffer_size @var{integer}
|
||||
Set the buffer size, in bytes, of underlying protocol.
|
||||
Default value is -1(auto). The UDP auto selects a reasonable value.
|
||||
|
||||
@item whip_flags @var{flags}
|
||||
Possible values:
|
||||
|
||||
@table @samp
|
||||
@item dtls_active
|
||||
The muxer will try to set dtls active role and send the first client hello.
|
||||
@end table
|
||||
|
||||
@item rtp_history @var{integer}
|
||||
Set the number of RTP history items to store.
|
||||
Default value is 512.
|
||||
Default value is 1500.
|
||||
|
||||
@item authorization @var{string}
|
||||
The optional Bearer token for WHIP Authorization.
|
||||
|
||||
@@ -5,7 +5,7 @@ What to optimize:
|
||||
-----------------
|
||||
If you plan to do non-x86 architecture specific optimizations (SIMD normally),
|
||||
then take a look in the x86/ directory, as most important functions are
|
||||
already optimized for x86.
|
||||
already optimized for MMX.
|
||||
|
||||
If you want to do x86 optimizations then you can either try to fine-tune the
|
||||
stuff in the x86 directory or find some other functions in the C source to
|
||||
@@ -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)
|
||||
|
||||
@@ -330,20 +330,4 @@ and for a build with shared libraries
|
||||
./configure --target-os=mingw32 --enable-shared --disable-static --extra-cflags=-mno-cygwin --extra-libs=-mno-cygwin
|
||||
@end example
|
||||
|
||||
@section ARM64EC
|
||||
|
||||
FFmpeg does not intend to support the Windows ARM64EC build configuration;
|
||||
patches for changing the individual libraries for the purposes of ARM64EC will
|
||||
not be accepted.
|
||||
|
||||
It may still be possible to build FFmpeg in this build configuration;
|
||||
such a build may seem to work to some extent. Such a build may have some
|
||||
amounts of ABI inconsistencies though - which we are not willing to fix.
|
||||
|
||||
(Changing aarch64 assembly code to strictly support ARM64EC would require
|
||||
ifdeffing/changing essentially all such assembly code, and would be a
|
||||
huge maintenance burden. Additionally, changing the library ABI
|
||||
surfaces to fix ABI inconsistencies could require extensive and intrusive
|
||||
changes.)
|
||||
|
||||
@bye
|
||||
|
||||
+50
-256
@@ -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
|
||||
@@ -354,17 +352,6 @@ means auto (seekable for normal files, non-seekable for named pipes).
|
||||
Many demuxers handle seekable and non-seekable resources differently,
|
||||
overriding this might speed up opening certain files at the cost of losing some
|
||||
features (e.g. accurate seeking).
|
||||
|
||||
@item pkt_size
|
||||
Set the maximum packet size used for file I/O. A smaller value may reduce
|
||||
memory usage. A higher value may increase throughput especially with networked
|
||||
filesystems.
|
||||
|
||||
For reading, if explicitly set, it overrides the default internal buffer size
|
||||
(32 KB) and limits the maximum amount of data read per operation.
|
||||
|
||||
For writing, this sets the size of each write operation. The default is 256 KB
|
||||
for regular files, 32 KB otherwise.
|
||||
@end table
|
||||
|
||||
@section ftp
|
||||
@@ -419,6 +406,26 @@ Gophers protocol.
|
||||
|
||||
The Gopher protocol with TLS encapsulation.
|
||||
|
||||
@section hls
|
||||
|
||||
Read Apple HTTP Live Streaming compliant segmented stream as
|
||||
a uniform one. The M3U8 playlists describing the segments can be
|
||||
remote HTTP resources or local files, accessed using the standard
|
||||
file protocol.
|
||||
The nested protocol is declared by specifying
|
||||
"+@var{proto}" after the hls URI scheme name, where @var{proto}
|
||||
is either "file" or "http".
|
||||
|
||||
@example
|
||||
hls+http://host/path/to/remote/resource.m3u8
|
||||
hls+file://path/to/local/resource.m3u8
|
||||
@end example
|
||||
|
||||
Using this protocol is discouraged - the hls demuxer should work
|
||||
just as well (if not, please report the issues) and is more complete.
|
||||
To use the hls demuxer instead, simply use the direct URLs to the
|
||||
m3u8 files.
|
||||
|
||||
@section http
|
||||
|
||||
HTTP (Hyper Text Transfer Protocol).
|
||||
@@ -453,30 +460,7 @@ 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).
|
||||
|
||||
@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
|
||||
@option{short_seek_size} to the same value or higher. Doing so allows FFmpeg
|
||||
to reuse a single HTTP connection wherever possible.
|
||||
|
||||
@item initial_request_size
|
||||
Limit the size of initial requests. Similar to @code{request_size}, but only
|
||||
used during initial format parsing. Useful for formats like MXF or MOV that
|
||||
require frequent seeks during header parsing. Lasts until the demuxer makes a
|
||||
read request larger than this size (without a seek in between), after which
|
||||
the implementation will continue using requests as usual. Disabled (set to 0)
|
||||
by default.
|
||||
|
||||
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.
|
||||
Use persistent connections if set to 1, default is 0.
|
||||
|
||||
@item post_data
|
||||
Set custom HTTP post data.
|
||||
@@ -1002,11 +986,6 @@ Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0.
|
||||
|
||||
@emph{Remark: Writing to the socket is currently not optimized to minimize system calls and reduces the efficiency / effect of TCP_NODELAY.}
|
||||
|
||||
@item tcp_keepalive=@var{1|0}
|
||||
Enable the TCP keepalive mechanism to detect dead peers and help maintain long-lived idle connections. Default value is 0.
|
||||
|
||||
Only the basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are not configurable and will use the operating system's default values.
|
||||
|
||||
@end table
|
||||
|
||||
For example to read with @command{ffplay} a multimedia resource named
|
||||
@@ -1178,13 +1157,9 @@ rtp://@var{hostname}[:@var{port}][?@var{options}]
|
||||
@var{port} specifies the RTP port to use.
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
@var{key}=@var{val}.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
|
||||
The list of supported options follows.
|
||||
The following URL options are supported:
|
||||
|
||||
@table @option
|
||||
|
||||
@@ -1194,12 +1169,10 @@ Set the TTL (Time-To-Live) value (for multicast only).
|
||||
@item rtcpport=@var{n}
|
||||
Set the remote RTCP port to @var{n}.
|
||||
|
||||
@item localport, local_rtpport, localrtpport=@var{n}
|
||||
@item localrtpport=@var{n}
|
||||
Set the local RTP port to @var{n}.
|
||||
|
||||
Using the localport option name is deprecated and should not be used.
|
||||
|
||||
@item local_rtcpport, localrtcpport=@var{n}'
|
||||
@item localrtcpport=@var{n}'
|
||||
Set the local RTCP port to @var{n}.
|
||||
|
||||
@item pkt_size=@var{n}
|
||||
@@ -1222,6 +1195,12 @@ List disallowed (blocked) source IP addresses.
|
||||
Send packets to the source address of the latest received packet (if
|
||||
set to 1) or to a default remote address (if set to 0).
|
||||
|
||||
@item localport=@var{n}
|
||||
Set the local RTP port to @var{n}.
|
||||
|
||||
This is a deprecated option. Instead, @option{localrtpport} should be
|
||||
used.
|
||||
|
||||
@item localaddr=@var{addr}
|
||||
Local IP address of a network interface used for sending packets or joining
|
||||
multicast groups.
|
||||
@@ -1555,15 +1534,7 @@ The accepted URL syntax is:
|
||||
sctp://@var{host}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
|
||||
The list of supported options follows.
|
||||
|
||||
The protocol accepts the following options:
|
||||
@table @option
|
||||
@item listen
|
||||
If set to any value, listen for an incoming connection. Outgoing connection is done by default.
|
||||
@@ -1572,67 +1543,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.
|
||||
@@ -1643,13 +1553,18 @@ srt://@var{hostname}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
@var{key}=@var{val}.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
or
|
||||
|
||||
The list of supported options follows.
|
||||
@example
|
||||
@var{options} srt://@var{hostname}:@var{port}
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of '-@var{key} @var{val}'
|
||||
options.
|
||||
|
||||
This protocol accepts the following options.
|
||||
|
||||
@table @option
|
||||
@item connect_timeout=@var{milliseconds}
|
||||
@@ -1921,10 +1836,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}.
|
||||
@@ -2006,11 +1917,7 @@ tcp://@var{hostname}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
@var{key}=@var{val}.
|
||||
|
||||
The list of supported options follows.
|
||||
|
||||
@@ -2065,14 +1972,8 @@ The required syntax for a TLS/SSL url is:
|
||||
tls://@var{hostname}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
|
||||
The list of supported options follows.
|
||||
The following parameters can be set via command line options
|
||||
(or in code via @code{AVOption}s):
|
||||
|
||||
@table @option
|
||||
|
||||
@@ -2083,7 +1984,7 @@ need to be specified for verification to work, but not all libraries and
|
||||
setups have defaults built in.
|
||||
The file must be in OpenSSL PEM format.
|
||||
|
||||
@item tls_verify, verify=@var{1|0}
|
||||
@item tls_verify=@var{1|0}
|
||||
If enabled, try to verify the peer that we are communicating with.
|
||||
Note, if using OpenSSL, this currently only makes sure that the
|
||||
peer certificate is signed by one of the root certificates in the CA
|
||||
@@ -2091,8 +1992,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.
|
||||
@@ -2127,94 +2028,6 @@ To play back a stream from the TLS/SSL server using @command{ffplay}:
|
||||
ffplay tls://@var{hostname}:@var{port}
|
||||
@end example
|
||||
|
||||
@section dtls
|
||||
|
||||
Datagram Transport Layer Security (DTLS)
|
||||
|
||||
The required syntax for a DTLS URL is:
|
||||
@example
|
||||
dtls://@var{hostname}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
|
||||
DTLS shares most options with TLS, but operates over UDP instead of TCP.
|
||||
|
||||
The list of supported options follows.
|
||||
|
||||
@table @option
|
||||
|
||||
@item ca_file, cafile=@var{filename}
|
||||
A file containing certificate authority (CA) root certificates to treat
|
||||
as trusted. If the linked TLS library contains a default this might not
|
||||
need to be specified for verification to work, but not all libraries and
|
||||
setups have defaults built in.
|
||||
The file must be in OpenSSL PEM format.
|
||||
|
||||
@item tls_verify, verify=@var{1|0}
|
||||
If enabled, try to verify the peer that we are communicating with.
|
||||
Note, if using OpenSSL, this currently only makes sure that the
|
||||
peer certificate is signed by one of the root certificates in the CA
|
||||
database, but it does not validate that the certificate actually
|
||||
matches the host name we are trying to connect to.
|
||||
|
||||
This is enabled by default. Verifying the peer requires a CA database,
|
||||
which in some cases has to be provided by the caller.
|
||||
|
||||
@item cert_file, cert=@var{filename}
|
||||
A file containing a certificate to use in the handshake with the peer.
|
||||
(When operating as server, in listen mode, this is more often required
|
||||
by the peer, while client certificates only are mandated in certain
|
||||
setups.)
|
||||
|
||||
@item key_file, key=@var{filename}
|
||||
A file containing the private key for the certificate.
|
||||
|
||||
@item cert_pem=@var{string}
|
||||
Certificate PEM string
|
||||
|
||||
@item key_pem=@var{string}
|
||||
Private key PEM string
|
||||
|
||||
@item listen=@var{1|0}
|
||||
If enabled, listen for connections on the provided port, and assume
|
||||
the server role in the handshake instead of the client role.
|
||||
|
||||
@item mtu=@var{size}
|
||||
Set the Maximum Transmission Unit (MTU) for DTLS packets.
|
||||
|
||||
@item use_srtp=@var{1|0}
|
||||
Enable the use_srtp DTLS extension.
|
||||
This is used in WebRTC applications to establish SRTP encryption keys
|
||||
through the DTLS handshake. Default is disabled.
|
||||
|
||||
@item external_sock=@var{1|0}
|
||||
Use an external socket instead of creating a new one.
|
||||
This option only makes sense to pass when interacting with the code via
|
||||
API, enabling this from CLI will cause immediate failure.
|
||||
Default is disabled.
|
||||
|
||||
@end table
|
||||
|
||||
Example command lines:
|
||||
|
||||
To create a DTLS server:
|
||||
|
||||
@example
|
||||
ffmpeg -listen 1 -i dtls://@var{hostname}:@var{port} @var{output}
|
||||
@end example
|
||||
|
||||
To create a DTLS client and send data to server:
|
||||
|
||||
@example
|
||||
ffmpeg -i @var{input} -f @var{format} dtls://@var{hostname}:@var{port}
|
||||
@end example
|
||||
|
||||
@section udp
|
||||
|
||||
User Datagram Protocol.
|
||||
@@ -2224,12 +2037,7 @@ The required syntax for an UDP URL is:
|
||||
udp://@var{hostname}:@var{port}[?@var{options}]
|
||||
@end example
|
||||
|
||||
@var{options} contains a list of &-separated options of the form
|
||||
@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
|
||||
space) can be used to escape keys and values.
|
||||
|
||||
Options can also can be specified via command line options (or in code via
|
||||
@code{AVOption}s).
|
||||
@var{options} contains a list of &-separated options of the form @var{key}=@var{val}.
|
||||
|
||||
In case threading is enabled on the system, a circular buffer is used
|
||||
to store the incoming data, which allows one to reduce loss of data due to
|
||||
@@ -2268,9 +2076,6 @@ Explicitly allow or disallow reusing UDP sockets.
|
||||
@item ttl=@var{ttl}
|
||||
Set the time to live value (for multicast only).
|
||||
|
||||
@item dscp=@var{dscp}
|
||||
Set the 6-bit DSCP field for outgoing packets.
|
||||
|
||||
@item connect=@var{1|0}
|
||||
Initialize the UDP socket with @code{connect()}. In this case, the
|
||||
destination address can't be changed with ff_udp_set_remote_url later.
|
||||
@@ -2352,17 +2157,6 @@ The following parameters can be set via command line options
|
||||
Timeout in ms.
|
||||
@item listen
|
||||
Create the Unix socket in listening mode.
|
||||
@item type
|
||||
Select socket type.
|
||||
@table @samp
|
||||
@item stream Corresponds to SOCK_STREAM (reliable stream-oriented)
|
||||
@item datagram Corresponds to SOCK_DGRAM (unreliable packet-oriented)
|
||||
@item seqpacket Corresponds to SOCK_SEQPACKET (reliable packet-oriented)
|
||||
@end table
|
||||
@item pkt_size
|
||||
Maximum packet size for packet-oriented sockets (SOCK_DGRAM and
|
||||
SOCK_SEQPACKET). If greater than zero, this value is used as
|
||||
@code{max_packet_size}. Ignored for SOCK_STREAM. Default is @code{0}.
|
||||
@end table
|
||||
|
||||
@section zmq
|
||||
|
||||
+13
-98
@@ -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.
|
||||
@@ -108,10 +68,6 @@ Select full chroma input.
|
||||
|
||||
@item bitexact
|
||||
Enable bitexact output.
|
||||
|
||||
@item unstable
|
||||
Allow the use of experimental new code. May subtly affect the output or even
|
||||
produce wrong results. For testing only.
|
||||
@end table
|
||||
|
||||
@item srcw @var{(API only)}
|
||||
@@ -191,47 +147,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
|
||||
|
||||
+3
-4
@@ -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.
|
||||
|
||||
@@ -63,7 +62,7 @@ This overall approach has a considerable number of benefits:
|
||||
multiple levels of complicated, interwoven format handling code that is
|
||||
legacy swscale.
|
||||
|
||||
2. Because most of the brains lives inside the powerful optimizer, we get
|
||||
2. Because most of the brains lives inside the the powerful optimizer, we get
|
||||
fast paths "for free" for any suitable format conversion, rather than having
|
||||
to enumerate them one by one. SIMD code itself can be written in a very
|
||||
general way and does need to be tied to specific pixel formats - subsequent
|
||||
|
||||
+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:
|
||||
|
||||
|
||||
+1
-2
@@ -5,8 +5,6 @@ OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes)
|
||||
OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes)
|
||||
OBJS-$(HAVE_SVE) += $(SVE-OBJS) $(SVE-OBJS-yes)
|
||||
OBJS-$(HAVE_SVE2) += $(SVE2-OBJS) $(SVE2-OBJS-yes)
|
||||
OBJS-$(HAVE_SME) += $(SME-OBJS) $(SME-OBJS-yes)
|
||||
OBJS-$(HAVE_SME2) += $(SME2-OBJS) $(SME2-OBJS-yes)
|
||||
|
||||
OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes)
|
||||
OBJS-$(HAVE_MIPSDSP) += $(MIPSDSP-OBJS) $(MIPSDSP-OBJS-yes)
|
||||
@@ -25,4 +23,5 @@ OBJS-$(HAVE_RV_ZVBB) += $(RVVB-OBJS) $(RVVB-OBJS-yes)
|
||||
|
||||
OBJS-$(HAVE_SIMD128) += $(SIMD128-OBJS) $(SIMD128-OBJS-yes)
|
||||
|
||||
OBJS-$(HAVE_MMX) += $(MMX-OBJS) $(MMX-OBJS-yes)
|
||||
OBJS-$(HAVE_X86ASM) += $(X86ASM-OBJS) $(X86ASM-OBJS-yes)
|
||||
|
||||
+51
-55
@@ -2,32 +2,31 @@
|
||||
# common bits used by all libraries
|
||||
#
|
||||
|
||||
DEFAULT_X86ASMD=.dbg
|
||||
|
||||
ifeq ($(DBG),1)
|
||||
X86ASMD=$(DEFAULT_X86ASMD)
|
||||
else
|
||||
X86ASMD=
|
||||
endif
|
||||
|
||||
ifndef SUBDIR
|
||||
|
||||
LINK = $(LD) $(1)
|
||||
|
||||
ifeq ($(LD),$(CC))
|
||||
ifneq ($(CXX),)
|
||||
LDXX := $(CXX)
|
||||
LINK = $(if $(filter -lstdc++,$(1)),$(LDXX) $(filter-out -lstdc++,$(1)),$(LD) $(1))
|
||||
endif
|
||||
endif
|
||||
|
||||
BIN2CEXE = ffbuild/bin2c$(HOSTEXESUF)
|
||||
BIN2C = $(BIN2CEXE)
|
||||
|
||||
ifndef V
|
||||
Q = @
|
||||
ECHO = printf "$(1)\t%s\n" $(2)
|
||||
BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD LDXX STRIP CP WINDRES GLSLC NVCC BIN2C METALCC METALLIB
|
||||
SILENT = DEPCC DEPCXX DEPHOSTCC DEPAS DEPX86ASM RANLIB RM
|
||||
BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD STRIP CP WINDRES NVCC BIN2C METALCC METALLIB
|
||||
SILENT = DEPCC DEPHOSTCC DEPAS DEPX86ASM RANLIB RM
|
||||
|
||||
MSG = $@
|
||||
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.
|
||||
@@ -43,7 +42,7 @@ OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS)
|
||||
ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
|
||||
# Use PREPEND here so that later (target-dependent) additions to CPPFLAGS
|
||||
# end up in CXXFLAGS.
|
||||
$(call PREPEND,CXXFLAGS, CPPFLAGS)
|
||||
$(call PREPEND,CXXFLAGS, CPPFLAGS CFLAGS)
|
||||
X86ASMFLAGS += $(IFLAGS:%=%/) -I$(<D)/ -Pconfig.asm
|
||||
|
||||
HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
|
||||
@@ -60,7 +59,6 @@ COMPILE_S = $(call COMPILE,AS)
|
||||
COMPILE_M = $(call COMPILE,OBJCC)
|
||||
COMPILE_X86ASM = $(call COMPILE,X86ASM)
|
||||
COMPILE_HOSTC = $(call COMPILE,HOSTCC)
|
||||
COMPILE_GLSLC = $(call COMPILE,GLSLC)
|
||||
COMPILE_NVCC = $(call COMPILE,NVCC)
|
||||
COMPILE_MMI = $(call COMPILE,CC,MMIFLAGS)
|
||||
COMPILE_MSA = $(call COMPILE,CC,MSAFLAGS)
|
||||
@@ -97,6 +95,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) $@)
|
||||
@@ -113,26 +115,6 @@ COMPILE_LASX = $(call COMPILE,CC,LASXFLAGS)
|
||||
$(BIN2CEXE): ffbuild/bin2c_host.o
|
||||
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS)
|
||||
|
||||
RUN_BIN2C = $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
RUN_GZIP = $(M)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/ $$//' > $@
|
||||
%.gz: TAG = GZIP
|
||||
%.min: TAG = MINIFY
|
||||
|
||||
%.spv: %.glsl
|
||||
$(COMPILE_GLSLC)
|
||||
|
||||
ifdef CONFIG_SHADER_COMPRESSION
|
||||
%.spv.gz: %.spv
|
||||
$(RUN_GZIP)
|
||||
|
||||
%.spv.c: %.spv.gz $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
else
|
||||
%.spv.c: %.spv $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
endif
|
||||
|
||||
%.metal.air: %.metal
|
||||
$(METALCC) $< -o $@
|
||||
|
||||
@@ -140,52 +122,67 @@ endif
|
||||
$(METALLIB) --split-module-without-linking $< -o $@
|
||||
|
||||
%.metallib.c: %.metallib $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
|
||||
%.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h
|
||||
$(COMPILE_NVCC)
|
||||
|
||||
ifdef CONFIG_SHADER_COMPRESSION
|
||||
ifdef CONFIG_PTX_COMPRESSION
|
||||
%.ptx.gz: TAG = GZIP
|
||||
%.ptx.gz: %.ptx
|
||||
$(RUN_GZIP)
|
||||
$(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
|
||||
|
||||
%.ptx.c: %.ptx.gz $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
else
|
||||
%.ptx.c: %.ptx $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
endif
|
||||
|
||||
# 1) Preprocess CSS to a minified version
|
||||
%.css.min: TAG = SED
|
||||
%.css.min: %.css
|
||||
$(RUN_MINIFY)
|
||||
$(M)sed 's!/\\*.*\\*/!!g' $< \
|
||||
| tr '\n' ' ' \
|
||||
| tr -s ' ' \
|
||||
| sed 's/^ //; s/ $$//' \
|
||||
> $@
|
||||
|
||||
ifdef CONFIG_RESOURCE_COMPRESSION
|
||||
|
||||
# 2) Gzip the minified CSS
|
||||
%.css.min.gz: TAG = GZIP
|
||||
%.css.min.gz: %.css.min
|
||||
$(RUN_GZIP)
|
||||
$(M)gzip -nc9 $< > $@
|
||||
|
||||
# 3) Convert the gzipped CSS to a .c array
|
||||
%.css.c: %.css.min.gz $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
|
||||
# 4) Gzip the HTML file (no minification needed)
|
||||
%.html.gz: TAG = GZIP
|
||||
%.html.gz: %.html
|
||||
$(RUN_GZIP)
|
||||
$(M)gzip -nc9 $< > $@
|
||||
|
||||
# 5) Convert the gzipped HTML to a .c array
|
||||
%.html.c: %.html.gz $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
|
||||
else # NO COMPRESSION
|
||||
|
||||
# 2) Convert the minified CSS to a .c array
|
||||
%.css.c: %.css.min $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
|
||||
# 3) Convert the plain HTML to a .c array
|
||||
%.html.c: %.html $(BIN2CEXE)
|
||||
$(RUN_BIN2C)
|
||||
$(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@)))
|
||||
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 +202,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 +210,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))
|
||||
@@ -233,11 +228,12 @@ ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)
|
||||
SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
|
||||
SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
|
||||
HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
|
||||
SPVOBJS = $(filter %.spv.o,$(OBJS))
|
||||
PTXOBJS = $(filter %.ptx.o,$(OBJS))
|
||||
RESOURCEOBJS = $(filter %.css.o %.html.o,$(OBJS))
|
||||
$(HOBJS): CCFLAGS += $(CFLAGS_HEADERS)
|
||||
checkheaders: $(HOBJS)
|
||||
.SECONDARY: $(HOBJS:.o=.c) $(SPVOBJS:.o=.c) $(SPVOBJS:.o=.gz) $(SPVOBJS:.o=) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=)
|
||||
.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=) $(RESOURCEOBJS:.o=.c) $(RESOURCEOBJS:%.css.o=%.css.min) $(RESOURCEOBJS:%.css.o=%.css.min.gz) $(RESOURCEOBJS:%.html.o=%.html.gz) $(RESOURCEOBJS:.o=)
|
||||
|
||||
alltools: $(TOOLS)
|
||||
|
||||
$(HOSTOBJS): %.o: %.c
|
||||
@@ -256,14 +252,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 *.ver *.version *.html.gz *.html.c *.css.gz *.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)) $(OBJS:.o=$(DEFAULT_X86ASMD).d)
|
||||
|
||||
+9
-32
@@ -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,14 +51,12 @@ install-libs-$(CONFIG_SHARED): install-lib$(NAME)-shared
|
||||
|
||||
define RULES
|
||||
$(TOOLS): THISLIB = $(FULLNAME:%=$(LD_LIB))
|
||||
$(TESTPROGS) $(DEVPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
|
||||
$(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
|
||||
|
||||
$(NAME)LINK_EXE_ARGS = $(LDFLAGS) $(LDEXEFLAGS)
|
||||
$(NAME)LINK_SO_ARGS = $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS)
|
||||
$(NAME)LINK_EXTRA = $(FFEXTRALIBS)
|
||||
$(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME)
|
||||
|
||||
$(DEVPROGS) $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
|
||||
$$(call LINK,$$(call $(NAME)LINK_EXE_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $$(call $(NAME)LINK_EXTRA) $$(EXTRALIBS-$$(*F)) $$(ELIBS))
|
||||
$(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
|
||||
$$(LD) $(LDFLAGS) $(LDEXEFLAGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $(FFEXTRALIBS) $$(EXTRALIBS-$$(*F)) $$(ELIBS)
|
||||
|
||||
$(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h $(SUBDIR)version_major.h | $(SUBDIR)
|
||||
$$(M) $$(SRC_PATH)/ffbuild/libversion.sh $(NAME) $$^ > $$@
|
||||
@@ -86,20 +71,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))
|
||||
$$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) @$$@.objs $(FFEXTRALIBS)
|
||||
else
|
||||
$$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(call $(NAME)LINK_EXTRA))
|
||||
$$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
|
||||
endif
|
||||
$(Q)$(SLIB_EXTRA_CMD)
|
||||
$(SLIB_EXTRA_CMD)
|
||||
-$(RM) $$@.objs
|
||||
|
||||
ifdef SUBDIR
|
||||
@@ -113,9 +92,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 +130,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)
|
||||
|
||||
@@ -36,7 +36,6 @@ OBJS-ffmpeg += \
|
||||
fftools/textformat/tw_buffer.o \
|
||||
fftools/textformat/tw_stdout.o \
|
||||
$(OBJS-resman) \
|
||||
$(RESOBJS) \
|
||||
|
||||
OBJS-ffprobe += \
|
||||
fftools/textformat/avtextformat.o \
|
||||
@@ -51,7 +50,6 @@ OBJS-ffprobe += \
|
||||
fftools/textformat/tw_buffer.o \
|
||||
fftools/textformat/tw_stdout.o \
|
||||
|
||||
OBJS-ffmpeg += $(COMPAT_OBJS:%=compat/%)
|
||||
OBJS-ffplay += fftools/ffplay_renderer.o
|
||||
|
||||
define DOFFTOOL
|
||||
|
||||
+6
-101
@@ -263,7 +263,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
arg_allocated = read_file_to_string(arg);
|
||||
arg_allocated = file_read(arg);
|
||||
if (!arg_allocated) {
|
||||
av_log(NULL, AV_LOG_FATAL,
|
||||
"Error reading the value for option '%s' from file: %s\n",
|
||||
@@ -275,7 +275,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
|
||||
}
|
||||
|
||||
if (po->flags & OPT_FLAG_SPEC) {
|
||||
const char *p = strchr(opt, ':');
|
||||
char *p = strchr(opt, ':');
|
||||
char *str;
|
||||
|
||||
sol = dst;
|
||||
@@ -962,7 +962,8 @@ FILE *get_preset_file(char *filename, size_t filename_size,
|
||||
datadir, desired_size, sizeof *datadir);
|
||||
if (new_datadir) {
|
||||
datadir = new_datadir;
|
||||
strcpy(datadir + datadir_len, "/ffpresets");
|
||||
datadir[datadir_len] = 0;
|
||||
strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len);
|
||||
base[2] = datadir;
|
||||
}
|
||||
}
|
||||
@@ -1267,7 +1268,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)
|
||||
@@ -1349,77 +1350,6 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx)
|
||||
{
|
||||
int start_stream_group = 0, nb_stream_groups;
|
||||
int nb_matched = 0;
|
||||
|
||||
if (ss->idx >= 0)
|
||||
return 0;
|
||||
|
||||
switch (ss->stream_list) {
|
||||
case STREAM_LIST_STREAM_ID:
|
||||
case STREAM_LIST_ALL:
|
||||
case STREAM_LIST_PROGRAM:
|
||||
return 0;
|
||||
case STREAM_LIST_GROUP_ID:
|
||||
// <n-th> stream with given ID makes no sense and should be impossible to request
|
||||
av_assert0(ss->idx < 0);
|
||||
// return early if we know for sure the stream does not match
|
||||
if (stg->id != ss->list_id)
|
||||
return 0;
|
||||
start_stream_group = stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
case STREAM_LIST_GROUP_IDX:
|
||||
start_stream_group = ss->list_id >= 0 ? 0 : stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
for (int i = start_stream_group; i < nb_stream_groups; i++) {
|
||||
const AVStreamGroup *candidate = s->stream_groups[i];
|
||||
|
||||
if (ss->meta_key) {
|
||||
const AVDictionaryEntry *tag = av_dict_get(candidate->metadata,
|
||||
ss->meta_key, NULL, 0);
|
||||
|
||||
if (!tag)
|
||||
continue;
|
||||
if (ss->meta_val && strcmp(tag->value, ss->meta_val))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ss->usable_only) {
|
||||
switch (candidate->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
|
||||
const AVStreamGroupTileGrid *tg = candidate->params.tile_grid;
|
||||
if (!tg->coded_width || !tg->coded_height || !tg->nb_tiles ||
|
||||
!tg->width || !tg->height || !tg->nb_tiles)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ss->disposition &&
|
||||
(candidate->disposition & ss->disposition) != ss->disposition)
|
||||
continue;
|
||||
|
||||
if (stg == candidate)
|
||||
return ss->list_id < 0 || ss->list_id == nb_matched;
|
||||
|
||||
nb_matched++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id,
|
||||
AVFormatContext *s, AVStream *st, const AVCodec *codec,
|
||||
AVDictionary **dst, AVDictionary **opts_used)
|
||||
@@ -1568,7 +1498,7 @@ double get_rotation(const int32_t *displaymatrix)
|
||||
}
|
||||
|
||||
/* read file contents into a string */
|
||||
char *read_file_to_string(const char *filename)
|
||||
char *file_read(const char *filename)
|
||||
{
|
||||
AVIOContext *pb = NULL;
|
||||
int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
|
||||
@@ -1612,28 +1542,3 @@ int check_avoptions(AVDictionary *m)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_dictionary(void *ctx, const AVDictionary *m,
|
||||
const char *name, const char *indent,
|
||||
int log_level)
|
||||
{
|
||||
const AVDictionaryEntry *tag = NULL;
|
||||
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
av_log(ctx, log_level, "%s%s:\n", indent, name);
|
||||
while ((tag = av_dict_iterate(m, tag))) {
|
||||
const char *p = tag->value;
|
||||
av_log(ctx, log_level, "%s %-16s: ", indent, tag->key);
|
||||
while (*p) {
|
||||
size_t len = strcspn(p, "\x8\xa\xb\xc\xd");
|
||||
av_log(ctx, log_level, "%.*s", (int)(FFMIN(255, len)), p);
|
||||
p += len;
|
||||
if (*p == 0xd) av_log(ctx, log_level, " ");
|
||||
if (*p == 0xa) av_log(ctx, log_level, "\n%s %-16s: ", indent, "");
|
||||
if (*p) p++;
|
||||
}
|
||||
av_log(ctx, log_level, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-13
@@ -158,10 +158,6 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStream *st,
|
||||
void *logctx);
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx);
|
||||
|
||||
void stream_specifier_uninit(StreamSpecifier *ss);
|
||||
|
||||
typedef struct SpecifierOpt {
|
||||
@@ -539,7 +535,7 @@ void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);
|
||||
double get_rotation(const int32_t *displaymatrix);
|
||||
|
||||
/* read file contents into a string */
|
||||
char *read_file_to_string(const char *filename);
|
||||
char *file_read(const char *filename);
|
||||
|
||||
/* Remove keys in dictionary b from dictionary a */
|
||||
void remove_avoptions(AVDictionary **a, AVDictionary *b);
|
||||
@@ -549,12 +545,4 @@ int check_avoptions(AVDictionary *m);
|
||||
|
||||
int cmdutils_isalnum(char c);
|
||||
|
||||
/**
|
||||
* This does the same as libavformat/dump.c corresponding function
|
||||
* and should probably be kept in sync when the other one changes.
|
||||
*/
|
||||
void dump_dictionary(void *ctx, const AVDictionary *m,
|
||||
const char *name, const char *indent,
|
||||
int log_level);
|
||||
|
||||
#endif /* FFTOOLS_CMDUTILS_H */
|
||||
|
||||
+1
-32
@@ -78,9 +78,6 @@
|
||||
#include "libavdevice/avdevice.h"
|
||||
|
||||
#include "cmdutils.h"
|
||||
#if CONFIG_MEDIACODEC
|
||||
#include "compat/android/binder.h"
|
||||
#endif
|
||||
#include "ffmpeg.h"
|
||||
#include "ffmpeg_sched.h"
|
||||
#include "ffmpeg_utils.h"
|
||||
@@ -216,16 +213,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) {
|
||||
@@ -263,6 +250,7 @@ void term_init(void)
|
||||
/* read a key without blocking */
|
||||
static int read_key(void)
|
||||
{
|
||||
unsigned char ch;
|
||||
#if HAVE_TERMIOS_H
|
||||
int n = 1;
|
||||
struct timeval tv;
|
||||
@@ -274,7 +262,6 @@ static int read_key(void)
|
||||
tv.tv_usec = 0;
|
||||
n = select(1, &rfds, NULL, NULL, &tv);
|
||||
if (n > 0) {
|
||||
unsigned char ch;
|
||||
n = read(0, &ch, 1);
|
||||
if (n == 1)
|
||||
return ch;
|
||||
@@ -299,7 +286,6 @@ static int read_key(void)
|
||||
}
|
||||
//Read it
|
||||
if(nchars != 0) {
|
||||
unsigned char ch;
|
||||
if (read(0, &ch, 1) == 1)
|
||||
return ch;
|
||||
return 0;
|
||||
@@ -414,7 +400,6 @@ static void frame_data_free(void *opaque, uint8_t *data)
|
||||
{
|
||||
FrameData *fd = (FrameData *)data;
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
avcodec_parameters_free(&fd->par_enc);
|
||||
|
||||
av_free(data);
|
||||
@@ -444,8 +429,6 @@ static int frame_data_ensure(AVBufferRef **dst, int writable)
|
||||
|
||||
memcpy(fd, fd_src, sizeof(*fd));
|
||||
fd->par_enc = NULL;
|
||||
fd->side_data = NULL;
|
||||
fd->nb_side_data = 0;
|
||||
|
||||
if (fd_src->par_enc) {
|
||||
int ret = 0;
|
||||
@@ -461,16 +444,6 @@ static int frame_data_ensure(AVBufferRef **dst, int writable)
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_src->nb_side_data) {
|
||||
int ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
fd_src->side_data, fd_src->nb_side_data, 0);
|
||||
if (ret < 0) {
|
||||
av_buffer_unref(dst);
|
||||
av_buffer_unref(&src);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
av_buffer_unref(&src);
|
||||
} else {
|
||||
fd->dec.frame_num = UINT64_MAX;
|
||||
@@ -1033,10 +1006,6 @@ int main(int argc, char **argv)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#if CONFIG_MEDIACODEC
|
||||
android_binder_threadpool_init_if_required();
|
||||
#endif
|
||||
|
||||
current_time = ti = get_benchmark_time_stamps();
|
||||
ret = transcode(sch);
|
||||
if (ret >= 0 && do_benchmark) {
|
||||
|
||||
+38
-62
@@ -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 {
|
||||
@@ -123,7 +136,6 @@ typedef struct StreamMap {
|
||||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||
int file_index;
|
||||
int stream_index;
|
||||
int group_index;
|
||||
char *linklabel; /* name of an output link, for mapping lavfi outputs */
|
||||
|
||||
ViewSpecifier vs;
|
||||
@@ -205,17 +217,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;
|
||||
@@ -241,8 +257,6 @@ typedef struct OptionsContext {
|
||||
SpecifierOptList enc_stats_pre_fmt;
|
||||
SpecifierOptList enc_stats_post_fmt;
|
||||
SpecifierOptList mux_stats_fmt;
|
||||
|
||||
int depth;
|
||||
} OptionsContext;
|
||||
|
||||
enum IFilterFlags {
|
||||
@@ -285,8 +299,6 @@ enum OFilterFlags {
|
||||
// produce 24-bit audio
|
||||
OFILTER_FLAG_AUDIO_24BIT = (1 << 1),
|
||||
OFILTER_FLAG_AUTOSCALE = (1 << 2),
|
||||
OFILTER_FLAG_AUTOROTATE = (1 << 3),
|
||||
OFILTER_FLAG_CROP = (1 << 4),
|
||||
};
|
||||
|
||||
typedef struct OutputFilterOptions {
|
||||
@@ -318,12 +330,6 @@ typedef struct OutputFilterOptions {
|
||||
int height;
|
||||
enum AVColorSpace color_space;
|
||||
enum AVColorRange color_range;
|
||||
enum AVAlphaMode alpha_mode;
|
||||
|
||||
unsigned crop_top;
|
||||
unsigned crop_bottom;
|
||||
unsigned crop_left;
|
||||
unsigned crop_right;
|
||||
|
||||
enum VideoSyncMethod vsync_method;
|
||||
AVRational frame_rate;
|
||||
@@ -332,19 +338,12 @@ typedef struct OutputFilterOptions {
|
||||
int sample_rate;
|
||||
AVChannelLayout ch_layout;
|
||||
|
||||
union {
|
||||
const enum AVPixelFormat *pix_fmts;
|
||||
const enum AVSampleFormat *sample_fmts;
|
||||
};
|
||||
const int *formats;
|
||||
const int *sample_rates;
|
||||
const AVChannelLayout *ch_layouts;
|
||||
const AVRational *frame_rates;
|
||||
const enum AVColorSpace *color_spaces;
|
||||
const enum AVColorRange *color_ranges;
|
||||
const enum AVAlphaMode *alpha_modes;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
|
||||
// for simple filtergraphs only, view specifier passed
|
||||
// along to the decoder
|
||||
@@ -401,11 +400,6 @@ typedef struct FilterGraph {
|
||||
OutputFilter **outputs;
|
||||
int nb_outputs;
|
||||
|
||||
// true when the filtergraph is created internally for
|
||||
// purposes like stream group merging. Meant to be freed
|
||||
// if unbound.
|
||||
int is_internal;
|
||||
|
||||
const char *graph_desc;
|
||||
struct AVBPrint graph_print_buf;
|
||||
} FilterGraph;
|
||||
@@ -417,6 +411,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),
|
||||
@@ -449,7 +446,7 @@ typedef struct Decoder {
|
||||
|
||||
enum AVMediaType type;
|
||||
|
||||
uint8_t *subtitle_header;
|
||||
const uint8_t *subtitle_header;
|
||||
int subtitle_header_size;
|
||||
|
||||
// number of frames/samples retrieved from the decoder
|
||||
@@ -480,6 +477,9 @@ typedef struct InputStream {
|
||||
|
||||
/* framerate forced with -r */
|
||||
AVRational framerate;
|
||||
#if FFMPEG_OPT_TOP
|
||||
int top_field_first;
|
||||
#endif
|
||||
|
||||
int fix_sub_duration;
|
||||
|
||||
@@ -489,18 +489,6 @@ typedef struct InputStream {
|
||||
int nb_filters;
|
||||
} InputStream;
|
||||
|
||||
typedef struct InputStreamGroup {
|
||||
const AVClass *class;
|
||||
|
||||
/* parent source */
|
||||
struct InputFile *file;
|
||||
|
||||
int index;
|
||||
|
||||
FilterGraph *fg;
|
||||
AVStreamGroup *stg;
|
||||
} InputStreamGroup;
|
||||
|
||||
typedef struct InputFile {
|
||||
const AVClass *class;
|
||||
|
||||
@@ -522,10 +510,6 @@ typedef struct InputFile {
|
||||
* if new streams appear dynamically during demuxing */
|
||||
InputStream **streams;
|
||||
int nb_streams;
|
||||
|
||||
/* stream groups that ffmpeg is aware of; */
|
||||
InputStreamGroup **stream_groups;
|
||||
int nb_stream_groups;
|
||||
} InputFile;
|
||||
|
||||
enum forced_keyframes_const {
|
||||
@@ -581,8 +565,9 @@ typedef struct EncStats {
|
||||
|
||||
enum {
|
||||
KF_FORCE_SOURCE = 1,
|
||||
// force keyframe if lavfi.scd.time metadata is set
|
||||
KF_FORCE_SCD_METADATA = 3,
|
||||
#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
|
||||
KF_FORCE_SOURCE_NO_DROP = 2,
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct KeyframeForceCtx {
|
||||
@@ -637,6 +622,10 @@ typedef struct OutputStream {
|
||||
|
||||
Encoder *enc;
|
||||
|
||||
/* video only */
|
||||
#if FFMPEG_OPT_TOP
|
||||
int top_field_first;
|
||||
#endif
|
||||
int bitexact;
|
||||
int bits_per_raw_sample;
|
||||
|
||||
@@ -707,9 +696,6 @@ typedef struct FrameData {
|
||||
int64_t wallclock[LATENCY_PROBE_NB];
|
||||
|
||||
AVCodecParameters *par_enc;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
} FrameData;
|
||||
|
||||
extern InputFile **input_files;
|
||||
@@ -783,12 +769,12 @@ 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, int *vsync_var, int file_idx, int st_idx, int is_global);
|
||||
|
||||
int filtergraph_is_simple(const FilterGraph *fg);
|
||||
int fg_create_simple(FilterGraph **pfg,
|
||||
InputStream *ist,
|
||||
char **graph_desc,
|
||||
char *graph_desc,
|
||||
Scheduler *sch, unsigned sched_idx_enc,
|
||||
const OutputFilterOptions *opts);
|
||||
int fg_finalise_bindings(void);
|
||||
@@ -811,11 +797,10 @@ int ofilter_bind_enc(OutputFilter *ofilter,
|
||||
/**
|
||||
* Create a new filtergraph in the global filtergraph list.
|
||||
*
|
||||
* @param graph_desc Pointer to graph description; an av_malloc()ed string, filtergraph
|
||||
* @param graph_desc Graph description; an av_malloc()ed string, filtergraph
|
||||
* takes ownership of it.
|
||||
*/
|
||||
int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
const OutputFilterOptions *opts);
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch);
|
||||
|
||||
void fg_free(FilterGraph **pfg);
|
||||
|
||||
@@ -942,15 +927,6 @@ void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
|
||||
void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStream *st, double *out);
|
||||
|
||||
void opt_match_per_stream_group_str(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, const char **out);
|
||||
void opt_match_per_stream_group_int(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int *out);
|
||||
void opt_match_per_stream_group_int64(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int64_t *out);
|
||||
void opt_match_per_stream_group_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, double *out);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs);
|
||||
|
||||
int muxer_thread(void *arg);
|
||||
|
||||
+11
-18
@@ -136,8 +136,6 @@ void dec_free(Decoder **pdec)
|
||||
av_frame_free(&dp->sub_prev[i]);
|
||||
av_frame_free(&dp->sub_heartbeat);
|
||||
|
||||
av_freep(&dp->dec.subtitle_header);
|
||||
|
||||
av_freep(&dp->parent_name);
|
||||
|
||||
av_freep(&dp->views_requested);
|
||||
@@ -387,6 +385,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)
|
||||
@@ -739,14 +744,11 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame)
|
||||
while (1) {
|
||||
FrameData *fd;
|
||||
unsigned outputs_mask = 1;
|
||||
unsigned flags = 0;
|
||||
if (!dp->dec.frames_decoded)
|
||||
flags |= AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS;
|
||||
|
||||
av_frame_unref(frame);
|
||||
|
||||
update_benchmark(NULL);
|
||||
ret = avcodec_receive_frame_flags(dec, frame, flags);
|
||||
ret = avcodec_receive_frame(dec, frame);
|
||||
update_benchmark("decode_%s %s", type_desc, dp->parent_name);
|
||||
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
@@ -1005,7 +1007,7 @@ static int decoder_thread(void *arg)
|
||||
ret = 0;
|
||||
|
||||
err_rate = (dp->dec.frames_decoded || dp->dec.decode_errors) ?
|
||||
(float)dp->dec.decode_errors / (dp->dec.frames_decoded + dp->dec.decode_errors) : 0.f;
|
||||
dp->dec.decode_errors / (dp->dec.frames_decoded + dp->dec.decode_errors) : 0.f;
|
||||
if (err_rate > max_error_rate) {
|
||||
av_log(dp, AV_LOG_FATAL, "Decode error rate %g exceeds maximum %g\n",
|
||||
err_rate, max_error_rate);
|
||||
@@ -1016,7 +1018,6 @@ static int decoder_thread(void *arg)
|
||||
|
||||
finish:
|
||||
dec_thread_uninit(&dt);
|
||||
avcodec_free_context(&dp->dec_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1616,15 +1617,8 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts,
|
||||
dp->dec_ctx->extra_hw_frames = extra_frames;
|
||||
}
|
||||
|
||||
if (dp->dec_ctx->subtitle_header) {
|
||||
/* ASS code assumes this buffer is null terminated so add extra byte. */
|
||||
dp->dec.subtitle_header = av_mallocz(dp->dec_ctx->subtitle_header_size + 1);
|
||||
if (!dp->dec.subtitle_header)
|
||||
return AVERROR(ENOMEM);
|
||||
memcpy(dp->dec.subtitle_header, dp->dec_ctx->subtitle_header,
|
||||
dp->dec_ctx->subtitle_header_size);
|
||||
dp->dec.subtitle_header_size = dp->dec_ctx->subtitle_header_size;
|
||||
}
|
||||
dp->dec.subtitle_header = dp->dec_ctx->subtitle_header;
|
||||
dp->dec.subtitle_header_size = dp->dec_ctx->subtitle_header_size;
|
||||
|
||||
if (param_out) {
|
||||
if (dp->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
@@ -1641,7 +1635,6 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts,
|
||||
param_out->sample_aspect_ratio = dp->dec_ctx->sample_aspect_ratio;
|
||||
param_out->colorspace = dp->dec_ctx->colorspace;
|
||||
param_out->color_range = dp->dec_ctx->color_range;
|
||||
param_out->alpha_mode = dp->dec_ctx->alpha_mode;
|
||||
}
|
||||
|
||||
av_frame_side_data_free(¶m_out->side_data, ¶m_out->nb_side_data);
|
||||
|
||||
+51
-428
@@ -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;
|
||||
|
||||
|
||||
@@ -99,15 +96,14 @@ typedef struct DemuxStream {
|
||||
uint64_t nb_packets;
|
||||
// combined size of all the packets read
|
||||
uint64_t data_size;
|
||||
// latest wallclock time at which packet reading resumed after a stall - used for readrate
|
||||
int64_t resume_wc;
|
||||
// timestamp of first packet sent after the latest stall - used for readrate
|
||||
int64_t resume_pts;
|
||||
// measure of how far behind packet reading is against spceified readrate
|
||||
int64_t lag;
|
||||
} DemuxStream;
|
||||
|
||||
typedef struct DemuxStreamGroup {
|
||||
InputStreamGroup istg;
|
||||
|
||||
// name used for logging
|
||||
char log_name[32];
|
||||
} DemuxStreamGroup;
|
||||
|
||||
typedef struct Demuxer {
|
||||
InputFile f;
|
||||
|
||||
@@ -141,13 +137,6 @@ typedef struct Demuxer {
|
||||
double readrate_initial_burst;
|
||||
float readrate_catchup;
|
||||
|
||||
// latest wallclock time at which packet reading resumed after a stall - used for readrate
|
||||
int64_t resume_wc;
|
||||
// relative timestamp of first packet sent after the latest stall - used for readrate
|
||||
int64_t resume_progress;
|
||||
// measure of how far behind packet reading is against spceified readrate
|
||||
int64_t lag;
|
||||
|
||||
Scheduler *sch;
|
||||
|
||||
AVPacket *pkt_heartbeat;
|
||||
@@ -518,55 +507,40 @@ static void readrate_sleep(Demuxer *d)
|
||||
int64_t initial_burst = AV_TIME_BASE * d->readrate_initial_burst;
|
||||
int resume_warn = 0;
|
||||
|
||||
DemuxStream *slowest = NULL;
|
||||
int64_t progress = INT64_MAX;
|
||||
|
||||
for (int i = 0; i < f->nb_streams; i++) {
|
||||
InputStream *ist = f->streams[i];
|
||||
DemuxStream *ds = ds_from_ist(ist);
|
||||
int64_t stream_ts_offset, pts, pts_diff;
|
||||
if (ds->discard || ds->finished || ds->first_dts == AV_NOPTS_VALUE)
|
||||
continue;
|
||||
int64_t stream_ts_offset, pts, now, wc_elapsed, elapsed, lag, max_pts, limit_pts;
|
||||
|
||||
stream_ts_offset = FFMAX(ds->first_dts, file_start);
|
||||
if (ds->discard) continue;
|
||||
|
||||
stream_ts_offset = FFMAX(ds->first_dts != AV_NOPTS_VALUE ? ds->first_dts : 0, file_start);
|
||||
pts = av_rescale(ds->dts, 1000000, AV_TIME_BASE);
|
||||
pts_diff = pts - stream_ts_offset;
|
||||
if (pts_diff < progress) {
|
||||
progress = pts_diff;
|
||||
slowest = ds;
|
||||
now = av_gettime_relative();
|
||||
wc_elapsed = now - d->wallclock_start;
|
||||
max_pts = stream_ts_offset + initial_burst + wc_elapsed * d->readrate;
|
||||
lag = FFMAX(max_pts - pts, 0);
|
||||
if ( (!ds->lag && lag > 0.3 * AV_TIME_BASE) || ( lag > ds->lag + 0.3 * AV_TIME_BASE) ) {
|
||||
ds->lag = lag;
|
||||
ds->resume_wc = now;
|
||||
ds->resume_pts = pts;
|
||||
av_log_once(ds, AV_LOG_WARNING, AV_LOG_DEBUG, &resume_warn,
|
||||
"Resumed reading at pts %0.3f with rate %0.3f after a lag of %0.3fs\n",
|
||||
(float)pts/AV_TIME_BASE, d->readrate_catchup, (float)lag/AV_TIME_BASE);
|
||||
}
|
||||
if (ds->lag && !lag)
|
||||
ds->lag = ds->resume_wc = ds->resume_pts = 0;
|
||||
if (ds->resume_wc) {
|
||||
elapsed = now - ds->resume_wc;
|
||||
limit_pts = ds->resume_pts + elapsed * d->readrate_catchup;
|
||||
} else {
|
||||
elapsed = wc_elapsed;
|
||||
limit_pts = max_pts;
|
||||
}
|
||||
|
||||
if (pts > limit_pts)
|
||||
av_usleep(pts - limit_pts);
|
||||
}
|
||||
|
||||
if (!slowest || progress <= initial_burst)
|
||||
return;
|
||||
|
||||
int64_t now = av_gettime_relative();
|
||||
int64_t wc_elapsed = now - d->wallclock_start;
|
||||
int64_t max_prog = initial_burst + (int64_t)(wc_elapsed * d->readrate);
|
||||
int64_t lag = FFMAX(max_prog - progress, 0);
|
||||
int64_t limit;
|
||||
|
||||
if ( (!d->lag && lag > 0.3 * AV_TIME_BASE) || ( lag > d->lag + 0.3 * AV_TIME_BASE) ) {
|
||||
d->lag = lag;
|
||||
d->resume_wc = now;
|
||||
d->resume_progress = progress;
|
||||
|
||||
int64_t pts = FFMAX(slowest->first_dts, file_start) + progress;
|
||||
av_log_once(slowest, AV_LOG_WARNING, AV_LOG_DEBUG, &resume_warn,
|
||||
"Resumed reading at pts %0.3f with rate %0.3f after a lag of %0.3fs\n",
|
||||
(float)pts/AV_TIME_BASE, d->readrate_catchup, (float)lag/AV_TIME_BASE);
|
||||
}
|
||||
if (d->lag && !lag)
|
||||
d->lag = d->resume_wc = d->resume_progress = 0;
|
||||
if (d->resume_wc) {
|
||||
int64_t elapsed = now - d->resume_wc;
|
||||
limit = d->resume_progress + (int64_t)(elapsed * d->readrate_catchup);
|
||||
} else {
|
||||
limit = max_prog;
|
||||
}
|
||||
|
||||
if (progress > limit)
|
||||
av_usleep(progress - limit);
|
||||
}
|
||||
|
||||
static int do_send(Demuxer *d, DemuxStream *ds, AVPacket *pkt, unsigned flags,
|
||||
@@ -912,16 +886,6 @@ static void ist_free(InputStream **pist)
|
||||
av_freep(pist);
|
||||
}
|
||||
|
||||
static void istg_free(InputStreamGroup **pistg)
|
||||
{
|
||||
InputStreamGroup *istg = *pistg;
|
||||
|
||||
if (!istg)
|
||||
return;
|
||||
|
||||
av_freep(pistg);
|
||||
}
|
||||
|
||||
void ifile_close(InputFile **pf)
|
||||
{
|
||||
InputFile *f = *pf;
|
||||
@@ -937,10 +901,6 @@ void ifile_close(InputFile **pf)
|
||||
ist_free(&f->streams[i]);
|
||||
av_freep(&f->streams);
|
||||
|
||||
for (int i = 0; i < f->nb_stream_groups; i++)
|
||||
istg_free(&f->stream_groups[i]);
|
||||
av_freep(&f->stream_groups);
|
||||
|
||||
avformat_close_input(&f->ctx);
|
||||
|
||||
av_packet_free(&d->pkt_heartbeat);
|
||||
@@ -998,7 +958,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 +1224,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 +1277,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 +1342,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 +1459,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 +1484,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;
|
||||
@@ -1755,199 +1586,6 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *input_stream_group_item_name(void *obj)
|
||||
{
|
||||
const DemuxStreamGroup *dsg = obj;
|
||||
|
||||
return dsg->log_name;
|
||||
}
|
||||
|
||||
static const AVClass input_stream_group_class = {
|
||||
.class_name = "InputStreamGroup",
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.item_name = input_stream_group_item_name,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
static DemuxStreamGroup *demux_stream_group_alloc(Demuxer *d, AVStreamGroup *stg)
|
||||
{
|
||||
InputFile *f = &d->f;
|
||||
DemuxStreamGroup *dsg;
|
||||
|
||||
dsg = allocate_array_elem(&f->stream_groups, sizeof(*dsg), &f->nb_stream_groups);
|
||||
if (!dsg)
|
||||
return NULL;
|
||||
|
||||
dsg->istg.stg = stg;
|
||||
dsg->istg.file = f;
|
||||
dsg->istg.index = stg->index;
|
||||
dsg->istg.class = &input_stream_group_class;
|
||||
|
||||
snprintf(dsg->log_name, sizeof(dsg->log_name), "istg#%d:%d/%s",
|
||||
d->f.index, stg->index, avformat_stream_group_name(stg->type));
|
||||
|
||||
return dsg;
|
||||
}
|
||||
|
||||
static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStreamGroup *istg)
|
||||
{
|
||||
InputFile *f = &d->f;
|
||||
AVFormatContext *ic = d->f.ctx;
|
||||
AVStreamGroup *stg = istg->stg;
|
||||
const AVStreamGroupTileGrid *tg = stg->params.tile_grid;
|
||||
OutputFilterOptions opts;
|
||||
AVBPrint bp;
|
||||
char *graph_str;
|
||||
int autorotate = 1;
|
||||
const char *apply_cropping = NULL;
|
||||
int ret;
|
||||
|
||||
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));
|
||||
|
||||
opt_match_per_stream_group_int(istg, &o->autorotate, ic, stg, &autorotate);
|
||||
if (autorotate)
|
||||
opts.flags |= OFILTER_FLAG_AUTOROTATE;
|
||||
|
||||
opts.flags |= OFILTER_FLAG_CROP;
|
||||
opt_match_per_stream_group_str(istg, &o->apply_cropping, ic, stg, &apply_cropping);
|
||||
if (apply_cropping) {
|
||||
char *p;
|
||||
int crop = strtol(apply_cropping, &p, 0);
|
||||
if (*p)
|
||||
return AVERROR(EINVAL);
|
||||
if (!crop)
|
||||
opts.flags &= ~OFILTER_FLAG_CROP;
|
||||
}
|
||||
|
||||
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
for (int i = 0; i < tg->nb_tiles; i++)
|
||||
av_bprintf(&bp, "[%d:g:%d:%d]", f->index, stg->index, tg->offsets[i].idx);
|
||||
av_bprintf(&bp, "xstack=inputs=%d:layout=", tg->nb_tiles);
|
||||
for (int i = 0; i < tg->nb_tiles - 1; i++)
|
||||
av_bprintf(&bp, "%d_%d|", tg->offsets[i].horizontal,
|
||||
tg->offsets[i].vertical);
|
||||
av_bprintf(&bp, "%d_%d:fill=0x%02X%02X%02X@0x%02X", tg->offsets[tg->nb_tiles - 1].horizontal,
|
||||
tg->offsets[tg->nb_tiles - 1].vertical,
|
||||
tg->background[0], tg->background[1],
|
||||
tg->background[2], tg->background[3]);
|
||||
av_bprintf(&bp, "[%d:g:%d]", f->index, stg->index);
|
||||
ret = av_bprint_finalize(&bp, &graph_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tg->coded_width != tg->width || tg->coded_height != tg->height) {
|
||||
opts.crop_top = tg->vertical_offset;
|
||||
opts.crop_bottom = tg->coded_height - tg->height - tg->vertical_offset;
|
||||
opts.crop_left = tg->horizontal_offset;
|
||||
opts.crop_right = tg->coded_width - tg->width - tg->horizontal_offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tg->nb_coded_side_data; i++) {
|
||||
const AVPacketSideData *sd = &tg->coded_side_data[i];
|
||||
|
||||
ret = av_packet_side_data_to_frame(&opts.side_data, &opts.nb_side_data, sd, 0);
|
||||
if (ret < 0 && ret != AVERROR(EINVAL))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = fg_create(NULL, &graph_str, d->sch, &opts);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
istg->fg = filtergraphs[nb_filtergraphs-1];
|
||||
istg->fg->is_internal = 1;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (ret < 0)
|
||||
av_freep(&graph_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int istg_add(const OptionsContext *o, Demuxer *d, AVStreamGroup *stg)
|
||||
{
|
||||
DemuxStreamGroup *dsg;
|
||||
InputStreamGroup *istg;
|
||||
int ret;
|
||||
|
||||
dsg = demux_stream_group_alloc(d, stg);
|
||||
if (!dsg)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
istg = &dsg->istg;
|
||||
|
||||
switch (stg->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID:
|
||||
ret = istg_parse_tile_grid(o, d, istg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_windows_reserved_device_name(const char *f)
|
||||
{
|
||||
#if HAVE_DOS_PATHS
|
||||
for (const char *p = f; p && *p; ) {
|
||||
char stem[6], *s;
|
||||
av_strlcpy(stem, p, sizeof(stem));
|
||||
if ((s = strchr(stem, '.')))
|
||||
*s = 0;
|
||||
if ((s = strpbrk(stem, "123456789")))
|
||||
*s = '1';
|
||||
|
||||
if( !av_strcasecmp(stem, "AUX") ||
|
||||
!av_strcasecmp(stem, "CON") ||
|
||||
!av_strcasecmp(stem, "NUL") ||
|
||||
!av_strcasecmp(stem, "PRN") ||
|
||||
!av_strcasecmp(stem, "COM1") ||
|
||||
!av_strcasecmp(stem, "LPT1")
|
||||
)
|
||||
return 1;
|
||||
|
||||
p = strchr(p, '/');
|
||||
if (p)
|
||||
p++;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int safe_filename(const char *f, int allow_subdir)
|
||||
{
|
||||
const char *start = f;
|
||||
|
||||
if (!*f || is_windows_reserved_device_name(f))
|
||||
return 0;
|
||||
|
||||
for (; *f; f++) {
|
||||
/* A-Za-z0-9_- */
|
||||
if (!((unsigned)((*f | 32) - 'a') < 26 ||
|
||||
(unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) {
|
||||
if (f == start)
|
||||
return 0;
|
||||
else if (allow_subdir && *f == '/')
|
||||
start = f + 1;
|
||||
else if (*f != '.')
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dump_attachment(InputStream *ist, const char *filename)
|
||||
{
|
||||
AVStream *st = ist->st;
|
||||
@@ -1959,13 +1597,8 @@ static int dump_attachment(InputStream *ist, const char *filename)
|
||||
av_log(ist, AV_LOG_WARNING, "No extradata to dump.\n");
|
||||
return 0;
|
||||
}
|
||||
if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0))) {
|
||||
if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
|
||||
filename = e->value;
|
||||
if (!safe_filename(filename, 0)) {
|
||||
av_log(ist, AV_LOG_ERROR, "Filename %s is unsafe\n", filename);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
if (!*filename) {
|
||||
av_log(ist, AV_LOG_FATAL, "No filename specified and no 'filename' tag");
|
||||
return AVERROR(EINVAL);
|
||||
@@ -2084,7 +1717,6 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
|
||||
ic = avformat_alloc_context();
|
||||
if (!ic)
|
||||
return AVERROR(ENOMEM);
|
||||
ic->name = av_strdup(d->log_name);
|
||||
if (o->audio_sample_rate.nb_opt) {
|
||||
av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate.opt[o->audio_sample_rate.nb_opt - 1].u.i, 0);
|
||||
}
|
||||
@@ -2173,8 +1805,6 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
|
||||
|
||||
av_strlcat(d->log_name, "/", sizeof(d->log_name));
|
||||
av_strlcat(d->log_name, ic->iformat->name, sizeof(d->log_name));
|
||||
av_freep(&ic->name);
|
||||
ic->name = av_strdup(d->log_name);
|
||||
|
||||
if (scan_all_pmts_set)
|
||||
av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
|
||||
@@ -2324,13 +1954,6 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all the stream groups from the given input file to the demuxer */
|
||||
for (int i = 0; i < ic->nb_stream_groups; i++) {
|
||||
ret = istg_add(o, d, ic->stream_groups[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* dump the file content */
|
||||
av_dump_format(ic, f->index, filename, 0);
|
||||
|
||||
|
||||
+33
-30
@@ -205,10 +205,19 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||
av_assert0(frame->opaque_ref);
|
||||
fd = (FrameData*)frame->opaque_ref->data;
|
||||
|
||||
ret = clone_side_data(&enc_ctx->decoded_side_data, &enc_ctx->nb_decoded_side_data,
|
||||
fd->side_data, fd->nb_side_data, AV_FRAME_SIDE_DATA_FLAG_UNIQUE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
for (int i = 0; i < frame->nb_side_data; i++) {
|
||||
const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type);
|
||||
|
||||
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL))
|
||||
continue;
|
||||
|
||||
ret = av_frame_side_data_clone(&enc_ctx->decoded_side_data,
|
||||
&enc_ctx->nb_decoded_side_data,
|
||||
frame->side_data[i],
|
||||
AV_FRAME_SIDE_DATA_FLAG_UNIQUE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ist)
|
||||
@@ -227,9 +236,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;
|
||||
@@ -260,31 +266,24 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||
enc_ctx->bits_per_raw_sample = FFMIN(fd->bits_per_raw_sample,
|
||||
av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);
|
||||
|
||||
/**
|
||||
* The video color properties should always be in sync with the user-
|
||||
* requested values, since we forward them to the filter graph.
|
||||
*/
|
||||
enc_ctx->color_range = frame->color_range;
|
||||
enc_ctx->color_primaries = frame->color_primaries;
|
||||
enc_ctx->color_trc = frame->color_trc;
|
||||
enc_ctx->colorspace = frame->colorspace;
|
||||
enc_ctx->alpha_mode = frame->alpha_mode;
|
||||
|
||||
/* Video properties which are not part of filter graph negotiation */
|
||||
if (enc_ctx->chroma_sample_location == AVCHROMA_LOC_UNSPECIFIED) {
|
||||
enc_ctx->chroma_sample_location = frame->chroma_location;
|
||||
} else if (enc_ctx->chroma_sample_location != frame->chroma_location &&
|
||||
frame->chroma_location != AVCHROMA_LOC_UNSPECIFIED) {
|
||||
av_log(e, AV_LOG_WARNING,
|
||||
"Requested chroma sample location '%s' does not match the "
|
||||
"frame tagged sample location '%s'; result may be incorrect.\n",
|
||||
av_chroma_location_name(enc_ctx->chroma_sample_location),
|
||||
av_chroma_location_name(frame->chroma_location));
|
||||
}
|
||||
enc_ctx->chroma_sample_location = frame->chroma_location;
|
||||
|
||||
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;
|
||||
@@ -722,7 +721,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||
}
|
||||
}
|
||||
|
||||
av_unreachable("encode_frame() loop should return");
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf,
|
||||
@@ -762,9 +761,6 @@ static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf,
|
||||
}
|
||||
} else if (kf->type == KF_FORCE_SOURCE && (frame->flags & AV_FRAME_FLAG_KEY)) {
|
||||
goto force_keyframe;
|
||||
} else if (kf->type == KF_FORCE_SCD_METADATA &&
|
||||
av_dict_get(frame->metadata, "lavfi.scd.time", NULL, 0)) {
|
||||
goto force_keyframe;
|
||||
}
|
||||
|
||||
return AV_PICTURE_TYPE_NONE;
|
||||
@@ -796,6 +792,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) {
|
||||
|
||||
+96
-323
@@ -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"
|
||||
@@ -41,6 +40,9 @@
|
||||
#include "libavutil/time.h"
|
||||
#include "libavutil/timestamp.h"
|
||||
|
||||
// FIXME private header, used for mid_pred()
|
||||
#include "libavcodec/mathops.h"
|
||||
|
||||
typedef struct FilterGraphPriv {
|
||||
FilterGraph fg;
|
||||
|
||||
@@ -51,6 +53,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;
|
||||
@@ -105,9 +109,6 @@ typedef struct InputFilterPriv {
|
||||
// used to hold submitted input
|
||||
AVFrame *frame;
|
||||
|
||||
// For inputs bound to a filtergraph output
|
||||
OutputFilter *ofilter_src;
|
||||
|
||||
// source data type: AVMEDIA_TYPE_SUBTITLE for sub2video,
|
||||
// same as type otherwise
|
||||
enum AVMediaType type_src;
|
||||
@@ -124,7 +125,6 @@ typedef struct InputFilterPriv {
|
||||
AVRational sample_aspect_ratio;
|
||||
enum AVColorSpace color_space;
|
||||
enum AVColorRange color_range;
|
||||
enum AVAlphaMode alpha_mode;
|
||||
|
||||
int sample_rate;
|
||||
AVChannelLayout ch_layout;
|
||||
@@ -189,8 +189,6 @@ typedef struct OutputFilterPriv {
|
||||
void *log_parent;
|
||||
char log_name[32];
|
||||
|
||||
int needed;
|
||||
|
||||
/* desired output stream properties */
|
||||
int format;
|
||||
int width, height;
|
||||
@@ -198,12 +196,6 @@ typedef struct OutputFilterPriv {
|
||||
AVChannelLayout ch_layout;
|
||||
enum AVColorSpace color_space;
|
||||
enum AVColorRange color_range;
|
||||
enum AVAlphaMode alpha_mode;
|
||||
|
||||
unsigned crop_top;
|
||||
unsigned crop_bottom;
|
||||
unsigned crop_left;
|
||||
unsigned crop_right;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
@@ -222,17 +214,11 @@ typedef struct OutputFilterPriv {
|
||||
|
||||
// those are only set if no format is specified and the encoder gives us multiple options
|
||||
// They point directly to the relevant lists of the encoder.
|
||||
union {
|
||||
const enum AVPixelFormat *pix_fmts;
|
||||
const enum AVSampleFormat *sample_fmts;
|
||||
};
|
||||
const int *formats;
|
||||
const AVChannelLayout *ch_layouts;
|
||||
const int *sample_rates;
|
||||
const enum AVColorSpace *color_spaces;
|
||||
const enum AVColorRange *color_ranges;
|
||||
const enum AVAlphaMode *alpha_modes;
|
||||
|
||||
int32_t displaymatrix[9];
|
||||
|
||||
AVRational enc_timebase;
|
||||
int64_t trim_start_us;
|
||||
@@ -282,7 +268,6 @@ static int sub2video_get_blank_frame(InputFilterPriv *ifp)
|
||||
frame->format = ifp->format;
|
||||
frame->colorspace = ifp->color_space;
|
||||
frame->color_range = ifp->color_range;
|
||||
frame->alpha_mode = ifp->alpha_mode;
|
||||
|
||||
ret = av_frame_get_buffer(frame, 0);
|
||||
if (ret < 0)
|
||||
@@ -401,10 +386,10 @@ static void choose_ ## name (OutputFilterPriv *ofp, AVBPrint *bprint) \
|
||||
av_bprint_chars(bprint, ':', 1); \
|
||||
}
|
||||
|
||||
DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, pix_fmts,
|
||||
DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats,
|
||||
AV_PIX_FMT_NONE, "%s", av_get_pix_fmt_name)
|
||||
|
||||
DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, sample_fmts,
|
||||
DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats,
|
||||
AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name)
|
||||
|
||||
DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0,
|
||||
@@ -416,9 +401,6 @@ DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces,
|
||||
DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_ranges,
|
||||
AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name);
|
||||
|
||||
DEF_CHOOSE_FORMAT(alpha_modes, enum AVAlphaMode, alpha_mode, alpha_modes,
|
||||
AVALPHA_MODE_UNSPECIFIED, "%s", av_alpha_mode_name);
|
||||
|
||||
static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint)
|
||||
{
|
||||
if (av_channel_layout_check(&ofp->ch_layout)) {
|
||||
@@ -518,7 +500,7 @@ static int filter_opt_apply(void *logctx, AVFilterContext *f,
|
||||
ret = av_opt_set_bin(f, key, data, len, AV_OPT_SEARCH_CHILDREN);
|
||||
av_freep(&data);
|
||||
} else {
|
||||
char *data = read_file_to_string(val);
|
||||
char *data = file_read(val);
|
||||
if (!data) {
|
||||
ret = AVERROR(EIO);
|
||||
goto err_load;
|
||||
@@ -668,7 +650,6 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg, enum AVMediaType type)
|
||||
ofp->format = -1;
|
||||
ofp->color_space = AVCOL_SPC_UNSPECIFIED;
|
||||
ofp->color_range = AVCOL_RANGE_UNSPECIFIED;
|
||||
ofp->alpha_mode = AVALPHA_MODE_UNSPECIFIED;
|
||||
ofilter->index = fg->nb_outputs - 1;
|
||||
|
||||
snprintf(ofp->log_name, sizeof(ofp->log_name), "%co%d",
|
||||
@@ -821,10 +802,10 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
|
||||
av_assert0(!opts->enc ||
|
||||
ofilter->type == opts->enc->type);
|
||||
|
||||
ofp->needed = ofilter->bound = 1;
|
||||
ofilter->bound = 1;
|
||||
av_freep(&ofilter->linklabel);
|
||||
|
||||
ofp->flags |= opts->flags;
|
||||
ofp->flags = opts->flags;
|
||||
ofp->ts_offset = opts->ts_offset;
|
||||
ofp->enc_timebase = opts->output_tb;
|
||||
|
||||
@@ -861,7 +842,7 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
|
||||
if (opts->format != AV_PIX_FMT_NONE) {
|
||||
ofp->format = opts->format;
|
||||
} else
|
||||
ofp->pix_fmts = opts->pix_fmts;
|
||||
ofp->formats = opts->formats;
|
||||
|
||||
if (opts->color_space != AVCOL_SPC_UNSPECIFIED)
|
||||
ofp->color_space = opts->color_space;
|
||||
@@ -873,11 +854,6 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
|
||||
else
|
||||
ofp->color_ranges = opts->color_ranges;
|
||||
|
||||
if (opts->alpha_mode != AVALPHA_MODE_UNSPECIFIED)
|
||||
ofp->alpha_mode = opts->alpha_mode;
|
||||
else
|
||||
ofp->alpha_modes = opts->alpha_modes;
|
||||
|
||||
fgp->disable_conversions |= !!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT);
|
||||
|
||||
ofp->fps.last_frame = av_frame_alloc();
|
||||
@@ -900,7 +876,7 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
|
||||
if (opts->format != AV_SAMPLE_FMT_NONE) {
|
||||
ofp->format = opts->format;
|
||||
} else {
|
||||
ofp->sample_fmts = opts->sample_fmts;
|
||||
ofp->formats = opts->formats;
|
||||
}
|
||||
if (opts->sample_rate) {
|
||||
ofp->sample_rate = opts->sample_rate;
|
||||
@@ -932,15 +908,13 @@ static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp,
|
||||
av_assert0(!ofilter->bound);
|
||||
av_assert0(ofilter->type == ifp->ifilter.type);
|
||||
|
||||
ofp->needed = ofilter->bound = 1;
|
||||
ofilter->bound = 1;
|
||||
av_freep(&ofilter->linklabel);
|
||||
|
||||
ofilter->output_name = av_strdup(opts->name);
|
||||
if (!ofilter->output_name)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
ifp->ofilter_src = ofilter;
|
||||
|
||||
av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name);
|
||||
|
||||
return 0;
|
||||
@@ -1003,7 +977,6 @@ static InputFilter *ifilter_alloc(FilterGraph *fg)
|
||||
ifp->format = -1;
|
||||
ifp->color_space = AVCOL_SPC_UNSPECIFIED;
|
||||
ifp->color_range = AVCOL_RANGE_UNSPECIFIED;
|
||||
ifp->alpha_mode = AVALPHA_MODE_UNSPECIFIED;
|
||||
|
||||
ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
|
||||
if (!ifp->frame_queue)
|
||||
@@ -1037,7 +1010,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);
|
||||
@@ -1085,8 +1057,7 @@ static const AVClass fg_class = {
|
||||
.category = AV_CLASS_CATEGORY_FILTER,
|
||||
};
|
||||
|
||||
int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
const OutputFilterOptions *opts)
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
|
||||
{
|
||||
FilterGraphPriv *fgp;
|
||||
FilterGraph *fg;
|
||||
@@ -1097,7 +1068,7 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
|
||||
fgp = av_mallocz(sizeof(*fgp));
|
||||
if (!fgp) {
|
||||
av_freep(graph_desc);
|
||||
av_freep(&graph_desc);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
fg = &fgp->fg;
|
||||
@@ -1108,7 +1079,7 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
} else {
|
||||
ret = av_dynarray_add_nofree(&filtergraphs, &nb_filtergraphs, fgp);
|
||||
if (ret < 0) {
|
||||
av_freep(graph_desc);
|
||||
av_freep(&graph_desc);
|
||||
av_freep(&fgp);
|
||||
return ret;
|
||||
}
|
||||
@@ -1117,13 +1088,11 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
}
|
||||
|
||||
fg->class = &fg_class;
|
||||
fg->graph_desc = *graph_desc;
|
||||
fg->graph_desc = graph_desc;
|
||||
fgp->disable_conversions = !auto_conversion_filters;
|
||||
fgp->nb_threads = -1;
|
||||
fgp->sch = sch;
|
||||
|
||||
*graph_desc = NULL;
|
||||
|
||||
snprintf(fgp->log_name, sizeof(fgp->log_name), "fc#%d", fg->index);
|
||||
|
||||
fgp->frame = av_frame_alloc();
|
||||
@@ -1143,6 +1112,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);
|
||||
|
||||
@@ -1175,13 +1154,11 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
const enum AVMediaType type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
|
||||
cur->pad_idx);
|
||||
OutputFilter *const ofilter = ofilter_alloc(fg, type);
|
||||
OutputFilterPriv *ofp;
|
||||
|
||||
if (!ofilter) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
ofp = ofp_from_ofilter(ofilter);
|
||||
|
||||
ofilter->linklabel = cur->name;
|
||||
cur->name = NULL;
|
||||
@@ -1191,25 +1168,6 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// opts should only be needed in this function to fill fields from filtergraphs
|
||||
// whose output is meant to be treated as if it was stream, e.g. merged HEIF
|
||||
// tile groups.
|
||||
if (opts) {
|
||||
ofp->flags = opts->flags;
|
||||
ofp->side_data = opts->side_data;
|
||||
ofp->nb_side_data = opts->nb_side_data;
|
||||
|
||||
ofp->crop_top = opts->crop_top;
|
||||
ofp->crop_bottom = opts->crop_bottom;
|
||||
ofp->crop_left = opts->crop_left;
|
||||
ofp->crop_right = opts->crop_right;
|
||||
|
||||
const AVFrameSideData *sd = av_frame_side_data_get(ofp->side_data, ofp->nb_side_data,
|
||||
AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
if (sd)
|
||||
memcpy(ofp->displaymatrix, sd->data, sizeof(ofp->displaymatrix));
|
||||
}
|
||||
}
|
||||
|
||||
if (!fg->nb_outputs) {
|
||||
@@ -1237,7 +1195,7 @@ fail:
|
||||
|
||||
int fg_create_simple(FilterGraph **pfg,
|
||||
InputStream *ist,
|
||||
char **graph_desc,
|
||||
char *graph_desc,
|
||||
Scheduler *sch, unsigned sched_idx_enc,
|
||||
const OutputFilterOptions *opts)
|
||||
{
|
||||
@@ -1246,7 +1204,7 @@ int fg_create_simple(FilterGraph **pfg,
|
||||
FilterGraphPriv *fgp;
|
||||
int ret;
|
||||
|
||||
ret = fg_create(pfg, graph_desc, sch, NULL);
|
||||
ret = fg_create(pfg, graph_desc, sch);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fg = *pfg;
|
||||
@@ -1262,7 +1220,7 @@ int fg_create_simple(FilterGraph **pfg,
|
||||
"to have exactly 1 input and 1 output. "
|
||||
"However, it had %d input(s) and %d output(s). Please adjust, "
|
||||
"or use a complex filtergraph (-filter_complex) instead.\n",
|
||||
*graph_desc, fg->nb_inputs, fg->nb_outputs);
|
||||
graph_desc, fg->nb_inputs, fg->nb_outputs);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (fg->outputs[0]->type != type) {
|
||||
@@ -1287,7 +1245,7 @@ int fg_create_simple(FilterGraph **pfg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int commit)
|
||||
static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
|
||||
{
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||
InputStream *ist = NULL;
|
||||
@@ -1338,20 +1296,15 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int comm
|
||||
|
||||
if (!ofilter->bound && ofilter->linklabel &&
|
||||
!strcmp(ofilter->linklabel, ifilter->linklabel)) {
|
||||
if (commit) {
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to filtergraph output %d:%d\n",
|
||||
ifilter->linklabel, i, j);
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to filtergraph output %d:%d\n",
|
||||
ifilter->linklabel, i, j);
|
||||
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n",
|
||||
ifilter->linklabel);
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
ofp_from_ofilter(ofilter)->needed = 1;
|
||||
return 0;
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0)
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n",
|
||||
ifilter->linklabel);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1399,38 +1352,10 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int comm
|
||||
}
|
||||
ist = input_files[file_idx]->streams[st->index];
|
||||
|
||||
if (commit)
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to input stream %d:%d\n",
|
||||
ifilter->linklabel, ist->file->index, ist->index);
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to input stream %d:%d\n",
|
||||
ifilter->linklabel, ist->file->index, ist->index);
|
||||
} else {
|
||||
// try finding an unbound filtergraph output
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
FilterGraph *fg_src = filtergraphs[i];
|
||||
|
||||
if (fg == fg_src)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < fg_src->nb_outputs; j++) {
|
||||
OutputFilter *ofilter = fg_src->outputs[j];
|
||||
|
||||
if (!ofilter->bound) {
|
||||
if (commit) {
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled filtergraph input to filtergraph output %d:%d\n", i, j);
|
||||
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %d:%d\n", i, j);
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
ofp_from_ofilter(ofilter)->needed = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ist = ist_find_unused(type);
|
||||
if (!ist) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
@@ -1440,27 +1365,24 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int comm
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (commit)
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled input %d to input stream %d:%d\n",
|
||||
ifilter->index, ist->file->index, ist->index);
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled input %d to input stream %d:%d\n",
|
||||
ifilter->index, ist->file->index, ist->index);
|
||||
}
|
||||
av_assert0(ist);
|
||||
|
||||
if (commit) {
|
||||
ret = ifilter_bind_ist(ifilter, ist, &vs);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR,
|
||||
"Error binding an input stream to complex filtergraph input %s.\n",
|
||||
ifilter->name);
|
||||
return ret;
|
||||
}
|
||||
ret = ifilter_bind_ist(ifilter, ist, &vs);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR,
|
||||
"Error binding an input stream to complex filtergraph input %s.\n",
|
||||
ifilter->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bind_inputs(FilterGraph *fg, int commit)
|
||||
static int bind_inputs(FilterGraph *fg)
|
||||
{
|
||||
// bind filtergraph inputs to input streams or other filtergraphs
|
||||
for (int i = 0; i < fg->nb_inputs; i++) {
|
||||
@@ -1470,7 +1392,7 @@ static int bind_inputs(FilterGraph *fg, int commit)
|
||||
if (ifp->bound)
|
||||
continue;
|
||||
|
||||
ret = fg_complex_bind_input(fg, &ifp->ifilter, commit);
|
||||
ret = fg_complex_bind_input(fg, &ifp->ifilter);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -1483,49 +1405,27 @@ int fg_finalise_bindings(void)
|
||||
int ret;
|
||||
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
ret = bind_inputs(filtergraphs[i], 0);
|
||||
ret = bind_inputs(filtergraphs[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// check that all outputs were bound
|
||||
for (int i = nb_filtergraphs - 1; i >= 0; i--) {
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
FilterGraph *fg = filtergraphs[i];
|
||||
FilterGraphPriv *fgp = fgp_from_fg(filtergraphs[i]);
|
||||
|
||||
for (int j = 0; j < fg->nb_outputs; j++) {
|
||||
OutputFilter *output = fg->outputs[j];
|
||||
if (!ofp_from_ofilter(output)->needed) {
|
||||
if (!fg->is_internal) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
"Filter '%s' has output %d (%s) unconnected\n",
|
||||
output->name, j,
|
||||
output->linklabel ? (const char *)output->linklabel : "unlabeled");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
av_log(fg, AV_LOG_DEBUG,
|
||||
"Internal filter '%s' has output %d (%s) unconnected. Removing graph\n",
|
||||
if (!output->bound) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
"Filter '%s' has output %d (%s) unconnected\n",
|
||||
output->name, j,
|
||||
output->linklabel ? (const char *)output->linklabel : "unlabeled");
|
||||
sch_remove_filtergraph(fgp->sch, fgp->sch_idx);
|
||||
fg_free(&filtergraphs[i]);
|
||||
nb_filtergraphs--;
|
||||
if (nb_filtergraphs > 0)
|
||||
memmove(&filtergraphs[i],
|
||||
&filtergraphs[i + 1],
|
||||
(nb_filtergraphs - i) * sizeof(*filtergraphs));
|
||||
break;
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
ret = bind_inputs(filtergraphs[i], 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1624,57 +1524,7 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ofp->flags & OFILTER_FLAG_CROP) {
|
||||
char crop_buf[64];
|
||||
snprintf(crop_buf, sizeof(crop_buf), "w=iw-%u-%u:h=ih-%u-%u:x=%u:y=%u",
|
||||
ofp->crop_left, ofp->crop_right,
|
||||
ofp->crop_top, ofp->crop_bottom,
|
||||
ofp->crop_left, ofp->crop_top);
|
||||
ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ofp->flags & OFILTER_FLAG_AUTOROTATE) {
|
||||
int32_t *displaymatrix = ofp->displaymatrix;
|
||||
double theta;
|
||||
|
||||
theta = get_rotation(displaymatrix);
|
||||
|
||||
if (fabs(theta - 90) < 1.0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "transpose",
|
||||
displaymatrix[3] > 0 ? "cclock_flip" : "clock");
|
||||
} else if (fabs(theta - 180) < 1.0) {
|
||||
if (displaymatrix[0] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (displaymatrix[4] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
|
||||
}
|
||||
} else if (fabs(theta - 270) < 1.0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "transpose",
|
||||
displaymatrix[3] < 0 ? "clock_flip" : "cclock");
|
||||
} else if (fabs(theta) > 1.0) {
|
||||
char rotate_buf[64];
|
||||
snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
|
||||
ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
|
||||
} else if (fabs(theta) < 1.0) {
|
||||
if (displaymatrix && displaymatrix[4] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
@@ -1698,12 +1548,11 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
|
||||
}
|
||||
|
||||
av_assert0(!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT) ||
|
||||
ofp->format != AV_PIX_FMT_NONE || !ofp->pix_fmts);
|
||||
ofp->format != AV_PIX_FMT_NONE || !ofp->formats);
|
||||
av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
choose_pix_fmts(ofp, &bprint);
|
||||
choose_color_spaces(ofp, &bprint);
|
||||
choose_color_ranges(ofp, &bprint);
|
||||
choose_alpha_modes(ofp, &bprint);
|
||||
if (!av_bprint_is_complete(&bprint))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
@@ -1799,8 +1648,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,
|
||||
@@ -1872,7 +1723,6 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph,
|
||||
ifp->sample_aspect_ratio : (AVRational){ 0, 1 };
|
||||
par->color_space = ifp->color_space;
|
||||
par->color_range = ifp->color_range;
|
||||
par->alpha_mode = ifp->alpha_mode;
|
||||
par->hw_frames_ctx = ifp->hw_frames_ctx;
|
||||
par->side_data = ifp->side_data;
|
||||
par->nb_side_data = ifp->nb_side_data;
|
||||
@@ -2150,7 +2000,6 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt)
|
||||
ofp->height = av_buffersink_get_h(sink);
|
||||
ofp->color_space = av_buffersink_get_colorspace(sink);
|
||||
ofp->color_range = av_buffersink_get_color_range(sink);
|
||||
ofp->alpha_mode = av_buffersink_get_alpha_mode(sink);
|
||||
|
||||
// If the timing parameters are not locked yet, get the tentative values
|
||||
// here but don't lock them. They will only be used if no output frames
|
||||
@@ -2169,11 +2018,12 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt)
|
||||
ret = av_buffersink_get_ch_layout(sink, &ofp->ch_layout);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
|
||||
sd = av_buffersink_get_side_data(sink, &nb_sd);
|
||||
if (nb_sd)
|
||||
for (int j = 0; j < nb_sd; j++) {
|
||||
ret = av_frame_side_data_clone(&ofp->side_data, &ofp->nb_side_data,
|
||||
sd[j], AV_FRAME_SIDE_DATA_FLAG_REPLACE);
|
||||
sd[j], 0);
|
||||
if (ret < 0) {
|
||||
av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
|
||||
goto fail;
|
||||
@@ -2246,7 +2096,6 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
||||
ifp->sample_aspect_ratio = frame->sample_aspect_ratio;
|
||||
ifp->color_space = frame->colorspace;
|
||||
ifp->color_range = frame->color_range;
|
||||
ifp->alpha_mode = frame->alpha_mode;
|
||||
|
||||
ifp->sample_rate = frame->sample_rate;
|
||||
ret = av_channel_layout_copy(&ifp->ch_layout, &frame->ch_layout);
|
||||
@@ -2268,11 +2117,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
|
||||
@@ -2291,27 +2137,6 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifilter_parameters_from_ofilter(InputFilter *ifilter, OutputFilter *ofilter)
|
||||
{
|
||||
const OutputFilterPriv *ofp = ofp_from_ofilter(ofilter);
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||
|
||||
if (!ifp->opts.framerate.num) {
|
||||
ifp->opts.framerate = ofp->fps.framerate;
|
||||
if (ifp->opts.framerate.num > 0 && ifp->opts.framerate.den > 0)
|
||||
ifp->opts.flags |= IFILTER_FLAG_CFR;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ofp->nb_side_data; i++) {
|
||||
int ret = av_frame_side_data_clone(&ifp->side_data, &ifp->nb_side_data,
|
||||
ofp->side_data[i], AV_FRAME_SIDE_DATA_FLAG_REPLACE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filtergraph_is_simple(const FilterGraph *fg)
|
||||
{
|
||||
const FilterGraphPriv *fgp = cfgp_from_cfg(fg);
|
||||
@@ -2482,23 +2307,6 @@ early_exit:
|
||||
return float_pts;
|
||||
}
|
||||
|
||||
static int64_t median3(int64_t a, int64_t b, int64_t c)
|
||||
{
|
||||
int64_t max2, min2, m;
|
||||
|
||||
if (a >= b) {
|
||||
max2 = a;
|
||||
min2 = b;
|
||||
} else {
|
||||
max2 = b;
|
||||
min2 = a;
|
||||
}
|
||||
m = (c >= max2) ? max2 : c;
|
||||
|
||||
return (m >= min2) ? m : min2;
|
||||
}
|
||||
|
||||
|
||||
/* Convert frame timestamps to the encoder timebase and decide how many times
|
||||
* should this (and possibly previous) frame be repeated in order to conform to
|
||||
* desired target framerate (if any).
|
||||
@@ -2511,9 +2319,9 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
|
||||
double delta0, delta, sync_ipts, duration;
|
||||
|
||||
if (!frame) {
|
||||
*nb_frames_prev = *nb_frames = median3(fps->frames_prev_hist[0],
|
||||
fps->frames_prev_hist[1],
|
||||
fps->frames_prev_hist[2]);
|
||||
*nb_frames_prev = *nb_frames = mid_pred(fps->frames_prev_hist[0],
|
||||
fps->frames_prev_hist[1],
|
||||
fps->frames_prev_hist[2]);
|
||||
|
||||
if (!*nb_frames && fps->last_dropped) {
|
||||
atomic_fetch_add(&ofilter->nb_frames_drop, 1);
|
||||
@@ -2540,7 +2348,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 +2370,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 +2390,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);
|
||||
@@ -2620,16 +2434,6 @@ finish:
|
||||
fps->dropped_keyframe |= fps->last_dropped && (frame->flags & AV_FRAME_FLAG_KEY);
|
||||
}
|
||||
|
||||
static void close_input(InputFilterPriv *ifp)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph);
|
||||
|
||||
if (!ifp->eof) {
|
||||
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, ifp->ifilter.index);
|
||||
ifp->eof = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph);
|
||||
@@ -2654,17 +2458,16 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
av_frame_side_data_free(&frame->side_data, &frame->nb_side_data);
|
||||
ret = clone_side_data(&frame->side_data, &frame->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fd = frame_data(frame);
|
||||
if (!fd)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fd->frame_rate_filter = ofp->fps.framerate;
|
||||
|
||||
av_assert0(!frame->buf[0]);
|
||||
@@ -2819,16 +2622,6 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt,
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fd->wallclock[LATENCY_PROBE_FILTER_POST] = av_gettime_relative();
|
||||
|
||||
// only use bits_per_raw_sample passed through from the decoder
|
||||
@@ -2860,6 +2653,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 +2672,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 +2687,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 +2706,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;
|
||||
@@ -3013,7 +2809,6 @@ static int send_eof(FilterGraphThread *fgt, InputFilter *ifilter,
|
||||
ifp->sample_aspect_ratio = ifp->opts.fallback->sample_aspect_ratio;
|
||||
ifp->color_space = ifp->opts.fallback->colorspace;
|
||||
ifp->color_range = ifp->opts.fallback->color_range;
|
||||
ifp->alpha_mode = ifp->opts.fallback->alpha_mode;
|
||||
ifp->time_base = ifp->opts.fallback->time_base;
|
||||
|
||||
ret = av_channel_layout_copy(&ifp->ch_layout,
|
||||
@@ -3064,7 +2859,6 @@ static const char *unknown_if_null(const char *str)
|
||||
static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
InputFilter *ifilter, AVFrame *frame)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||
FrameData *fd;
|
||||
AVFrameSideData *sd;
|
||||
@@ -3083,8 +2877,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
ifp->width != frame->width ||
|
||||
ifp->height != frame->height ||
|
||||
ifp->color_space != frame->colorspace ||
|
||||
ifp->color_range != frame->color_range ||
|
||||
ifp->alpha_mode != frame->alpha_mode)
|
||||
ifp->color_range != frame->color_range)
|
||||
need_reinit |= VIDEO_CHANGED;
|
||||
break;
|
||||
}
|
||||
@@ -3121,14 +2914,6 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
ret = ifilter_parameters_from_frame(ifilter, frame);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Inputs bound to a filtergraph output will have some fields unset.
|
||||
* Handle them here */
|
||||
if (ifp->ofilter_src) {
|
||||
ret = ifilter_parameters_from_ofilter(ifilter, ifp->ofilter_src);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* (re)init the graph if possible, otherwise buffer the frame and return */
|
||||
@@ -3166,11 +2951,9 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
const char *pixel_format_name = av_get_pix_fmt_name(frame->format);
|
||||
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, ",
|
||||
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));
|
||||
unknown_if_null(color_space_name), frame->width, frame->height);
|
||||
}
|
||||
if (need_reinit & MATRIX_CHANGED)
|
||||
av_bprintf(&reason, "display matrix changed, ");
|
||||
@@ -3181,11 +2964,6 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
||||
if (reason.len > 1)
|
||||
reason.str[reason.len - 2] = '\0'; // remove last comma
|
||||
av_log(fg, AV_LOG_INFO, "Reconfiguring filter graph%s%s\n", reason.len ? " because " : "", reason.str);
|
||||
} else {
|
||||
/* Choke all input to avoid buffering excessive frames while the
|
||||
* initial filter graph is being configured, and before we have a
|
||||
* preferred input */
|
||||
sch_filter_choke_inputs(fgp->sch, fgp->sch_idx);
|
||||
}
|
||||
|
||||
ret = configure_filtergraph(fg, fgt);
|
||||
@@ -3323,6 +3101,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;
|
||||
@@ -3354,7 +3134,7 @@ static int filter_thread(void *arg)
|
||||
if (ret == AVERROR_EOF) {
|
||||
av_log(fg, AV_LOG_VERBOSE, "Input %u no longer accepts new data\n",
|
||||
input_idx);
|
||||
close_input(ifp);
|
||||
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx);
|
||||
continue;
|
||||
}
|
||||
if (ret < 0)
|
||||
@@ -3373,13 +3153,6 @@ read_frames:
|
||||
av_err2str(ret));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// ensure all inputs no longer accepting data are closed
|
||||
for (int i = 0; fgt.graph && i < fg->nb_inputs; i++) {
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]);
|
||||
if (av_buffersrc_get_status(ifp->ifilter.filter))
|
||||
close_input(ifp);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < fg->nb_outputs; i++) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+93
-102
@@ -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 = file_read(filters_script);
|
||||
else
|
||||
#endif
|
||||
if (filters)
|
||||
*dst = av_strdup(filters);
|
||||
else
|
||||
@@ -456,9 +482,9 @@ static int parse_matrix_coeffs(void *logctx, uint16_t *dest, const char *str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pixfmt_in_list(const enum AVPixelFormat *formats, enum AVPixelFormat format)
|
||||
static int fmt_in_list(const int *formats, int format)
|
||||
{
|
||||
for (; *formats != AV_PIX_FMT_NONE; formats++)
|
||||
for (; *formats != -1; formats++)
|
||||
if (*formats == format)
|
||||
return 1;
|
||||
return 0;
|
||||
@@ -518,7 +544,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name)
|
||||
* endianness by av_get_pix_fmt();
|
||||
* the following code handles the case when the native endianness is not
|
||||
* supported by the encoder, but the other one is */
|
||||
if (fmts && !pixfmt_in_list(fmts, fmt)) {
|
||||
if (fmts && !fmt_in_list(fmts, fmt)) {
|
||||
const char *name_canonical = av_get_pix_fmt_name(fmt);
|
||||
int len = strlen(name_canonical);
|
||||
|
||||
@@ -531,7 +557,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name)
|
||||
snprintf(name_other, sizeof(name_other), "%s%ce",
|
||||
name, name_canonical[len - 2] == 'l' ? 'b' : 'l');
|
||||
fmt_other = av_get_pix_fmt(name_other);
|
||||
if (fmt_other != AV_PIX_FMT_NONE && pixfmt_in_list(fmts, fmt_other)) {
|
||||
if (fmt_other != AV_PIX_FMT_NONE && fmt_in_list(fmts, fmt_other)) {
|
||||
av_log(ost, AV_LOG_VERBOSE, "Mapping pixel format %s->%s\n",
|
||||
name, name_other);
|
||||
fmt = fmt_other;
|
||||
@@ -539,7 +565,7 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
if (fmts && !pixfmt_in_list(fmts, fmt))
|
||||
if (fmts && !fmt_in_list(fmts, fmt))
|
||||
fmt = choose_pixel_fmt(ost->enc->enc_ctx, fmt);
|
||||
|
||||
return fmt;
|
||||
@@ -704,14 +730,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
|
||||
AV_OPT_SEARCH_CHILDREN) > 0)
|
||||
av_opt_set(video_enc, "stats", logfilename,
|
||||
AV_OPT_SEARCH_CHILDREN);
|
||||
} else if (!strcmp(video_enc->codec->name, "libx265")) {
|
||||
if (av_opt_is_set_to_default_by_name(video_enc, "x265-stats",
|
||||
AV_OPT_SEARCH_CHILDREN) > 0)
|
||||
av_opt_set(video_enc, "x265-stats", logfilename,
|
||||
AV_OPT_SEARCH_CHILDREN);
|
||||
} else {
|
||||
if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
|
||||
char *logbuffer = read_file_to_string(logfilename);
|
||||
char *logbuffer = file_read(logfilename);
|
||||
|
||||
if (!logbuffer) {
|
||||
av_log(ost, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
|
||||
@@ -735,10 +756,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 +805,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;
|
||||
@@ -881,7 +917,6 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter,
|
||||
.height = enc_ctx->height,
|
||||
.color_space = enc_ctx->colorspace,
|
||||
.color_range = enc_ctx->color_range,
|
||||
.alpha_mode = enc_ctx->alpha_mode,
|
||||
.vsync_method = vsync_method,
|
||||
.frame_rate = ms->frame_rate,
|
||||
.max_frame_rate = ms->max_frame_rate,
|
||||
@@ -908,7 +943,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter,
|
||||
if (!keep_pix_fmt) {
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
AV_CODEC_CONFIG_PIX_FORMAT, 0,
|
||||
(const void **) &opts.pix_fmts, NULL);
|
||||
(const void **) &opts.formats, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -929,15 +964,10 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter,
|
||||
(const void **) &opts.color_ranges, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
AV_CODEC_CONFIG_ALPHA_MODE, 0,
|
||||
(const void **) &opts.alpha_modes, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
AV_CODEC_CONFIG_SAMPLE_FORMAT, 0,
|
||||
(const void **) &opts.sample_fmts, NULL);
|
||||
(const void **) &opts.formats, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = avcodec_get_supported_config(enc_ctx, NULL,
|
||||
@@ -967,7 +997,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter,
|
||||
ost->filter = ofilter;
|
||||
ret = ofilter_bind_enc(ofilter, ms->sch_idx_enc, &opts);
|
||||
} else {
|
||||
ret = fg_create_simple(&ost->fg_simple, ost->ist, &filters,
|
||||
ret = fg_create_simple(&ost->fg_simple, ost->ist, filters,
|
||||
mux->sch, ms->sch_idx_enc, &opts);
|
||||
if (ret >= 0)
|
||||
ost->filter = ost->fg_simple->outputs[0];
|
||||
@@ -999,12 +1029,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 +1390,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 +1520,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);
|
||||
@@ -1539,7 +1592,6 @@ fail:
|
||||
static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
||||
{
|
||||
AVFormatContext *oc = mux->fc;
|
||||
InputStreamGroup *best_istg = NULL;
|
||||
InputStream *best_ist = NULL;
|
||||
int64_t best_score = 0;
|
||||
int qcr;
|
||||
@@ -1551,49 +1603,14 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
||||
qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
|
||||
for (int j = 0; j < nb_input_files; j++) {
|
||||
InputFile *ifile = input_files[j];
|
||||
InputStreamGroup *file_best_istg = NULL;
|
||||
InputStream *file_best_ist = NULL;
|
||||
int64_t file_best_score = 0;
|
||||
for (int i = 0; i < ifile->nb_stream_groups; i++) {
|
||||
InputStreamGroup *istg = ifile->stream_groups[i];
|
||||
int64_t score = 0;
|
||||
|
||||
if (!istg->fg)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < istg->stg->nb_streams; j++) {
|
||||
AVStream *st = istg->stg->streams[j];
|
||||
|
||||
if (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) {
|
||||
score = 100000000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (istg->stg->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
|
||||
const AVStreamGroupTileGrid *tg = istg->stg->params.tile_grid;
|
||||
score += tg->width * (int64_t)tg->height
|
||||
+ 5000000*!!(istg->stg->disposition & AV_DISPOSITION_DEFAULT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (score > file_best_score) {
|
||||
file_best_score = score;
|
||||
file_best_istg = istg;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ifile->nb_streams; i++) {
|
||||
InputStream *ist = ifile->streams[i];
|
||||
const AVCodecDescriptor *desc = avcodec_descriptor_get(ist->st->codecpar->codec_id);
|
||||
int64_t score;
|
||||
|
||||
if (ist->user_set_discard == AVDISCARD_ALL ||
|
||||
ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
|
||||
(desc && (desc->props & AV_CODEC_PROP_ENHANCEMENT)))
|
||||
ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
|
||||
continue;
|
||||
|
||||
score = ist->st->codecpar->width * (int64_t)ist->st->codecpar->height
|
||||
@@ -1607,15 +1624,6 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
||||
continue;
|
||||
file_best_score = score;
|
||||
file_best_ist = ist;
|
||||
file_best_istg = NULL;
|
||||
}
|
||||
}
|
||||
if (file_best_istg) {
|
||||
file_best_score -= 5000000*!!(file_best_istg->stg->disposition & AV_DISPOSITION_DEFAULT);
|
||||
if (file_best_score > best_score) {
|
||||
best_score = file_best_score;
|
||||
best_istg = file_best_istg;
|
||||
best_ist = NULL;
|
||||
}
|
||||
}
|
||||
if (file_best_ist) {
|
||||
@@ -1625,19 +1633,9 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
||||
if (file_best_score > best_score) {
|
||||
best_score = file_best_score;
|
||||
best_ist = file_best_ist;
|
||||
best_istg = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_istg) {
|
||||
FilterGraph *fg = best_istg->fg;
|
||||
OutputFilter *ofilter = fg->outputs[0];
|
||||
|
||||
av_assert0(fg->nb_outputs == 1);
|
||||
av_log(mux, AV_LOG_VERBOSE, "Creating output stream from stream group derived complex filtergraph %d.\n", fg->index);
|
||||
|
||||
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, NULL, ofilter, NULL, NULL);
|
||||
}
|
||||
if (best_ist)
|
||||
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL);
|
||||
|
||||
@@ -2063,8 +2061,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 +2486,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 +2508,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 +2582,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 +2606,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,8 +3214,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;
|
||||
} else if (!strcmp(forced_keyframes, "scd_metadata")) {
|
||||
ost->kf.type = KF_FORCE_SCD_METADATA;
|
||||
#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 {
|
||||
int ret = parse_forced_key_frames(ost, &ost->kf, mux, forced_keyframes);
|
||||
if (ret < 0)
|
||||
|
||||
+111
-113
@@ -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;
|
||||
@@ -239,70 +242,6 @@ OPT_MATCH_PER_STREAM(int, int, OPT_TYPE_INT, i);
|
||||
OPT_MATCH_PER_STREAM(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
static unsigned opt_match_per_stream_group(void *logctx, enum OptionType type,
|
||||
const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg)
|
||||
{
|
||||
int matches = 0, match_idx = -1;
|
||||
|
||||
av_assert0((type == sol->type) || !sol->nb_opt);
|
||||
|
||||
for (int i = 0; i < sol->nb_opt; i++) {
|
||||
const StreamSpecifier *ss = &sol->opt[i].stream_spec;
|
||||
|
||||
if (stream_group_specifier_match(ss, fc, stg, logctx)) {
|
||||
match_idx = i;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches > 1 && sol->opt_canon) {
|
||||
const SpecifierOpt *so = &sol->opt[match_idx];
|
||||
const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";
|
||||
|
||||
char namestr[128] = "";
|
||||
char optval_buf[32];
|
||||
const char *optval = optval_buf;
|
||||
|
||||
snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name);
|
||||
if (sol->opt_canon->flags & OPT_HAS_ALT) {
|
||||
const char * const *names_alt = sol->opt_canon->u1.names_alt;
|
||||
for (int i = 0; names_alt[i]; i++)
|
||||
av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]);
|
||||
}
|
||||
|
||||
switch (sol->type) {
|
||||
case OPT_TYPE_STRING: optval = so->u.str; break;
|
||||
case OPT_TYPE_INT: snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i); break;
|
||||
case OPT_TYPE_INT64: snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break;
|
||||
case OPT_TYPE_FLOAT: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f); break;
|
||||
case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl); break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for "
|
||||
"stream group %d, only the last option '-%s%s%s %s' will be used.\n",
|
||||
namestr, stg->index, sol->opt_canon->name, spec[0] ? ":" : "",
|
||||
spec, optval);
|
||||
}
|
||||
|
||||
return match_idx + 1;
|
||||
}
|
||||
|
||||
#define OPT_MATCH_PER_STREAM_GROUP(name, type, opt_type, m) \
|
||||
void opt_match_per_stream_group_ ## name(void *logctx, const SpecifierOptList *sol, \
|
||||
AVFormatContext *fc, AVStreamGroup *stg, type *out) \
|
||||
{ \
|
||||
unsigned ret = opt_match_per_stream_group(logctx, opt_type, sol, fc, stg); \
|
||||
if (ret > 0) \
|
||||
*out = sol->opt[ret - 1].u.m; \
|
||||
}
|
||||
|
||||
OPT_MATCH_PER_STREAM_GROUP(str, const char *, OPT_TYPE_STRING, str);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int, int, OPT_TYPE_INT, i);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM_GROUP(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs)
|
||||
{
|
||||
const char *spec = *pspec;
|
||||
@@ -356,17 +295,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, int *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;
|
||||
}
|
||||
|
||||
@@ -544,10 +504,8 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
}
|
||||
|
||||
if (arg[0] == '[') {
|
||||
ViewSpecifier vs;
|
||||
/* this mapping refers to lavfi output */
|
||||
const char *c = arg + 1;
|
||||
char *endptr;
|
||||
|
||||
ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
|
||||
if (ret < 0)
|
||||
@@ -560,27 +518,6 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
arg++;
|
||||
|
||||
m->group_index = -1;
|
||||
file_idx = strtol(arg, &endptr, 0);
|
||||
if (file_idx >= nb_input_files || file_idx < 0)
|
||||
goto end;
|
||||
|
||||
arg = endptr;
|
||||
ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
arg = ss.remainder ? ss.remainder : "";
|
||||
ret = view_specifier_parse(&arg, &vs);
|
||||
if (ret < 0 || (*arg && strcmp(arg, "]")))
|
||||
goto end;
|
||||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = ss.idx;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
} else {
|
||||
ViewSpecifier vs;
|
||||
char *endptr;
|
||||
@@ -621,9 +558,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,
|
||||
input_files[m->file_index]->ctx,
|
||||
input_files[m->file_index]->ctx->streams[m->stream_index],
|
||||
@@ -649,7 +583,6 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = i;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
m->vs = vs;
|
||||
}
|
||||
}
|
||||
@@ -669,7 +602,6 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
end:
|
||||
ret = 0;
|
||||
fail:
|
||||
stream_specifier_uninit(&ss);
|
||||
@@ -1089,12 +1021,6 @@ static int opt_preset(void *optctx, const char *opt, const char *arg)
|
||||
char filename[1000], line[1000], tmp_line[1000];
|
||||
const char *codec_name = NULL;
|
||||
int ret = 0;
|
||||
int depth = o->depth;
|
||||
|
||||
if (depth > 2) {
|
||||
av_log(NULL, AV_LOG_ERROR, "too deep recursion\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
codec_name = opt_match_per_type_str(&o->codec_names, *opt);
|
||||
|
||||
@@ -1106,7 +1032,6 @@ static int opt_preset(void *optctx, const char *opt, const char *arg)
|
||||
return AVERROR(ENOENT);
|
||||
}
|
||||
|
||||
o->depth ++;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *key = tmp_line, *value, *endptr;
|
||||
|
||||
@@ -1125,8 +1050,7 @@ static int opt_preset(void *optctx, const char *opt, const char *arg)
|
||||
else if (!strcmp(key, "vcodec")) opt_video_codec (o, key, value);
|
||||
else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
|
||||
else if (!strcmp(key, "dcodec")) opt_data_codec (o, key, value);
|
||||
else if ((parse_option(o, key, value, options) < 0) &&
|
||||
(opt_default_new(o, key, value) < 0)) {
|
||||
else if (opt_default_new(o, key, value) < 0) {
|
||||
av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
|
||||
filename, line, key, value);
|
||||
ret = AVERROR(EINVAL);
|
||||
@@ -1135,7 +1059,6 @@ static int opt_preset(void *optctx, const char *opt, const char *arg)
|
||||
}
|
||||
|
||||
fail:
|
||||
o->depth = depth;
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
@@ -1210,6 +1133,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 +1181,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 = file_read(arg);
|
||||
if (!graph_desc)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -/filter_complex %s instead\n",
|
||||
opt, arg);
|
||||
|
||||
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;
|
||||
@@ -1450,7 +1406,7 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch)
|
||||
|
||||
/* create complex filtergraphs */
|
||||
for (int i = 0; i < go.nb_filtergraphs; i++) {
|
||||
ret = fg_create(NULL, &go.filtergraphs[i], sch, NULL);
|
||||
ret = fg_create(NULL, go.filtergraphs[i], sch);
|
||||
go.filtergraphs[i] = NULL;
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
@@ -1540,6 +1496,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 +1718,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 +1738,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 +1842,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 +1889,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 +2074,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, },
|
||||
};
|
||||
|
||||
+94
-350
@@ -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 {
|
||||
@@ -194,6 +189,7 @@ typedef struct PreMuxQueue {
|
||||
|
||||
typedef struct SchMuxStream {
|
||||
SchedulerNode src;
|
||||
SchedulerNode src_sched;
|
||||
|
||||
unsigned *sub_heartbeat_dst;
|
||||
unsigned nb_sub_heartbeat_dst;
|
||||
@@ -239,6 +235,7 @@ typedef struct SchMux {
|
||||
|
||||
typedef struct SchFilterIn {
|
||||
SchedulerNode src;
|
||||
SchedulerNode src_sched;
|
||||
int send_finished;
|
||||
int receive_finished;
|
||||
} SchFilterIn;
|
||||
@@ -252,7 +249,7 @@ typedef struct SchFilterGraph {
|
||||
|
||||
SchFilterIn *inputs;
|
||||
unsigned nb_inputs;
|
||||
unsigned nb_inputs_finished_send;
|
||||
atomic_uint nb_inputs_finished_send;
|
||||
unsigned nb_inputs_finished_receive;
|
||||
|
||||
SchFilterOut *outputs;
|
||||
@@ -392,7 +389,7 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si
|
||||
// for frames held in queues inside the ffmpeg utility. If this
|
||||
// can ever dynamically change then the corresponding decode
|
||||
// code needs to be updated as well.
|
||||
av_assert0(queue_size <= DEFAULT_FRAME_THREAD_QUEUE_SIZE);
|
||||
av_assert0(queue_size == DEFAULT_FRAME_THREAD_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
tq = tq_alloc(nb_streams, queue_size,
|
||||
@@ -410,9 +407,6 @@ static int task_start(SchTask *task)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!task->parent)
|
||||
return 0;
|
||||
|
||||
av_log(task->func_arg, AV_LOG_VERBOSE, "Starting thread...\n");
|
||||
|
||||
av_assert0(!task->thread_running);
|
||||
@@ -440,7 +434,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 +444,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,43 +456,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];
|
||||
|
||||
av_assert0(!fg->task.thread_running);
|
||||
memset(&fg->task, 0, sizeof(fg->task));
|
||||
|
||||
tq_free(&fg->queue);
|
||||
|
||||
av_freep(&fg->inputs);
|
||||
fg->nb_inputs = 0;
|
||||
av_freep(&fg->outputs);
|
||||
fg->nb_outputs = 0;
|
||||
|
||||
fg->task_exited = 1;
|
||||
}
|
||||
|
||||
void sch_free(Scheduler **psch)
|
||||
{
|
||||
Scheduler *sch = *psch;
|
||||
@@ -553,7 +510,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 +521,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 +771,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,128 +1264,28 @@ 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);
|
||||
|
||||
// Unchoke any filter graphs that are downstream of this node, to prevent it
|
||||
// from getting stuck trying to push data to a full queue
|
||||
static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
|
||||
{
|
||||
SchFilterGraph *fg;
|
||||
SchDec *dec;
|
||||
SchEnc *enc;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
enc = &sch->enc[dst->idx];
|
||||
for (int i = 0; i < enc->nb_dst; i++)
|
||||
unchoke_downstream(sch, &enc->dst[i]);
|
||||
break;
|
||||
case SCH_NODE_TYPE_MUX:
|
||||
// muxers are never choked
|
||||
break;
|
||||
case SCH_NODE_TYPE_FILTER_IN:
|
||||
fg = &sch->filters[dst->idx];
|
||||
if (fg->best_input == fg->nb_inputs) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
av_unreachable("Invalid destination node type?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return;
|
||||
case SCH_NODE_TYPE_DEC:
|
||||
dec = &sch->dec[src.idx];
|
||||
if (!(flags & UNCHOKE_DECODE))
|
||||
return;
|
||||
dec->waiter.choked_next = 0;
|
||||
src = dec->src;
|
||||
continue;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
src = sch->enc[src.idx].src;
|
||||
continue;
|
||||
case SCH_NODE_TYPE_FILTER_OUT:
|
||||
fg = &sch->filters[src.idx];
|
||||
// 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;
|
||||
return;
|
||||
}
|
||||
src = fg->inputs[fg->best_input].src;
|
||||
continue;
|
||||
default:
|
||||
av_unreachable("Invalid source node type?");
|
||||
|
||||
// fed directly by a demuxer (i.e. not through a filtergraph)
|
||||
if (src.type == SCH_NODE_TYPE_DEMUX) {
|
||||
sch->demux[src.idx].waiter.choked_next = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void choke_demux(const Scheduler *sch, int demux_id, int choked)
|
||||
{
|
||||
av_assert1(demux_id < sch->nb_demux);
|
||||
SchDemux *demux = &sch->demux[demux_id];
|
||||
av_assert0(src.type == SCH_NODE_TYPE_FILTER_OUT);
|
||||
fg = &sch->filters[src.idx];
|
||||
|
||||
for (int i = 0; i < demux->nb_streams; i++) {
|
||||
SchedulerNode *dst = demux->streams[i].dst;
|
||||
SchFilterGraph *fg;
|
||||
|
||||
switch (dst->type) {
|
||||
case SCH_NODE_TYPE_DEC:
|
||||
tq_choke(sch->dec[dst->idx].queue, choked);
|
||||
break;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
tq_choke(sch->enc[dst->idx].queue, choked);
|
||||
break;
|
||||
case SCH_NODE_TYPE_MUX:
|
||||
break;
|
||||
case SCH_NODE_TYPE_FILTER_IN:
|
||||
fg = &sch->filters[dst->idx];
|
||||
if (fg->nb_inputs == 1)
|
||||
tq_choke(fg->queue, choked);
|
||||
break;
|
||||
default:
|
||||
av_unreachable("Invalid destination node type?");
|
||||
break;
|
||||
// the filtergraph contains internal sources and
|
||||
// requested to be scheduled directly
|
||||
if (fg->best_input == fg->nb_inputs) {
|
||||
fg->waiter.choked_next = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
src = fg->inputs[fg->best_input].src_sched;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1453,23 +1299,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,65 +1320,39 @@ 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_sched);
|
||||
have_unchoked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// also unchoke any sources feeding into closed filter graph inputs, so
|
||||
// that they can observe the downstream EOF
|
||||
for (unsigned i = 0; i < sch->nb_filters; i++) {
|
||||
SchFilterGraph *fg = &sch->filters[i];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
#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)
|
||||
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);
|
||||
}
|
||||
|
||||
UPDATE_WAITER(demux);
|
||||
UPDATE_WAITER(filters);
|
||||
UPDATE_WAITER(dec);
|
||||
}
|
||||
|
||||
enum {
|
||||
@@ -1547,27 +1361,6 @@ enum {
|
||||
CYCLE_NODE_DONE,
|
||||
};
|
||||
|
||||
// Finds the filtergraph or muxer upstream of a scheduler node
|
||||
static SchedulerNode src_filtergraph(const Scheduler *sch, SchedulerNode src)
|
||||
{
|
||||
while (1) {
|
||||
switch (src.type) {
|
||||
case SCH_NODE_TYPE_DEMUX:
|
||||
case SCH_NODE_TYPE_FILTER_OUT:
|
||||
return src;
|
||||
case SCH_NODE_TYPE_DEC:
|
||||
src = sch->dec[src.idx].src;
|
||||
continue;
|
||||
case SCH_NODE_TYPE_ENC:
|
||||
src = sch->enc[src.idx].src;
|
||||
continue;
|
||||
default:
|
||||
av_unreachable("Invalid source node type?");
|
||||
return (SchedulerNode) {0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
|
||||
uint8_t *filters_visited, SchedulerNode *filters_stack)
|
||||
@@ -1584,23 +1377,22 @@ check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
|
||||
// descend into every input, depth first
|
||||
if (src.idx_stream < fg->nb_inputs) {
|
||||
const SchFilterIn *fi = &fg->inputs[src.idx_stream++];
|
||||
SchedulerNode node = src_filtergraph(sch, fi->src);
|
||||
|
||||
// connected to demuxer, no cycles possible
|
||||
if (node.type == SCH_NODE_TYPE_DEMUX)
|
||||
if (fi->src_sched.type == SCH_NODE_TYPE_DEMUX)
|
||||
continue;
|
||||
|
||||
// otherwise connected to another filtergraph
|
||||
av_assert0(node.type == SCH_NODE_TYPE_FILTER_OUT);
|
||||
av_assert0(fi->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
|
||||
|
||||
// found a cycle
|
||||
if (filters_visited[node.idx] == CYCLE_NODE_STARTED)
|
||||
if (filters_visited[fi->src_sched.idx] == CYCLE_NODE_STARTED)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
// place current position on stack and descend
|
||||
av_assert0(nb_filters_stack < sch->nb_filters);
|
||||
filters_stack[nb_filters_stack++] = src;
|
||||
src = (SchedulerNode){ .idx = node.idx, .idx_stream = 0 };
|
||||
src = (SchedulerNode){ .idx = fi->src_sched.idx, .idx_stream = 0 };
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1722,7 +1514,22 @@ static int start_prepare(Scheduler *sch)
|
||||
for (unsigned j = 0; j < mux->nb_streams; j++) {
|
||||
SchMuxStream *ms = &mux->streams[j];
|
||||
|
||||
if (!ms->src.type) {
|
||||
switch (ms->src.type) {
|
||||
case SCH_NODE_TYPE_ENC: {
|
||||
SchEnc *enc = &sch->enc[ms->src.idx];
|
||||
if (enc->src.type == SCH_NODE_TYPE_DEC) {
|
||||
ms->src_sched = sch->dec[enc->src.idx].src;
|
||||
av_assert0(ms->src_sched.type == SCH_NODE_TYPE_DEMUX);
|
||||
} else {
|
||||
ms->src_sched = enc->src;
|
||||
av_assert0(ms->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCH_NODE_TYPE_DEMUX:
|
||||
ms->src_sched = ms->src;
|
||||
break;
|
||||
default:
|
||||
av_log(mux, AV_LOG_ERROR,
|
||||
"Muxer stream #%u not connected to a source\n", j);
|
||||
return AVERROR(EINVAL);
|
||||
@@ -1740,12 +1547,26 @@ static int start_prepare(Scheduler *sch)
|
||||
|
||||
for (unsigned j = 0; j < fg->nb_inputs; j++) {
|
||||
SchFilterIn *fi = &fg->inputs[j];
|
||||
SchDec *dec;
|
||||
|
||||
if (!fi->src.type) {
|
||||
av_log(fg, AV_LOG_ERROR,
|
||||
"Filtergraph input %u not connected to a source\n", j);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (fi->src.type == SCH_NODE_TYPE_FILTER_OUT)
|
||||
fi->src_sched = fi->src;
|
||||
else {
|
||||
av_assert0(fi->src.type == SCH_NODE_TYPE_DEC);
|
||||
dec = &sch->dec[fi->src.idx];
|
||||
|
||||
switch (dec->src.type) {
|
||||
case SCH_NODE_TYPE_DEMUX: fi->src_sched = dec->src; break;
|
||||
case SCH_NODE_TYPE_ENC: fi->src_sched = sch->enc[dec->src.idx].src; break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < fg->nb_outputs; j++) {
|
||||
@@ -2257,7 +2078,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 +2162,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 +2172,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;
|
||||
}
|
||||
|
||||
@@ -2392,20 +2189,14 @@ static int send_to_filter(Scheduler *sch, SchFilterGraph *fg,
|
||||
if (frame)
|
||||
return tq_send(fg->queue, in_idx, frame);
|
||||
|
||||
pthread_mutex_lock(&sch->schedule_lock);
|
||||
|
||||
if (!fg->inputs[in_idx].send_finished) {
|
||||
fg->inputs[in_idx].send_finished = 1;
|
||||
tq_send_finish(fg->queue, in_idx);
|
||||
|
||||
// close the control stream when all actual inputs are done
|
||||
if (++fg->nb_inputs_finished_send == fg->nb_inputs)
|
||||
if (atomic_fetch_add(&fg->nb_inputs_finished_send, 1) == fg->nb_inputs - 1)
|
||||
tq_send_finish(fg->queue, fg->nb_inputs);
|
||||
|
||||
schedule_update_locked(sch);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&sch->schedule_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2516,7 +2307,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 +2396,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 +2416,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) {
|
||||
@@ -2663,8 +2447,6 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx)
|
||||
av_assert0(in_idx < fg->nb_inputs);
|
||||
fi = &fg->inputs[in_idx];
|
||||
|
||||
pthread_mutex_lock(&sch->schedule_lock);
|
||||
|
||||
if (!fi->receive_finished) {
|
||||
fi->receive_finished = 1;
|
||||
tq_receive_finish(fg->queue, in_idx);
|
||||
@@ -2672,18 +2454,13 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx)
|
||||
// close the control stream when all actual inputs are done
|
||||
if (++fg->nb_inputs_finished_receive == fg->nb_inputs)
|
||||
tq_receive_finish(fg->queue, fg->nb_inputs);
|
||||
|
||||
schedule_update_locked(sch);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&sch->schedule_lock);
|
||||
}
|
||||
|
||||
int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *frame)
|
||||
{
|
||||
SchFilterGraph *fg;
|
||||
SchedulerNode dst;
|
||||
int ret;
|
||||
|
||||
av_assert0(fg_idx < sch->nb_filters);
|
||||
fg = &sch->filters[fg_idx];
|
||||
@@ -2691,16 +2468,9 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *
|
||||
av_assert0(out_idx < fg->nb_outputs);
|
||||
dst = fg->outputs[out_idx].dst;
|
||||
|
||||
if (dst.type == SCH_NODE_TYPE_ENC) {
|
||||
ret = send_to_enc(sch, &sch->enc[dst.idx], frame);
|
||||
if (ret == AVERROR_EOF)
|
||||
send_to_enc(sch, &sch->enc[dst.idx], NULL);
|
||||
} else {
|
||||
ret = send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame);
|
||||
if (ret == AVERROR_EOF)
|
||||
send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, NULL);
|
||||
}
|
||||
return ret;
|
||||
return (dst.type == SCH_NODE_TYPE_ENC) ?
|
||||
send_to_enc (sch, &sch->enc[dst.idx], frame) :
|
||||
send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame);
|
||||
}
|
||||
|
||||
static int filter_done(Scheduler *sch, unsigned fg_idx)
|
||||
@@ -2742,18 +2512,6 @@ int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame)
|
||||
return send_to_filter(sch, fg, fg->nb_inputs, frame);
|
||||
}
|
||||
|
||||
void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx)
|
||||
{
|
||||
SchFilterGraph *fg;
|
||||
av_assert0(fg_idx < sch->nb_filters);
|
||||
fg = &sch->filters[fg_idx];
|
||||
|
||||
pthread_mutex_lock(&sch->schedule_lock);
|
||||
fg->best_input = fg->nb_inputs;
|
||||
schedule_update_locked(sch);
|
||||
pthread_mutex_unlock(&sch->schedule_lock);
|
||||
}
|
||||
|
||||
static int task_cleanup(Scheduler *sch, SchedulerNode node)
|
||||
{
|
||||
switch (node.type) {
|
||||
@@ -2762,7 +2520,7 @@ static int task_cleanup(Scheduler *sch, SchedulerNode node)
|
||||
case SCH_NODE_TYPE_DEC: return dec_done (sch, node.idx);
|
||||
case SCH_NODE_TYPE_ENC: return enc_done (sch, node.idx);
|
||||
case SCH_NODE_TYPE_FILTER_IN: return filter_done(sch, node.idx);
|
||||
default: av_unreachable("Invalid node type?");
|
||||
default: av_assert0(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2803,9 +2561,6 @@ static int task_stop(Scheduler *sch, SchTask *task)
|
||||
int ret;
|
||||
void *thread_ret;
|
||||
|
||||
if (!task->parent)
|
||||
return 0;
|
||||
|
||||
if (!task->thread_running)
|
||||
return task_cleanup(sch, task->node);
|
||||
|
||||
@@ -2826,23 +2581,12 @@ 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;
|
||||
waiter_set(w, 1);
|
||||
if (type)
|
||||
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 +2623,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;
|
||||
|
||||
|
||||
+1
-10
@@ -205,8 +205,6 @@ int sch_add_dec_output(Scheduler *sch, unsigned dec_idx);
|
||||
int sch_add_filtergraph(Scheduler *sch, unsigned nb_inputs, unsigned nb_outputs,
|
||||
SchThreadFunc func, void *ctx);
|
||||
|
||||
void sch_remove_filtergraph(Scheduler *sch, int idx);
|
||||
|
||||
/**
|
||||
* Add a muxer to the scheduler.
|
||||
*
|
||||
@@ -259,7 +257,7 @@ int sch_add_mux(Scheduler *sch, SchThreadFunc func, int (*init)(void *),
|
||||
/**
|
||||
* Default size of a frame thread queue.
|
||||
*/
|
||||
#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 2
|
||||
#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 8
|
||||
|
||||
/**
|
||||
* Add a muxed stream for a previously added muxer.
|
||||
@@ -445,13 +443,6 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx,
|
||||
|
||||
int sch_filter_command(Scheduler *sch, unsigned fg_idx, struct AVFrame *frame);
|
||||
|
||||
/**
|
||||
* Called by filtergraph tasks to choke all filter inputs, preventing them from
|
||||
* receiving more frames until woken up again by the scheduler. Used during
|
||||
* initial graph configuration to avoid unnecessary buffering.
|
||||
*/
|
||||
void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx);
|
||||
|
||||
/**
|
||||
* Called by encoder tasks to obtain frames for encoding. Will wait for a frame
|
||||
* to become available and return it in frame.
|
||||
|
||||
+16
-100
@@ -37,7 +37,6 @@
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/parseutils.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
#include "libavutil/time.h"
|
||||
#include "libavutil/bprint.h"
|
||||
@@ -268,7 +267,6 @@ typedef struct VideoState {
|
||||
AVComplexFloat *rdft_data;
|
||||
int xpos;
|
||||
double last_vis_time;
|
||||
RenderParams render_params;
|
||||
SDL_Texture *vis_texture;
|
||||
SDL_Texture *sub_texture;
|
||||
SDL_Texture *vid_texture;
|
||||
@@ -352,7 +350,6 @@ static int find_stream_info = 1;
|
||||
static int filter_nbthreads = 0;
|
||||
static int enable_vulkan = 0;
|
||||
static char *vulkan_params = NULL;
|
||||
static char *video_background = NULL;
|
||||
static const char *hwaccel = NULL;
|
||||
|
||||
/* current context */
|
||||
@@ -945,11 +942,6 @@ static enum AVColorSpace sdl_supported_color_spaces[] = {
|
||||
AVCOL_SPC_SMPTE170M,
|
||||
};
|
||||
|
||||
static enum AVAlphaMode sdl_supported_alpha_modes[] = {
|
||||
AVALPHA_MODE_UNSPECIFIED,
|
||||
AVALPHA_MODE_STRAIGHT,
|
||||
};
|
||||
|
||||
static void set_sdl_yuv_conversion_mode(AVFrame *frame)
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2,0,8)
|
||||
@@ -966,52 +958,15 @@ static void set_sdl_yuv_conversion_mode(AVFrame *frame)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_video_background(VideoState *is)
|
||||
{
|
||||
const int tile_size = VIDEO_BACKGROUND_TILE_SIZE;
|
||||
SDL_Rect *rect = &is->render_params.target_rect;
|
||||
SDL_BlendMode blendMode;
|
||||
|
||||
if (!SDL_GetTextureBlendMode(is->vid_texture, &blendMode) && blendMode == SDL_BLENDMODE_BLEND) {
|
||||
switch (is->render_params.video_background_type) {
|
||||
case VIDEO_BACKGROUND_TILES:
|
||||
SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255);
|
||||
fill_rectangle(rect->x, rect->y, rect->w, rect->h);
|
||||
SDL_SetRenderDrawColor(renderer, 222, 222, 222, 255);
|
||||
for (int x = 0; x < rect->w; x += tile_size * 2)
|
||||
fill_rectangle(rect->x + x, rect->y, FFMIN(tile_size, rect->w - x), rect->h);
|
||||
for (int y = 0; y < rect->h; y += tile_size * 2)
|
||||
fill_rectangle(rect->x, rect->y + y, rect->w, FFMIN(tile_size, rect->h - y));
|
||||
SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255);
|
||||
for (int y = 0; y < rect->h; y += tile_size * 2) {
|
||||
int h = FFMIN(tile_size, rect->h - y);
|
||||
for (int x = 0; x < rect->w; x += tile_size * 2)
|
||||
fill_rectangle(x + rect->x, y + rect->y, FFMIN(tile_size, rect->w - x), h);
|
||||
}
|
||||
break;
|
||||
case VIDEO_BACKGROUND_COLOR: {
|
||||
const uint8_t *c = is->render_params.video_background_color;
|
||||
SDL_SetRenderDrawColor(renderer, c[0], c[1], c[2], c[3]);
|
||||
fill_rectangle(rect->x, rect->y, rect->w, rect->h);
|
||||
break;
|
||||
}
|
||||
case VIDEO_BACKGROUND_NONE:
|
||||
SDL_SetTextureBlendMode(is->vid_texture, SDL_BLENDMODE_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void video_image_display(VideoState *is)
|
||||
{
|
||||
Frame *vp;
|
||||
Frame *sp = NULL;
|
||||
SDL_Rect *rect = &is->render_params.target_rect;
|
||||
SDL_Rect rect;
|
||||
|
||||
vp = frame_queue_peek_last(&is->pictq);
|
||||
calculate_display_rect(rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
|
||||
if (vk_renderer) {
|
||||
vk_renderer_display(vk_renderer, vp->frame, &is->render_params);
|
||||
vk_renderer_display(vk_renderer, vp->frame);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1060,6 +1015,7 @@ static void video_image_display(VideoState *is)
|
||||
}
|
||||
}
|
||||
|
||||
calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
|
||||
set_sdl_yuv_conversion_mode(vp->frame);
|
||||
|
||||
if (!vp->uploaded) {
|
||||
@@ -1071,16 +1027,15 @@ static void video_image_display(VideoState *is)
|
||||
vp->flip_v = vp->frame->linesize[0] < 0;
|
||||
}
|
||||
|
||||
draw_video_background(is);
|
||||
SDL_RenderCopyEx(renderer, is->vid_texture, NULL, rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);
|
||||
SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);
|
||||
set_sdl_yuv_conversion_mode(NULL);
|
||||
if (sp) {
|
||||
#if USE_ONEPASS_SUBTITLE_RENDER
|
||||
SDL_RenderCopy(renderer, is->sub_texture, NULL, rect);
|
||||
SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect);
|
||||
#else
|
||||
int i;
|
||||
double xratio = (double)rect->w / (double)sp->width;
|
||||
double yratio = (double)rect->h / (double)sp->height;
|
||||
double xratio = (double)rect.w / (double)sp->width;
|
||||
double yratio = (double)rect.h / (double)sp->height;
|
||||
for (i = 0; i < sp->sub.num_rects; i++) {
|
||||
SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i];
|
||||
SDL_Rect target = {.x = rect.x + sub_rect->x * xratio,
|
||||
@@ -1951,7 +1906,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
|
||||
par->sample_aspect_ratio = codecpar->sample_aspect_ratio;
|
||||
par->color_space = frame->colorspace;
|
||||
par->color_range = frame->color_range;
|
||||
par->alpha_mode = frame->alpha_mode;
|
||||
par->frame_rate = fr;
|
||||
par->hw_frames_ctx = frame->hw_frames_ctx;
|
||||
ret = av_buffersrc_parameters_set(filt_src, par);
|
||||
@@ -1978,11 +1932,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
|
||||
AV_OPT_TYPE_INT, sdl_supported_color_spaces)) < 0)
|
||||
goto fail;
|
||||
|
||||
if ((ret = av_opt_set_array(filt_out, "alphamodes", AV_OPT_SEARCH_CHILDREN,
|
||||
0, FF_ARRAY_ELEMS(sdl_supported_alpha_modes),
|
||||
AV_OPT_TYPE_INT, sdl_supported_alpha_modes)) < 0)
|
||||
goto fail;
|
||||
|
||||
ret = avfilter_init_dict(filt_out, NULL);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
@@ -2883,7 +2832,6 @@ static int read_thread(void *arg)
|
||||
int st_index[AVMEDIA_TYPE_NB];
|
||||
AVPacket *pkt = NULL;
|
||||
int64_t stream_start_time;
|
||||
char metadata_description[96];
|
||||
int pkt_in_play_range = 0;
|
||||
const AVDictionaryEntry *t;
|
||||
SDL_mutex *wait_mutex = SDL_CreateMutex();
|
||||
@@ -2991,10 +2939,8 @@ static int read_thread(void *arg)
|
||||
|
||||
is->realtime = is_realtime(ic);
|
||||
|
||||
if (show_status) {
|
||||
fprintf(stderr, "\x1b[2K\r");
|
||||
if (show_status)
|
||||
av_dump_format(ic, 0, is->filename, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < ic->nb_streams; i++) {
|
||||
AVStream *st = ic->streams[i];
|
||||
@@ -3003,11 +2949,7 @@ static int read_thread(void *arg)
|
||||
if (type >= 0 && wanted_stream_spec[type] && st_index[type] == -1)
|
||||
if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)
|
||||
st_index[type] = i;
|
||||
// Clear all pre-existing metadata update flags to avoid printing
|
||||
// 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));
|
||||
@@ -3175,27 +3117,6 @@ static int read_thread(void *arg)
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 */
|
||||
stream_start_time = ic->streams[pkt->stream_index]->start_time;
|
||||
pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
|
||||
@@ -3277,16 +3198,6 @@ static VideoState *stream_open(const char *filename,
|
||||
av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", startup_volume);
|
||||
if (startup_volume > 100)
|
||||
av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", startup_volume);
|
||||
if (video_background) {
|
||||
if (!strcmp(video_background, "none")) {
|
||||
is->render_params.video_background_type = VIDEO_BACKGROUND_NONE;
|
||||
} else if (strcmp(video_background, "tiles")) {
|
||||
if (av_parse_color(is->render_params.video_background_color, video_background, -1, NULL) >= 0)
|
||||
is->render_params.video_background_type = VIDEO_BACKGROUND_COLOR;
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
startup_volume = av_clip(startup_volume, 0, 100);
|
||||
startup_volume = av_clip(SDL_MIX_MAXVOLUME * startup_volume / 100, 0, SDL_MIX_MAXVOLUME);
|
||||
is->audio_volume = startup_volume;
|
||||
@@ -3800,7 +3711,6 @@ static const OptionDef options[] = {
|
||||
{ "filter_threads", OPT_TYPE_INT, OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" },
|
||||
{ "enable_vulkan", OPT_TYPE_BOOL, 0, { &enable_vulkan }, "enable vulkan renderer" },
|
||||
{ "vulkan_params", OPT_TYPE_STRING, OPT_EXPERT, { &vulkan_params }, "vulkan configuration using a list of key=value pairs separated by ':'" },
|
||||
{ "video_bg", OPT_TYPE_STRING, OPT_EXPERT, { &video_background }, "set video background for transparent videos" },
|
||||
{ "hwaccel", OPT_TYPE_STRING, OPT_EXPERT, { &hwaccel }, "use HW accelerated decoding" },
|
||||
{ NULL, },
|
||||
};
|
||||
@@ -3835,9 +3745,9 @@ void show_help_default(const char *opt, const char *arg)
|
||||
"c cycle program\n"
|
||||
"w cycle video filters or show modes\n"
|
||||
"s activate frame-step mode\n"
|
||||
"left/right seek backward/forward by 10 seconds or a custom interval if -seek_interval is set\n"
|
||||
"left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
|
||||
"down/up seek backward/forward 1 minute\n"
|
||||
"page down/page up seek to previous/next chapter or backward/forward 10 minutes if no chapters\n"
|
||||
"page down/page up seek backward/forward 10 minutes\n"
|
||||
"right mouse click seek to percentage in file corresponding to fraction of width\n"
|
||||
"left double-click toggle full screen\n"
|
||||
);
|
||||
@@ -3883,6 +3793,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)) {
|
||||
|
||||
+41
-57
@@ -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
|
||||
@@ -41,7 +43,6 @@
|
||||
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/internal.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +53,7 @@ struct VkRenderer {
|
||||
|
||||
int (*get_hw_dev)(VkRenderer *renderer, AVBufferRef **dev);
|
||||
|
||||
int (*display)(VkRenderer *renderer, AVFrame *frame, RenderParams *params);
|
||||
int (*display)(VkRenderer *renderer, AVFrame *frame);
|
||||
|
||||
int (*resize)(VkRenderer *renderer, int width, int height);
|
||||
|
||||
@@ -103,6 +104,36 @@ static void vk_log_cb(void *log_priv, enum pl_log_level level,
|
||||
av_log(log_priv, level_map[level], "%s\n", msg);
|
||||
}
|
||||
|
||||
// Should keep sync with optional_device_exts inside hwcontext_vulkan.c
|
||||
static const char *optional_device_exts[] = {
|
||||
/* Misc or required by other extensions */
|
||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
||||
VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME,
|
||||
VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME,
|
||||
VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME,
|
||||
VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME,
|
||||
|
||||
/* Imports/exports */
|
||||
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
|
||||
VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
|
||||
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
|
||||
VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
|
||||
#ifdef _WIN32
|
||||
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
|
||||
#endif
|
||||
|
||||
/* Video encoding/decoding */
|
||||
VK_KHR_VIDEO_QUEUE_EXTENSION_NAME,
|
||||
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
|
||||
VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
|
||||
VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
|
||||
"VK_MESA_video_decode_av1",
|
||||
};
|
||||
|
||||
static inline int enable_debug(const AVDictionary *opt)
|
||||
{
|
||||
AVDictionaryEntry *entry = av_dict_get(opt, "debug", NULL, 0);
|
||||
@@ -114,22 +145,14 @@ static void hwctx_lock_queue(void *priv, uint32_t qf, uint32_t qidx)
|
||||
{
|
||||
AVHWDeviceContext *avhwctx = priv;
|
||||
const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
|
||||
#if FF_API_VULKAN_SYNC_QUEUES
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
hwctx->lock_queue(avhwctx, qf, qidx);
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
}
|
||||
|
||||
static void hwctx_unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
|
||||
{
|
||||
AVHWDeviceContext *avhwctx = priv;
|
||||
const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
|
||||
#if FF_API_VULKAN_SYNC_QUEUES
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
hwctx->unlock_queue(avhwctx, qf, qidx);
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
}
|
||||
|
||||
static int add_instance_extension(const char **ext, unsigned num_ext,
|
||||
@@ -290,11 +313,7 @@ static void placebo_lock_queue(struct AVHWDeviceContext *dev_ctx,
|
||||
{
|
||||
RendererContext *ctx = dev_ctx->user_opaque;
|
||||
pl_vulkan vk = ctx->placebo_vulkan;
|
||||
#if FF_API_VULKAN_SYNC_QUEUES
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
vk->lock_queue(vk, queue_family, index);
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
}
|
||||
|
||||
static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx,
|
||||
@@ -303,11 +322,7 @@ static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx,
|
||||
{
|
||||
RendererContext *ctx = dev_ctx->user_opaque;
|
||||
pl_vulkan vk = ctx->placebo_vulkan;
|
||||
#if FF_API_VULKAN_SYNC_QUEUES
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
vk->unlock_queue(vk, queue_family, index);
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
}
|
||||
|
||||
static int get_decode_queue(VkRenderer *renderer, int *index, int *count)
|
||||
@@ -359,8 +374,6 @@ static int create_vk_by_placebo(VkRenderer *renderer,
|
||||
int decode_index;
|
||||
int decode_count;
|
||||
int ret;
|
||||
const char **dev_exts;
|
||||
int num_dev_exts;
|
||||
|
||||
ctx->get_proc_addr = SDL_Vulkan_GetVkGetInstanceProcAddr();
|
||||
|
||||
@@ -375,21 +388,16 @@ static int create_vk_by_placebo(VkRenderer *renderer,
|
||||
}
|
||||
ctx->inst = ctx->placebo_instance->instance;
|
||||
|
||||
dev_exts = av_vk_get_optional_device_extensions(&num_dev_exts);
|
||||
if (!dev_exts)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ctx->placebo_vulkan = pl_vulkan_create(ctx->vk_log, pl_vulkan_params(
|
||||
.instance = ctx->placebo_instance->instance,
|
||||
.get_proc_addr = ctx->placebo_instance->get_proc_addr,
|
||||
.surface = ctx->vk_surface,
|
||||
.allow_software = false,
|
||||
.opt_extensions = dev_exts,
|
||||
.num_opt_extensions = num_dev_exts,
|
||||
.opt_extensions = optional_device_exts,
|
||||
.num_opt_extensions = FF_ARRAY_ELEMS(optional_device_exts),
|
||||
.extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
|
||||
.device_name = select_device(opt),
|
||||
));
|
||||
av_free(dev_exts);
|
||||
if (!ctx->placebo_vulkan)
|
||||
return AVERROR_EXTERNAL;
|
||||
ctx->hw_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VULKAN);
|
||||
@@ -401,12 +409,8 @@ static int create_vk_by_placebo(VkRenderer *renderer,
|
||||
device_ctx->user_opaque = ctx;
|
||||
|
||||
vk_dev_ctx = device_ctx->hwctx;
|
||||
#if FF_API_VULKAN_SYNC_QUEUES
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
vk_dev_ctx->lock_queue = placebo_lock_queue;
|
||||
vk_dev_ctx->unlock_queue = placebo_unlock_queue;
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
vk_dev_ctx->get_proc_addr = ctx->placebo_instance->get_proc_addr;
|
||||
|
||||
@@ -721,13 +725,11 @@ static int convert_frame(VkRenderer *renderer, AVFrame *frame)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int display(VkRenderer *renderer, AVFrame *frame, RenderParams *params)
|
||||
static int display(VkRenderer *renderer, AVFrame *frame)
|
||||
{
|
||||
SDL_Rect *rect = ¶ms->target_rect;
|
||||
struct pl_swapchain_frame swap_frame = {0};
|
||||
struct pl_frame pl_frame = {0};
|
||||
struct pl_frame target = {0};
|
||||
struct pl_render_params pl_params = pl_render_default_params;
|
||||
RendererContext *ctx = (RendererContext *) renderer;
|
||||
int ret = 0;
|
||||
struct pl_color_space hint = {0};
|
||||
@@ -752,26 +754,8 @@ static int display(VkRenderer *renderer, AVFrame *frame, RenderParams *params)
|
||||
}
|
||||
|
||||
pl_frame_from_swapchain(&target, &swap_frame);
|
||||
|
||||
target.crop = (pl_rect2df){.x0 = rect->x, .x1 = rect->x + rect->w,
|
||||
.y0 = rect->y, .y1 = rect->y + rect->h};
|
||||
switch (params->video_background_type) {
|
||||
case VIDEO_BACKGROUND_TILES:
|
||||
pl_params.background = PL_CLEAR_TILES;
|
||||
pl_params.tile_size = VIDEO_BACKGROUND_TILE_SIZE * 2;
|
||||
break;
|
||||
case VIDEO_BACKGROUND_COLOR:
|
||||
pl_params.background = PL_CLEAR_COLOR;
|
||||
for (int i = 0; i < 3; i++)
|
||||
pl_params.background_color[i] = params->video_background_color[i] / 255.0;
|
||||
pl_params.background_transparency = (255 - params->video_background_color[3]) / 255.0;
|
||||
break;
|
||||
case VIDEO_BACKGROUND_NONE:
|
||||
pl_frame.repr.alpha = PL_ALPHA_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pl_render_image(ctx->renderer, &pl_frame, &target, &pl_params)) {
|
||||
if (!pl_render_image(ctx->renderer, &pl_frame, &target,
|
||||
&pl_render_default_params)) {
|
||||
av_log(NULL, AV_LOG_ERROR, "pl_render_image failed\n");
|
||||
ret = AVERROR_EXTERNAL;
|
||||
goto out;
|
||||
@@ -874,9 +858,9 @@ int vk_renderer_get_hw_dev(VkRenderer *renderer, AVBufferRef **dev)
|
||||
return renderer->get_hw_dev(renderer, dev);
|
||||
}
|
||||
|
||||
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *render_params)
|
||||
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame)
|
||||
{
|
||||
return renderer->display(renderer, frame, render_params);
|
||||
return renderer->display(renderer, frame);
|
||||
}
|
||||
|
||||
int vk_renderer_resize(VkRenderer *renderer, int width, int height)
|
||||
|
||||
@@ -25,20 +25,6 @@
|
||||
|
||||
typedef struct VkRenderer VkRenderer;
|
||||
|
||||
#define VIDEO_BACKGROUND_TILE_SIZE 64
|
||||
|
||||
enum VideoBackgroundType {
|
||||
VIDEO_BACKGROUND_TILES,
|
||||
VIDEO_BACKGROUND_COLOR,
|
||||
VIDEO_BACKGROUND_NONE,
|
||||
};
|
||||
|
||||
typedef struct RenderParams {
|
||||
SDL_Rect target_rect;
|
||||
uint8_t video_background_color[4];
|
||||
enum VideoBackgroundType video_background_type;
|
||||
} RenderParams;
|
||||
|
||||
VkRenderer *vk_get_renderer(void);
|
||||
|
||||
int vk_renderer_create(VkRenderer *renderer, SDL_Window *window,
|
||||
@@ -46,7 +32,7 @@ int vk_renderer_create(VkRenderer *renderer, SDL_Window *window,
|
||||
|
||||
int vk_renderer_get_hw_dev(VkRenderer *renderer, AVBufferRef **dev);
|
||||
|
||||
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *params);
|
||||
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame);
|
||||
|
||||
int vk_renderer_resize(VkRenderer *renderer, int width, int height);
|
||||
|
||||
|
||||
+78
-398
@@ -36,10 +36,8 @@
|
||||
#include "libavutil/ambient_viewing_environment.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/downmix_info.h"
|
||||
#include "libavutil/display.h"
|
||||
#include "libavutil/film_grain_params.h"
|
||||
#include "libavutil/hdr_dynamic_metadata.h"
|
||||
@@ -132,11 +130,6 @@ static int use_byte_value_binary_prefix = 0;
|
||||
static int use_value_sexagesimal_format = 0;
|
||||
static int show_private_data = 1;
|
||||
|
||||
static const char *audio_codec_name = NULL;
|
||||
static const char *data_codec_name = NULL;
|
||||
static const char *subtitle_codec_name = NULL;
|
||||
static const char *video_codec_name = NULL;
|
||||
|
||||
#define SHOW_OPTIONAL_FIELDS_AUTO -1
|
||||
#define SHOW_OPTIONAL_FIELDS_NEVER 0
|
||||
#define SHOW_OPTIONAL_FIELDS_ALWAYS 1
|
||||
@@ -145,7 +138,6 @@ static int show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;
|
||||
static char *output_format;
|
||||
static char *stream_specifier;
|
||||
static char *show_data_hash;
|
||||
static char *data_dump_format;
|
||||
|
||||
typedef struct ReadInterval {
|
||||
int id; ///< identifier
|
||||
@@ -216,8 +208,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,
|
||||
@@ -256,7 +246,7 @@ static const char *get_stream_group_type(const void *data)
|
||||
return av_x_if_null(avformat_stream_group_name(stg->type), "unknown");
|
||||
}
|
||||
|
||||
static const AVTextFormatSection sections[] = {
|
||||
static struct AVTextFormatSection sections[] = {
|
||||
[SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
|
||||
[SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
|
||||
[SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
|
||||
@@ -301,7 +291,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 +300,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" },
|
||||
@@ -330,13 +318,6 @@ static const AVTextFormatSection sections[] = {
|
||||
[SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
|
||||
};
|
||||
|
||||
typedef struct EntrySelection {
|
||||
int show_all_entries;
|
||||
AVDictionary *entries_to_show;
|
||||
} EntrySelection;
|
||||
|
||||
static EntrySelection selected_entries[FF_ARRAY_ELEMS(sections)] = { 0 };
|
||||
|
||||
static const OptionDef *options;
|
||||
|
||||
/* FFprobe context */
|
||||
@@ -345,11 +326,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;
|
||||
@@ -370,14 +352,6 @@ typedef struct LogBuffer {
|
||||
static LogBuffer *log_buffer;
|
||||
static int log_buffer_size;
|
||||
|
||||
static int is_key_selected_callback(AVTextFormatContext *tctx, const char *key)
|
||||
{
|
||||
const AVTextFormatSection *section = tctx->section[tctx->level];
|
||||
const EntrySelection *selection = &selected_entries[section - sections];
|
||||
|
||||
return selection->show_all_entries || av_dict_get(selection->entries_to_show, key, NULL, 0);
|
||||
}
|
||||
|
||||
static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
|
||||
{
|
||||
AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
|
||||
@@ -436,8 +410,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,33 +429,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)
|
||||
|
||||
static void print_integers(AVTextFormatContext *tfc, const char *key,
|
||||
const void *data, int size, const char *format,
|
||||
int columns, int bytes, int offset_add)
|
||||
{
|
||||
AVBPrint bp;
|
||||
unsigned offset = 0;
|
||||
|
||||
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
|
||||
av_bprint_chars(&bp, '\n', 1);
|
||||
while (size) {
|
||||
av_bprintf(&bp, "%08x: ", offset);
|
||||
for (int i = 0, l = FFMIN(size, columns); i < l; i++) {
|
||||
if (bytes == 1) av_bprintf(&bp, format, *(const uint8_t*)data);
|
||||
else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
|
||||
else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
|
||||
data = (const char*)data + bytes;
|
||||
size--;
|
||||
}
|
||||
av_bprint_chars(&bp, '\n', 1);
|
||||
offset += offset_add;
|
||||
}
|
||||
avtext_print_string(tfc, key, bp.str, 0);
|
||||
}
|
||||
#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u)
|
||||
|
||||
#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
|
||||
{ \
|
||||
@@ -509,36 +457,12 @@ 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);
|
||||
if (isnan(rotation))
|
||||
rotation = 0;
|
||||
print_integers(tfc, "displaymatrix", matrix, 9, " %11d", 3, 4, 1);
|
||||
avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1);
|
||||
print_int("rotation", rotation);
|
||||
}
|
||||
|
||||
@@ -831,62 +755,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 +896,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 +962,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 +988,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);
|
||||
@@ -1190,12 +1057,6 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
|
||||
print_int("crop_right", AV_RL32(sd->data + 12));
|
||||
} else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
|
||||
print_int("active_format", *sd->data);
|
||||
} else if (sd->type == AV_PKT_DATA_EXIF) {
|
||||
print_int("size", sd->size);
|
||||
} else if (sd->type == AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL && sd->size >= 8) {
|
||||
print_int("block_additional_id", AV_RB64(sd->data));
|
||||
if (do_show_data)
|
||||
avtext_print_data(tfc, "block_additional_data", sd->data + 8, sd->size - 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1287,16 +1148,6 @@ static void print_chroma_location(AVTextFormatContext *tfc, enum AVChromaLocatio
|
||||
}
|
||||
}
|
||||
|
||||
static void print_alpha_mode(AVTextFormatContext *tfc, enum AVAlphaMode alpha_mode)
|
||||
{
|
||||
const char *val = av_alpha_mode_name(alpha_mode);
|
||||
if (!val || alpha_mode == AVALPHA_MODE_UNSPECIFIED) {
|
||||
print_str_opt("alpha_mode", "unspecified");
|
||||
} else {
|
||||
print_str("alpha_mode", val);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_log(int need_lock)
|
||||
{
|
||||
int i;
|
||||
@@ -1368,7 +1219,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 +1243,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 +1279,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 +1292,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 +1317,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) {
|
||||
@@ -1493,13 +1336,6 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
|
||||
print_film_grain_params(tfc, fgp);
|
||||
} else if (sd->type == AV_FRAME_DATA_VIEW_ID) {
|
||||
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 +1369,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) {
|
||||
@@ -1564,7 +1400,6 @@ static void show_frame(AVTextFormatContext *tfc, AVFrame *frame, AVStream *strea
|
||||
print_primaries(tfc, frame->color_primaries);
|
||||
print_color_trc(tfc, frame->color_trc);
|
||||
print_chroma_location(tfc, frame->chroma_location);
|
||||
print_alpha_mode(tfc, frame->alpha_mode);
|
||||
break;
|
||||
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
@@ -1796,10 +1631,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 +1650,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 +1673,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)
|
||||
@@ -1934,10 +1755,6 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
|
||||
print_str("codec_tag_string", av_fourcc2str(par->codec_tag));
|
||||
print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
|
||||
|
||||
av_bprint_clear(&pbuf);
|
||||
if (!av_mime_codec_str(par, stream->avg_frame_rate, &pbuf))
|
||||
print_str("mime_codec_string", pbuf.str);
|
||||
|
||||
switch (par->codec_type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
print_int("width", par->width);
|
||||
@@ -1986,7 +1803,7 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
|
||||
else
|
||||
print_str_opt("field_order", "unknown");
|
||||
|
||||
if (dec_ctx && do_read_frames)
|
||||
if (dec_ctx)
|
||||
print_int("refs", dec_ctx->refs);
|
||||
break;
|
||||
|
||||
@@ -2075,7 +1892,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 +1909,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 +1926,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 +1940,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 +1957,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 +1984,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 +1992,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 +1999,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 +2013,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,24 +2047,18 @@ 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,
|
||||
const AVIAMFAudioElement *audio_element)
|
||||
{
|
||||
AVBPrint pbuf;
|
||||
|
||||
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
avtext_print_section_header(tfc, stg, SECTION_ID_STREAM_GROUP_COMPONENT);
|
||||
print_int("nb_layers", audio_element->nb_layers);
|
||||
print_int("audio_element_type", audio_element->audio_element_type);
|
||||
print_int("default_w", audio_element->default_w);
|
||||
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);
|
||||
@@ -2274,12 +2067,8 @@ static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVSt
|
||||
if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL) {
|
||||
print_int("output_gain_flags", layer->output_gain_flags);
|
||||
print_q("output_gain", layer->output_gain, '/');
|
||||
} else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) {
|
||||
} else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE)
|
||||
print_int("ambisonics_mode", layer->ambisonics_mode);
|
||||
if (layer->ambisonics_mode == AV_IAMF_AMBISONICS_MODE_PROJECTION)
|
||||
print_list_fmt("demixing_matrix", "%d/%d", layer->nb_demixing_matrix, 1, layer->demixing_matrix[idx].num,
|
||||
layer->demixing_matrix[idx].den);
|
||||
}
|
||||
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
|
||||
}
|
||||
if (audio_element->demixing_info)
|
||||
@@ -2290,8 +2079,6 @@ static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVSt
|
||||
SECTION_ID_STREAM_GROUP_SUBCOMPONENT);
|
||||
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS
|
||||
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT
|
||||
|
||||
av_bprint_finalize(&pbuf, NULL);
|
||||
}
|
||||
|
||||
static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmix *submix)
|
||||
@@ -2301,7 +2088,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 +2111,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 +2141,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 +2163,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 +2188,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 +2206,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 +2223,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 +2263,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");
|
||||
@@ -2497,69 +2284,10 @@ static void show_error(AVTextFormatContext *tfc, int err)
|
||||
avtext_print_section_footer(tfc);
|
||||
}
|
||||
|
||||
static int get_decoder_by_name(const char *codec_name, const AVCodec **codec)
|
||||
{
|
||||
if (codec_name == NULL)
|
||||
return 0;
|
||||
|
||||
*codec = avcodec_find_decoder_by_name(codec_name);
|
||||
if (*codec == NULL) {
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"No codec could be found with name '%s'\n", codec_name);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_decoders(AVFormatContext *fmt_ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#define GET_DECODER(type_) \
|
||||
ret = get_decoder_by_name(type_##_codec_name, &fmt_ctx->type_##_codec); \
|
||||
if (ret < 0) return ret;
|
||||
|
||||
GET_DECODER(audio);
|
||||
GET_DECODER(data);
|
||||
GET_DECODER(subtitle);
|
||||
GET_DECODER(video);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream *stream)
|
||||
{
|
||||
const AVCodec *codec = NULL;
|
||||
switch (stream->codecpar->codec_type) {
|
||||
case AVMEDIA_TYPE_VIDEO: codec = fmt_ctx->video_codec; break;
|
||||
case AVMEDIA_TYPE_AUDIO: codec = fmt_ctx->audio_codec; break;
|
||||
case AVMEDIA_TYPE_SUBTITLE: codec = fmt_ctx->subtitle_codec; break;
|
||||
case AVMEDIA_TYPE_DATA: codec = fmt_ctx->data_codec; break;
|
||||
}
|
||||
|
||||
if (codec != NULL)
|
||||
return codec;
|
||||
|
||||
if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"Failed to probe codec for input stream %d\n", stream->index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
codec = avcodec_find_decoder(stream->codecpar->codec_id);
|
||||
if (codec == NULL) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"Unsupported codec with id %d for input stream %d\n",
|
||||
stream->codecpar->codec_id, stream->index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
static int open_input_file(InputFile *ifile, const char *filename,
|
||||
const char *print_filename)
|
||||
{
|
||||
int err;
|
||||
int err, i;
|
||||
AVFormatContext *fmt_ctx = NULL;
|
||||
const AVDictionaryEntry *t = NULL;
|
||||
int scan_all_pmts_set = 0;
|
||||
@@ -2568,9 +2296,6 @@ static int open_input_file(InputFile *ifile, const char *filename,
|
||||
if (!fmt_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
err = set_decoders(fmt_ctx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
|
||||
av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
|
||||
scan_all_pmts_set = 1;
|
||||
@@ -2600,7 +2325,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,17 +2343,27 @@ 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;
|
||||
|
||||
ist->st = stream;
|
||||
|
||||
codec = get_decoder_for_stream(fmt_ctx, stream);
|
||||
if (!codec)
|
||||
if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"Failed to probe codec for input stream %d\n",
|
||||
stream->index);
|
||||
continue;
|
||||
}
|
||||
|
||||
codec = avcodec_find_decoder(stream->codecpar->codec_id);
|
||||
if (!codec) {
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"Unsupported codec with id %d for input stream %d\n",
|
||||
stream->codecpar->codec_id, stream->index);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
AVDictionary *opts;
|
||||
|
||||
@@ -2676,9 +2411,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 +2427,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 +2447,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],
|
||||
@@ -2774,10 +2510,6 @@ end:
|
||||
av_freep(&selected_streams);
|
||||
av_freep(&streams_with_closed_captions);
|
||||
av_freep(&streams_with_film_grain);
|
||||
av_freep(&audio_codec_name);
|
||||
av_freep(&data_codec_name);
|
||||
av_freep(&subtitle_codec_name);
|
||||
av_freep(&video_codec_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -2914,24 +2646,23 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
|
||||
static inline void mark_section_show_entries(SectionID section_id,
|
||||
int show_all_entries, AVDictionary *entries)
|
||||
{
|
||||
EntrySelection *selection = &selected_entries[section_id];
|
||||
struct AVTextFormatSection *section = §ions[section_id];
|
||||
|
||||
selection->show_all_entries = show_all_entries;
|
||||
section->show_all_entries = show_all_entries;
|
||||
if (show_all_entries) {
|
||||
const AVTextFormatSection *section = §ions[section_id];
|
||||
for (const int *id = section->children_ids; *id != -1; id++)
|
||||
mark_section_show_entries(*id, show_all_entries, entries);
|
||||
} else {
|
||||
av_dict_copy(&selection->entries_to_show, entries, 0);
|
||||
av_dict_copy(§ion->entries_to_show, entries, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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))) {
|
||||
@@ -3233,36 +2964,6 @@ static int opt_sections(void *optctx, const char *opt, const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_codec(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
const char *spec = strchr(opt, ':');
|
||||
const char **name;
|
||||
if (!spec) {
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"No media specifier was specified for '%s' in option '%s'. Use -%s:<media_spec> "
|
||||
"where <media_spec> can be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n",
|
||||
arg, opt, opt);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
spec++;
|
||||
|
||||
switch (spec[0]) {
|
||||
case 'a' : name = &audio_codec_name; break;
|
||||
case 'd' : name = &data_codec_name; break;
|
||||
case 's' : name = &subtitle_codec_name; break;
|
||||
case 'v' : name = &video_codec_name; break;
|
||||
default:
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Invalid media specifier '%s' in option '%s'. "
|
||||
"Must be one of: 'a' (audio), 'v' (video), 's' (subtitle), 'd' (data)\n", spec, opt);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
av_freep(name);
|
||||
*name = av_strdup(arg);
|
||||
return *name ? 0 : AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
static int opt_show_versions(void *optctx, const char *opt, const char *arg)
|
||||
{
|
||||
mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
|
||||
@@ -3306,7 +3007,6 @@ static const OptionDef real_options[] = {
|
||||
{ "of", OPT_TYPE_STRING, 0, { &output_format }, "alias for -output_format", "format" },
|
||||
{ "select_streams", OPT_TYPE_STRING, 0, { &stream_specifier }, "select the specified streams", "stream_specifier" },
|
||||
{ "sections", OPT_TYPE_FUNC, OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
|
||||
{ "data_dump_format", OPT_TYPE_STRING, 0, { &data_dump_format }, "set data dump format (available formats are: xxd, base64)" },
|
||||
{ "show_data", OPT_TYPE_BOOL, 0, { &do_show_data }, "show packets data" },
|
||||
{ "show_data_hash", OPT_TYPE_STRING, 0, { &show_data_hash }, "show packets data hash" },
|
||||
{ "show_error", OPT_TYPE_FUNC, 0, { .func_arg = &opt_show_error }, "show probing error" },
|
||||
@@ -3339,19 +3039,14 @@ static const OptionDef real_options[] = {
|
||||
{ "print_filename", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_print_filename}, "override the printed input filename", "print_file"},
|
||||
{ "find_stream_info", OPT_TYPE_BOOL, OPT_INPUT | OPT_EXPERT, { &find_stream_info },
|
||||
"read and decode the streams to fill missing information with heuristics" },
|
||||
{ "c", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
|
||||
{ "codec", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "alias for -c (force decoder)", "decoder_name" },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
static inline int check_section_show_entries(int section_id)
|
||||
{
|
||||
const EntrySelection *selection = &selected_entries[section_id];
|
||||
|
||||
if (selection->show_all_entries || selection->entries_to_show)
|
||||
struct AVTextFormatSection *section = §ions[section_id];
|
||||
if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
|
||||
return 1;
|
||||
|
||||
const AVTextFormatSection *section = §ions[section_id];
|
||||
for (const int *id = section->children_ids; *id != -1; id++)
|
||||
if (check_section_show_entries(*id))
|
||||
return 1;
|
||||
@@ -3370,8 +3065,7 @@ int main(int argc, char **argv)
|
||||
AVTextWriterContext *wctx;
|
||||
char *buf;
|
||||
char *f_name = NULL, *f_args = NULL;
|
||||
int ret, input_ret;
|
||||
AVTextFormatDataDump data_dump_format_id = AV_TEXTFORMAT_DATADUMP_XXD;
|
||||
int ret, input_ret, i;
|
||||
|
||||
init_dynload();
|
||||
|
||||
@@ -3456,18 +3150,6 @@ int main(int argc, char **argv)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (data_dump_format) {
|
||||
if (!strcmp(data_dump_format, "xxd")) {
|
||||
data_dump_format_id = AV_TEXTFORMAT_DATADUMP_XXD;
|
||||
} else if (!strcmp(data_dump_format, "base64")) {
|
||||
data_dump_format_id = AV_TEXTFORMAT_DATADUMP_BASE64;
|
||||
} else {
|
||||
av_log(NULL, AV_LOG_ERROR, "Unknown data dump format with name '%s'\n", data_dump_format);
|
||||
ret = AVERROR(EINVAL);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (output_filename) {
|
||||
ret = avtextwriter_create_file(&wctx, output_filename);
|
||||
} else
|
||||
@@ -3477,13 +3159,11 @@ int main(int argc, char **argv)
|
||||
goto end;
|
||||
|
||||
AVTextFormatOptions tf_options = {
|
||||
.is_key_selected = is_key_selected_callback,
|
||||
.show_optional_fields = show_optional_fields,
|
||||
.show_value_unit = show_value_unit,
|
||||
.use_value_prefix = use_value_prefix,
|
||||
.use_byte_value_binary_prefix = use_byte_value_binary_prefix,
|
||||
.use_value_sexagesimal_format = use_value_sexagesimal_format,
|
||||
.data_dump_format = data_dump_format_id,
|
||||
};
|
||||
|
||||
if ((ret = avtext_context_open(&tctx, f, wctx, f_args, sections, FF_ARRAY_ELEMS(sections), tf_options, show_data_hash)) >= 0) {
|
||||
@@ -3535,8 +3215,8 @@ end:
|
||||
av_freep(&read_intervals);
|
||||
|
||||
uninit_opts();
|
||||
for (size_t i = 0; i < FF_ARRAY_ELEMS(selected_entries); ++i)
|
||||
av_dict_free(&selected_entries[i].entries_to_show);
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
|
||||
av_dict_free(&(sections[i].entries_to_show));
|
||||
|
||||
avformat_network_deinit();
|
||||
|
||||
|
||||
+29
-10
@@ -33,7 +33,6 @@
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/common.h"
|
||||
@@ -75,7 +74,7 @@ typedef enum {
|
||||
SECTION_ID_ENCODER,
|
||||
} SectionID;
|
||||
|
||||
static const AVTextFormatSection sections[] = {
|
||||
static struct AVTextFormatSection sections[] = {
|
||||
[SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_FILTERGRAPHS, SECTION_ID_INPUTFILES, SECTION_ID_OUTPUTFILES, SECTION_ID_DECODERS, SECTION_ID_ENCODERS, SECTION_ID_STREAMLINKS, -1 } },
|
||||
|
||||
[SECTION_ID_FILTERGRAPHS] = { SECTION_ID_FILTERGRAPHS, "graphs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTERGRAPH, -1 } },
|
||||
@@ -141,7 +140,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); \
|
||||
@@ -272,7 +271,7 @@ static void print_link(GraphPrintContext *gpc, AVFilterLink *link)
|
||||
}
|
||||
|
||||
if (link->w && link->h) {
|
||||
if (tfc->opts.show_value_unit) {
|
||||
if (tfc->show_value_unit) {
|
||||
print_fmt("size", "%dx%d", link->w, link->h);
|
||||
} else {
|
||||
print_int("width", link->w);
|
||||
@@ -293,7 +292,7 @@ static void print_link(GraphPrintContext *gpc, AVFilterLink *link)
|
||||
////print_str("format", av_x_if_null(av_get_subtitle_fmt_name(link->format), "?"));
|
||||
|
||||
if (link->w && link->h) {
|
||||
if (tfc->opts.show_value_unit) {
|
||||
if (tfc->show_value_unit) {
|
||||
print_fmt("size", "%dx%d", link->w, link->h);
|
||||
} else {
|
||||
print_int("width", link->w);
|
||||
@@ -307,7 +306,7 @@ static void print_link(GraphPrintContext *gpc, AVFilterLink *link)
|
||||
av_channel_layout_describe(&link->ch_layout, layout_string, sizeof(layout_string));
|
||||
print_str("channel_layout", layout_string);
|
||||
print_val("channels", link->ch_layout.nb_channels, "ch");
|
||||
if (tfc->opts.show_value_unit)
|
||||
if (tfc->show_value_unit)
|
||||
print_fmt("sample_rate", "%d.1 kHz", link->sample_rate / 1000);
|
||||
else
|
||||
print_val("sample_rate", link->sample_rate, "Hz");
|
||||
@@ -471,6 +470,12 @@ static void print_filter(GraphPrintContext *gpc, const AVFilterContext *filter,
|
||||
avtext_print_section_footer(tfc); // SECTION_ID_FILTER
|
||||
}
|
||||
|
||||
static void init_sections(void)
|
||||
{
|
||||
for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++)
|
||||
sections[i].show_all_entries = 1;
|
||||
}
|
||||
|
||||
static void print_filtergraph_single(GraphPrintContext *gpc, FilterGraph *fg, AVFilterGraph *graph)
|
||||
{
|
||||
AVTextFormatContext *tfc = gpc->tfc;
|
||||
@@ -871,6 +876,7 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
|
||||
GraphPrintContext *gpc = NULL;
|
||||
int ret;
|
||||
|
||||
init_sections();
|
||||
*pgpc = NULL;
|
||||
|
||||
av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
@@ -913,8 +919,8 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
|
||||
gpc->id_prefix_num = atomic_fetch_add(&prefix_num, 1);
|
||||
gpc->is_diagram = !!(tfc->formatter->flags & AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER);
|
||||
if (gpc->is_diagram) {
|
||||
tfc->opts.show_value_unit = 1;
|
||||
tfc->opts.show_optional_fields = -1;
|
||||
tfc->show_value_unit = 1;
|
||||
tfc->show_optional_fields = -1;
|
||||
gpc->opt_flags = AV_TEXTFORMAT_PRINT_STRING_OPTIONAL;
|
||||
gpc->skip_buffer_filters = 1;
|
||||
////} else {
|
||||
@@ -947,13 +953,16 @@ fail:
|
||||
|
||||
int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph)
|
||||
{
|
||||
av_assert2(fg);
|
||||
|
||||
GraphPrintContext *gpc = NULL;
|
||||
AVTextFormatContext *tfc;
|
||||
AVBPrint *target_buf = &fg->graph_print_buf;
|
||||
int ret;
|
||||
|
||||
if (!fg) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Invalid filter graph provided\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (target_buf->len)
|
||||
av_bprint_finalize(target_buf, NULL);
|
||||
|
||||
@@ -961,6 +970,11 @@ int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!gpc) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Failed to initialize graph print context\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
tfc = gpc->tfc;
|
||||
|
||||
// Due to the threading model each graph needs to print itself into a buffer
|
||||
@@ -997,6 +1011,11 @@ static int print_filtergraphs_priv(FilterGraph **graphs, int nb_graphs, InputFil
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
if (!gpc) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
tfc = gpc->tfc;
|
||||
|
||||
avtext_print_section_header(tfc, NULL, SECTION_ID_ROOT);
|
||||
|
||||
+12
-25
@@ -23,7 +23,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cmdutils.h"
|
||||
#include "fopen_utf8.h"
|
||||
#include "opt_common.h"
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
@@ -68,11 +67,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 +320,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 +590,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 +707,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 +773,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)
|
||||
@@ -820,8 +808,7 @@ int show_filters(void *optctx, const char *opt, const char *arg)
|
||||
" A = Audio input/output\n"
|
||||
" V = Video input/output\n"
|
||||
" N = Dynamic number and/or type of input/output\n"
|
||||
" | = Source or sink filter\n"
|
||||
" ------\n");
|
||||
" | = Source or sink filter\n");
|
||||
while ((filter = av_filter_iterate(&opaque))) {
|
||||
descr_cur = descr;
|
||||
for (i = 0; i < 2; i++) {
|
||||
@@ -887,7 +874,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);
|
||||
@@ -1003,7 +990,7 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg)
|
||||
#endif
|
||||
|
||||
while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
|
||||
av_unused enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
|
||||
enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
|
||||
printf("%c%c%c%c%c %-16s %d %3d %d",
|
||||
sws_isSupportedInput (pix_fmt) ? 'I' : '.',
|
||||
sws_isSupportedOutput(pix_fmt) ? 'O' : '.',
|
||||
@@ -1217,7 +1204,7 @@ int init_report(const char *env, FILE **file)
|
||||
if (!envlevel)
|
||||
report_file_level = FFMAX(report_file_level, prog_loglevel);
|
||||
|
||||
report_file = fopen_utf8(filename.str, "w");
|
||||
report_file = fopen(filename.str, "w");
|
||||
if (!report_file) {
|
||||
int ret = AVERROR(errno);
|
||||
av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
|
||||
|
||||
@@ -41,9 +41,9 @@ int show_sources(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
#if CONFIG_AVDEVICE
|
||||
#define CMDUTILS_COMMON_OPTIONS_AVDEVICE \
|
||||
{ "sources" , OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_sources }, \
|
||||
{ "sources" , OPT_TYPE_FUNC, OPT_EXIT | OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = show_sources }, \
|
||||
"list sources of the input device", "device" }, \
|
||||
{ "sinks" , OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_sinks }, \
|
||||
{ "sinks" , OPT_TYPE_FUNC, OPT_EXIT | OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = show_sinks }, \
|
||||
"list sinks of the output device", "device" }, \
|
||||
|
||||
#else
|
||||
@@ -198,7 +198,6 @@ int opt_cpucount(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
#define CMDUTILS_COMMON_OPTIONS \
|
||||
{ "L", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_license }, "show license" }, \
|
||||
{ "license", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_license }, "show license" }, \
|
||||
{ "h", OPT_TYPE_FUNC, OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
|
||||
{ "?", OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_help }, "show help", "topic" }, \
|
||||
{ "help", OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_help }, "show help", "topic" }, \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user