Compare commits

...

34 Commits

Author SHA1 Message Date
James Almer
09dc319bf3 avfilter/vf_lcevc: attach a reference to the source frame to each passed in base picture
And free them once they are guaranteed to be no longer needed, instead of freeing them
when returned with an enhanced output.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit af136db1c3)
2026-01-12 20:53:46 -03:00
James Almer
e95d47ad5f avfilter/vf_lcevc: support LCEVCdec version 4
Signed-off-by: James Almer <jamrial@gmail.com>
2026-01-12 20:53:45 -03:00
James Almer
0e1dd33701 avcodec/lcevc: attach a reference to the source frame to each passed in base picture
This way we can ensure a frame reference will always exists for as long as the
external library needs the base picture.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 188521c7ad)
2026-01-12 20:53:40 -03:00
James Almer
c74b4512e0 avcodec/lcevcdec: free pictures on error
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit fe1dae1e18)
2026-01-12 20:53:35 -03:00
James Almer
0d9b8bfc0e avcodec/lcevcdec: fix input dimensions for the base picture
Fixes crashes with some samples.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 4f86ebfe94)
2026-01-12 20:53:29 -03:00
James Almer
044ca5f5ef avcodec/lcevcdec: avoid copying the input frame
Based on the lcevc filter implementation.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit b392d75cf7)
2026-01-12 20:53:23 -03:00
Andreas Rheinhardt
4007d2a532 avcodec/decode: Optimize lcevc away if disabled
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 8e90f150eb)
2026-01-12 20:53:17 -03:00
Andreas Rheinhardt
4fff1187ac avcodec/decode: Put lcevc fields into structure of their own
Makes it easier to see that width and height in DecodeContext is
actually a lcevc field.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 2786e5a9ad)
2026-01-12 20:53:06 -03:00
Andreas Rheinhardt
4ef4474d65 avcodec/decode: Don't allocate LCEVC context for non-video
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 182b9c7a4a)
2026-01-12 20:52:18 -03:00
James Almer
75c42f558b avcodec/lcevcdec: support LCEVCdec version 4
Signed-off-by: James Almer <jamrial@gmail.com>
2026-01-12 20:32:31 -03:00
Timo Rothenpieler
4771a9dd75 forgejo: backport CI job names 2026-01-02 20:02:52 +01:00
Timo Rothenpieler
7ce7207770 avformat/img2dec: reject input images too big to fit into a single packet
Not entirely sure if it should instead use some entirely different
approach here, given that images exceeding 2GB don't seem that crazy
to me, but so far processing such images results in a heap overflow,
since the size addition overflows and a much too small packet is
allocated and its size never checked again when writing into it.

Fixes #YWH-PGM40646-32

(cherry picked from commit f6a95c7eb7)
2025-12-31 17:48:24 +01:00
James Almer
40b336e650 avformat/iamf_writer: check that stream count is consistent for ambisonic Audio Elements
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit a0fc454871)
2025-12-30 20:25:18 -03:00
James Almer
c0272bf654 avformat/iamf_writer: fix writting some ambisonics fields in Audio Elements
The fields are defined as 8 bit long unsigned ints. Fortunately, writing most sane values
as leb is equivalent, which is why no tests are affected.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 21ff60d2cf)
2025-12-30 20:25:18 -03:00
James Almer
bdfaec89fe avformat/iamf_parse: fix setting denominator in AVIAMFLayer.demixing_matrix
The format of demixing_matrix is Q15 fixed point values.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 03a981445e)
2025-12-30 20:25:18 -03:00
Jan Ekström
dac2a1116d fate/ffmpeg: remove comparison against ref from fix_sub_duration_heartbeat
After the full ffmpeg CLI multithreading changes went in, this
test started depending on how far the input side read and decoded
the input compared to how quickly the output encoded things, causing
spurious failures on the CI.

To my knowledge all of the failures have so far been valid correct
results, but unfortunately FATE's built in checks mostly consist of
whether there is a difference against an exact result.

This way we still get the CI and valgrind running of the code,
but stop its comparison. Reference file is left around so that
the previous reference is still available.

(cherry picked from commit e54bd7065d)
2025-12-16 21:19:36 +02:00
Neal Gompa
416962282f configure: Lower libdvdnav and libdvdread minimum versions for EL9
Red Hat Enterprise Linux 9 is one patch version lower than what
FFmpeg currently requests. The slightly older versions still result
in a working build of FFmpeg with DVD support, so allow those
versions to be consumed to build FFmpeg.

(cherry picked from commit 069d465895)
Signed-off-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
2025-12-09 21:01:50 +01:00
Marvin Scholz
a606f632f1 avformat/rtsp: fix leading space in RTSP reason
When parsing the RTSP message reason, the whole remainder
after parsing the status code was used, which would lead to
a leading space in the parsed reason string.

(cherry picked from commit e63e040f0c)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2025-12-09 15:14:05 +00:00
Marvin Scholz
5f40afe429 avformat/rtsp: do not log invalid values
When reading fails the first time, ch would be uninitialized and
printed in the log message. Instead check for an error early and
log it properly.

(cherry picked from commit 2ed47ab725)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2025-12-09 15:14:05 +00:00
Marvin Scholz
1b36826050 avformat/http: Handle IPv6 Zone ID in hostname
When using a literal IPv6 address as hostname, it can contain a Zone ID
especially in the case of link-local addresses. Sending this to the
server in the Host header is not useful to the server and in some cases
servers refuse such requests.

To prevent any such issues, strip the Zone ID from the address if it's
an IPv6 address. This also removes it for the Cookies lookup.

Based on a patch by: Daniel N Pettersson <danielnp@axis.com>

(cherry picked from commit 5cb6d2221a)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2025-12-09 15:14:05 +00:00
Marton Balint
a3a36f059a avfilter/af_amerge: fix possible crash with custom layouts
The check if a native layout can be created from the sources was incomplete and
casued a crash with custom layouts if the layout contained a native channel
multiple times, as in this example command line:

ffmpeg -lavfi "sine[a0];sine,pan=FL+FL[a1];[a0][a1]amerge[aout]" -map "[aout]" -t 1 -f framecrc -

Signed-off-by: Marton Balint <cus@passwd.hu>
(cherry picked from commit e8b10a9b09)
2025-12-07 21:17:23 +01:00
Kacper Michajłow
882a51ee18 avfilter/stack_internal: fix checkheaders test
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
(cherry picked from commit 1a1377c53d)
2025-12-07 15:54:59 +00:00
Timo Rothenpieler
4543d0509b all: apply linter fixes 2025-12-07 15:54:59 +00:00
Timo Rothenpieler
c937e34c43 forgejo: apply needed CI changes for 7.1 2025-12-07 15:54:59 +00:00
Timo Rothenpieler
1a9e715010 forgejo: backport CI to release/7.1 2025-12-07 15:54:59 +00:00
Andreas Rheinhardt
c83d3b98b1 avcodec/vp3: Sync VLCs once during init, fix crash
6c7a344b65 made the VLCs shared between
threads and did so in a way that was designed to support stream
reconfigurations, so that the structure containing the VLCs was
synced in update_thread_context. The idea was that the currently
active VLCs would just be passed along between threads.

Yet this was broken by 5acbdd2264:
Before this commit, submit_packet() was a no-op during flushing
for VP3, as it is a no-delay decoder, so it won't produce any output
during flushing. This meant that prev_thread in pthread_frame.c
contained the last dst thread that update_thread_context()
was called for (so that these VLCs could be passed along between
threads). Yet after said commit, submit_packet was no longer
a no-op during flushing and changed prev_thread in such a way
that it did not need to contain any VLCs at all*. When flushing,
prev_thread is used to pass the current state to the first worker
thread which is the one that is used to restart decoding.
It could therefore happen that the decoding thread did not contain
the VLCs at all any more after decoding restarts after flushing
leading to a crash (this scenario was never anticipated and
must not happen at all).

There is a simple, easily backportable fix given that we do not
support stream reconfigurations (yet) when using frame threading:
Don't sync the VLCs in update_thread_context(), instead do it once
during init.

This fixes forgejo issue #20346 and trac issue #11592.

(I don't know why 5acbdd2264
changed submit_packet() to no longer be a no-op when draining
no-delay decoders.)

*: The exact condition for the crash is nb_threads > 2*nb_frames.

Reviewed-by: Peter Ross <pross@xvid.org>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
(cherry picked from commit 90551b7d80)
2025-12-03 15:34:39 +01:00
Gyan Doshi
292b30bbe0 configure: unbreak glslang build
Don't unconditionally link to libSPVRemapper which was removed in 16.0 in 3a7f787
2025-12-01 16:49:31 +01:00
James Almer
f65fc0b137 avformat/iamf_parse: fix compilation error
Regression since a2a6728285.

Signed-off-by: James Almer <jamrial@gmail.com>
2025-11-28 09:51:36 -03:00
James Almer
c0e599e9d8 avfilter/vf_scale: don't attempt to rescale AV_NOPTS_VALUE
Finishes fixing issue #20589.

Signed-off-by: James Almer <jamrial@gmail.com>
2025-11-27 22:02:55 -03:00
James Almer
46293e9905 avfilter/framesync: don't attempt to rescale AV_NOPTS_VALUE
Part of a fix for issue #20589.

Signed-off-by: James Almer <jamrial@gmail.com>
2025-11-27 22:02:43 -03:00
James Almer
9403cdd6e8 avformat/iamf_parse: ensure the stream count in a scalable channel representation is equal to the audio element's stream count
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit faa382e5b1)
2025-11-27 22:00:39 -03:00
James Almer
a2a6728285 avformat/iamf_parse: ensure each layout in an scalable channel representation has an increasing number of channels
Fixes issue #21013

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 554ae5ada9)
2025-11-27 22:00:30 -03:00
Niklas Haas
9e3030bc44 fftools/ffmpeg_filter: close all no-longer needed inputs
Currently, the thread loop of ffmpeg_filter essentially works like this:

while (1) {
    frame, idx = get_from_decoder();
    err = send_to_filter_graph(frame);
    if (err) { // i.e. EOF
        close_input(idx);
        continue;
    }

    while (filtered_frame = get_filtered_frame())
        send_to_encoder(filtered_frame);
}

The exact details are not 100% correct since the actual control flow is a bit
more complicated as a result of the scheduler, but this is the general flow.

Notably, this leaves the possibility of leaving a no-longer-needed input
permanently open if the filter graph starts producing infinite frames (during
the second loop) *after* it finishes reading from an input, e.g. in a filter
graph like -af atrim,apad.

This patch avoids this issue by always querying the status of all filter graph
inputs and explicitly closing any that were closed downstream; after each round
of reading output frames. As a result, information about the filtergraph being
closed can now propagate back upstream, even if the filter is no longer
requesting any input frames (i.e. input_idx == fg->nb_inputs).

Fixes: https://trac.ffmpeg.org/ticket/11061
See-Also: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20457#issuecomment-6208

Backported-from: 38a5fcc02c

During backporting, I had to change the signature of `close_input()` to
`void close_input(FilterGraph *fg, int input_idx)` since this version of
FFmpeg does not contain a reference to the input index in the InputFilterPriv.
2025-11-27 13:27:54 +01:00
Niklas Haas
a665413248 avfilter/buffersrc: add av_buffersrc_get_status()
There is currently no way for API users to know that a buffersrc is no longer
accepting input, except by trying to feed it a frame and seeing what happens.

Of course, this is not possible if the user does not *have* a frame to feed,
but may still wish to know if the filter is still accepting input or not.

Since passing `frame == NULL` to `av_buffersrc_add_frame()` is already treated
as closing the input, we are left with no choice but to introduce a new
function for this.

We don't explicitly return the result of `ff_outlink_get_status()` to avoid
leaking internal status codes, and instead translate them all to AVERROR(EOF).

Backported-from: 623669a02c
2025-11-27 13:21:42 +01:00
79 changed files with 690 additions and 184 deletions

View File

@@ -0,0 +1,23 @@
exclude: ^tests/ref/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-illegal-windows-names
- id: check-shebang-scripts-are-executable
- id: check-yaml
- id: end-of-file-fixer
- id: fix-byte-order-marker
- id: mixed-line-ending
- id: trailing-whitespace
- repo: local
hooks:
- id: aarch64-asm-indent
name: fix aarch64 assembly indentation
files: ^.*/aarch64/.*\.S$
language: script
entry: ./tools/check_arm_indent.sh --apply
pass_filenames: false

View File

@@ -0,0 +1,29 @@
name: Lint
on:
push:
branches:
- release/7.1
pull_request:
jobs:
lint:
name: Pre-Commit
runs-on: utilities
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pre-commit CI
id: install
run: |
python3 -m venv ~/pre-commit
~/pre-commit/bin/pip install --upgrade pip setuptools
~/pre-commit/bin/pip install pre-commit
echo "envhash=$({ python3 --version && cat .forgejo/pre-commit/config.yaml; } | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
- name: Cache
uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ steps.install.outputs.envhash }}
- name: Run pre-commit CI
run: ~/pre-commit/bin/pre-commit run -c .forgejo/pre-commit/config.yaml --show-diff-on-failure --color=always --all-files

View File

@@ -0,0 +1,80 @@
name: Test
on:
push:
branches:
- release/7.1
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'
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure
run: |
./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 \
$([ "${{ 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=$? && CFGRES=$?
cat ffbuild/config.log
exit $CFGRES
- name: Build
run: make -j$(nproc)
- name: Restore Cached Fate-Suite
id: cache
uses: actions/cache/restore@v4
with:
path: fate-suite
key: fate-suite
restore-keys: |
fate-suite-
- name: Sync Fate-Suite
id: fate
run: |
make fate-rsync SAMPLES=$PWD/fate-suite
echo "hash=$(find fate-suite -type f -printf "%P %s %T@\n" | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
- name: Cache Fate-Suite
uses: actions/cache/save@v4
if: ${{ format('fate-suite-{0}', steps.fate.outputs.hash) != steps.cache.outputs.cache-matched-key }}
with:
path: fate-suite
key: fate-suite-${{ steps.fate.outputs.hash }}
- name: Run Fate
run: LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES=$PWD/fate-suite -j$(nproc)
compile_only:
name: Fate (Win64, Build-Only)
strategy:
fail-fast: false
matrix:
image: ["ghcr.io/btbn/ffmpeg-builds/win64-gpl-7.1:latest"]
runs-on: linux-amd64
container: ${{ matrix.image }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure
run: |
./configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \
--cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" --nm="$NM" \
--extra-cflags="$FF_CFLAGS" --extra-cxxflags="$FF_CXXFLAGS" \
--extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" --extra-ldexeflags="$FF_LDEXEFLAGS"
- name: Build
run: make -j$(nproc)
- name: Run Fate
run: make -j$(nproc) fate-build

View File

@@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
@@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -158,7 +158,7 @@ Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
@@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
@@ -267,7 +267,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
@@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
@@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
@@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
@@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest

14
configure vendored
View File

@@ -6905,8 +6905,8 @@ enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d
enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open
enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
enabled libdrm && check_pkg_config libdrm libdrm xf86drm.h drmGetVersion
enabled libdvdnav && require_pkg_config libdvdnav "dvdnav >= 6.1.1" dvdnav/dvdnav.h dvdnav_open2
enabled libdvdread && require_pkg_config libdvdread "dvdread >= 6.1.2" dvdread/dvd_reader.h DVDOpen2
enabled libdvdnav && require_pkg_config libdvdnav "dvdnav >= 6.1.0" dvdnav/dvdnav.h dvdnav_open2
enabled libdvdread && require_pkg_config libdvdread "dvdread >= 6.1.1" dvdread/dvd_reader.h DVDOpen2
enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen ||
{ require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac &&
warn "using libfdk without pkg-config"; } }
@@ -6917,12 +6917,16 @@ enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontco
enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType
enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info
enabled libharfbuzz && require_pkg_config libharfbuzz harfbuzz hb.h hb_buffer_create
enabled libglslang && { check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
if enabled libglslang; then
spvremap="-lSPVRemapper"
require_headers "glslang/build_info.h" && { test_cpp_condition glslang/build_info.h "GLSLANG_VERSION_MAJOR >= 16" && spvremap="" ; }
check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lGenericCodeGen \
-lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ||
${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ||
require spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lOSDependent -lHLSL -lOGLCompiler -lGenericCodeGen \
-lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ; }
${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ;
fi
enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu ||
require libgme gme/gme.h gme_new_emu -lgme -lstdc++; }
enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do

View File

@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07
API changes, most recent first:
2025-09-xx - xxxxxxxxxx - lavfi 10.5.100 - buffersrc.h
Add av_buffersrc_get_status().
2024-09-23 - 6940a6de2f0 - lavu 59.38.100 - frame.h
Add AV_FRAME_DATA_VIEW_ID.

View File

@@ -63,4 +63,3 @@ make -j<num>
make -k
Continue build in case of errors, this is useful for the regression tests
sometimes but note that it will still not run all reg tests.

View File

@@ -96,4 +96,3 @@ IRC:
~~~~
irc channels are at https://libera.chat/
irc channel archives are at https://libera.irclog.whitequark.org

View File

@@ -157,4 +157,3 @@ PFD[32] would for example be signed 32 bit little-endian IEEE float
@item XVID @tab non-compliant MPEG-4 generated by old Xvid
@item XVIX @tab non-compliant MPEG-4 generated by old Xvid with interlacing bug
@end multitable

0
doc/texi2pod.pl Normal file → Executable file
View File

0
doc/texidep.pl Normal file → Executable file
View File

View File

@@ -44,4 +44,3 @@ a+b*c;
here the reader knows that a,b,c are meant to be signed integers but for C
standard compliance / to avoid undefined behavior they are stored in unsigned
ints.

View File

@@ -2365,6 +2365,18 @@ finish:
fps->dropped_keyframe |= fps->last_dropped && (frame->flags & AV_FRAME_FLAG_KEY);
}
static void close_input(FilterGraph *fg, int input_idx)
{
InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[input_idx]);
FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph);
if (!ifp->eof) {
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx);
ifp->eof = 1;
}
}
static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt)
{
FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph);
@@ -3035,7 +3047,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);
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx);
close_input(fg, input_idx);
continue;
}
if (ret < 0)
@@ -3052,6 +3064,13 @@ 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->filter))
close_input(fg, i);
}
}
for (unsigned i = 0; i < fg->nb_outputs; i++) {

View File

@@ -46,7 +46,6 @@ OBJS = ac3_parser.o \
get_buffer.o \
imgconvert.o \
jni.o \
lcevcdec.o \
mathtables.o \
mediacodec.o \
mpeg12framerate.o \
@@ -124,6 +123,7 @@ OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o
OBJS-$(CONFIG_JNI) += ffjni.o jni.o
OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o
OBJS-$(CONFIG_LCMS2) += fflcms2.o
OBJS-$(CONFIG_LIBLCEVC_DEC) += lcevcdec.o
OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o
OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o
OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o

View File

@@ -48,4 +48,3 @@ function ff_scalarproduct_int16_neon, export=1
vmov.32 r0, d3[0]
bx lr
endfunc

View File

@@ -88,4 +88,3 @@ const FFCodec ff_cljr_decoder = {
FF_CODEC_DECODE_CB(decode_frame),
.p.capabilities = AV_CODEC_CAP_DR1,
};

View File

@@ -92,10 +92,14 @@ typedef struct DecodeContext {
*/
uint64_t side_data_pref_mask;
FFLCEVCContext *lcevc;
int lcevc_frame;
int width;
int height;
#if CONFIG_LIBLCEVC_DEC
struct {
FFLCEVCContext *ctx;
int frame;
int width;
int height;
} lcevc;
#endif
} DecodeContext;
static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1657,26 +1661,29 @@ int ff_attach_decode_data(AVFrame *frame)
static void update_frame_props(AVCodecContext *avctx, AVFrame *frame)
{
#if CONFIG_LIBLCEVC_DEC
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
dc->lcevc_frame = dc->lcevc && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
dc->lcevc.frame = dc->lcevc.ctx && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
if (dc->lcevc_frame) {
dc->width = frame->width;
dc->height = frame->height;
if (dc->lcevc.frame) {
dc->lcevc.width = frame->width;
dc->lcevc.height = frame->height;
frame->width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
}
#endif
}
static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
{
#if CONFIG_LIBLCEVC_DEC
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
if (dc->lcevc_frame) {
if (dc->lcevc.frame) {
FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
FFLCEVCFrame *frame_ctx;
int ret;
@@ -1691,13 +1698,13 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
return AVERROR(ENOMEM);
}
frame_ctx->lcevc = ff_refstruct_ref(dc->lcevc);
frame_ctx->lcevc = ff_refstruct_ref(dc->lcevc.ctx);
frame_ctx->frame->width = frame->width;
frame_ctx->frame->height = frame->height;
frame_ctx->frame->format = frame->format;
frame->width = dc->width;
frame->height = dc->height;
frame->width = dc->lcevc.width;
frame->height = dc->lcevc.height;
ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0);
if (ret < 0) {
@@ -1711,7 +1718,8 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame)
fdd->post_process_opaque_free = ff_lcevc_unref;
fdd->post_process = ff_lcevc_process;
}
dc->lcevc_frame = 0;
dc->lcevc.frame = 0;
#endif
return 0;
}
@@ -2084,9 +2092,13 @@ int ff_decode_preinit(AVCodecContext *avctx)
return ret;
if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
ret = ff_lcevc_alloc(&dc->lcevc);
if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return ret;
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
#if CONFIG_LIBLCEVC_DEC
ret = ff_lcevc_alloc(&dc->lcevc.ctx);
if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return ret;
#endif
}
}
#if FF_API_DROPCHANGED
@@ -2331,13 +2343,17 @@ void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext *src)
dst_dc->initial_pict_type = src_dc->initial_pict_type;
dst_dc->intra_only_flag = src_dc->intra_only_flag;
ff_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc);
#if CONFIG_LIBLCEVC_DEC
ff_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx);
#endif
}
void ff_decode_internal_uninit(AVCodecContext *avctx)
{
#if CONFIG_LIBLCEVC_DEC
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
ff_refstruct_unref(&dc->lcevc);
ff_refstruct_unref(&dc->lcevc.ctx);
#endif
}

View File

@@ -337,4 +337,3 @@ const AVDVProfile *av_dv_codec_profile2(int width, int height,
return p;
}

View File

@@ -50,4 +50,3 @@ static inline int RENAME(get_context)(const int16_t quant_table[MAX_CONTEXT_INPU
quant_table[1][(LT - T) & MAX_QUANT_TABLE_MASK] +
quant_table[2][(T - RT) & MAX_QUANT_TABLE_MASK];
}

View File

@@ -208,4 +208,3 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc,
}
return 0;
}

View File

@@ -162,4 +162,3 @@ static void MCFUNC(hl_motion)(const H264Context *h, H264SliceContext *sl,
if (USES_LIST(mb_type, 1))
prefetch_motion(h, sl, 1, PIXEL_SHIFT, CHROMA_IDC);
}

View File

@@ -1512,4 +1512,3 @@ void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_si
case 0: lc->pu.mvd.y = 0; break;
}
}

View File

@@ -45,4 +45,3 @@ enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *p
*loss_ptr = loss;
return best;
}

View File

@@ -16,8 +16,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config_components.h"
#include "libavutil/avassert.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
@@ -26,7 +24,6 @@
#include "decode.h"
#include "lcevcdec.h"
#if CONFIG_LIBLCEVC_DEC
static LCEVC_ColorFormat map_format(int format)
{
switch (format) {
@@ -50,13 +47,12 @@ static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
{
LCEVC_PictureDesc desc;
LCEVC_ColorFormat fmt = map_format(frame->format);
LCEVC_PictureLockHandle lock;
uint8_t *data[4] = { NULL };
int linesizes[4] = { 0 };
uint32_t planes;
LCEVC_PicturePlaneDesc planes[AV_VIDEO_MAX_PLANES] = { 0 };
int width = frame->width - frame->crop_left - frame->crop_right;
int height = frame->height - frame->crop_top - frame->crop_bottom;
LCEVC_ReturnCode res;
res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
@@ -67,36 +63,16 @@ static int alloc_base_frame(void *logctx, FFLCEVCContext *lcevc,
desc.sampleAspectRatioNum = frame->sample_aspect_ratio.num;
desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den;
for (int i = 0; i < AV_VIDEO_MAX_PLANES; i++) {
planes[i].firstSample = frame->data[i];
planes[i].rowByteStride = frame->linesize[i];
}
/* Allocate LCEVC Picture */
res = LCEVC_AllocPicture(lcevc->decoder, &desc, picture);
res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture);
if (res != LCEVC_Success) {
return AVERROR_EXTERNAL;
}
res = LCEVC_LockPicture(lcevc->decoder, *picture, LCEVC_Access_Write, &lock);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
res = LCEVC_GetPicturePlaneCount(lcevc->decoder, *picture, &planes);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
for (unsigned i = 0; i < planes; i++) {
LCEVC_PicturePlaneDesc plane;
res = LCEVC_GetPictureLockPlaneDesc(lcevc->decoder, lock, i, &plane);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
data[i] = plane.firstSample;
linesizes[i] = plane.rowByteStride;
}
av_image_copy2(data, linesizes, frame->data, frame->linesize,
frame->format, frame->width, frame->height);
res = LCEVC_UnlockPicture(lcevc->decoder, lock);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
return 0;
}
@@ -132,6 +108,7 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
{
FFLCEVCContext *lcevc = frame_ctx->lcevc;
const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
AVFrame *opaque;
LCEVC_PictureHandle picture;
LCEVC_ReturnCode res;
int ret = 0;
@@ -139,7 +116,11 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
if (!sd)
return 1;
#ifdef LCEVC_DEC_VERSION_MAJOR
res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, sd->data, sd->size);
#else
res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
#endif
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
@@ -147,9 +128,29 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
if (ret < 0)
return ret;
res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
if (res != LCEVC_Success)
opaque = av_frame_clone(in);
if (!opaque) {
LCEVC_FreePicture(lcevc->decoder, picture);
return AVERROR(ENOMEM);
}
res = LCEVC_SetPictureUserData(lcevc->decoder, picture, opaque);
if (res != LCEVC_Success) {
LCEVC_FreePicture(lcevc->decoder, picture);
av_frame_free(&opaque);
return AVERROR_EXTERNAL;
}
#ifdef LCEVC_DEC_VERSION_MAJOR
res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, opaque);
#else
res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, opaque);
#endif
if (res != LCEVC_Success) {
LCEVC_FreePicture(lcevc->decoder, picture);
av_frame_free(&opaque);
return AVERROR_EXTERNAL;
}
memset(&picture, 0, sizeof(picture));
ret = alloc_enhanced_frame(logctx, frame_ctx, &picture);
@@ -157,8 +158,10 @@ static int lcevc_send_frame(void *logctx, FFLCEVCFrame *frame_ctx, const AVFrame
return ret;
res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
if (res != LCEVC_Success)
if (res != LCEVC_Success) {
LCEVC_FreePicture(lcevc->decoder, picture);
return AVERROR_EXTERNAL;
}
return 0;
}
@@ -176,8 +179,14 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
return AVERROR_EXTERNAL;
res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
if (res != LCEVC_Success)
if (res != LCEVC_Success) {
LCEVC_FreePicture(lcevc->decoder, picture);
return AVERROR_EXTERNAL;
}
av_frame_unref(out);
av_frame_copy_props(frame_ctx->frame, (AVFrame *)info.baseUserData);
av_frame_move_ref(out, frame_ctx->frame);
out->crop_top = desc.cropTop;
out->crop_bottom = desc.cropBottom;
@@ -185,11 +194,6 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
out->crop_right = desc.cropRight;
out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
av_frame_copy_props(frame_ctx->frame, out);
av_frame_unref(out);
av_frame_move_ref(out, frame_ctx->frame);
out->width = desc.width + out->crop_left + out->crop_right;
out->height = desc.height + out->crop_top + out->crop_bottom;
@@ -200,18 +204,13 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
return 0;
}
static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
static int lcevc_flush_pictures(FFLCEVCContext *lcevc)
{
FFLCEVCContext *lcevc = frame_ctx->lcevc;
LCEVC_PictureHandle picture;
LCEVC_ReturnCode res;
int ret;
ret = generate_output(logctx, frame_ctx, out);
if (ret < 0)
return ret;
while (1) {
AVFrame *base = NULL;
res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
if (res != LCEVC_Success && res != LCEVC_Again)
return AVERROR_EXTERNAL;
@@ -219,6 +218,9 @@ static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *o
if (res == LCEVC_Again)
break;
LCEVC_GetPictureUserData(lcevc->decoder, picture, (void **)&base);
av_frame_free(&base);
res = LCEVC_FreePicture(lcevc->decoder, picture);
if (res != LCEVC_Success)
return AVERROR_EXTERNAL;
@@ -227,6 +229,18 @@ static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *o
return 0;
}
static int lcevc_receive_frame(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out)
{
FFLCEVCContext *lcevc = frame_ctx->lcevc;
int ret;
ret = generate_output(logctx, frame_ctx, out);
if (ret < 0)
return ret;
return lcevc_flush_pictures(lcevc);
}
static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
const uint8_t *data, uint32_t size, void *logctx)
@@ -243,15 +257,16 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
static void lcevc_free(FFRefStructOpaque unused, void *obj)
{
FFLCEVCContext *lcevc = obj;
if (lcevc->initialized)
if (lcevc->initialized) {
LCEVC_FlushDecoder(lcevc->decoder);
lcevc_flush_pictures(lcevc);
LCEVC_DestroyDecoder(lcevc->decoder);
}
memset(lcevc, 0, sizeof(*lcevc));
}
#endif
static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
{
#if CONFIG_LIBLCEVC_DEC
LCEVC_AccelContextHandle dummy = { 0 };
const int32_t event = LCEVC_Log;
@@ -270,7 +285,6 @@ static int lcevc_init(FFLCEVCContext *lcevc, void *logctx)
return AVERROR_EXTERNAL;
}
#endif
lcevc->initialized = 1;
return 0;
@@ -289,7 +303,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
return ret;
}
#if CONFIG_LIBLCEVC_DEC
av_assert0(frame_ctx->frame);
@@ -297,12 +310,11 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
if (ret)
return ret < 0 ? ret : 0;
lcevc_receive_frame(logctx, frame_ctx, frame);
ret = lcevc_receive_frame(logctx, frame_ctx, frame);
if (ret < 0)
return ret;
av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
#endif
return 0;
}
@@ -310,11 +322,9 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
int ff_lcevc_alloc(FFLCEVCContext **plcevc)
{
FFLCEVCContext *lcevc = NULL;
#if CONFIG_LIBLCEVC_DEC
lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
if (!lcevc)
return AVERROR(ENOMEM);
#endif
*plcevc = lcevc;
return 0;
}

View File

@@ -369,4 +369,3 @@ void RENAME(ff_imdct36_blocks)(INTFLOAT *out, INTFLOAT *buf, INTFLOAT *in,
out++;
}
}

View File

@@ -778,4 +778,3 @@ static const FFCodecDefault mp2_defaults[] = {
{ "b", "0" },
{ NULL },
};

View File

@@ -282,4 +282,3 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64],
}
}
}

View File

@@ -336,4 +336,3 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n,
*dc_val_ptr = &dc_val[0];
return pred;
}

View File

@@ -466,4 +466,3 @@ fail:
av_channel_layout_uninit(&layout);
return ret;
}

View File

@@ -858,5 +858,3 @@ av_cold void ff_dwt_init(SnowDWTContext *c)
ff_dwt_init_x86(c);
#endif
}

View File

@@ -46,7 +46,6 @@
#include "decode.h"
#include "get_bits.h"
#include "hpeldsp.h"
#include "internal.h"
#include "jpegquanttables.h"
#include "mathops.h"
#include "progressframe.h"
@@ -2458,7 +2457,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
}
}
if (!avctx->internal->is_copy) {
if (ff_thread_sync_ref(avctx, offsetof(Vp3DecodeContext, coeff_vlc)) != FF_THREAD_IS_COPY) {
CoeffVLCs *vlcs = ff_refstruct_alloc_ext(sizeof(*s->coeff_vlc), 0,
NULL, free_vlc_tables);
if (!vlcs)
@@ -2527,8 +2526,6 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *
const Vp3DecodeContext *s1 = src->priv_data;
int qps_changed = 0;
ff_refstruct_replace(&s->coeff_vlc, s1->coeff_vlc);
// copy previous frame data
ref_frames(s, s1);
if (!s1->current_frame.f ||

View File

@@ -693,4 +693,3 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in
ff_vvc_ctu_free_cus(fc->tab.cus + rs);
return ret;
}

View File

@@ -85,4 +85,3 @@ cglobal int32_to_float_fmul_array8, 5, 5, 5, c, dst, src, mul, len
INIT_XMM sse2
INT32_TO_FLOAT_FMUL_ARRAY8

View File

@@ -104,4 +104,3 @@ cglobal pix_norm1, 2, 3, %1
INIT_XMM sse2
PIX_NORM1 6, 8

View File

@@ -122,4 +122,3 @@ ff_bwdif_init_aarch64(BWDIFDSPContext *s, int bit_depth)
s->filter_edge = filter_edge_helper;
s->filter_line3 = filter_line3_helper;
}

View File

@@ -77,7 +77,7 @@ static int query_formats(AVFilterContext *ctx)
AVChannelLayout *inlayout[SWR_CH_MAX] = { NULL }, outlayout = { 0 };
uint64_t outmask = 0;
AVFilterChannelLayouts *layouts;
int i, ret, overlap = 0, nb_ch = 0;
int i, ret, nb_ch = 0;
for (i = 0; i < s->nb_inputs; i++) {
if (!ctx->inputs[i]->incfg.channel_layouts ||
@@ -92,15 +92,11 @@ static int query_formats(AVFilterContext *ctx)
av_channel_layout_describe(inlayout[i], buf, sizeof(buf));
av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
}
s->in[i].nb_ch = FF_LAYOUT2COUNT(inlayout[i]);
if (s->in[i].nb_ch) {
overlap++;
} else {
s->in[i].nb_ch = inlayout[i]->nb_channels;
if (av_channel_layout_subset(inlayout[i], outmask))
overlap++;
outmask |= inlayout[i]->order == AV_CHANNEL_ORDER_NATIVE ?
inlayout[i]->u.mask : 0;
s->in[i].nb_ch = inlayout[i]->nb_channels;
for (int j = 0; j < s->in[i].nb_ch; j++) {
enum AVChannel id = av_channel_layout_channel_from_index(inlayout[i], j);
if (id >= 0 && id < 64)
outmask |= (1ULL << id);
}
nb_ch += s->in[i].nb_ch;
}
@@ -108,7 +104,7 @@ static int query_formats(AVFilterContext *ctx)
av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
return AVERROR(EINVAL);
}
if (overlap) {
if (av_popcount64(outmask) != nb_ch) {
av_log(ctx, AV_LOG_WARNING,
"Input channel layouts overlap: "
"output layout will be determined by the number of distinct input channels\n");

View File

@@ -283,6 +283,16 @@ int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags)
return (flags & AV_BUFFERSRC_FLAG_PUSH) ? push_frame(ctx->graph) : 0;
}
int av_buffersrc_get_status(AVFilterContext *ctx)
{
BufferSourceContext *s = ctx->priv;
if (!s->eof && ff_outlink_get_status(ctx->outputs[0]))
s->eof = 1;
return s->eof ? AVERROR(EOF) : 0;
}
static av_cold int init_video(AVFilterContext *ctx)
{
BufferSourceContext *c = ctx->priv;

View File

@@ -208,6 +208,14 @@ int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src,
*/
int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags);
/**
* Returns 0 or a negative AVERROR code. Currently, this will only ever
* return AVERROR(EOF), to indicate that the buffer source has been closed,
* either as a result of av_buffersrc_close(), or because the downstream
* filter is no longer accepting new data.
*/
int av_buffersrc_get_status(AVFilterContext *ctx);
/**
* @}
*/

View File

@@ -137,4 +137,3 @@ const AVClass *ff_dnn_child_class_iterate_with_mask(void **iter, uint32_t backen
return NULL;
}

View File

@@ -248,7 +248,7 @@ static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
av_assert0(!fs->in[in].have_next);
av_assert0(frame);
pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
pts = av_rescale_q_rnd(frame->pts, fs->in[in].time_base, fs->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
frame->pts = pts;
fs->in[in].frame_next = frame;
fs->in[in].pts_next = pts;

View File

@@ -221,4 +221,3 @@ double ff_perlin_get(FFPerlin *perlin, double x, double y, double z)
return total / max_value;
}

View File

@@ -66,4 +66,3 @@ int ff_qp_table_extract(AVFrame *frame, int8_t **table, int *table_w, int *table
return 0;
}

View File

@@ -70,4 +70,3 @@ ff_scene_sad_fn ff_scene_sad_get_fn(int depth)
}
return sad;
}

View File

@@ -19,6 +19,10 @@
#ifndef AVFILTER_STACK_INTERNAL_H
#define AVFILTER_STACK_INTERNAL_H
#ifdef HWContext
#include "libavfilter/framesync.h"
enum {
STACK_H = 0,
STACK_V = 1,
@@ -57,4 +61,6 @@ static int stack_init(AVFilterContext *avctx);
static av_cold void stack_uninit(AVFilterContext *avctx);
static int stack_activate(AVFilterContext *avctx);
#endif
#endif /* AVFILTER_STACK_INTERNAL_H */

View File

@@ -380,4 +380,3 @@ int ff_load_textfile(void *log_ctx, const char *textfile,
return 0;
}

View File

@@ -31,7 +31,7 @@
#include "version_major.h"
#define LIBAVFILTER_VERSION_MINOR 4
#define LIBAVFILTER_VERSION_MINOR 5
#define LIBAVFILTER_VERSION_MICRO 100

View File

@@ -139,7 +139,11 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in)
return ret;
if (sd) {
#ifdef LCEVC_DEC_VERSION_MAJOR
res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, sd->data, sd->size);
#else
res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
#endif
if (res == LCEVC_Again)
return AVERROR(EAGAIN);
else if (res != LCEVC_Success) {
@@ -148,7 +152,18 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in)
}
}
res = LCEVC_SetPictureUserData(lcevc->decoder, picture, in);
if (res != LCEVC_Success) {
av_log(ctx, AV_LOG_ERROR, "LCEVC_SetPictureUserData failed\n");
LCEVC_FreePicture(lcevc->decoder, picture);
return AVERROR_EXTERNAL;
}
#ifdef LCEVC_DEC_VERSION_MAJOR
res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, picture, -1, in);
#else
res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, in);
#endif
if (res != LCEVC_Success) {
av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderBase failed\n");
LCEVC_FreePicture(lcevc->decoder, picture);
@@ -215,8 +230,6 @@ static int generate_output(AVFilterLink *inlink, AVFrame *out)
av_frame_copy_props(out, (AVFrame *)info.baseUserData);
av_frame_remove_side_data(out, AV_FRAME_DATA_LCEVC);
av_frame_free((AVFrame **)&info.baseUserData);
res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
LCEVC_FreePicture(lcevc->decoder, picture);
@@ -284,8 +297,12 @@ static void flush_bases(AVFilterContext *ctx)
LCEVCContext *lcevc = ctx->priv;
LCEVC_PictureHandle picture;
while (LCEVC_ReceiveDecoderBase(lcevc->decoder, &picture) == LCEVC_Success)
while (LCEVC_ReceiveDecoderBase(lcevc->decoder, &picture) == LCEVC_Success) {
AVFrame *base = NULL;
LCEVC_GetPictureUserData(lcevc->decoder, picture, (void **)&base);
LCEVC_FreePicture(lcevc->decoder, picture);
av_frame_free(&base);
}
}
static int activate(AVFilterContext *ctx)
@@ -399,6 +416,8 @@ static av_cold void uninit(AVFilterContext *ctx)
{
LCEVCContext *lcevc = ctx->priv;
LCEVC_FlushDecoder(lcevc->decoder);
flush_bases(ctx);
LCEVC_DestroyDecoder(lcevc->decoder);
}

View File

@@ -51,4 +51,3 @@ __global__ void Overlay_Cuda(
}
}

View File

@@ -182,4 +182,3 @@ const AVFilter ff_vf_quirc = {
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
AVFILTER_FLAG_METADATA_ONLY,
};

View File

@@ -1119,7 +1119,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
goto err;
av_assert0(out);
out->pts = av_rescale_q(fs->pts, fs->time_base, outlink->time_base);
out->pts = av_rescale_q_rnd(fs->pts, fs->time_base, outlink->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
return ff_filter_frame(outlink, out);
err:

View File

@@ -152,5 +152,3 @@ void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size,
t_cur = t_next;
}
}

View File

@@ -98,4 +98,3 @@ const FFInputFormat ff_g726le_demuxer = {
.raw_codec_id = AV_CODEC_ID_ADPCM_G726LE,
};
#endif

View File

@@ -63,4 +63,3 @@ int ff_hls_senc_parse_audio_setup_info(AVStream *st, HLSAudioSetupInfo *info);
int ff_hls_senc_decrypt_frame(enum AVCodecID codec_id, HLSCryptoContext *crypto_ctx, AVPacket *pkt);
#endif /* AVFORMAT_HLS_SAMPLE_ENCRYPTION_H */

View File

@@ -199,4 +199,3 @@ void ff_hls_write_end_list(AVIOContext *out)
return;
avio_printf(out, "#EXT-X-ENDLIST\n");
}

View File

@@ -22,6 +22,7 @@
#include "config.h"
#include "config_components.h"
#include <string.h>
#include <time.h>
#if CONFIG_ZLIB
#include <zlib.h>
@@ -212,7 +213,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
char *env_http_proxy, *env_no_proxy;
char *hashmark;
char hostname[1024], hoststr[1024], proto[10];
char hostname[1024], hoststr[1024], proto[10], tmp_host[1024];
char auth[1024], proxyauth[1024] = "";
char path1[MAX_URL_SIZE], sanitized_path[MAX_URL_SIZE + 1];
char buf[1024], urlbuf[MAX_URL_SIZE];
@@ -222,7 +223,14 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
av_url_split(proto, sizeof(proto), auth, sizeof(auth),
hostname, sizeof(hostname), &port,
path1, sizeof(path1), s->location);
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
av_strlcpy(tmp_host, hostname, sizeof(tmp_host));
// In case of an IPv6 address, we need to strip the Zone ID,
// if any. We do it at the first % sign, as percent encoding
// can be used in the Zone ID itself.
if (strchr(tmp_host, ':'))
tmp_host[strcspn(tmp_host, "%")] = '\0';
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, tmp_host, port, NULL);
env_http_proxy = getenv_utf8("http_proxy");
proxy_path = s->http_proxy ? s->http_proxy : env_http_proxy;

View File

@@ -398,6 +398,9 @@ static int scalable_channel_layout_config(void *s, AVIOContext *pb,
.nb_channels = substream_count +
coupled_substream_count };
if (i && layer->ch_layout.nb_channels <= audio_element->element->layers[i-1]->ch_layout.nb_channels)
return AVERROR_INVALIDDATA;
for (int j = 0; j < substream_count; j++) {
IAMFSubStream *substream = &audio_element->substreams[k++];
@@ -411,6 +414,9 @@ static int scalable_channel_layout_config(void *s, AVIOContext *pb,
}
if (k != audio_element->nb_substreams)
return AVERROR_INVALIDDATA;
return 0;
}
@@ -481,7 +487,7 @@ static int ambisonics_config(void *s, AVIOContext *pb,
return AVERROR(ENOMEM);
for (int i = 0; i < demixing_matrix_size; i++)
layer->demixing_matrix[i] = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8);
layer->demixing_matrix[i] = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 15);
for (int i = 0; i < substream_count; i++) {
IAMFSubStream *substream = &audio_element->substreams[i];

View File

@@ -583,11 +583,15 @@ static int ambisonics_config(const IAMFAudioElement *audio_element,
AVIOContext *dyn_bc)
{
const AVIAMFAudioElement *element = audio_element->celement;
const IAMFLayer *ilayer = &audio_element->layers[0];
const AVIAMFLayer *layer = element->layers[0];
if (audio_element->nb_substreams != ilayer->substream_count)
return AVERROR(EINVAL);
ffio_write_leb(dyn_bc, 0); // ambisonics_mode
ffio_write_leb(dyn_bc, layer->ch_layout.nb_channels); // output_channel_count
ffio_write_leb(dyn_bc, audio_element->nb_substreams); // substream_count
avio_w8(dyn_bc, layer->ch_layout.nb_channels); // output_channel_count
avio_w8(dyn_bc, audio_element->nb_substreams); // substream_count
if (layer->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC)
for (int i = 0; i < layer->ch_layout.nb_channels; i++)

View File

@@ -416,8 +416,10 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
char filename_bytes[1024];
char *filename = filename_bytes;
int i, res;
int size[3] = { 0 }, ret[3] = { 0 };
AVIOContext *f[3] = { NULL };
int ret[3] = { 0 };
int64_t size[3] = { 0 };
int64_t total_size;
AVIOContext *f[3] = { NULL };
AVCodecParameters *par = s1->streams[0]->codecpar;
if (!s->is_pipe) {
@@ -497,7 +499,17 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
}
res = av_new_packet(pkt, size[0] + size[1] + size[2]);
total_size = size[0];
if (total_size > INT64_MAX - size[1])
return AVERROR_INVALIDDATA;
total_size += size[1];
if (total_size > INT64_MAX - size[2])
return AVERROR_INVALIDDATA;
total_size += size[2];
if (total_size > INT_MAX)
return AVERROR_INVALIDDATA;
res = av_new_packet(pkt, total_size);
if (res < 0) {
goto fail;
}

View File

@@ -573,4 +573,3 @@ RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", AVMEDIA_TYPE_VIDEO);
RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO);
RDT_HANDLER(video, "x-pn-realvideo", AVMEDIA_TYPE_VIDEO);
RDT_HANDLER(audio, "x-pn-realaudio", AVMEDIA_TYPE_AUDIO);

View File

@@ -1205,9 +1205,12 @@ start:
q = buf;
for (;;) {
ret = ffurl_read_complete(rt->rtsp_hd, &ch, 1);
if (ret != 1) {
ret = (ret < 0) ? ret : AVERROR(EIO);
av_log(s, AV_LOG_WARNING, "Failed reading RTSP data: %s\n", av_err2str(ret));
return ret;
}
av_log(s, AV_LOG_TRACE, "ret=%d c=%02x [%c]\n", ret, ch, ch);
if (ret != 1)
return ret < 0 ? ret : AVERROR(EIO);
if (ch == '\n')
break;
if (ch == '$' && q == buf) {
@@ -1237,6 +1240,7 @@ start:
if (!strncmp(buf1, "RTSP/", 5)) {
get_word(buf1, sizeof(buf1), &p);
reply->status_code = atoi(buf1);
p += strspn(p, SPACE_CHARS);
av_strlcpy(reply->reason, p, sizeof(reply->reason));
} else {
av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method

View File

@@ -271,4 +271,3 @@ int av_aes_init(AVAES *a, const uint8_t *key, int key_bits, int decrypt)
return 0;
}

View File

@@ -36,4 +36,3 @@ struct AVCUDADeviceContextInternal {
};
#endif /* AVUTIL_HWCONTEXT_CUDA_INTERNAL_H */

View File

@@ -84,4 +84,3 @@ typedef struct AVQSVFramesContext {
} AVQSVFramesContext;
#endif /* AVUTIL_HWCONTEXT_QSV_H */

View File

@@ -191,4 +191,3 @@ int main(void)
return 0;
}

View File

@@ -30,7 +30,7 @@ function ff_resample_common_apply_filter_x4_float_neon, export=1
faddp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
faddp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
st1 {v0.s}[0], [x0], #4 // write accumulator
ret
ret
endfunc
function ff_resample_common_apply_filter_x8_float_neon, export=1
@@ -46,7 +46,7 @@ function ff_resample_common_apply_filter_x8_float_neon, export=1
faddp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
faddp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
st1 {v0.s}[0], [x0], #4 // write accumulator
ret
ret
endfunc
function ff_resample_common_apply_filter_x4_s16_neon, export=1
@@ -59,7 +59,7 @@ function ff_resample_common_apply_filter_x4_s16_neon, export=1
addp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
addp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
st1 {v0.s}[0], [x0], #4 // write accumulator
ret
ret
endfunc
function ff_resample_common_apply_filter_x8_s16_neon, export=1
@@ -73,5 +73,5 @@ function ff_resample_common_apply_filter_x8_s16_neon, export=1
addp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
addp v0.4s, v0.4s, v0.4s // pair adding of the 4x32-bit accumulated values
st1 {v0.s}[0], [x0], #4 // write accumulator
ret
ret
endfunc

View File

@@ -127,4 +127,3 @@ struct Resampler const swri_soxr_resampler={
create, destroy, process, flush, NULL /* set_compensation */, get_delay,
invert_initial_buffer, get_out_samples
};

View File

@@ -172,4 +172,3 @@ int swr_convert_frame(SwrContext *s,
return convert_frame(s, out, in);
}

View File

@@ -43,4 +43,3 @@ const char *swresample_license(void)
#define LICENSE_PREFIX "libswresample license: "
return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1];
}

View File

@@ -126,7 +126,7 @@
.endm
.macro load_chroma_yuv422p
load_chroma_yuv420p
load_chroma_yuv420p
.endm
.macro increment_nv12
@@ -136,7 +136,7 @@
.endm
.macro increment_nv21
increment_nv12
increment_nv12
.endm
.macro increment_yuv420p
@@ -182,7 +182,7 @@ function ff_\ifmt\()_to_\ofmt\()_neon, export=1
mov w8, w0 // w8 = width
2:
movi v5.8h, #4, lsl #8 // 128 * (1<<3)
load_chroma_\ifmt
load_chroma_\ifmt
sub v18.8h, v18.8h, v5.8h // U*(1<<3) - 128*(1<<3)
sub v19.8h, v19.8h, v5.8h // V*(1<<3) - 128*(1<<3)
sqdmulh v20.8h, v19.8h, v1.h[0] // V * v2r (R)
@@ -237,11 +237,11 @@ function ff_\ifmt\()_to_\ofmt\()_neon, export=1
add x15, x15, w16, sxtw // dst2 += padding2
.endif
add x4, x4, w5, sxtw // srcY += paddingY
increment_\ifmt
increment_\ifmt
subs w1, w1, #1 // height -= 1
b.gt 1b
mov w0, w9
ret
ret
endfunc
.endm

View File

@@ -70,4 +70,3 @@ int ff_init_gamma_convert(SwsFilterDescriptor *desc, SwsSlice * src, uint16_t *t
return 0;
}

View File

@@ -319,5 +319,3 @@ void ff_init_vscale_pfn(SwsContext *c,
lumCtx->pfn.yuv2anyX = yuv2anyX;
}
}

View File

@@ -111,4 +111,3 @@ outpoint 00:00.40
file %SRCFILE%
inpoint 00:00.40

View File

@@ -128,6 +128,11 @@ fate-ffmpeg-fix_sub_duration_heartbeat: CMD = fmtstdout srt -fix_sub_duration \
-c:v mpeg2video -b:v 2M -g 30 -sc_threshold 1000000000 \
-c:s srt \
-f null -
# FIXME: disabling comparison against reference as after ffmpeg multithreading
# went in, this test started depending on how far the input side
# progressed compared to how quickly the output encoded packets,
# causing spurious failures on the CI.
fate-ffmpeg-fix_sub_duration_heartbeat: CMP = null
# FIXME: the integer AAC decoder does not produce the same output on all platforms
# so until that is fixed we use the volume filter to silence the data

View File

@@ -25,4 +25,3 @@ FATE_FFPROBE-$(call FILTERDEMDECENCMUX, AEVALSRC TESTSRC ARESAMPLE, FFMETADATA,
+= $(FFPROBE_TEST_FILE_TESTS-yes)
fate-ffprobe: $(FATE_FFPROBE-yes)

View File

@@ -36,4 +36,3 @@ FATE_SAMPLES_LOSSLESS_AUDIO += $(FATE_SAMPLES_LOSSLESS_AUDIO-yes)
FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_LOSSLESS_AUDIO)
fate-lossless-audio: $(FATE_SAMPLES_LOSSLESS_AUDIO)

View File

@@ -9,4 +9,3 @@ file %SRCFILE%
inpoint 00:00.20
outpoint 00:00.40
file_packet_meta dummy 1

View File

@@ -18,4 +18,3 @@ inpoint 00:02.20
file %SRCFILE%
inpoint 00:01.80
outpoint 00:02.00

55
tools/check_arm_indent.sh Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/sh
#
# Copyright (c) 2025 Martin Storsjo
# All rights reserved.
#
# 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.
cd $(dirname $0)/..
if [ "$1" = "--apply" ]; then
apply=1
fi
ret=0
for i in */aarch64/*.S */aarch64/*/*.S; do
case $i in
libavcodec/aarch64/h264idct_neon.S|libavcodec/aarch64/h26x/epel_neon.S|libavcodec/aarch64/h26x/qpel_neon.S|libavcodec/aarch64/vc1dsp_neon.S)
# Skip files with known (and tolerated) deviations from the tool.
continue
esac
./tools/indent_arm_assembly.pl < "$i" > tmp.S || ret=$?
if ! git diff --quiet --no-index "$i" tmp.S; then
if [ -n "$apply" ]; then
mv tmp.S "$i"
else
git --no-pager diff --no-index "$i" tmp.S
fi
ret=1
fi
done
rm -f tmp.S
exit $ret

243
tools/indent_arm_assembly.pl Executable file
View File

@@ -0,0 +1,243 @@
#!/usr/bin/env perl
#
# Copyright (c) 2025 Martin Storsjo
# All rights reserved.
#
# 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.
# A script for reformatting ARM/AArch64 assembly according to the following
# style:
# - Instructions start after 8 columns, operands start after 24 columns
# - Vector register layouts and modifiers like "uxtw" are written in lowercase
# - Optionally align operand columns vertically according to their
# maximum width (accommodating for e.g. x0 vs x10, or v0.8b vs v16.16b).
#
# The script can be executed as "indent_arm_assembly.pl file [outfile]".
# If no outfile is specified, the given file is overwritten in place.
#
# Alternatively, the if no file parameters are given, the script reads input
# code on stdin, and outputs the reformatted code on stdout.
use strict;
my $indent_operands = 0;
my $instr_indent = 8;
my $operand_indent = 24;
my $match_indent = 0;
my $file;
my $outfile;
while (@ARGV) {
my $opt = shift;
if ($opt eq "-operands") {
$indent_operands = 1;
} elsif ($opt eq "-indent") {
$instr_indent = shift;
} elsif ($opt eq "-operand-indent") {
$operand_indent = shift;
} elsif ($opt eq "-match-indent") {
$match_indent = 1;
} else {
if (!$file) {
$file = $opt;
} elsif (!$outfile) {
$outfile = $opt;
} else {
die "Unrecognized parameter $opt\n";
}
}
}
if ($operand_indent < $instr_indent) {
die "Can't indent operands to $operand_indent while indenting " .
"instructions to $instr_indent\n";
}
# Return a string consisting of n spaces
sub spaces {
my $n = $_[0];
return " " x $n;
}
sub indentcolumns {
my $input = $_[0];
my $chars = $_[1];
my @operands = split(/,/, $input);
my $num = @operands;
my $ret = "";
for (my $i = 0; $i < $num; $i++) {
my $cur = $operands[$i];
# Trim out leading/trailing whitespace
$cur =~ s/^\s+|\s+$//g;
$ret .= $cur;
if ($i + 1 < $num) {
# If we have a following operand, add a comma and whitespace to
# align the next operand.
my $next = $operands[$i+1];
my $len = length($cur);
if ($len > $chars) {
# If this operand was too wide for the intended column width,
# don't try to realign the line at all, just return the input
# untouched.
return $input;
}
my $pad = $chars - $len;
if ($next =~ /[su]xt[bhw]|[la]s[lr]/) {
# If the next item isn't a regular operand, but a modifier,
# don't try to align that. E.g. "add x0, x0, w1, uxtw #1".
$pad = 0;
}
$ret .= "," . spaces(1 + $pad);
}
}
return $ret;
}
# Realign the operands part of an instruction line, making each operand
# take up the maximum width for that kind of operand.
sub columns {
my $rest = $_[0];
if ($rest !~ /,/) {
# No commas, no operands to split and align
return $rest;
}
if ($rest =~ /{|[^\w]\[/) {
# Check for instructions that use register ranges, like {v0.8b,v1.8b}
# or mem address operands, like "ldr x0, [sp]" - we skip trying to
# realign these.
return $rest;
}
if ($rest =~ /v[0-9]+\.[0-9]+[bhsd]/) {
# If we have references to aarch64 style vector registers, like
# v0.8b, then align all operands to the maximum width of such
# operands - v16.16b.
#
# TODO: Ideally, we'd handle mixed operand types individually.
return indentcolumns($rest, 7);
}
# Indent operands according to the maximum width of regular registers,
# like x10.
return indentcolumns($rest, 3);
}
my $in;
my $out;
my $tempfile;
if ($file) {
open(INPUT, "$file") or die "Unable to open $file: $!";
$in = *INPUT;
if ($outfile) {
open(OUTPUT, ">$outfile") or die "Unable to open $outfile: $!";
} else {
$tempfile = "$file.tmp";
open(OUTPUT, ">$tempfile") or die "Unable to open $tempfile: $!";
}
$out = *OUTPUT;
} else {
$in = *STDIN;
$out = *STDOUT;
}
while (<$in>) {
# Trim off trailing whitespace.
chomp;
if (/^([\.\w\d]+:)?(\s+)([\w\\][\w\\\.]*)(?:(\s+)(.*)|$)/) {
my $label = $1;
my $indent = $2;
my $instr = $3;
my $origspace = $4;
my $rest = $5;
my $orig_operand_indent = length($label) + length($indent) +
length($instr) + length($origspace);
if ($indent_operands) {
$rest = columns($rest);
}
my $size = $instr_indent;
if ($match_indent) {
# Try to check the current attempted indent size and normalize
# to it; match existing ident sizes of 4, 8, 10 and 12 columns.
my $cur_indent = length($label) + length($indent);
if ($cur_indent >= 3 && $cur_indent <= 5) {
$size = 4;
} elsif ($cur_indent >= 7 && $cur_indent <= 9) {
$size = 8;
} elsif ($cur_indent == 10 || $cur_indent == 12) {
$size = $cur_indent;
}
}
if (length($label) >= $size) {
# Not enough space for the label; just add a space between the label
# and the instruction.
$indent = " ";
} else {
$indent = spaces($size - length($label));
}
my $instr_end = length($label) + length($indent) + length($instr);
$size = $operand_indent - $instr_end;
if ($match_indent) {
# Check how the operands currently seem to be indented.
my $cur_indent = $orig_operand_indent;
if ($cur_indent >= 11 && $cur_indent <= 13) {
$size = 12;
} elsif ($cur_indent >= 14 && $cur_indent <= 17) {
$size = 16;
} elsif ($cur_indent >= 18 && $cur_indent <= 22) {
$size = 20;
} elsif ($cur_indent >= 23 && $cur_indent <= 27) {
$size = 24;
}
$size -= $instr_end;
}
my $operand_space = " ";
if ($size > 0) {
$operand_space = spaces($size);
}
# Lowercase the aarch64 vector layout description, .8B -> .8b
$rest =~ s/(\.[84216]*[BHSD])/lc($1)/ge;
# Lowercase modifiers like "uxtw" or "lsl"
$rest =~ s/([SU]XT[BWH]|[LA]S[LR])/lc($1)/ge;
# Reassemble the line
if ($rest eq "") {
$_ = $label . $indent . $instr;
} else {
$_ = $label . $indent . $instr . $operand_space . $rest;
}
}
print $out $_ . "\n";
}
if ($file) {
close(INPUT);
close(OUTPUT);
}
if ($tempfile) {
rename($tempfile, $file);
}